|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Copyright (c) 2010-2011, Red Hat, Inc.
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
* Permission to use, copy, modify, and/or distribute this software for any
|
|
Packit |
61cb5a |
* purpose with or without fee is hereby granted, provided that the above
|
|
Packit |
61cb5a |
* copyright notice and this permission notice appear in all copies.
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
* THE SOFTWARE IS PROVIDED "AS IS" AND RED HAT, INC. DISCLAIMS ALL WARRANTIES
|
|
Packit |
61cb5a |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
Packit |
61cb5a |
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RED HAT, INC. BE LIABLE
|
|
Packit |
61cb5a |
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit |
61cb5a |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
Packit |
61cb5a |
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
Packit |
61cb5a |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Author: Jan Friesse <jfriesse@redhat.com>
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <arpa/inet.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <netinet/in.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#ifdef __sun
|
|
Packit |
61cb5a |
#include <alloca.h>
|
|
Packit |
61cb5a |
#endif /* __sun */
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <err.h>
|
|
Packit |
61cb5a |
#define __STDC_FORMAT_MACROS
|
|
Packit |
61cb5a |
#include <inttypes.h>
|
|
Packit |
61cb5a |
#include <stdio.h>
|
|
Packit |
61cb5a |
#include <stdlib.h>
|
|
Packit |
61cb5a |
#include <string.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include "addrfunc.h"
|
|
Packit |
61cb5a |
#include "logging.h"
|
|
Packit |
61cb5a |
#include "omping.h"
|
|
Packit |
61cb5a |
#include "tlv.h"
|
|
Packit |
61cb5a |
#include "util.h"
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int tlv_add_actual_ts(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int tlv_add_sas(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt,
|
|
Packit |
61cb5a |
const struct sockaddr_storage *sas, int store_prefix_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int tlv_add_ts(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt,
|
|
Packit |
61cb5a |
struct timeval *tv);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int tlv_add_u8(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt,
|
|
Packit |
61cb5a |
uint8_t val);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add option opt_type with length opt_len and value to message msg with msg_len length to position
|
|
Packit |
61cb5a |
* pos. Position is automatically adjusted to new position, so subsequent calls of function add
|
|
Packit |
61cb5a |
* new option to correct position. Function returns 0 on success, otherwise -1.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt_type, uint16_t opt_len,
|
|
Packit |
61cb5a |
const void *value)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t nlen;
|
|
Packit |
61cb5a |
uint16_t nopt_type;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("Add option %"PRIu16" with len %"PRIu16" pos %zu", opt_type, opt_len, *pos);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (*pos + sizeof(nopt_type) + sizeof(nlen) + opt_len > msg_len) {
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("Can't store option. msg_len too small.");
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
nopt_type = ntohs((uint16_t)opt_type);
|
|
Packit |
61cb5a |
memcpy(msg + *pos, &nopt_type, sizeof(nopt_type));
|
|
Packit |
61cb5a |
*pos += sizeof(nopt_type);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
nlen = htons(opt_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(msg + *pos, &nlen, sizeof(nlen));
|
|
Packit |
61cb5a |
*pos += sizeof(nlen);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(msg + *pos, value, opt_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
*pos += opt_len;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with actual time stamp
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
tlv_add_actual_ts(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct timeval tv;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
tv = util_get_time();
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_add_ts(msg, msg_len, pos, opt, &tv));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with actual client time stamp
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_client_tstamp(char *msg, size_t msg_len, size_t *pos)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_add_actual_ts(msg, msg_len, pos, TLV_OPT_TYPE_CLIENT_TSTAMP));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with mcast group
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_mcast_grp(char *msg, size_t msg_len, size_t *pos, const struct sockaddr_storage *sas)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_add_sas(msg, msg_len, pos, TLV_OPT_TYPE_MCAST_GRP, sas, 0));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with mcast prefix
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_mcast_prefix(char *msg, size_t msg_len, size_t *pos, const struct sockaddr_storage *sas)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_add_sas(msg, msg_len, pos, TLV_OPT_TYPE_MCAST_PREFIX, sas, 1));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with option request option. Options are passed in opts array with opts_len length.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_opt_request(char *msg, size_t msg_len, size_t *pos, uint16_t *opts, size_t opts_len)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char *value;
|
|
Packit |
61cb5a |
size_t val_len;
|
|
Packit |
61cb5a |
unsigned int i;
|
|
Packit |
61cb5a |
uint16_t opt;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (opts_len == 0)
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
val_len = opts_len * sizeof(uint16_t);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
value = (char *)alloca(val_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
for (i = 0; i < opts_len; i++) {
|
|
Packit |
61cb5a |
opt = htons(opts[i]);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(value + i * sizeof(opt), &opt, sizeof(opt));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_add(msg, msg_len, pos, TLV_OPT_TYPE_OPT_REQUEST, val_len, value));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with sockaddr_storage ip address. If store_prefix_len is set, prefix length of address
|
|
Packit |
61cb5a |
* (always full prefix) is also stored.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
tlv_add_sas(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt,
|
|
Packit |
61cb5a |
const struct sockaddr_storage *sas, int store_prefix_len)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char *value;
|
|
Packit |
61cb5a |
void *addr_pointer;
|
|
Packit |
61cb5a |
size_t addr_len;
|
|
Packit |
61cb5a |
size_t opt_len;
|
|
Packit |
61cb5a |
uint16_t af;
|
|
Packit |
61cb5a |
uint8_t pref_len_val;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (sas->ss_family) {
|
|
Packit |
61cb5a |
case AF_INET:
|
|
Packit |
61cb5a |
af = AF_IANA_IP;
|
|
Packit |
61cb5a |
addr_len = sizeof(struct in_addr);
|
|
Packit |
61cb5a |
addr_pointer = &((struct sockaddr_in *)sas)->sin_addr;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case AF_INET6:
|
|
Packit |
61cb5a |
af = AF_IANA_IP6;
|
|
Packit |
61cb5a |
addr_len = sizeof(struct in6_addr);
|
|
Packit |
61cb5a |
addr_pointer = &((struct sockaddr_in6 *)sas)->sin6_addr;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Unknown sas family %d", sas->ss_family);
|
|
Packit |
61cb5a |
errx(1, "Unknown sas family %d", sas->ss_family);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
pref_len_val = addr_len * 8;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
opt_len = sizeof(af) + addr_len;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (store_prefix_len)
|
|
Packit |
61cb5a |
opt_len += sizeof(pref_len_val);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
value = (char *)alloca(opt_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
af = htons(af);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(value, &af, sizeof(af));
|
|
Packit |
61cb5a |
if (store_prefix_len)
|
|
Packit |
61cb5a |
memcpy(value + sizeof(af), &pref_len_val, sizeof(pref_len_val));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(value + sizeof(af) + (store_prefix_len ? sizeof(pref_len_val) : 0), addr_pointer,
|
|
Packit |
61cb5a |
addr_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_add(msg, msg_len, pos, opt, opt_len, value));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add sequence number TLV.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_seq_num(char *msg, size_t msg_len, size_t *pos, uint32_t seq)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint32_t nseq;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
nseq = htonl(seq);
|
|
Packit |
61cb5a |
return (tlv_add(msg, msg_len, pos, TLV_OPT_TYPE_SEQ_NUM, sizeof(nseq), &nseq));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with server info
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_server_info(char *msg, size_t msg_len, size_t *pos, const char *server_info)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
if (strlen(server_info) == 0)
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_add(msg, msg_len, pos, TLV_OPT_TYPE_SERVER_INFO, strlen(server_info),
|
|
Packit |
61cb5a |
server_info));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with actual server timestamp
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_server_tstamp(char *msg, size_t msg_len, size_t *pos)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_add_actual_ts(msg, msg_len, pos, TLV_OPT_TYPE_SERVER_TSTAMP));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add timestamp
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
tlv_add_ts(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt, struct timeval *tv)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char value[8];
|
|
Packit |
61cb5a |
uint32_t u32;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
u32 = tv->tv_sec;
|
|
Packit |
61cb5a |
u32 = htonl(u32);
|
|
Packit |
61cb5a |
memcpy(value, &u32, sizeof(u32));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
u32 = tv->tv_usec;
|
|
Packit |
61cb5a |
u32 = htonl(u32);
|
|
Packit |
61cb5a |
memcpy(value + sizeof(u32), &u32, sizeof(u32));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_add(msg, msg_len, pos, opt, sizeof(value), value));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add server's TTL TLV
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_ttl(char *msg, size_t msg_len, size_t *pos, uint8_t ttl)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_add_u8(msg, msg_len, pos, TLV_OPT_TYPE_TTL, ttl));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add uint8_t type as option opt.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
tlv_add_u8(char *msg, size_t msg_len, size_t *pos, enum tlv_opt_type opt, uint8_t val)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_add(msg, msg_len, pos, opt, sizeof(val), &val));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Add TLV with protocol version.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_add_version(char *msg, size_t msg_len, size_t *pos)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint8_t ver;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ver = PROTOCOL_VERSION;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_add_u8(msg, msg_len, pos, TLV_OPT_TYPE_VERSION, ver));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Return pointer to tlv data
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
const char *
|
|
Packit |
61cb5a |
tlv_iter_get_data(const struct tlv_iterator *tlv_iter)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
return (tlv_iter->msg + tlv_iter->pos + 2 * sizeof(uint16_t));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Get length of item currently pointed by iterator
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
uint16_t
|
|
Packit |
61cb5a |
tlv_iter_get_len(const struct tlv_iterator *tlv_iter)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t len;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&len, tlv_iter->msg + tlv_iter->pos + sizeof(uint16_t), sizeof(len));
|
|
Packit |
61cb5a |
len = ntohs(len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (len);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Get type of item currently pointed by iterator
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
enum tlv_opt_type
|
|
Packit |
61cb5a |
tlv_iter_get_type(const struct tlv_iterator *tlv_iter)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&res, tlv_iter->msg + tlv_iter->pos, sizeof(res));
|
|
Packit |
61cb5a |
res = ntohs(res);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return ((enum tlv_opt_type)res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Initialize iterator
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
void
|
|
Packit |
61cb5a |
tlv_iter_init(const char *msg, size_t msg_len, struct tlv_iterator *tlv_iter)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
tlv_iter->msg = msg;
|
|
Packit |
61cb5a |
tlv_iter->msg_len = msg_len;
|
|
Packit |
61cb5a |
tlv_iter->pos = 0;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Copy item from message pointed with iterator tlv_iter to new message new_msg with new_msg_len
|
|
Packit |
61cb5a |
* length to position pos. Return 0 on success, and -1 on failure.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_iter_item_copy(const struct tlv_iterator *tlv_iter, char *new_msg, size_t new_msg_len,
|
|
Packit |
61cb5a |
size_t *pos)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
size_t item_size;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("Copy option %"PRIu16" with len %"PRIu16" pos %zu",
|
|
Packit |
61cb5a |
tlv_iter_get_type(tlv_iter), tlv_iter_get_len(tlv_iter), *pos);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
item_size = tlv_iter_get_len(tlv_iter) + 2 * sizeof(uint16_t);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (*pos + item_size > new_msg_len) {
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("Can't copy option. new_msg_len too small.");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(new_msg + *pos, tlv_iter->msg + tlv_iter->pos, item_size);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
*pos += item_size;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Move iterator to the next item. Returns 0 when move was successful, or -1 if end of the message
|
|
Packit |
61cb5a |
* was reached.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_iter_next(struct tlv_iterator *tlv_iter)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t nlen;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (tlv_iter->pos == 0) {
|
|
Packit |
61cb5a |
tlv_iter->pos = 1;
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
nlen = tlv_iter_get_len(tlv_iter);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (tlv_iter->pos + sizeof(uint16_t) + sizeof(nlen) + nlen >= tlv_iter->msg_len) {
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
tlv_iter->pos += sizeof(uint16_t) + sizeof(nlen) + nlen;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Compare msg item pointed by iterator of MCAST_PREFIX type with sockaddr address
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_iter_pref_eq(const struct tlv_iterator *tlv_iter, const struct sockaddr_storage *sas)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t tlv_len;
|
|
Packit |
61cb5a |
uint16_t u16;
|
|
Packit |
61cb5a |
uint8_t pref_len;
|
|
Packit |
61cb5a |
uint8_t min_len;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (tlv_iter_get_type(tlv_iter) != TLV_OPT_TYPE_MCAST_PREFIX) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
tlv_len = tlv_iter_get_len(tlv_iter);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (tlv_len <= 2) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&u16, tlv_iter_get_data(tlv_iter), sizeof(u16));
|
|
Packit |
61cb5a |
u16 = ntohs(u16);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (u16 != AF_IANA_IP && u16 != AF_IANA_IP6) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&pref_len, tlv_iter_get_data(tlv_iter) + 2, sizeof(pref_len));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
min_len = pref_len / 8;
|
|
Packit |
61cb5a |
if (pref_len % 8 != 0)
|
|
Packit |
61cb5a |
min_len++;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (tlv_len - 3 < min_len) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_pref_eq(sas, u16, pref_len, tlv_iter_get_data(tlv_iter) + 3));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Compare sockaddr_storage address sas with mcast_grp received in message with length
|
|
Packit |
61cb5a |
* mcast_grp_len. Return 0 if addresses mismatch, otherwise not 0.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_mcast_grp_eq(const struct sockaddr_storage *sas, const char *mcast_grp, size_t mcast_grp_len)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t u16;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(&u16, mcast_grp, sizeof(u16));
|
|
Packit |
61cb5a |
u16 = ntohs(u16);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!((u16 == AF_IANA_IP && mcast_grp_len == 6) ||
|
|
Packit |
61cb5a |
(u16 == AF_IANA_IP6 && mcast_grp_len == 18))) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (u16 == AF_IANA_IP && sas->ss_family != AF_INET) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (u16 == AF_IANA_IP6 && sas->ss_family != AF_INET6) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (tlv_pref_eq(sas, u16, (mcast_grp_len - 2) * 8, mcast_grp + 2));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Return static string with opt name
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
const char *
|
|
Packit |
61cb5a |
tlv_opt_type_to_str(enum tlv_opt_type opt)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
const char *res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (opt) {
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_VERSION: res = "Version"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_CLIENT_ID: res = "Client ID"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_SEQ_NUM: res = "Sequence Number"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_CLIENT_TSTAMP: res = "Client Timestamp"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_MCAST_GRP: res = "Multicast Group"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_OPT_REQUEST: res = "Option Request Option"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_SERVER_INFO: res = "Server Information"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_TTL: res = "TTL"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_MCAST_PREFIX: res = "Multicast Prefix"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_SES_ID: res = "Session ID"; break;
|
|
Packit |
61cb5a |
case TLV_OPT_TYPE_SERVER_TSTAMP: res = "Server Timestamp"; break;
|
|
Packit |
61cb5a |
default: res = "Unknown"; break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Compare prefix address with sockaddr_storage address. iana_af is IANA address family, prefix is
|
|
Packit |
61cb5a |
* prefix length and addr is pointer to bytes of prefixed address. Only needed number of bytes is
|
|
Packit |
61cb5a |
* compared.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
tlv_pref_eq(const struct sockaddr_storage *sas, uint16_t iana_af, uint8_t prefix, const char *addr)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char sas_addr[32];
|
|
Packit |
61cb5a |
size_t sas_addr_len;
|
|
Packit |
61cb5a |
uint16_t sas_iana_af;
|
|
Packit |
61cb5a |
unsigned char cb1, cb2;
|
|
Packit |
61cb5a |
uint8_t plen_max, plen_min;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memset(sas_addr, 0, sizeof(sas_addr));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (sas->ss_family) {
|
|
Packit |
61cb5a |
case AF_INET:
|
|
Packit |
61cb5a |
sas_iana_af = AF_IANA_IP;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
plen_min = 4;
|
|
Packit |
61cb5a |
plen_max = 32;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
sas_addr_len = sizeof(struct in_addr);
|
|
Packit |
61cb5a |
memcpy(sas_addr, &((struct sockaddr_in *)sas)->sin_addr, sas_addr_len);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case AF_INET6:
|
|
Packit |
61cb5a |
sas_iana_af = AF_IANA_IP6;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
plen_min = 8;
|
|
Packit |
61cb5a |
plen_max = 128;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
sas_addr_len = sizeof(struct in6_addr);
|
|
Packit |
61cb5a |
memcpy(sas_addr, &((struct sockaddr_in6 *)sas)->sin6_addr, sas_addr_len);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Unknown ss family %d", sas->ss_family);
|
|
Packit |
61cb5a |
errx(1, "Unknown ss family %d", sas->ss_family);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (iana_af != sas_iana_af) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (prefix == 0) {
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Wildcard
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
return (1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (prefix < plen_min || prefix > plen_max) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Full bytes comparation
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (memcmp(sas_addr, addr, prefix / 8) != 0) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Rest bit comparation
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (prefix % 8 != 0 && prefix / 8 < sizeof(sas_addr_len)) {
|
|
Packit |
61cb5a |
cb1 = (unsigned char)(sas_addr[prefix / 8] & (0xff << (8 - (prefix % 8))));
|
|
Packit |
61cb5a |
cb2 = (unsigned char)(addr[prefix / 8] & (0xff << (8 - (prefix % 8))));
|
|
Packit |
61cb5a |
if (cb1 != cb2) {
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (1);
|
|
Packit |
61cb5a |
}
|