poll: Document reentrancy restriction on before()
[secnet] / udp.c
1 /* UDP send/receive module for secnet */
2
3 /* This module enables sites to communicate by sending UDP
4 * packets. When an instance of the module is created we can
5 * optionally bind to a particular local IP address (not implemented
6 * yet).
7 *
8 * Packets are offered to registered receivers in turn. Once one
9 * accepts it, it isn't offered to any more. */
10
11 #include "secnet.h"
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <sys/socket.h>
18 #include <sys/wait.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include "util.h"
22 #include "magic.h"
23 #include "unaligned.h"
24 #include "ipaddr.h"
25 #include "magic.h"
26
27 static beforepoll_fn udp_beforepoll;
28 static afterpoll_fn udp_afterpoll;
29 static comm_request_notify_fn request_notify;
30 static comm_release_notify_fn release_notify;
31 static comm_sendmsg_fn udp_sendmsg;
32
33 struct comm_notify_entry {
34 comm_notify_fn *fn;
35 void *state;
36 LIST_ENTRY(comm_notify_entry) entry;
37 };
38 LIST_HEAD(comm_notify_list, comm_notify_entry) notify;
39
40 #define MAX_SOCKETS 3 /* 2 ought to do really */
41
42 struct udpsock {
43 union iaddr addr;
44 int fd;
45 };
46
47 struct udp {
48 closure_t cl;
49 struct comm_if ops;
50 struct cloc loc;
51 int n_socks;
52 struct udpsock socks[MAX_SOCKETS];
53 string_t authbind;
54 struct buffer_if *rbuf;
55 struct comm_notify_list notify;
56 bool_t use_proxy;
57 union iaddr proxy;
58 };
59
60 /*
61 * Re comm_addr.ix: This field allows us to note in the comm_addr
62 * which socket an incoming packet was received on. This is required
63 * for conveniently logging the actual source of a packet. But the ix
64 * does not formally form part of the address: it is not used when
65 * sending, nor when comparing two comm_addrs.
66 *
67 * The special value -1 means that the comm_addr was constructed by
68 * another module in secnet (eg the resolver), rather than being a
69 * description of the source of an incoming packet.
70 */
71
72 static const char *addr_to_string(void *commst, const struct comm_addr *ca) {
73 struct udp *st=commst;
74 static char sbuf[100];
75 int ix=ca->ix>=0 ? ca->ix : 0;
76
77 assert(ix>=0 && ix<st->n_socks);
78 snprintf(sbuf, sizeof(sbuf), "udp:%s%s-%s",
79 iaddr_to_string(&st->socks[ix].addr),
80 ca->ix<0 ? "&" : "",
81 iaddr_to_string(&ca->ia));
82 return sbuf;
83 }
84
85 static int udp_beforepoll(void *state, struct pollfd *fds, int *nfds_io,
86 int *timeout_io)
87 {
88 int i;
89 struct udp *st=state;
90 BEFOREPOLL_WANT_FDS(st->n_socks);
91 for (i=0; i<st->n_socks; i++) {
92 fds[i].fd=st->socks[i].fd;
93 fds[i].events=POLLIN;
94 }
95 return 0;
96 }
97
98 static void udp_afterpoll(void *state, struct pollfd *fds, int nfds)
99 {
100 struct udp *st=state;
101 union iaddr from;
102 socklen_t fromlen;
103 struct comm_notify_entry *n;
104 bool_t done;
105 int rv;
106 int i;
107
108 for (i=0; i<st->n_socks; i++) {
109 if (i>=nfds) continue;
110 if (!(fds[i].revents & POLLIN)) continue;
111 assert(fds[i].fd == st->socks[i].fd);
112 int fd=st->socks[i].fd;
113 do {
114 fromlen=sizeof(from);
115 BUF_ASSERT_FREE(st->rbuf);
116 BUF_ALLOC(st->rbuf,"udp_afterpoll");
117 buffer_init(st->rbuf,calculate_max_start_pad());
118 rv=recvfrom(fd, st->rbuf->start,
119 buf_remaining_space(st->rbuf),
120 0, &from.sa, &fromlen);
121 if (rv>0) {
122 st->rbuf->size=rv;
123 if (st->use_proxy) {
124 /* Check that the packet came from our poxy server;
125 we shouldn't be contacted directly by anybody else
126 (since they can trivially forge source addresses) */
127 if (!iaddr_equal(&from,&st->proxy)) {
128 Message(M_INFO,"udp: received packet that's not "
129 "from the proxy\n");
130 BUF_FREE(st->rbuf);
131 continue;
132 }
133 /* proxy protocol supports ipv4 transport only */
134 from.sa.sa_family=AF_INET;
135 memcpy(&from.sin.sin_addr,buf_unprepend(st->rbuf,4),4);
136 buf_unprepend(st->rbuf,2);
137 memcpy(&from.sin.sin_port,buf_unprepend(st->rbuf,2),2);
138 }
139 struct comm_addr ca;
140 ca.comm=&st->ops;
141 ca.ia=from;
142 ca.ix=i;
143 done=False;
144 LIST_FOREACH(n, &st->notify, entry) {
145 if (n->fn(n->state, st->rbuf, &ca)) {
146 done=True;
147 break;
148 }
149 }
150 if (!done) {
151 uint32_t msgtype;
152 if (st->rbuf->size>12 /* prevents traffic amplification */
153 && ((msgtype=get_uint32(st->rbuf->start+8))
154 != LABEL_NAK)) {
155 uint32_t source,dest;
156 /* Manufacture and send NAK packet */
157 source=get_uint32(st->rbuf->start); /* Us */
158 dest=get_uint32(st->rbuf->start+4); /* Them */
159 send_nak(&ca,source,dest,msgtype,st->rbuf,"unwanted");
160 }
161 BUF_FREE(st->rbuf);
162 }
163 BUF_ASSERT_FREE(st->rbuf);
164 } else {
165 BUF_FREE(st->rbuf);
166 }
167 } while (rv>=0);
168 }
169 }
170
171 static void request_notify(void *commst, void *nst, comm_notify_fn *fn)
172 {
173 struct udp *st=commst;
174 struct comm_notify_entry *n;
175
176 n=safe_malloc(sizeof(*n),"request_notify");
177 n->fn=fn;
178 n->state=nst;
179 LIST_INSERT_HEAD(&st->notify, n, entry);
180 }
181
182 static void release_notify(void *commst, void *nst, comm_notify_fn *fn)
183 {
184 struct udp *st=commst;
185 struct comm_notify_entry *n, *t;
186
187 /* XXX untested */
188 LIST_FOREACH_SAFE(n, &st->notify, entry, t) {
189 if (n->state==nst && n->fn==fn) {
190 LIST_REMOVE(n, entry);
191 free(n);
192 }
193 }
194 }
195
196 static bool_t udp_sendmsg(void *commst, struct buffer_if *buf,
197 const struct comm_addr *dest)
198 {
199 struct udp *st=commst;
200 uint8_t *sa;
201
202 if (st->use_proxy) {
203 sa=buf_prepend(buf,8);
204 if (dest->ia.sa.sa_family != AF_INET) {
205 Message(M_INFO,
206 "udp: proxy means dropping outgoing non-IPv4 packet to %s\n",
207 iaddr_to_string(&dest->ia));
208 return False;
209 }
210 memcpy(sa,&dest->ia.sin.sin_addr,4);
211 memset(sa+4,0,4);
212 memcpy(sa+6,&dest->ia.sin.sin_port,2);
213 sendto(st->socks[0].fd,sa,buf->size+8,0,&st->proxy.sa,
214 iaddr_socklen(&st->proxy));
215 buf_unprepend(buf,8);
216 } else {
217 int i,r;
218 bool_t allunsupported=True;
219 for (i=0; i<st->n_socks; i++) {
220 if (dest->ia.sa.sa_family != st->socks[i].addr.sa.sa_family)
221 /* no point even trying */
222 continue;
223 r=sendto(st->socks[i].fd, buf->start, buf->size, 0,
224 &dest->ia.sa, iaddr_socklen(&dest->ia));
225 if (r>=0) return True;
226 if (!(errno==EAFNOSUPPORT || errno==ENETUNREACH))
227 /* who knows what that error means? */
228 allunsupported=False;
229 }
230 return !allunsupported; /* see doc for comm_sendmsg_fn in secnet.h */
231 }
232
233 return True;
234 }
235
236 static void udp_make_socket(struct udp *st, struct udpsock *us)
237 {
238 const union iaddr *addr=&us->addr;
239 us->fd=socket(addr->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
240 if (us->fd<0) {
241 fatal_perror("udp (%s:%d): socket",st->loc.file,st->loc.line);
242 }
243 if (fcntl(us->fd, F_SETFL, fcntl(us->fd, F_GETFL)|O_NONBLOCK)==-1) {
244 fatal_perror("udp (%s:%d): fcntl(set O_NONBLOCK)",
245 st->loc.file,st->loc.line);
246 }
247 setcloexec(us->fd);
248 #ifdef CONFIG_IPV6
249 if (addr->sa.sa_family==AF_INET6) {
250 int r;
251 int optval=1;
252 socklen_t optlen=sizeof(optval);
253 r=setsockopt(us->fd,IPPROTO_IPV6,IPV6_V6ONLY,&optval,optlen);
254 if (r) fatal_perror("udp (%s:%d): setsockopt(,IPV6_V6ONLY,&1,)",
255 st->loc.file,st->loc.line);
256 }
257 #endif
258
259 if (st->authbind) {
260 pid_t c;
261 int status;
262
263 /* XXX this fork() and waitpid() business needs to be hidden
264 in some system-specific library functions. */
265 c=fork();
266 if (c==-1) {
267 fatal_perror("udp_phase_hook: fork() for authbind");
268 }
269 if (c==0) {
270 char *argv[5], addrstr[33], portstr[5];
271 const char *addrfam;
272 int port;
273 switch (addr->sa.sa_family) {
274 case AF_INET:
275 sprintf(addrstr,"%08lX",(long)addr->sin.sin_addr.s_addr);
276 port=addr->sin.sin_port;
277 addrfam=NULL;
278 break;
279 #ifdef CONFIG_IPV6
280 case AF_INET6: {
281 int i;
282 for (i=0; i<16; i++)
283 sprintf(addrstr+i*2,"%02X",addr->sin6.sin6_addr.s6_addr[i]);
284 port=addr->sin6.sin6_port;
285 addrfam="6";
286 break;
287 }
288 #endif /*CONFIG_IPV6*/
289 default:
290 fatal("udp (%s:%d): unsupported address family for authbind",
291 st->loc.file,st->loc.line);
292 }
293 sprintf(portstr,"%04X",port);
294 argv[0]=st->authbind;
295 argv[1]=addrstr;
296 argv[2]=portstr;
297 argv[3]=(char*)addrfam;
298 argv[4]=NULL;
299 dup2(us->fd,0);
300 execvp(st->authbind,argv);
301 _exit(255);
302 }
303 while (waitpid(c,&status,0)==-1) {
304 if (errno==EINTR) continue;
305 fatal_perror("udp (%s:%d): authbind",st->loc.file,st->loc.line);
306 }
307 if (WIFSIGNALED(status)) {
308 fatal("udp (%s:%d): authbind died on signal %d",st->loc.file,
309 st->loc.line, WTERMSIG(status));
310 }
311 if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
312 fatal("udp (%s:%d): authbind died with status %d",st->loc.file,
313 st->loc.line, WEXITSTATUS(status));
314 }
315 } else {
316 if (bind(us->fd, &addr->sa, iaddr_socklen(addr))!=0) {
317 fatal_perror("udp (%s:%d): bind",st->loc.file,st->loc.line);
318 }
319 }
320 }
321
322 static void udp_phase_hook(void *sst, uint32_t new_phase)
323 {
324 struct udp *st=sst;
325 int i;
326 for (i=0; i<st->n_socks; i++)
327 udp_make_socket(st,&st->socks[i]);
328
329 register_for_poll(st,udp_beforepoll,udp_afterpoll,"udp");
330 }
331
332 static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
333 list_t *args)
334 {
335 struct udp *st;
336 item_t *item;
337 list_t *caddrl;
338 dict_t *d;
339 list_t *l;
340 uint32_t a;
341 int i;
342
343 st=safe_malloc(sizeof(*st),"udp_apply(st)");
344 st->loc=loc;
345 st->cl.description="udp";
346 st->cl.type=CL_COMM;
347 st->cl.apply=NULL;
348 st->cl.interface=&st->ops;
349 st->ops.st=st;
350 st->ops.request_notify=request_notify;
351 st->ops.release_notify=release_notify;
352 st->ops.sendmsg=udp_sendmsg;
353 st->ops.addr_to_string=addr_to_string;
354 st->use_proxy=False;
355 LIST_INIT(&st->notify);
356
357 item=list_elem(args,0);
358 if (!item || item->type!=t_dict) {
359 cfgfatal(st->loc,"udp","first argument must be a dictionary\n");
360 }
361 d=item->data.dict;
362
363 int port=dict_read_number(d,"port",True,"udp",st->loc,0);
364
365 union iaddr defaultaddrs[] = {
366 #ifdef CONFIG_IPV6
367 { .sin6 = { .sin6_family=AF_INET6,
368 .sin6_port=htons(port),
369 .sin6_addr=IN6ADDR_ANY_INIT } },
370 #endif
371 { .sin = { .sin_family=AF_INET,
372 .sin_port=htons(port),
373 .sin_addr= { .s_addr=INADDR_ANY } } }
374 };
375
376 caddrl=dict_lookup(d,"address");
377 st->n_socks=caddrl ? list_length(caddrl) : (int)ARRAY_SIZE(defaultaddrs);
378 if (st->n_socks<=0 || st->n_socks>MAX_SOCKETS)
379 cfgfatal(st->loc,"udp","`address' must be 1..%d addresses",
380 MAX_SOCKETS);
381
382 for (i=0; i<st->n_socks; i++) {
383 struct udpsock *us=&st->socks[i];
384 if (!list_length(caddrl)) {
385 us->addr=defaultaddrs[i];
386 } else {
387 string_item_to_iaddr(list_elem(caddrl,i),port,&us->addr,"udp");
388 }
389 us->fd=-1;
390 }
391
392 st->rbuf=find_cl_if(d,"buffer",CL_BUFFER,True,"udp",st->loc);
393 st->authbind=dict_read_string(d,"authbind",False,"udp",st->loc);
394 l=dict_lookup(d,"proxy");
395 if (l) {
396 st->use_proxy=True;
397 st->proxy.sa.sa_family=AF_INET;
398 item=list_elem(l,0);
399 if (!item || item->type!=t_string) {
400 cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
401 }
402 a=string_item_to_ipaddr(item,"proxy");
403 st->proxy.sin.sin_addr.s_addr=htonl(a);
404 item=list_elem(l,1);
405 if (!item || item->type!=t_number) {
406 cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
407 }
408 st->proxy.sin.sin_port=htons(item->data.number);
409 }
410
411 update_max_start_pad(&comm_max_start_pad, st->use_proxy ? 8 : 0);
412
413 add_hook(PHASE_GETRESOURCES,udp_phase_hook,st);
414
415 return new_closure(&st->cl);
416 }
417
418 void udp_module(dict_t *dict)
419 {
420 add_closure(dict,"udp",udp_apply);
421 }