aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.config2
-rw-r--r--eperd/eooqd.c20
-rw-r--r--eperd/eperd.c7
-rw-r--r--eperd/eperd.h5
-rw-r--r--eperd/evtdig.c13
-rw-r--r--eperd/ping.c4
-rw-r--r--eperd/sslgetcert.c112
-rw-r--r--eperd/tcputil.c6
-rw-r--r--eperd/traceroute.c15
-rw-r--r--networking/rptra6.c614
10 files changed, 549 insertions, 249 deletions
diff --git a/.config b/.config
index d76fe13..5fbd96b 100644
--- a/.config
+++ b/.config
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Busybox version: 1.13.3
-# Sat Jun 21 16:01:25 2014
+# Mon Dec 15 16:50:25 2014
#
CONFIG_HAVE_DOT_CONFIG=y
diff --git a/eperd/eooqd.c b/eperd/eooqd.c
index 8ce460f..04bfcd6 100644
--- a/eperd/eooqd.c
+++ b/eperd/eooqd.c
@@ -88,17 +88,19 @@ int eooqd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int eooqd_main(int argc, char *argv[])
{
int r;
- char *pid_file_name;
+ char *pid_file_name, *instance_id_str;
+ char *check;
struct event *checkQueueEvent, *rePostEvent;
struct timeval tv;
struct rlimit limit;
atlas_id= NULL;
+ instance_id_str= NULL;
pid_file_name= NULL;
queue_id= "";
- (void)getopt32(argv, "A:P:q:", &atlas_id, &pid_file_name,
- &queue_id);
+ (void)getopt32(argv, "A:i:P:q:", &atlas_id, &instance_id_str,
+ &pid_file_name, &queue_id);
if (argc != optind+1)
{
@@ -106,6 +108,18 @@ int eooqd_main(int argc, char *argv[])
return 1;
}
+ instance_id= 0;
+ if (instance_id_str)
+ {
+ instance_id= strtoul(instance_id_str, &check, 0);
+ if (check[0] != '\0')
+ {
+ report("unable to parse instance id '%s'",
+ instance_id_str);
+ return 1;
+ }
+ }
+
if(pid_file_name)
{
write_pidfile(pid_file_name);
diff --git a/eperd/eperd.c b/eperd/eperd.c
index 2ccaa6a..49c5884 100644
--- a/eperd/eperd.c
+++ b/eperd/eperd.c
@@ -262,9 +262,10 @@ int eperd_main(int argc UNUSED_PARAM, char **argv)
/* "-b after -f is ignored", and so on for every pair a-b */
opt_complementary = "f-b:b-f:S-L:L-S" USE_FEATURE_PERD_D(":d-l")
- ":l+:d+"; /* -l and -d have numeric param */
- opt = getopt32(argv, "l:L:fbSc:A:DP:" USE_FEATURE_PERD_D("d:") "O:",
- &LogLevel, &LogFile, &CDir, &atlas_id, &PidFileName
+ "i:+:l+:d+"; /* -i, -l and -d have numeric param */
+ opt = getopt32(argv, "i:l:L:fbSc:A:DP:" USE_FEATURE_PERD_D("d:") "O:",
+ &instance_id, &LogLevel, &LogFile, &CDir,
+ &atlas_id, &PidFileName
USE_FEATURE_PERD_D(,&LogLevel), &out_filename);
/* both -d N and -l N set the same variable: LogLevel */
diff --git a/eperd/eperd.h b/eperd/eperd.h
index 16cb1d7..e19c1a0 100644
--- a/eperd/eperd.h
+++ b/eperd/eperd.h
@@ -12,6 +12,7 @@ struct globals {
const char *CDir; /* = CRONTABS; */
CronLine *LineBase;
CronLine *oldLine;
+ unsigned instance_id;
struct event_base *EventBase;
struct evdns_base *DnsBase;
};
@@ -22,9 +23,13 @@ extern struct globals G;
#define LineBase (G.LineBase )
#define FileBase (G.FileBase )
#define oldLine (G.oldLine )
+#define instance_id (G.instance_id )
#define EventBase (G.EventBase )
#define DnsBase (G.DnsBase )
+#define TRT_ICMP4_INSTANCE_ID_SHIFT 12
+#define TRT_ICMP4_INSTANCE_ID_MASK 0xf000
+
#define LVL5 "\x05"
#define LVL7 "\x07"
#define LVL8 "\x08"
diff --git a/eperd/evtdig.c b/eperd/evtdig.c
index c94e884..de71a6b 100644
--- a/eperd/evtdig.c
+++ b/eperd/evtdig.c
@@ -56,6 +56,7 @@
#define O_CLASS 1008
#define O_QUERY 1009
#define O_OUTPUT_COBINED 1101
+#define O_CD 1010
#define DNS_FLAG_RD 0x0100
@@ -287,6 +288,7 @@ struct query_state {
int opt_abuf;
int opt_resolv_conf;
int opt_rd;
+ int opt_cd;
int opt_prepend_probe_id;
int opt_evdns;
int opt_rset;
@@ -474,6 +476,7 @@ static struct option longopts[]=
{ "edns0", required_argument, NULL, 'e' },
{ "nsid", no_argument, NULL, 'n' },
{ "do", no_argument, NULL, 'd' },
+ { "cd", no_argument, NULL, 'O_CD'},
{ "retry", required_argument, NULL, O_RETRY },
{ "resolv", no_argument, NULL, O_RESOLV_CONF },
@@ -689,10 +692,13 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet)
dns->ns_count = 0;
dns->add_count = htons(0);
- if (qry->opt_resolv_conf || qry->opt_rd ){
+ if (qry->opt_resolv_conf || qry->opt_rd ) {
dns->rd = 1;
}
+ if (qry->opt_cd)
+ dns->cd = 1;
+
//point to the query portion
qname =(u_char *)&packet[sizeof(struct DNS_HEADER)];
@@ -1309,6 +1315,7 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
qry->opt_qbuf = 0;
qry->opt_abuf = 1;
qry->opt_rd = 0;
+ qry->opt_cd = 0;
qry->opt_evdns = 0;
qry->opt_rset = 0;
qry->opt_prepend_probe_id = 0;
@@ -1441,6 +1448,10 @@ static void *tdig_init(int argc, char *argv[], void (*done)(void *state))
}
break;
+ case 'O_CD':
+ qry->opt_cd = 1;
+ break;
+
case 'O_CLASS':
qry->qclass = strtoul(optarg, &check, 10);
if ((qry->qclass >= 0 ) &&
diff --git a/eperd/ping.c b/eperd/ping.c
index 8d0866d..8f7f4e0 100644
--- a/eperd/ping.c
+++ b/eperd/ping.c
@@ -475,7 +475,9 @@ static void fmticmp4(u_char *buffer, size_t *sizep, u_int8_t seq,
/* The ICMP header (no checksum here until user data has been filled in) */
icmp->icmp_type = ICMP_ECHO; /* type of message */
icmp->icmp_code = 0; /* type sub code */
- icmp->icmp_id = 0xffff & pid; /* unique process identifier */
+
+ /* Keep the high nibble clear for traceroute */
+ icmp->icmp_id = 0x0fff & pid; /* unique process identifier */
icmp->icmp_seq = htons(seq); /* message identifier */
/* User data */
diff --git a/eperd/sslgetcert.c b/eperd/sslgetcert.c
index d00bf7a..fa3c254 100644
--- a/eperd/sslgetcert.c
+++ b/eperd/sslgetcert.c
@@ -76,6 +76,8 @@ struct state
char *infname;
char only_v4;
char only_v6;
+ char major_version;
+ char minor_version;
/* State */
char busy;
@@ -104,6 +106,8 @@ struct state
double resptime;
FILE *post_fh;
char *post_buf;
+ char recv_major;
+ char recv_minor;
struct buf inbuf;
struct msgbuf msginbuf;
@@ -351,7 +355,8 @@ static void msgbuf_add(struct msgbuf *msgbuf, void *buf, size_t size)
buf_add(&msgbuf->buffer, buf, size);
}
-static int msgbuf_read(struct msgbuf *msgbuf, int type)
+static int msgbuf_read(struct msgbuf *msgbuf, int type,
+ char *majorp, char *minorp)
{
int r;
size_t len;
@@ -378,13 +383,8 @@ static int msgbuf_read(struct msgbuf *msgbuf, int type)
fprintf(stderr, "msgbuf_read: got type %d\n", p[0]);
return -1;
}
- if (p[1] != 3 || p[2] != 0)
- {
- fprintf(stderr,
- "msgbuf_read: got bad major/minor %d.%d\n",
- p[1], p[2]);
- return -1;
- }
+ *majorp= p[1];
+ *minorp= p[2];
len= (p[3] << 8) + p[4];
if (msgbuf->inbuf->size - msgbuf->inbuf->offset < 5 + len)
{
@@ -601,15 +601,16 @@ static void timeout_callback(int __attribute((unused)) unused,
static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
void (*done)(void *state))
{
- int c, i, only_v4, only_v6;
+ int c, i, only_v4, only_v6, major, minor;
size_t newsiz;
- char *hostname, *str_port, *infname;
+ char *hostname, *str_port, *infname, *version_str;
char *output_file, *A_arg;
struct state *state;
FILE *fh;
/* Arguments */
output_file= NULL;
+ version_str= NULL;
A_arg= NULL;
infname= NULL;
str_port= NULL;
@@ -626,7 +627,7 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
/* Allow us to be called directly by another program in busybox */
optind= 0;
- while (c= getopt_long(argc, argv, "A:O:i:p:46", longopts, NULL), c != -1)
+ while (c= getopt_long(argc, argv, "A:O:V:i:p:46", longopts, NULL), c != -1)
{
switch(c)
{
@@ -636,6 +637,9 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
case 'O':
output_file= optarg;
break;
+ case 'V':
+ version_str= optarg;
+ break;
case 'i':
infname= optarg;
break;
@@ -689,12 +693,40 @@ static void *sslgetcert_init(int __attribute((unused)) argc, char *argv[],
}
}
+ if (version_str == NULL || strcasecmp(version_str, "TLS1.2") == 0)
+ {
+ major= 3; /* TLS 1.2 */
+ minor= 3;
+ }
+ else if (strcasecmp(version_str, "TLS1.1") == 0)
+ {
+ major= 3;
+ minor= 2;
+ }
+ else if (strcasecmp(version_str, "TLS1.0") == 0)
+ {
+ major= 3;
+ minor= 1;
+ }
+ else if (strcasecmp(version_str, "SSL3.0") == 0)
+ {
+ major= 3;
+ minor= 0;
+ }
+ else
+ {
+ crondlog(LVL8 "bad protocol version '%s'", version_str);
+ return NULL;
+ }
+
state= xzalloc(sizeof(*state));
state->base= hg_base;
state->atlas= A_arg ? strdup(A_arg) : NULL;
state->output_file= output_file ? strdup(output_file) : NULL;
state->infname= infname ? strdup(infname) : NULL;
state->hostname= strdup(hostname);
+ state->major_version= major;
+ state->minor_version= minor;
if (str_port)
state->portname= strdup(str_port);
else
@@ -879,7 +911,8 @@ static int eat_server_hello(struct state *state)
{
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4)
{
- r= msgbuf_read(msgbuf, MSG_HANDSHAKE);
+ r= msgbuf_read(msgbuf, MSG_HANDSHAKE,
+ &state->recv_major, &state->recv_minor);
if (r < 0)
{
fprintf(stderr,
@@ -899,7 +932,8 @@ static int eat_server_hello(struct state *state)
len= (p[1] << 16) + (p[2] << 8) + p[3];
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len)
{
- r= msgbuf_read(msgbuf, MSG_HANDSHAKE);
+ r= msgbuf_read(msgbuf, MSG_HANDSHAKE,
+ &state->recv_major, &state->recv_minor);
if (r < 0)
{
fprintf(stderr,
@@ -916,8 +950,9 @@ static int eat_server_hello(struct state *state)
static int eat_certificate(struct state *state)
{
- int i, n, r, first, slen, need_nl;
+ int i, n, r, first, slen, need_nl, major, minor;
size_t o, len;
+ const char *method;
uint8_t *p;
struct msgbuf *msgbuf;
FILE *fh;
@@ -932,7 +967,8 @@ static int eat_certificate(struct state *state)
{
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4)
{
- r= msgbuf_read(msgbuf, MSG_HANDSHAKE);
+ r= msgbuf_read(msgbuf, MSG_HANDSHAKE,
+ &state->recv_major, &state->recv_minor);
if (r < 0)
{
if (errno != EAGAIN)
@@ -954,7 +990,8 @@ static int eat_certificate(struct state *state)
len= (p[1] << 16) + (p[2] << 8) + p[3];
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len)
{
- r= msgbuf_read(msgbuf, MSG_HANDSHAKE);
+ r= msgbuf_read(msgbuf, MSG_HANDSHAKE,
+ &state->recv_major, &state->recv_minor);
if (r < 0)
{
fprintf(stderr,
@@ -996,8 +1033,39 @@ static int eat_certificate(struct state *state)
DBQ(dst_port) ":" DBQ(%s),
state->hostname, state->portname);
- fprintf(fh, ", " DBQ(method) ":" DBQ(SSL) ", "
- DBQ(ver) ":" DBQ(3.0));
+ if (state->recv_major == 3 && state->recv_minor == 3)
+ {
+ method= "TLS";
+ major= 1;
+ minor= 2;
+ }
+ else if (state->recv_major == 3 && state->recv_minor == 2)
+ {
+ method= "TLS";
+ major= 1;
+ minor= 1;
+ }
+ else if (state->recv_major == 3 && state->recv_minor == 1)
+ {
+ method= "TLS";
+ major= 1;
+ minor= 0;
+ }
+ else if (state->recv_major == 3 && state->recv_minor == 0)
+ {
+ method= "SSL";
+ major= 3;
+ minor= 0;
+ }
+ else
+ {
+ method= "(unknown)";
+ major= state->recv_major;
+ minor= state->recv_minor;
+ }
+
+ fprintf(fh, ", " DBQ(method) ":" DBQ(%s) ", "
+ DBQ(ver) ":" DBQ(%d.%d), method, major, minor);
getnameinfo((struct sockaddr *)&state->sin6, state->socklen,
hostbuf, sizeof(hostbuf), NULL, 0,
NI_NUMERICHOST);
@@ -1077,6 +1145,7 @@ static int eat_certificate(struct state *state)
static void writecb(struct bufferevent *bev, void *ptr)
{
+ char c;
struct state *state;
struct buf outbuf;
struct msgbuf msgoutbuf;
@@ -1096,8 +1165,11 @@ static void writecb(struct bufferevent *bev, void *ptr)
hsbuf_init(&hsbuf);
/* Major/minor */
- hsbuf_add(&hsbuf, "\3", 1);
- hsbuf_add(&hsbuf, "\0", 1);
+ c= state->major_version;
+ hsbuf_add(&hsbuf, &c, 1);
+
+ c= state->minor_version;
+ hsbuf_add(&hsbuf, &c, 1);
add_random(&hsbuf);
add_sessionid(&hsbuf);
add_ciphers(&hsbuf);
diff --git a/eperd/tcputil.c b/eperd/tcputil.c
index 201f1eb..e1d4505 100644
--- a/eperd/tcputil.c
+++ b/eperd/tcputil.c
@@ -90,7 +90,11 @@ void tu_restart_connect(struct tu_env *env)
}
/* Immediate error? */
- printf("connect error\n");
+ if (!env->dns_curr)
+ {
+ /* Callback cleaned up */
+ return;
+ }
env->dns_curr= env->dns_curr->ai_next;
}
diff --git a/eperd/traceroute.c b/eperd/traceroute.c
index 06f6ac1..fbeb025 100644
--- a/eperd/traceroute.c
+++ b/eperd/traceroute.c
@@ -1021,7 +1021,8 @@ static void send_pkt(struct trtstate *state)
icmp_hdr->icmp_type= ICMP_ECHO;
icmp_hdr->icmp_code= 0;
icmp_hdr->icmp_cksum= 0;
- icmp_hdr->icmp_id= htons(state->index);
+ icmp_hdr->icmp_id= htons(state->index |
+ (instance_id << TRT_ICMP4_INSTANCE_ID_SHIFT));
icmp_hdr->icmp_seq= htons(state->seq);
icmp_hdr->icmp_data[0]= '\0';
icmp_hdr->icmp_data[1]= '\0';
@@ -1857,6 +1858,12 @@ printf("curpacksize: %d\n", state->curpacksize);
}
ind= ntohs(eicmp->icmp_id);
+ if ((ind >> TRT_ICMP4_INSTANCE_ID_SHIFT) != instance_id)
+ {
+ printf("wrong instance id\n");
+ return;
+ }
+ ind &= ~TRT_ICMP4_INSTANCE_ID_MASK;
if (ind >= base->tabsiz)
{
@@ -2134,6 +2141,12 @@ printf("%s, %d: sin6_family = %d\n", __FILE__, __LINE__, state->sin6.sin6_family
}
ind= ntohs(icmp->icmp_id);
+ if ((ind >> TRT_ICMP4_INSTANCE_ID_SHIFT) != instance_id)
+ {
+ printf("wrong instance id\n");
+ return;
+ }
+ ind &= ~TRT_ICMP4_INSTANCE_ID_MASK;
if (ind >= base->tabsiz)
{
diff --git a/networking/rptra6.c b/networking/rptra6.c
index 9499125..c015134 100644
--- a/networking/rptra6.c
+++ b/networking/rptra6.c
@@ -8,10 +8,16 @@
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
-#define OPT_STRING "P:"
+#define OPT_STRING "lP:r:"
+
+enum {
+ OPT_l = (1 << 0),
+};
#define DBQ(str) "\"" #str "\""
+#define N_DNS 3 /* Number of DNS resolvers to keep track of */
+
#define IN6ADDR_ALL_NODES_INIT { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
struct in6_addr in6addr_all_nodes = IN6ADDR_ALL_NODES_INIT; /* ff02::1 */
@@ -35,40 +41,394 @@ static void usage(void)
exit(1);
}
-int rptra6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
-int rptra6_main(int argc, char *argv[])
+static void do_resolv(char *str_resolv, char *str_resolv_new,
+ char *packet, ssize_t nrecv,
+ char dnscurr[N_DNS][INET6_ADDRSTRLEN],
+ time_t *dnsexpires)
+{
+ int i, olen, n_dns;
+ size_t o;
+ uint32_t lifetime;
+ struct nd_router_advert *ra;
+ struct nd_opt_hdr *oh;
+ struct opt_rdnss *rdnss;
+ FILE *f;
+ char namebuf[NI_MAXHOST];
+ char dnsnext[N_DNS][INET6_ADDRSTRLEN];
+
+ ra= (struct nd_router_advert *)packet;
+
+ /* Clear resolver list */
+ for (n_dns= 0; n_dns < N_DNS; n_dns++)
+ strcpy(dnsnext[n_dns], "");
+
+ for (o= sizeof(*ra); o<nrecv;)
+ {
+ if (o+sizeof(*oh) > nrecv)
+ {
+ printf("partial option\n");
+ break;
+ }
+
+ oh= (struct nd_opt_hdr *)&packet[o];
+ if (oh->nd_opt_len == 0)
+ {
+ printf("bad option length (0) at %ld\n",
+ (long)o);
+ break;
+ }
+ olen= oh->nd_opt_len * 8;
+
+ switch(oh->nd_opt_type)
+ {
+ case OPT_RDNSS: /* 25 */
+
+ rdnss= (struct opt_rdnss *)oh;
+ lifetime= ntohl(rdnss->nd_opt_rdnss_lifetime);
+ /* Assume one year is infinite enough */
+ if (lifetime == (uint32_t)-1)
+ lifetime= 365*24*3600;
+
+ n_dns= 0;
+
+ for (i= 8; i+16 <= olen; i+= 16)
+ {
+ if (lifetime == 0)
+ {
+ /* zero lifetime implies empty list */
+ break;
+ }
+ inet_ntop(AF_INET6, ((char *)oh)+i,
+ namebuf, sizeof(namebuf));
+ if (n_dns < N_DNS)
+ {
+ strcpy(dnsnext[n_dns], namebuf);
+ n_dns++;
+ }
+ }
+
+ /* Check if the list of resolvers changed */
+ for (n_dns= 0; n_dns < N_DNS; n_dns++)
+ {
+ if (strcmp(dnscurr[n_dns],
+ dnsnext[n_dns]) != 0)
+ {
+ break;
+ }
+ }
+ if (str_resolv && n_dns < N_DNS)
+ {
+ memcpy(dnscurr, dnsnext,
+ sizeof(dnsnext));
+
+ /* Ignore errors */
+ f= fopen(str_resolv_new, "w");
+ for (n_dns= 0; n_dns<N_DNS; n_dns++)
+ {
+ if (strlen(dnscurr[n_dns]) == 0)
+ break;
+ fprintf(f, "nameserver %s\n",
+ dnscurr[n_dns]);
+ }
+ fclose(f);
+ rename(str_resolv_new, str_resolv);
+ }
+ if (lifetime)
+ *dnsexpires= time(NULL) + lifetime;
+ else
+ *dnsexpires= 0;
+
+ break;
+ }
+
+
+ o += olen;
+ }
+
+ /* Check if we have to expire DNS entries */
+ if (*dnsexpires && *dnsexpires < time(NULL))
+ {
+ *dnsexpires= 0;
+ for (n_dns= 0; n_dns<N_DNS; n_dns++)
+ strcpy(dnscurr[n_dns], "!");
+ if (str_resolv)
+ {
+ /* Ignore errors */
+ f= fopen(str_resolv_new, "w");
+ fclose(f);
+ rename(str_resolv_new, str_resolv);
+ }
+ }
+}
+
+static void log_ra(char *out_name, char *new_name,
+ struct sockaddr_in6 *remotep,
+ struct msghdr *msgp, char *packet, ssize_t nrecv)
{
- int i, r, first, sock, on, nrecv, rcvd_ttl, olen;
+ int i, r, first, rcvd_ttl, olen;
uint8_t flags_reserved;
size_t o;
- char *new_name, *out_name;
+ FILE *of;
+ struct cmsghdr *cmsgptr;
+ struct sockaddr_in6 *sin6p;
+ struct sockaddr_in6 loc_sin6;
struct nd_router_advert *ra;
struct nd_opt_hdr *oh;
struct nd_opt_prefix_info *pi;
struct nd_opt_mtu *mtup;
struct opt_rdnss *rdnssp;
+ struct stat sb;
+ char namebuf[NI_MAXHOST];
+
+ of= fopen(new_name, "a");
+ if (of == NULL)
+ {
+ fprintf(stderr, "unable to open '%s': %s\n", new_name, strerror(errno));
+ exit(1);
+ }
+
+ fprintf(of, "RESULT { " DBQ(id) ": " DBQ(9019) ", " DBQ(time) ": %ld",
+ (long)time(NULL));
+ getnameinfo((struct sockaddr *)remotep, msgp->msg_namelen,
+ namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
+ fprintf(of, ", " DBQ(src) ": " DBQ(%s), namebuf);
+
+ /* Set destination address of packet as local address */
+ memset(&loc_sin6, '\0', sizeof(loc_sin6));
+ for (cmsgptr= CMSG_FIRSTHDR(msgp); cmsgptr;
+ cmsgptr= CMSG_NXTHDR(msgp, cmsgptr))
+ {
+ if (cmsgptr->cmsg_len == 0)
+ break; /* Can this happen? */
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+ cmsgptr->cmsg_type == IPV6_PKTINFO)
+ {
+ sin6p= &loc_sin6;
+ sin6p->sin6_family= AF_INET6;
+ sin6p->sin6_addr= ((struct in6_pktinfo *)
+ CMSG_DATA(cmsgptr))->ipi6_addr;
+ }
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+ cmsgptr->cmsg_type == IPV6_HOPLIMIT)
+ {
+ rcvd_ttl= *(int *)CMSG_DATA(cmsgptr);
+ }
+ }
+
+ if (memcmp(&loc_sin6.sin6_addr, &in6addr_all_nodes,
+ sizeof(loc_sin6.sin6_addr)) != 0)
+ {
+ getnameinfo((struct sockaddr *)&loc_sin6, sizeof(loc_sin6),
+ namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
+ fprintf(of, ", " DBQ(dst) ": " DBQ(%s), namebuf);
+ }
+ if (rcvd_ttl != 255)
+ fprintf(of, ", " DBQ(ttl) ": %d", rcvd_ttl);
+
+ ra= (struct nd_router_advert *)packet;
+ fprintf(of, ", " DBQ(hop_limit) ": %d", ra->nd_ra_curhoplimit);
+ flags_reserved= ra->nd_ra_flags_reserved;
+ if (flags_reserved & ND_RA_FLAG_OTHER)
+ {
+ fprintf(of, ", " DBQ(other_conf) ": true");
+ flags_reserved &= ~ND_RA_FLAG_OTHER;
+ }
+ switch(flags_reserved & RA_PREF_MASK)
+ {
+ case RA_PREF_HIGH:
+ fprintf(of, ", " DBQ(preference) ": " DBQ(high));
+ flags_reserved &= ~RA_PREF_MASK;
+ break;
+ case RA_PREF_LOW:
+ fprintf(of, ", " DBQ(preference) ": " DBQ(low));
+ flags_reserved &= ~RA_PREF_MASK;
+ break;
+ }
+ if (flags_reserved)
+ fprintf(of, ", " DBQ(reserved) ": 0x%x", flags_reserved);
+ fprintf(of, ", " DBQ(lifetime) ": %d", ntohs(ra->nd_ra_router_lifetime));
+ if (ra->nd_ra_reachable)
+ fprintf(of, ", " DBQ(reachable_time) ": %d", ntohl(ra->nd_ra_reachable));
+ if (ra->nd_ra_retransmit)
+ fprintf(of, ", " DBQ(retransmit_time) ": %d", ntohl(ra->nd_ra_retransmit));
+
+ fprintf(of, ", " DBQ(options) ": [ ");
+ first= 1;
+ for (o= sizeof(*ra); o<nrecv;)
+ {
+ if (!first)
+ fprintf(of, ", ");
+ else
+ first= 0;
+
+ if (o+sizeof(*oh) > nrecv)
+ {
+ printf("partial option\n");
+ break;
+ }
+
+ oh= (struct nd_opt_hdr *)&packet[o];
+ if (oh->nd_opt_len == 0)
+ {
+ printf("bad option length (0) at %ld\n",
+ (long)o);
+ break;
+ }
+ olen= oh->nd_opt_len * 8;
+
+ switch(oh->nd_opt_type)
+ {
+ case ND_OPT_SOURCE_LINKADDR: /* 1 */
+ fprintf(of, "{ " DBQ(type) ": " DBQ(link layer address) ", "
+ DBQ(addr) ": \"");
+ for (i= 2; i<olen; i++)
+ {
+ fprintf(of, "%s%02x", i == 2 ? "" : ":",
+ ((uint8_t *)oh)[i]);
+ }
+ fprintf(of, "\" }");
+ break;
+ case ND_OPT_PREFIX_INFORMATION: /* 3 */
+ if (olen < sizeof(*pi))
+ {
+ printf(
+ "bad option length (%d) for prefix info\n",
+ oh->nd_opt_len);
+ break;
+ }
+ pi= (struct nd_opt_prefix_info *)oh;
+ fprintf(of, "{ " DBQ(prefix_len) ": %d",
+ pi->nd_opt_pi_prefix_len);
+ flags_reserved= pi->nd_opt_pi_flags_reserved;
+ if (flags_reserved & ND_OPT_PI_FLAG_ONLINK)
+ {
+ fprintf(of, ", " DBQ(onlink) ": true");
+ flags_reserved &= ~ND_OPT_PI_FLAG_ONLINK;
+ }
+ if (flags_reserved & ND_OPT_PI_FLAG_AUTO)
+ {
+ fprintf(of, ", " DBQ(auto) ": true");
+ flags_reserved &= ~ND_OPT_PI_FLAG_AUTO;
+ }
+
+ if (flags_reserved)
+ {
+ fprintf(of, ", " DBQ(reserved1) ": 0x%x", flags_reserved);
+ }
+ fprintf(of, ", " DBQ(valid_time) ": %d",
+ ntohl(pi-> nd_opt_pi_valid_time));
+ fprintf(of, ", " DBQ(preferred_time) ": %d",
+ ntohl(pi-> nd_opt_pi_preferred_time));
+ if (pi-> nd_opt_pi_reserved2)
+ {
+ fprintf(of, ", " DBQ(reserved2) ": %d",
+ ntohl(pi-> nd_opt_pi_reserved2));
+ }
+
+ fprintf(of, ", " DBQ(prefix) ": " DBQ(%s) " }",
+ inet_ntop(AF_INET6, &pi->nd_opt_pi_prefix,
+ namebuf, sizeof(namebuf)));
+ break;
+
+ case ND_OPT_MTU: /* 5 */
+ fprintf(of, "{ " DBQ(type) ": " DBQ(mtu));
+ mtup= (struct nd_opt_mtu *)oh;
+ if (mtup->nd_opt_mtu_reserved)
+ {
+ fprintf(of, ", " DBQ(reserved) ": 0x%x",
+ ntohs(mtup->nd_opt_mtu_reserved));
+ }
+ fprintf(of, ", " DBQ(mtu) ": %d }",
+ ntohl(mtup->nd_opt_mtu_mtu));
+ break;
+
+ case OPT_RDNSS: /* 25 */
+ fprintf(of, "{ " DBQ(type) ": " DBQ(rdnss));
+ rdnssp= (struct opt_rdnss *)oh;
+ if (rdnssp->nd_opt_rdnss_reserved)
+ {
+ fprintf(of, ", " DBQ(reserved) ": %d",
+ ntohs(rdnssp->nd_opt_rdnss_reserved));
+ }
+ fprintf(of, ", " DBQ(lifetime) ": %d",
+ ntohl(rdnssp->nd_opt_rdnss_lifetime));
+
+ fprintf(of, ", " DBQ(addrs) ": [ ");
+ for (i= 8; i+16 <= olen; i+= 16)
+ {
+ inet_ntop(AF_INET6, ((char *)oh)+i,
+ namebuf, sizeof(namebuf));
+ fprintf(of, "%s" DBQ(%s),
+ i == 8 ? "" : ", ",
+ namebuf);
+ }
+ fprintf(of, " ] }");
+
+ break;
+
+ default:
+ fprintf(of, "{ " DBQ(type_no) ": %d }", oh->nd_opt_type);
+ break;
+ }
+
+
+ o += olen;
+ }
+ fprintf(of, " ] }\n");
+
+ fclose(of);
+
+ r= stat(out_name, &sb);
+ if (r == 0)
+ return;
+ if (errno == ENOENT)
+ {
+ rename(new_name, out_name);
+ return;
+ }
+ fprintf(stderr, "stat '%s' failed: %s\n", out_name, strerror(errno));
+ exit(1);
+}
+
+int rptra6_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
+int rptra6_main(int argc, char *argv[])
+{
+ int i, sock, on, nrecv, do_log;
+ unsigned opts;
+ size_t len;
+ time_t dnsexpires;
+ char *new_name, *out_name, *str_resolv, *str_resolv_new;
struct icmp6_hdr * icmp;
- struct cmsghdr *cmsgptr;
- struct sockaddr_in6 *sin6p;
FILE *of;
char *str_pidfile;
- struct stat sb;
struct sockaddr_in6 remote; /* responding internet address */
- struct sockaddr_in6 loc_sin6;
struct msghdr msg;
struct iovec iov[1];
- char namebuf[NI_MAXHOST];
+ char dnscurr[N_DNS][INET6_ADDRSTRLEN];
char cmsgbuf[256];
char packet[4096];
str_pidfile= NULL;
- (void) getopt32(argv, OPT_STRING, &str_pidfile);
+ str_resolv= NULL;
+ opts= getopt32(argv, OPT_STRING, &str_pidfile, &str_resolv);
+
+ do_log= !!(opts & OPT_l);
- if (argc != optind+2)
- usage();
+ if (do_log)
+ {
+ if (argc != optind+2)
+ usage();
- new_name= argv[optind];
- out_name= argv[optind+1];
+ new_name= argv[optind];
+ out_name= argv[optind+1];
+ }
+ else
+ {
+ if (argc != optind)
+ usage();
+ new_name= NULL;
+ out_name= NULL;
+ }
if (str_pidfile)
{
@@ -79,6 +439,14 @@ int rptra6_main(int argc, char *argv[])
fclose(of);
}
}
+
+ str_resolv_new= NULL;
+ if (str_resolv)
+ {
+ len= strlen(str_resolv) + 4 + 1;
+ str_resolv_new= malloc(len);
+ snprintf(str_resolv_new, len, "%s.new", str_resolv);
+ }
of= NULL;
@@ -98,6 +466,13 @@ int rptra6_main(int argc, char *argv[])
icmp = (struct icmp6_hdr *) packet;
+ /* Put something weird in the current list of DNS resolvers to
+ * trigger an update.
+ */
+ for (i= 0; i<N_DNS; i++)
+ strcpy(dnscurr[i], "!");
+ dnsexpires= 0; /* Currently, there is no DNS info */
+
for(;;)
{
iov[0].iov_base= packet;
@@ -139,213 +514,16 @@ int rptra6_main(int argc, char *argv[])
continue;
}
- of= fopen(new_name, "a");
- if (of == NULL)
- {
- fprintf(stderr, "unable to open '%s': %s\n", new_name, strerror(errno));
- exit(1);
- }
-
- fprintf(of, "RESULT { " DBQ(id) ": " DBQ(9019) ", " DBQ(time) ": %ld",
- (long)time(NULL));
- getnameinfo((struct sockaddr *)&remote, msg.msg_namelen,
- namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
- fprintf(of, ", " DBQ(src) ": " DBQ(%s), namebuf);
-
- /* Set destination address of packet as local address */
- memset(&loc_sin6, '\0', sizeof(loc_sin6));
- for (cmsgptr= CMSG_FIRSTHDR(&msg); cmsgptr;
- cmsgptr= CMSG_NXTHDR(&msg, cmsgptr))
- {
- if (cmsgptr->cmsg_len == 0)
- break; /* Can this happen? */
- if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
- cmsgptr->cmsg_type == IPV6_PKTINFO)
- {
- sin6p= &loc_sin6;
- sin6p->sin6_family= AF_INET6;
- sin6p->sin6_addr= ((struct in6_pktinfo *)
- CMSG_DATA(cmsgptr))->ipi6_addr;
- }
- if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
- cmsgptr->cmsg_type == IPV6_HOPLIMIT)
- {
- rcvd_ttl= *(int *)CMSG_DATA(cmsgptr);
- }
- }
-
- if (memcmp(&loc_sin6.sin6_addr, &in6addr_all_nodes,
- sizeof(loc_sin6.sin6_addr)) != 0)
- {
- getnameinfo((struct sockaddr *)&loc_sin6, sizeof(loc_sin6),
- namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
- fprintf(of, ", " DBQ(dst) ": " DBQ(%s), namebuf);
- }
- if (rcvd_ttl != 255)
- fprintf(of, ", " DBQ(ttl) ": %d", rcvd_ttl);
-
- ra= (struct nd_router_advert *)packet;
- fprintf(of, ", " DBQ(hop_limit) ": %d", ra->nd_ra_curhoplimit);
- flags_reserved= ra->nd_ra_flags_reserved;
- if (flags_reserved & ND_RA_FLAG_OTHER)
+ if (do_log)
{
- fprintf(of, ", " DBQ(other_conf) ": true");
- flags_reserved &= ~ND_RA_FLAG_OTHER;
+ log_ra(out_name, new_name, &remote, &msg,
+ packet, nrecv);
}
- switch(flags_reserved & RA_PREF_MASK)
+ if (str_resolv)
{
- case RA_PREF_HIGH:
- fprintf(of, ", " DBQ(preference) ": " DBQ(high));
- flags_reserved &= ~RA_PREF_MASK;
- break;
- case RA_PREF_LOW:
- fprintf(of, ", " DBQ(preference) ": " DBQ(low));
- flags_reserved &= ~RA_PREF_MASK;
- break;
- }
- if (flags_reserved)
- fprintf(of, ", " DBQ(reserved) ": 0x%x", flags_reserved);
- fprintf(of, ", " DBQ(lifetime) ": %d", ntohs(ra->nd_ra_router_lifetime));
- if (ra->nd_ra_reachable)
- fprintf(of, ", " DBQ(reachable_time) ": %d", ntohl(ra->nd_ra_reachable));
- if (ra->nd_ra_retransmit)
- fprintf(of, ", " DBQ(retransmit_time) ": %d", ntohl(ra->nd_ra_retransmit));
-
- fprintf(of, ", " DBQ(options) ": [ ");
- first= 1;
- for (o= sizeof(*ra); o<nrecv;)
- {
- if (!first)
- fprintf(of, ", ");
- else
- first= 0;
-
- if (o+sizeof(*oh) > nrecv)
- {
- printf("partial option\n");
- break;
- }
-
- oh= (struct nd_opt_hdr *)&packet[o];
- if (oh->nd_opt_len == 0)
- {
- printf("bad option length (0) at %ld\n",
- (long)o);
- break;
- }
- olen= oh->nd_opt_len * 8;
-
- switch(oh->nd_opt_type)
- {
- case ND_OPT_SOURCE_LINKADDR: /* 1 */
- fprintf(of, "{ " DBQ(type) ": " DBQ(link layer address) ", "
- DBQ(addr) ": \"");
- for (i= 2; i<olen; i++)
- {
- fprintf(of, "%s%02x", i == 2 ? "" : ":",
- ((uint8_t *)oh)[i]);
- }
- fprintf(of, "\" }");
- break;
- case ND_OPT_PREFIX_INFORMATION: /* 3 */
- if (olen < sizeof(*pi))
- {
- printf(
- "bad option length (%d) for prefix info\n",
- oh->nd_opt_len);
- break;
- }
- pi= (struct nd_opt_prefix_info *)oh;
- fprintf(of, "{ " DBQ(prefix_len) ": %d",
- pi->nd_opt_pi_prefix_len);
- flags_reserved= pi->nd_opt_pi_flags_reserved;
- if (flags_reserved & ND_OPT_PI_FLAG_ONLINK)
- {
- fprintf(of, ", " DBQ(onlink) ": true");
- flags_reserved &= ~ND_OPT_PI_FLAG_ONLINK;
- }
- if (flags_reserved & ND_OPT_PI_FLAG_AUTO)
- {
- fprintf(of, ", " DBQ(auto) ": true");
- flags_reserved &= ~ND_OPT_PI_FLAG_AUTO;
- }
-
- if (flags_reserved)
- {
- fprintf(of, ", " DBQ(reserved1) ": 0x%x", flags_reserved);
- }
- fprintf(of, ", " DBQ(valid_time) ": %d",
- ntohl(pi-> nd_opt_pi_valid_time));
- fprintf(of, ", " DBQ(preferred_time) ": %d",
- ntohl(pi-> nd_opt_pi_preferred_time));
- if (pi-> nd_opt_pi_reserved2)
- {
- fprintf(of, ", " DBQ(reserved2) ": %d",
- ntohl(pi-> nd_opt_pi_reserved2));
- }
-
- fprintf(of, ", " DBQ(prefix) ": " DBQ(%s) " }",
- inet_ntop(AF_INET6, &pi->nd_opt_pi_prefix,
- namebuf, sizeof(namebuf)));
- break;
-
- case ND_OPT_MTU: /* 5 */
- fprintf(of, "{ " DBQ(type) ": " DBQ(mtu));
- mtup= (struct nd_opt_mtu *)oh;
- if (mtup->nd_opt_mtu_reserved)
- {
- fprintf(of, ", " DBQ(reserved) ": 0x%x",
- ntohs(mtup->nd_opt_mtu_reserved));
- }
- fprintf(of, ", " DBQ(mtu) ": %d }",
- ntohl(mtup->nd_opt_mtu_mtu));
- break;
-
- case OPT_RDNSS: /* 25 */
- fprintf(of, "{ " DBQ(type) ": " DBQ(rdnss));
- rdnssp= (struct opt_rdnss *)oh;
- if (rdnssp->nd_opt_rdnss_reserved)
- {
- fprintf(of, ", " DBQ(reserved) ": %d",
- ntohs(rdnssp->nd_opt_rdnss_reserved));
- }
- fprintf(of, ", " DBQ(lifetime) ": %d",
- ntohl(rdnssp->nd_opt_rdnss_lifetime));
-
- fprintf(of, ", " DBQ(addrs) ": [ ");
- for (i= 8; i+16 <= olen; i+= 16)
- {
- inet_ntop(AF_INET6, ((char *)oh)+i,
- namebuf, sizeof(namebuf));
- fprintf(of, "%s" DBQ(%s),
- i == 8 ? "" : ", ",
- namebuf);
- }
- fprintf(of, " ] }");
- break;
-
- default:
- fprintf(of, "{ " DBQ(type_no) ": %d }", oh->nd_opt_type);
- break;
- }
-
-
- o += olen;
+ do_resolv(str_resolv, str_resolv_new, packet, nrecv,
+ dnscurr, &dnsexpires);
}
- fprintf(of, " ] }\n");
-
- fclose(of);
-
- r= stat(out_name, &sb);
- if (r == 0)
- continue;
- if (errno == ENOENT)
- {
- rename(new_name, out_name);
- continue;
- }
- fprintf(stderr, "stat '%s' failed: %s\n", out_name, strerror(errno));
- exit(1);
}
fprintf(stderr, "end of main\n");