From 8684a1933a3aad0731aec86ca242ea2e363cbe01 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 1 Aug 2023 14:31:25 -0400 Subject: [PATCH] MT#57977 use symmetric UDP UDP packets sent in response to a UDP request should have the same source address as the request's destination address. This can be achieved with sockets bound to a specific address, but in the case of ANY-bound sockets, we can use the PKTINFO mechanism to do this. Extend control_ng_process() to accept an extra socket address corresponding to the local address to use. Extend the signature of the callback function (to do the actual sending) accordingly. Extend socket_sendiov() to be able to set the PKTINFO cmsg when sending a packet. Add socket_sendto_from() as a convenience wrapper. Extend control_udp_incoming() to pass the address from udp_buf->local_addr back to socket_sendiov(). Change-Id: Idd019fdcfd796098e7807427e6686d4b05de35d1 --- daemon/control_ng.c | 26 ++++++++++++++++++-------- daemon/control_udp.c | 8 ++++---- daemon/websocket.c | 13 +++++++++---- include/control_ng.h | 4 ++-- lib/socket.h | 23 ++++++++++++++++++++++- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 6ea0ed12f..b5589f4b6 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -139,8 +139,9 @@ struct ng_buffer *ng_buffer_new(struct obj *ref) { return ngbuf; } -int control_ng_process(str *buf, const endpoint_t *sin, char *addr, - void (*cb)(str *, str *, const endpoint_t *, void *), void *p1, struct obj *ref) +int control_ng_process(str *buf, const endpoint_t *sin, char *addr, const sockaddr_t *local, + void (*cb)(str *, str *, const endpoint_t *, const sockaddr_t *, void *), + void *p1, struct obj *ref) { AUTO_CLEANUP(struct ng_buffer *ngbuf, ng_buffer_auto_release) = NULL; bencode_item_t *dict, *resp; @@ -398,7 +399,7 @@ send_resp: send_only: funcret = 0; - cb(&cookie, to_send, sin, p1); + cb(&cookie, to_send, sin, local, p1); if (resp) cookie_cache_insert(&ng_cookie_cache, &cookie, &reply); @@ -413,7 +414,9 @@ out: return funcret; } -static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void *p1) { +INLINE void control_ng_send_generic(str *cookie, str *body, const endpoint_t *sin, const sockaddr_t *from, + void *p1) +{ socket_t *ul = p1; struct iovec iov[3]; unsigned int iovlen; @@ -427,12 +430,19 @@ static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void iov[2].iov_base = body->s; iov[2].iov_len = body->len; - socket_sendiov(ul, iov, iovlen, sin); + socket_sendiov(ul, iov, iovlen, sin, from); +} +static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, const sockaddr_t *from, void *p1) { + control_ng_send_generic(cookie, body, sin, NULL, p1); +} +static void control_ng_send_from(str *cookie, str *body, const endpoint_t *sin, const sockaddr_t *from, void *p1) { + control_ng_send_generic(cookie, body, sin, from, p1); } static void control_ng_incoming(struct obj *obj, struct udp_buffer *udp_buf) { - control_ng_process(&udp_buf->str, &udp_buf->sin, udp_buf->addr, control_ng_send, udp_buf->listener, + control_ng_process(&udp_buf->str, &udp_buf->sin, udp_buf->addr, &udp_buf->local_addr, + control_ng_send_from, udp_buf->listener, &udp_buf->obj); } @@ -498,7 +508,7 @@ static void control_stream_readable(struct streambuf_stream *s) { ilog(LOG_DEBUG, "Got %zu bytes from %s", s->inbuf->buf->len, s->addr); while ((data = chunk_message(s->inbuf))) { ilog(LOG_DEBUG, "Got control ng message from %s", s->addr); - control_ng_process(data, &s->sock.remote, s->addr, control_ng_send, &s->sock, s->parent); + control_ng_process(data, &s->sock.remote, s->addr, NULL, control_ng_send, &s->sock, s->parent); free(data); } @@ -582,7 +592,7 @@ static void notify_tcp_client(gpointer key, gpointer value, gpointer user_data) str cookie = STR_CONST_INIT(cookie_buf); rand_hex_str(cookie_buf, cookie.len / 2); - control_ng_send(&cookie, to_send, &s->sock.remote, &s->sock); + control_ng_send(&cookie, to_send, &s->sock.remote, NULL, &s->sock); } void notify_ng_tcp_clients(str *data) { diff --git a/daemon/control_udp.c b/daemon/control_udp.c index 3bd2f85b6..1fd69f0c9 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -59,7 +59,7 @@ static void control_udp_incoming(struct obj *obj, struct udp_buffer *udp_buf) { iovlen = 2; } - socket_sendiov(udp_buf->listener, iov, iovlen, &udp_buf->sin); + socket_sendiov(udp_buf->listener, iov, iovlen, &udp_buf->sin, &udp_buf->local_addr); pcre2_substring_list_free((PCRE2_SPTR *) out); pcre2_match_data_free(md); @@ -75,7 +75,7 @@ static void control_udp_incoming(struct obj *obj, struct udp_buffer *udp_buf) { reply = cookie_cache_lookup(&u->cookie_cache, &cookie); if (reply) { ilogs(control, LOG_INFO, "Detected command from udp:%s as a duplicate", udp_buf->addr); - socket_sendto(udp_buf->listener, reply->s, reply->len, &udp_buf->sin); + socket_sendto_from(udp_buf->listener, reply->s, reply->len, &udp_buf->sin, &udp_buf->local_addr); free(reply); goto out; } @@ -118,11 +118,11 @@ static void control_udp_incoming(struct obj *obj, struct udp_buffer *udp_buf) { iov[2].iov_len = 9; iovlen++; } - socket_sendiov(udp_buf->listener, iov, iovlen, &udp_buf->sin); + socket_sendiov(udp_buf->listener, iov, iovlen, &udp_buf->sin, &udp_buf->local_addr); } if (reply) { - socket_sendto(udp_buf->listener, reply->s, reply->len, &udp_buf->sin); + socket_sendto_from(udp_buf->listener, reply->s, reply->len, &udp_buf->sin, &udp_buf->local_addr); cookie_cache_insert(&u->cookie_cache, &cookie, reply); free(reply); } diff --git a/daemon/websocket.c b/daemon/websocket.c index 0a7fab78c..fc73cb894 100644 --- a/daemon/websocket.c +++ b/daemon/websocket.c @@ -463,14 +463,18 @@ static const char *websocket_cli_process(struct websocket_message *wm) { } -static void websocket_ng_send_ws(str *cookie, str *body, const endpoint_t *sin, void *p1) { +static void websocket_ng_send_ws(str *cookie, str *body, const endpoint_t *sin, const sockaddr_t *from, + void *p1) +{ struct websocket_conn *wc = p1; websocket_queue_raw(wc, cookie->s, cookie->len); websocket_queue_raw(wc, " ", 1); websocket_queue_raw(wc, body->s, body->len); websocket_write_binary(wc, NULL, 0, true); } -static void websocket_ng_send_http(str *cookie, str *body, const endpoint_t *sin, void *p1) { +static void websocket_ng_send_http(str *cookie, str *body, const endpoint_t *sin, const sockaddr_t *from, + void *p1) +{ struct websocket_conn *wc = p1; websocket_http_response(wc, 200, "application/x-rtpengine-ng", cookie->len + 1 + body->len); websocket_queue_raw(wc, cookie->s, cookie->len); @@ -497,7 +501,7 @@ static const char *websocket_ng_process(struct websocket_message *wm) { str_init_len(&buf->cmd, buf->body->str, buf->body->len); buf->endpoint = wm->wc->endpoint; - control_ng_process(&buf->cmd, &buf->endpoint, buf->addr, websocket_ng_send_ws, wm->wc, &buf->obj); + control_ng_process(&buf->cmd, &buf->endpoint, buf->addr, NULL, websocket_ng_send_ws, wm->wc, &buf->obj); obj_put(buf); @@ -516,7 +520,8 @@ static const char *websocket_http_ng(struct websocket_message *wm) { str_init_len(&buf->cmd, buf->body->str, buf->body->len); buf->endpoint = wm->wc->endpoint; - if (control_ng_process(&buf->cmd, &buf->endpoint, buf->addr, websocket_ng_send_http, wm->wc, &buf->obj)) + if (control_ng_process(&buf->cmd, &buf->endpoint, buf->addr, NULL, websocket_ng_send_http, wm->wc, + &buf->obj)) websocket_http_complete(wm->wc, 600, "text/plain", 6, "error\n"); obj_put(buf); diff --git a/include/control_ng.h b/include/control_ng.h index b90814a3d..5fd87494b 100644 --- a/include/control_ng.h +++ b/include/control_ng.h @@ -70,8 +70,8 @@ struct control_ng *control_ng_tcp_new(const endpoint_t *); void notify_ng_tcp_clients(str *); void control_ng_init(void); void control_ng_cleanup(void); -int control_ng_process(str *buf, const endpoint_t *sin, char *addr, - void (*cb)(str *, str *, const endpoint_t *, void *), void *p1, struct obj *); +int control_ng_process(str *buf, const endpoint_t *sin, char *addr, const sockaddr_t *local, + void (*cb)(str *, str *, const endpoint_t *, const sockaddr_t *, void *), void *p1, struct obj *); struct ng_buffer *ng_buffer_new(struct obj *ref); diff --git a/lib/socket.h b/lib/socket.h index 3c0581aea..430c29b76 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -177,13 +177,34 @@ INLINE int is_addr_unspecified(const sockaddr_t *a) { #define socket_error(s) (s)->family->error((s)) #define socket_timestamping(s) (s)->family->timestamping((s)) #define socket_pktinfo(s) (s)->family->pktinfo((s)) -INLINE ssize_t socket_sendiov(socket_t *s, const struct iovec *v, unsigned int len, const endpoint_t *dst) { +INLINE ssize_t socket_sendiov(socket_t *s, const struct iovec *v, unsigned int len, const endpoint_t *dst, + const sockaddr_t *src) +{ struct msghdr mh; + char ctrl[64]; + ZERO(mh); mh.msg_iov = (void *) v; mh.msg_iovlen = len; + + if (src) { + mh.msg_control = ctrl; + mh.msg_controllen = sizeof(ctrl); + + struct cmsghdr *cm = CMSG_FIRSTHDR(&mh); + + s->family->cmsg_pktinfo(cm, src); + cm = CMSG_NXTHDR(&mh, cm); + assert(cm != NULL); + + mh.msg_controllen = (char *) cm - ctrl; + } + return socket_sendmsg(s, &mh, dst); } +INLINE ssize_t socket_sendto_from(socket_t *s, const void *b, size_t l, const endpoint_t *dst, sockaddr_t *src) { + return socket_sendiov(s, &(struct iovec) { .iov_base = (void *) b, .iov_len = l }, l, dst, src); +}