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
pull/1722/head
Richard Fuchs 2 years ago
parent ddc3565bfe
commit 8684a1933a

@ -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) {

@ -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);
}

@ -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);

@ -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);

@ -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);
}

Loading…
Cancel
Save