diff --git a/daemon/call.c b/daemon/call.c index 72bae47a9..548ebff41 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -500,6 +500,41 @@ dummy: in->handler = &__sh_noop; } +void callmaster_msg_mh_src(struct callmaster *cm, struct msghdr *mh) { + struct cmsghdr *ch; + struct in_pktinfo *pi; + struct in6_pktinfo *pi6; + struct sockaddr_in6 *sin6; + + sin6 = mh->msg_name; + + ch = CMSG_FIRSTHDR(mh); + ZERO(*ch); + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + ch->cmsg_len = CMSG_LEN(sizeof(*pi)); + ch->cmsg_level = IPPROTO_IP; + ch->cmsg_type = IP_PKTINFO; + + pi = (void *) CMSG_DATA(ch); + ZERO(*pi); + pi->ipi_spec_dst.s_addr = cm->conf.ipv4; + + mh->msg_controllen = CMSG_SPACE(sizeof(*pi)); + } + else { + ch->cmsg_len = CMSG_LEN(sizeof(*pi6)); + ch->cmsg_level = IPPROTO_IPV6; + ch->cmsg_type = IPV6_PKTINFO; + + pi6 = (void *) CMSG_DATA(ch); + ZERO(*pi6); + pi6->ipi6_addr = cm->conf.ipv6; + + mh->msg_controllen = CMSG_SPACE(sizeof(*pi6)); + } +} + /* called with r->up (== cs) locked */ static int stream_packet(struct streamrelay *sr_incoming, str *s, struct sockaddr_in6 *fsin) { struct streamrelay *sr_outgoing, *sr_out_rtcp, *sr_in_rtcp; @@ -510,9 +545,6 @@ static int stream_packet(struct streamrelay *sr_incoming, str *s, struct sockadd struct msghdr mh; struct iovec iov; unsigned char buf[256]; - struct cmsghdr *ch; - struct in_pktinfo *pi; - struct in6_pktinfo *pi6; struct call *c; struct callmaster *m; unsigned char cc; @@ -625,9 +657,6 @@ forward: mh.msg_control = buf; mh.msg_controllen = sizeof(buf); - ch = CMSG_FIRSTHDR(&mh); - ZERO(*ch); - ZERO(sin6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = sr_incoming->peer.ip46; @@ -635,28 +664,7 @@ forward: mh.msg_name = &sin6; mh.msg_namelen = sizeof(sin6); - if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { - ch->cmsg_len = CMSG_LEN(sizeof(*pi)); - ch->cmsg_level = IPPROTO_IP; - ch->cmsg_type = IP_PKTINFO; - - pi = (void *) CMSG_DATA(ch); - ZERO(*pi); - pi->ipi_spec_dst.s_addr = m->conf.ipv4; - - mh.msg_controllen = CMSG_SPACE(sizeof(*pi)); - } - else { - ch->cmsg_len = CMSG_LEN(sizeof(*pi6)); - ch->cmsg_level = IPPROTO_IPV6; - ch->cmsg_type = IPV6_PKTINFO; - - pi6 = (void *) CMSG_DATA(ch); - ZERO(*pi6); - pi6->ipi6_addr = m->conf.ipv6; - - mh.msg_controllen = CMSG_SPACE(sizeof(*pi6)); - } + callmaster_msg_mh_src(m, &mh); ZERO(iov); iov.iov_base = s->s; diff --git a/daemon/call.h b/daemon/call.h index 072b74e87..88e0e2ad6 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -183,6 +183,7 @@ struct callmaster *callmaster_new(struct poller *); void callmaster_config(struct callmaster *m, struct callmaster_config *c); void callmaster_exclude_port(struct callmaster *m, u_int16_t p); int callmaster_has_ipv6(struct callmaster *); +void callmaster_msg_mh_src(struct callmaster *, struct msghdr *); str *call_request_tcp(char **, struct callmaster *); diff --git a/daemon/stun.c b/daemon/stun.c index 54c32fe2f..1b4636242 100644 --- a/daemon/stun.c +++ b/daemon/stun.c @@ -174,9 +174,14 @@ out: } static void output_init(struct msghdr *mh, struct iovec *iov, struct sockaddr_in6 *sin, - struct header *hdr, unsigned short code, u_int32_t *transaction) + struct header *hdr, unsigned short code, u_int32_t *transaction, + unsigned char *buf, int buflen) { ZERO(*mh); + + mh->msg_control = buf; + mh->msg_controllen = buflen; + mh->msg_name = sin; mh->msg_namelen = sizeof(*sin); mh->msg_iov = iov; @@ -222,11 +227,13 @@ static inline void __output_add(struct msghdr *mh, struct tlv *tlv, unsigned int __output_add(mh, &(attr)->tlv, sizeof(*(attr)), code, data, len) -static void output_finish(struct msghdr *mh) { +static void output_finish(struct msghdr *mh, struct callmaster *cm) { struct header *hdr; hdr = mh->msg_iov->iov_base; hdr->msg_len = htons(hdr->msg_len); + + callmaster_msg_mh_src(cm, mh); } static void fingerprint(struct msghdr *mh, struct fingerprint *fp) { @@ -278,7 +285,7 @@ static void integrity(struct msghdr *mh, struct msg_integrity *mi, str *pwd) { static void stun_error_len(int fd, struct sockaddr_in6 *sin, struct header *req, int code, char *reason, int len, u_int16_t add_attr, void *attr_cont, - int attr_len) + int attr_len, struct callmaster *cm) { struct header hdr; struct error_code ec; @@ -286,8 +293,9 @@ static void stun_error_len(int fd, struct sockaddr_in6 *sin, struct header *req, struct generic aa; struct msghdr mh; struct iovec iov[6]; /* hdr, ec, reason, aa, attr_cont, fp */ + unsigned char buf[256]; - output_init(&mh, iov, sin, &hdr, STUN_BINDING_ERROR_RESPONSE, req->transaction); + output_init(&mh, iov, sin, &hdr, STUN_BINDING_ERROR_RESPONSE, req->transaction, buf, sizeof(buf)); ec.codes = htonl(((code / 100) << 8) | (code % 100)); output_add_data(&mh, &ec, STUN_ERROR_CODE, reason, len); @@ -296,16 +304,16 @@ static void stun_error_len(int fd, struct sockaddr_in6 *sin, struct header *req, fingerprint(&mh, &fp); - output_finish(&mh); + output_finish(&mh, cm); sendmsg(fd, &mh, 0); } -#define stun_error(fd, sin, str, code, reason) \ +#define stun_error(cm, fd, sin, str, code, reason) \ stun_error_len(fd, sin, str, code, reason "\0\0\0", strlen(reason), \ - 0, NULL, 0) -#define stun_error_attrs(fd, sin, str, code, reason, type, content, len) \ + 0, NULL, 0, cm) +#define stun_error_attrs(cm, fd, sin, str, code, reason, type, content, len) \ stun_error_len(fd, sin, str, code, reason "\0\0\0", strlen(reason), \ - type, content, len) + type, content, len, cm) @@ -367,8 +375,10 @@ static int stun_binding_success(int fd, struct header *req, struct stun_attrs *a struct fingerprint fp; struct msghdr mh; struct iovec iov[4]; /* hdr, xma, mi, fp */ + unsigned char buf[256]; + struct callmaster *cm = peer->up->call->callmaster; - output_init(&mh, iov, sin, &hdr, STUN_BINDING_SUCCESS_RESPONSE, req->transaction); + output_init(&mh, iov, sin, &hdr, STUN_BINDING_SUCCESS_RESPONSE, req->transaction, buf, sizeof(buf)); xma.port = sin->sin6_port ^ htons(STUN_COOKIE >> 16); if (IN6_IS_ADDR_V4MAPPED(&sin->sin6_addr)) { @@ -388,7 +398,7 @@ static int stun_binding_success(int fd, struct header *req, struct stun_attrs *a integrity(&mh, &mi, &peer->ice_pwd); fingerprint(&mh, &fp); - output_finish(&mh); + output_finish(&mh, cm); sendmsg(fd, &mh, 0); return 0; @@ -417,6 +427,7 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) { u_int16_t unknowns[UNKNOWNS_COUNT]; const char *err; char addr[64]; + struct callmaster *cm = sr->up->up->call->callmaster; smart_ntop_port(addr, sin, sizeof(addr)); @@ -442,7 +453,7 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) { goto ignore; mylog(LOG_WARNING, "STUN packet contained unknown " "\"comprehension required\" attribute(s)" SLF, SLP); - stun_error_attrs(sr->fd.fd, sin, req, 420, "Unknown attribute", + stun_error_attrs(cm, sr->fd.fd, sin, req, 420, "Unknown attribute", STUN_UNKNOWN_ATTRIBUTES, unknowns, u_int16_t_arr_len(unknowns) * 2); return 0; @@ -474,11 +485,11 @@ int stun(str *b, struct streamrelay *sr, struct sockaddr_in6 *sin) { bad_req: mylog(LOG_INFO, "Received invalid STUN packet" SLF ": %s", SLP, err); - stun_error(sr->fd.fd, sin, req, 400, "Bad request"); + stun_error(cm, sr->fd.fd, sin, req, 400, "Bad request"); return 0; unauth: mylog(LOG_INFO, "STUN authentication mismatch" SLF, SLP); - stun_error(sr->fd.fd, sin, req, 401, "Unauthorized"); + stun_error(cm, sr->fd.fd, sin, req, 401, "Unauthorized"); return 0; ignore: mylog(LOG_INFO, "Not handling potential STUN packet" SLF ": %s", SLP, err);