From d05f5831d4ba129e8209a1a65a19f78e296ec001 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 14 Dec 2011 20:48:55 +0000 Subject: [PATCH] add the ipv6 logic to the userspace daemon. problems with this: 1) not pretty 2) most certainly doesn't work 3) only compiles with no-redis 4) not pretty and most certainly doesn't work --- daemon/aux.h | 11 ++ daemon/call.c | 406 +++++++++++++++++++++++++++++++++---------- daemon/call.h | 13 +- daemon/control_udp.c | 8 +- daemon/kernel.c | 29 +++- daemon/kernel.h | 6 +- daemon/main.c | 4 +- 7 files changed, 365 insertions(+), 112 deletions(-) diff --git a/daemon/aux.h b/daemon/aux.h index 4fe3c1bbe..5f2ab9b45 100644 --- a/daemon/aux.h +++ b/daemon/aux.h @@ -23,6 +23,17 @@ #define IPP(x) ((unsigned char *) (&(x)))[0], ((unsigned char *) (&(x)))[1], ((unsigned char *) (&(x)))[2], ((unsigned char *) (&(x)))[3] #define DF IPF ":%u" #define DP(x) IPP((x).sin_addr.s_addr), ntohs((x).sin_port) +#define IP6F "%x:%x:%x:%x:%x:%x:%x:%x" +#define IP6P(x) ntohs(((u_int16_t *) (x))[0]), \ + ntohs(((u_int16_t *) (x))[1]), \ + ntohs(((u_int16_t *) (x))[2]), \ + ntohs(((u_int16_t *) (x))[3]), \ + ntohs(((u_int16_t *) (x))[4]), \ + ntohs(((u_int16_t *) (x))[5]), \ + ntohs(((u_int16_t *) (x))[6]), \ + ntohs(((u_int16_t *) (x))[7]) +#define D6F IP6F ":%u" +#define D6P(x) IP6P((x).sin6_addr.s6_addr), ntohs((x).sin6_port) #define NONBLOCK(x) fcntl(x, F_SETFL, O_NONBLOCK) #define REUSEADDR(x) do { int ONE = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &ONE, sizeof(ONE)); } while (0) diff --git a/daemon/call.c b/daemon/call.c index 90d9c11f9..725b9f386 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -119,17 +119,30 @@ static void kernelize(struct callstream *c) { r = &p->rtps[j]; rp = &pp->rtps[j]; - if (!r->peer.ip || !r->peer.port) + if (!r->peer.family || !r->peer.port) continue; - ZERO(r->kstats); - ks.local_port = r->localport; - ks.src.ip = c->call->callmaster->ip; + ks.tos = c->call->callmaster->tos; + ks.src.family = ks.dest.family = r->peer.family; ks.src.port = rp->localport; - ks.dest.ip = r->peer.ip; ks.dest.port = r->peer.port; - ks.tos = c->call->callmaster->tos; + + switch (r->peer.family) { + case AF_INET: + ks.src.ipv4 = c->call->callmaster->ipv4; + ks.dest.ipv4 = r->peer.ipv4; + break; + case AF_INET6: + memcpy(ks.src.ipv6, c->call->callmaster->ipv6, 16); + memcpy(ks.dest.ipv6, r->peer.ipv6, 16); + break; + default: + /* XXX panic */ + break; + } + + ZERO(r->kstats); kernel_add_stream(c->call->callmaster->kernelfd, &ks, 0); } @@ -141,12 +154,13 @@ static void kernelize(struct callstream *c) { -static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_in *fsin) { +static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_storage *xsin) { struct streamrelay *p, *p2; struct peer *pe, *pe2; struct callstream *cs; int ret; struct sockaddr_in sin; + struct sockaddr_in6 sin6; struct msghdr mh; struct iovec iov; unsigned char buf[256]; @@ -155,6 +169,11 @@ static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_ struct call *c; struct callmaster *m; unsigned char cc; + struct sockaddr_in *fsin; + struct sockaddr_in6 *fsin6; + + fsin = (void *) xsin; + fsin6 = (void *) xsin; pe = r->up; cs = pe->up; @@ -164,7 +183,17 @@ static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_ m = c->callmaster; if (p->fd == -1) { - mylog(LOG_WARNING, "[%s] RTP packet to port %u discarded from " DF, c->callid, r->localport, DP(*fsin)); + switch (xsin->ss_family) { + case AF_INET: + mylog(LOG_WARNING, "[%s] RTP packet to port %u discarded from " DF, c->callid, r->localport, DP(*fsin)); + break; + case AF_INET6: + mylog(LOG_WARNING, "[%s] RTP packet to port %u discarded from " D6F, c->callid, r->localport, D6P(*fsin6)); + break; + default: + /* XXX panic */ + ; + } r->stats.errors++; m->statsps.errors++; return 0; @@ -184,17 +213,39 @@ static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_ pe->codec = "unknown"; } - mylog(LOG_DEBUG, "[%s] Confirmed peer information for port %u - " DF, c->callid, r->localport, DP(*fsin)); + switch (xsin->ss_family) { + case AF_INET: + mylog(LOG_DEBUG, "[%s] Confirmed peer information for port %u - " DF, c->callid, r->localport, DP(*fsin)); + break; + case AF_INET6: + mylog(LOG_DEBUG, "[%s] Confirmed peer information for port %u - " D6F, c->callid, r->localport, D6P(*fsin6)); + break; + default: + /* XXX panic */ + ; + } pe->confirmed = 1; } - p->peer.ip = fsin->sin_addr.s_addr; - p->peer.port = ntohs(fsin->sin_port); - p2 = &p->up->rtps[p->idx ^ 1]; - p2->peer.ip = fsin->sin_addr.s_addr; - p2->peer.port = p->peer.port + ((int) (p2->idx * 2) - 1); + switch (xsin->ss_family) { + case AF_INET: + p->peer.ipv4 = fsin->sin_addr.s_addr; + p->peer.port = ntohs(fsin->sin_port); + p2->peer.ipv4 = fsin->sin_addr.s_addr; + p2->peer.port = p->peer.port + ((int) (p2->idx * 2) - 1); + break; + case AF_INET6: + memcpy(p->peer.ipv6, fsin6->sin6_addr.s6_addr, sizeof(p->peer.ipv6)); + p->peer.port = ntohs(fsin6->sin6_port); + memcpy(p2->peer.ipv6, fsin6->sin6_addr.s6_addr, sizeof(p2->peer.ipv6)); + p2->peer.port = p->peer.port + ((int) (p2->idx * 2) - 1); + break; + default: + /* XXX panic */ + ; + } @@ -207,37 +258,58 @@ static int stream_packet(struct streamrelay *r, char *b, int l, struct sockaddr_ } skip: - if (!r->peer.ip || !r->peer.port) + if (!r->peer.family || !r->peer.port) goto drop; - ZERO(sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = r->peer.ip; - sin.sin_port = htons(r->peer.port); + ZERO(mh); + + switch (r->peer.family) { + case AF_INET: + ZERO(sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = r->peer.ipv4; + sin.sin_port = htons(r->peer.port); + mh.msg_name = &sin; + mh.msg_namelen = sizeof(sin); + break; + + case AF_INET6: + ZERO(sin6); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, r->peer.ipv6, sizeof(sin6.sin6_addr.s6_addr)); + sin6.sin6_port = htons(r->peer.port); + mh.msg_name = &sin6; + mh.msg_namelen = sizeof(sin6); + break; + + default: + /* XXX panic */ + ; + } ZERO(iov); iov.iov_base = b; iov.iov_len = l; - ZERO(mh); - mh.msg_name = &sin; - mh.msg_namelen = sizeof(sin); mh.msg_iov = &iov; mh.msg_iovlen = 1; - mh.msg_control = buf; - mh.msg_controllen = sizeof(buf); - ch = CMSG_FIRSTHDR(&mh); - ZERO(*ch); - ch->cmsg_len = CMSG_LEN(sizeof(*pi)); - ch->cmsg_level = IPPROTO_IP; - ch->cmsg_type = IP_PKTINFO; + if (r->peer.family == AF_INET) { + mh.msg_control = buf; + mh.msg_controllen = sizeof(buf); - pi = (void *) CMSG_DATA(ch); - ZERO(*pi); - pi->ipi_spec_dst.s_addr = m->ip; + ch = CMSG_FIRSTHDR(&mh); + ZERO(*ch); + ch->cmsg_len = CMSG_LEN(sizeof(*pi)); + ch->cmsg_level = IPPROTO_IP; + ch->cmsg_type = IP_PKTINFO; - mh.msg_controllen = CMSG_SPACE(sizeof(*pi)); + pi = (void *) CMSG_DATA(ch); + ZERO(*pi); + pi->ipi_spec_dst.s_addr = m->ipv4; + + mh.msg_controllen = CMSG_SPACE(sizeof(*pi)); + } ret = sendmsg(p->fd, &mh, 0); @@ -264,7 +336,7 @@ static void stream_readable(int fd, void *p) { struct streamrelay *r = p; char buf[1024]; int ret; - struct sockaddr_in sin; + struct sockaddr_storage sin; unsigned int sinlen; for (;;) { @@ -317,11 +389,12 @@ static int streams_parse_func(char **a, void **ret, void *p) { st = g_slice_alloc0(sizeof(*st)); - st->ip = inet_addr(a[0]); + st->family = AF_INET; + st->ipv4 = inet_addr(a[0]); st->port = atoi(a[1]); st->mediatype = strdup(a[2] ? : ""); - if (st->ip == -1) + if (st->ipv4 == -1) goto fail; if (!st->port) goto fail; @@ -388,7 +461,11 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { hlp->ports[p->rtps[1].localport] = &p->rtps[1]; check = cm->timeout; - if (!p->rtps[0].peer.ip || !p->rtps[0].peer.port) + if (!p->rtps[0].peer.port) + check = cm->silent_timeout; + else if (p->rtps[0].peer.family == AF_INET && !p->rtps[0].peer.ipv4) + check = cm->silent_timeout; + else if (p->rtps[0].peer.family == AF_INET6 && !memcmp(p->rtps[0].peer.ipv6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) check = cm->silent_timeout; if (po->now - p->rtps[0].last < check) @@ -486,20 +563,17 @@ fail: -static int get_port(struct streamrelay *r, u_int16_t p) { +static int get_port4(struct streamrelay *r, u_int16_t p) { int fd; struct sockaddr_in sin; - if (BIT_ARRAY_ISSET(ports_used, p)) - return -1; - fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return -1; NONBLOCK(fd); REUSEADDR(fd); - setsockopt(fd, SOL_IP, IP_TOS, &r->up->up->call->callmaster->tos, sizeof(r->up->up->call->callmaster->tos)); + setsockopt(fd, IPPROTO_IP, IP_TOS, &r->up->up->call->callmaster->tos, sizeof(r->up->up->call->callmaster->tos)); ZERO(sin); sin.sin_family = AF_INET; @@ -508,7 +582,6 @@ static int get_port(struct streamrelay *r, u_int16_t p) { goto fail; r->fd = fd; - r->localport = p; return 0; @@ -517,8 +590,66 @@ fail: return -1; } +static int get_port6(struct streamrelay *r, u_int16_t p) { + int fd; + struct sockaddr_in6 sin; + int i; + + fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd < 0) + return -1; + + NONBLOCK(fd); + REUSEADDR(fd); + setsockopt(fd, IPPROTO_IP, IP_TOS, &r->up->up->call->callmaster->tos, sizeof(r->up->up->call->callmaster->tos)); + i = 1; + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)); + + ZERO(sin); + sin.sin6_family = AF_INET6; + sin.sin6_port = htons(p); + if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) + goto fail; + + r->fd = fd; + + return 0; + +fail: + close(fd); + return -1; +} + +static int get_port(struct streamrelay *r, u_int16_t p, int family) { + int ret; + + if (BIT_ARRAY_ISSET(ports_used, p)) + return -1; + + switch (family) { + case AF_INET: + ret = get_port4(r, p); + break; + case AF_INET6: + ret = get_port6(r, p); + break; + default: + /* panic XXX */ + return -1; + } + + if (ret) + return ret; + + r->localport = p; + r->peer.family = family; + r->peer_advertised.family = family; + + return 0; +} + -static void get_port_pair(struct peer *p, int wanted_port) { +static void get_port_pair(struct peer *p, int wanted_port, int family) { struct call *c; struct callmaster *m; struct streamrelay *a, *b; @@ -534,9 +665,9 @@ static void get_port_pair(struct peer *p, int wanted_port) { if (wanted_port > 0) { if ((wanted_port & 1)) goto fail; - if (get_port(a, wanted_port)) + if (get_port(a, wanted_port, family)) goto fail; - if (get_port(b, wanted_port + 1)) + if (get_port(b, wanted_port + 1, family)) goto fail; goto reserve; } @@ -560,11 +691,11 @@ static void get_port_pair(struct peer *p, int wanted_port) { if ((port & 1)) goto next; - if (get_port(a, port)) + if (get_port(a, port, family)) goto next; port++; - if (get_port(b, port)) + if (get_port(b, port, family)) goto tryagain; break; @@ -603,14 +734,17 @@ static int setup_peer(struct peer *p, struct stream *s, const char *tag) { a = &p->rtps[0]; b = &p->rtps[1]; - if (a->peer_advertised.ip != s->ip || a->peer_advertised.port != s->port) { + if (a->peer_advertised.port != s->port + || (s->family == AF_INET && a->peer_advertised.ipv4 != s->ipv4) + || (s->family == AF_INET6 && memcmp(a->peer_advertised.ipv6, s->ipv6, 16))) { cs->peers[0].confirmed = 0; unkernelize(&cs->peers[0]); cs->peers[1].confirmed = 0; unkernelize(&cs->peers[1]); } - a->peer.ip = b->peer.ip = s->ip; + memcpy(a->peer.all, s->all, sizeof(a->peer.all)); + memcpy(b->peer.all, s->all, sizeof(b->peer.all)); a->peer.port = b->peer.port = s->port; if (b->peer.port) b->peer.port++; @@ -663,19 +797,23 @@ static void steal_peer(struct peer *dest, struct peer *src) { sr->fd = srs->fd; - sr->peer.ip = srs->peer.ip; + sr->peer.family = srs->peer.family; + memcpy(sr->peer.all, srs->peer.all, sizeof(sr->peer.all)); sr->peer.port = srs->peer.port; - sr->peer_advertised.ip = srs->peer_advertised.ip; + sr->peer_advertised.family = srs->peer_advertised.family; + memcpy(sr->peer_advertised.all, srs->peer_advertised.all, sizeof(sr->peer_advertised.all)); sr->peer_advertised.port = srs->peer_advertised.port; sr->localport = srs->localport; srs->fd = -1; - srs->peer.ip = 0; + srs->peer.family = 0; + ZERO(srs->peer.all); srs->peer.port = 0; srs->localport = 0; - srs->peer_advertised.ip = 0; + srs->peer_advertised.family = 0; + ZERO(srs->peer_advertised.all); srs->peer_advertised.port = 0; pi.fd = sr->fd; @@ -688,7 +826,7 @@ static void steal_peer(struct peer *dest, struct peer *src) { } -static void callstream_init(struct callstream *s, struct call *ca, int port1, int port2) { +static void callstream_init(struct callstream *s, struct call *ca, int port1, int port2, int family) { int i, j, tport; struct peer *p; struct streamrelay *r; @@ -722,7 +860,7 @@ static void callstream_init(struct callstream *s, struct call *ca, int port1, in tport = (i == 0) ? port1 : port2; if (tport >= 0) { - get_port_pair(p, tport); + get_port_pair(p, tport, family); for (j = 0; j < 2; j++) { r = &p->rtps[j]; @@ -771,11 +909,24 @@ static int call_streams(struct call *c, GQueue *s, const char *tag, int opmode) cs_o = l->data; for (x = 0; x < 2; x++) { r = &cs_o->peers[x].rtps[0]; - DBG("comparing new "IPF":%u/%s to old "IPF":%u/%s", - IPP(t->ip), t->port, tag, - IPP(r->peer_advertised.ip), r->peer_advertised.port, cs_o->peers[x].tag); - if (r->peer_advertised.ip != t->ip) + DBG("comparing new %i:"IPF6":%u/%s to old %i:"IPF6":%u/%s", + IPP(t->ipv6), t->port, tag, + IPP(r->peer_advertised.ipv6), r->peer_advertised.port, cs_o->peers[x].tag); + if (r->peer_advertised.family != t->family) continue; + switch (t->family) { + case AF_INET: + if (r->peer_advertised.ipv4 != t->ipv4) + continue; + break; + case AF_INET6: + if (memcmp(r->peer_advertised.ipv6, t->ipv6, 16)) + continue; + break; + default: + /* XXX panic */ + ; + } if (r->peer_advertised.port != t->port) continue; if (strcmp(cs_o->peers[x].tag, tag)) @@ -799,13 +950,13 @@ found: if (!r) { /* nothing found to re-use, open new ports */ - callstream_init(cs, c, 0, 0); + callstream_init(cs, c, 0, 0, t->family); p = &cs->peers[0]; setup_peer(p, t, tag); } else { /* re-use, so don't open new ports */ - callstream_init(cs, c, -1, -1); + callstream_init(cs, c, -1, -1, t->family); if (r->up->idx == 0) { /* request/lookup came in the same order as before */ steal_peer(&cs->peers[0], &cs_o->peers[0]); @@ -870,7 +1021,7 @@ found: DBG("case 4"); cs_o = cs; cs = g_slice_alloc(sizeof(*cs)); - callstream_init(cs, c, 0, 0); + callstream_init(cs, c, 0, 0, t->family); steal_peer(&cs->peers[0], &cs_o->peers[0]); p = &cs->peers[1]; setup_peer(p, t, tag); @@ -987,7 +1138,7 @@ static char *streams_print(GQueue *s, unsigned int num, unsigned int off, const GList *l; struct callstream *t; struct streamrelay *x; - u_int32_t ip; + char ips[64]; o = g_string_new(""); if (prefix) @@ -997,16 +1148,34 @@ static char *streams_print(GQueue *s, unsigned int num, unsigned int off, const goto out; t = s->head->data; - ip = t->call->callmaster->ip; - if (t->call->callmaster->adv_ip) - ip = t->call->callmaster->adv_ip; + + switch (t->peers[off].rtps[0].peer.family) { + case AF_INET: + if (!t->peers[off].rtps[0].peer.ipv4) + strcpy(ips, "0.0.0.0"); + else if (t->call->callmaster->adv_ipv4) + sprintf(ips, IPF, IPP(t->call->callmaster->adv_ipv4)); + else + sprintf(ips, IPF, IPP(t->peers[off].rtps[0].peer.ipv4)); + break; + + case AF_INET6: + if (!memcmp(t->peers[off].rtps[0].peer.ipv6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + strcpy(ips, "::"); + else if (!memcmp(t->call->callmaster->adv_ipv6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + inet_ntop(AF_INET6, t->call->callmaster->adv_ipv6, ips, sizeof(ips)); + else + inet_ntop(AF_INET6, t->peers[off].rtps[0].peer.ipv6, ips, sizeof(ips)); + break; + default: + /* XXX panic */ + ; + } t = s->head->data; - if (t->peers[off].rtps[0].peer.ip == 0) - ip = 0; if (!swap) - g_string_append_printf(o, IPF, IPP(ip)); + g_string_append(o, ips); for (i = 0, l = s->head; i < num && l; i++, l = l->next) { t = l->data; @@ -1015,7 +1184,7 @@ static char *streams_print(GQueue *s, unsigned int num, unsigned int off, const } if (swap) - g_string_append_printf(o, IPF, IPP(ip)); + g_string_append(o, ips); out: g_string_append(o, "\n"); @@ -1043,6 +1212,32 @@ static struct call *call_get_or_create(const char *callid, struct callmaster *m) return c; } +static int addr_parse_udp(struct stream *st, const char **o) { + ZERO(st); + if (o[5] && *o[5]) { + st->family = AF_INET; + st->ipv4 = inet_addr(o[5]); + if (st->ipv4 == -1) + goto fail; + } + else if (o[6] && *o[6]) { + st->family = AF_INET6; + if (inet_pton(AF_INET6, o[6], st->ipv6) != 1) + goto fail; + } + else + goto fail; + + st->port = atoi(o[7]); + st->mediatype = "unknown"; + if (!st->port && strcmp(o[7], "0")) + goto fail; + + return 0; +fail: + return -1; +} + char *call_update_udp(const char **o, struct callmaster *m) { struct call *c; GQueue q = G_QUEUE_INIT; @@ -1053,17 +1248,11 @@ char *call_update_udp(const char **o, struct callmaster *m) { c = call_get_or_create(o[4], m); strdupfree(&c->calling_agent, "UNKNOWN(udp)"); - ZERO(st); - st.ip = inet_addr(o[5]); - st.port = atoi(o[6]); - st.mediatype = "unknown"; - if (st.ip == -1) - goto fail; - if (!st.port && strcmp(o[6], "0")) + if (addr_parse_udp(&st, o)) goto fail; g_queue_push_tail(&q, &st); - num = call_streams(c, &q, o[7], 0); + num = call_streams(c, &q, o[8], 0); g_queue_clear(&q); @@ -1076,7 +1265,7 @@ char *call_update_udp(const char **o, struct callmaster *m) { return ret; fail: - mylog(LOG_WARNING, "Failed to parse a media stream: %s:%s", o[5], o[6]); + mylog(LOG_WARNING, "Failed to parse a media stream: %s/%s:%s", o[5], o[6], o[7]); asprintf(&ret, "%s E8\n", o[1]); return ret; } @@ -1091,23 +1280,17 @@ char *call_lookup_udp(const char **o, struct callmaster *m) { c = g_hash_table_lookup(m->callhash, o[4]); if (!c) { mylog(LOG_WARNING, "[%s] Got UDP LOOKUP for unknown call-id", o[4]); - asprintf(&ret, "%s 0 " IPF "\n", o[1], IPP(m->ip)); + asprintf(&ret, "%s 0 " IPF "\n", o[1], IPP(m->ipv4)); return ret; } strdupfree(&c->called_agent, "UNKNOWN(udp)"); - ZERO(st); - st.ip = inet_addr(o[5]); - st.port = atoi(o[6]); - st.mediatype = "unknown"; - if (st.ip == -1) - goto fail; - if (!st.port && strcmp(o[6], "0")) + if (addr_parse_udp(&st, o)) goto fail; g_queue_push_tail(&q, &st); - num = call_streams(c, &q, o[8], 1); + num = call_streams(c, &q, o[9], 1); g_queue_clear(&q); @@ -1120,7 +1303,7 @@ char *call_lookup_udp(const char **o, struct callmaster *m) { return ret; fail: - mylog(LOG_WARNING, "Failed to parse a media stream: %s:%s", o[5], o[6]); + mylog(LOG_WARNING, "Failed to parse a media stream: %s/%s:%s", o[5], o[6], o[7]); asprintf(&ret, "%s E8\n", o[1]); return ret; } @@ -1239,17 +1422,50 @@ static void call_status_iterator(void *key, void *val, void *ptr) { if (r1->fd == -1 || r2->fd == -1) continue; - streambuf_printf(s->outbuf, "stream " IPF ":%u " IPF ":%u " IPF ":%u %llu/%llu/%llu %s %s %s %i\n", - IPP(r1->peer.ip), r1->peer.port, - IPP(r2->peer.ip), r2->peer.port, - IPP(m->ip), r1->localport, + streambuf_printf(s->outbuf, "stream "); + switch (r1->peer.family) { + case AF_INET: + streambuf_printf(s->outbuf, IPF, IPP(r1->peer.ipv4)); + break; + case AF_INET6: + streambuf_printf(s->outbuf, IP6F, IP6P(r1->peer.ipv6)); + break; + default: + /* XXX Panic */ + ; + } + streambuf_printf(s->outbuf, ":%u ", r1->peer.port); + switch (r2->peer.family) { + case AF_INET: + streambuf_printf(s->outbuf, IPF, IPP(r2->peer.ipv4)); + break; + case AF_INET6: + streambuf_printf(s->outbuf, IP6F, IP6P(r2->peer.ipv6)); + break; + default: + /* XXX Panic */ + ; + } + streambuf_printf(s->outbuf, ":%u ", r2->peer.port); + switch (r1->peer.family) { + case AF_INET: + streambuf_printf(s->outbuf, IPF, IPP(m->ipv4)); + break; + case AF_INET6: + streambuf_printf(s->outbuf, IP6F, IP6P(m->ipv6)); + break; + default: + /* XXX Panic */ + ; + } + streambuf_printf(s->outbuf, ":%u %llu/%llu/%llu %s %s %s %i\n", + r1->localport, (long long unsigned int) r1->stats.bytes + rx1->stats.bytes, (long long unsigned int) r2->stats.bytes + rx2->stats.bytes, (long long unsigned int) r1->stats.bytes + rx1->stats.bytes + r2->stats.bytes + rx2->stats.bytes, "active", p->codec ? : "unknown", p->mediatype, (int) (m->poller->now - r1->last)); - } } diff --git a/daemon/call.h b/daemon/call.h index 3c15a4208..32e739256 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -31,7 +31,12 @@ struct redis; struct stream { - u_int32_t ip; + int family; + union { + unsigned char all[16]; + u_int32_t ipv4; + unsigned char ipv6[16]; + }; u_int16_t port; char *mediatype; }; @@ -90,8 +95,10 @@ struct callmaster { #endif int kernelfd; unsigned int kernelid; - u_int32_t ip; - u_int32_t adv_ip; + u_int32_t ipv4; + u_int32_t adv_ipv4; + unsigned char ipv6[16]; + unsigned char adv_ipv6[16]; int port_min; int port_max; unsigned int timeout; diff --git a/daemon/control_udp.c b/daemon/control_udp.c index 0df9144fe..47b109166 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -56,6 +56,8 @@ static void control_udp_incoming(int fd, void *p) { mylog(LOG_WARNING, "Failed to properly parse UDP command line '%s' from "DF", using fallback RE", buf, DP(sin)); + pcre_get_substring_list(buf, ovec, ret, &out); + ZERO(mh); mh.msg_name = &sin; mh.msg_namelen = sizeof(sin); @@ -73,6 +75,8 @@ static void control_udp_incoming(int fd, void *p) { sendmsg(fd, &mh, 0); + pcre_free(out); + return; } @@ -185,8 +189,8 @@ struct control_udp *control_udp_new(struct poller *p, u_int32_t ip, u_int16_t po c->stale_chunks = g_string_chunk_new(4 * 1024); c->oven_time = p->now; c->parse_re = pcre_compile( - /* cookie cmd flags callid addr port from_tag to_tag cmd flags callid */ - "^(\\S+)\\s+(?:([ul])(\\S*)\\s+(\\S+)\\s+([\\d.]+)\\s+(\\d+)\\s+(\\S+?)(?:;\\S+)?(?:\\s+(\\S+?)(?:;\\S+)?(?:\\s+.*)?)?\r?\n?$|(d)(\\S*)\\s+(\\S+)|(v)(\\S*)(?:\\s+(\\S+))?)", + /* cookie:1 cmd:2 flags:3 callid:4 addr4:5 addr6:6 port:7 from_tag:8 to_tag:9 cmd flags callid */ + "^(\\S+)\\s+(?:([ul])(\\S*)\\s+(\\S+)\\s+(?:([\\d.]+)|([\\da-f:]+(?::[\\d.]+)?))\\s+(\\d+)\\s+(\\S+?)(?:;\\S+)?(?:\\s+(\\S+?)(?:;\\S+)?(?:\\s+.*)?)?\r?\n?$|(d)(\\S*)\\s+(\\S+)|(v)(\\S*)(?:\\s+(\\S+))?)", PCRE_DOLLAR_ENDONLY | PCRE_DOTALL | PCRE_CASELESS, &errptr, &erroff, NULL); c->parse_ree = pcre_study(c->parse_re, 0, &errptr); /* cookie cmd flags callid addr port */ diff --git a/daemon/kernel.c b/daemon/kernel.c index 5d929ebc8..bf47698cc 100644 --- a/daemon/kernel.c +++ b/daemon/kernel.c @@ -71,21 +71,32 @@ fail: } +static void addr_copy(struct mp_address *mp, struct ip_port *ap) { + mp->family = ap->family; + mp->port = ap->port; + switch (mp->family) { + case AF_INET: + mp->ipv4 = ap->ipv4; + break; + case AF_INET6: + memcpy(mp->ipv6, ap->ipv6, 16); + break; + default: + /* XXX panic */ + break; + } +} + + int kernel_add_stream(int fd, struct kernel_stream *info, int update) { struct mediaproxy_message msg; ZERO(msg); msg.cmd = update ? MMG_UPDATE : MMG_ADD; msg.target.target_port = info->local_port; - msg.target.src_addr.family = AF_INET; - msg.target.src_addr.ipv4 = info->src.ip; - msg.target.src_addr.port = info->src.port; - msg.target.dst_addr.family = AF_INET; - msg.target.dst_addr.ipv4 = info->dest.ip; - msg.target.dst_addr.port = info->dest.port; - msg.target.mirror_addr.family = AF_INET; - msg.target.mirror_addr.ipv4 = info->mirror.ip; - msg.target.mirror_addr.port = info->mirror.port; + addr_copy(&msg.target.src_addr, &info->src); + addr_copy(&msg.target.dst_addr, &info->dest); + addr_copy(&msg.target.mirror_addr, &info->mirror); msg.target.tos = info->tos; return write(fd, &msg, sizeof(msg)) <= 0 ? -1 : 0; diff --git a/daemon/kernel.h b/daemon/kernel.h index f3c34afd4..b6ac5e5d5 100644 --- a/daemon/kernel.h +++ b/daemon/kernel.h @@ -10,7 +10,11 @@ struct ip_port { - u_int32_t ip; + int family; + union { + u_int32_t ipv4; + unsigned char ipv6[16]; + }; u_int16_t port; }; diff --git a/daemon/main.c b/daemon/main.c index 20120caab..53453c44e 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -245,8 +245,8 @@ int main(int argc, char **argv) { return -1; m->kernelfd = kfd; m->kernelid = table; - m->ip = ip; - m->adv_ip = adv_ip; + m->ipv4 = ip; + m->adv_ipv4 = adv_ip; m->port_min = port_min; m->port_max = port_max; m->timeout = timeout;