From 8c746b3a2bfb67addbfa4d3d4b7c0dbc2e8ba985 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Tue, 23 Jun 2015 14:17:10 +0200 Subject: ripe-atlas-fw: imported version 4680 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- .config | 2 +- eperd/eooqd.c | 20 +- eperd/eperd.c | 7 +- eperd/eperd.h | 5 + eperd/evtdig.c | 13 +- eperd/ping.c | 4 +- eperd/sslgetcert.c | 112 ++++++++-- eperd/tcputil.c | 6 +- eperd/traceroute.c | 15 +- networking/rptra6.c | 614 +++++++++++++++++++++++++++++++++------------------- 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 #include -#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) + { + 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_dnsmsg_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) + { + 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; ind_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; icmsg_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) - { - 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; ind_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"); -- cgit v1.2.3