Import release 0.07
[secnet] / netlink.c
1 /* User-kernel network link */
2
3 /* We will eventually support a variety of methods for extracting
4 packets from the kernel: userv-ipif, ipif on its own (when we run
5 as root), the kernel TUN driver, SLIP to a pty, an external netlink
6 daemon. There is a performance/security tradeoff. */
7
8 /* When dealing with SLIP (to a pty, or ipif) we have separate rx, tx
9 and client buffers. When receiving we may read() any amount, not
10 just whole packets. When transmitting we need to bytestuff anyway,
11 and may be part-way through receiving. */
12
13 /* Each netlink device is actually a router, with its own IP
14 address. We do things like decreasing the TTL and recalculating the
15 header checksum, generating ICMP, responding to pings, etc. */
16
17 /* This is where we have the anti-spoofing paranoia - before sending a
18 packet to the kernel we check that the tunnel it came over could
19 reasonably have produced it. */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26
27 #include "config.h"
28 #include "secnet.h"
29 #include "util.h"
30
31 #ifdef HAVE_LINUX_IF_H
32 #include <linux/if.h>
33 #include <linux/if_tun.h>
34 #endif
35
36 /* XXX where do we find if_tun on other architectures? */
37
38 #define DEFAULT_BUFSIZE 2048
39 #define DEFAULT_MTU 1000
40 #define ICMP_BUFSIZE 1024
41
42 #define SLIP_END 192
43 #define SLIP_ESC 219
44 #define SLIP_ESCEND 220
45 #define SLIP_ESCESC 221
46
47 struct netlink_client {
48 struct subnet_list *networks;
49 netlink_deliver_fn *deliver;
50 void *dst;
51 string_t name;
52 bool_t can_deliver;
53 struct netlink_client *next;
54 };
55
56 /* Netlink provides one function to the device driver, to call to deliver
57 a packet from the device. The device driver provides one function to
58 netlink, for it to call to deliver a packet to the device. */
59
60 struct netlink {
61 closure_t cl;
62 struct netlink_if ops;
63 void *dst; /* Pointer to host interface state */
64 string_t name;
65 uint32_t max_start_pad;
66 uint32_t max_end_pad;
67 struct subnet_list networks;
68 uint32_t local_address; /* host interface address */
69 uint32_t secnet_address; /* our own address */
70 uint32_t mtu;
71 struct netlink_client *clients;
72 netlink_deliver_fn *deliver_to_host; /* Provided by driver */
73 struct buffer_if icmp; /* Buffer for assembly of outgoing ICMP */
74 };
75
76 /* Generic IP checksum routine */
77 static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
78 {
79 register uint32_t sum=0;
80
81 while (count>1) {
82 sum+=ntohs(*(uint16_t *)iph);
83 iph+=2;
84 count-=2;
85 }
86 if(count>0)
87 sum+=*(uint8_t *)iph;
88 while (sum>>16)
89 sum=(sum&0xffff)+(sum>>16);
90 return htons(~sum);
91 }
92
93 #ifdef i386
94 /*
95 * This is a version of ip_compute_csum() optimized for IP headers,
96 * which always checksum on 4 octet boundaries.
97 *
98 * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
99 * Arnt Gulbrandsen.
100 */
101 static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl) {
102 uint32_t sum;
103
104 __asm__ __volatile__("
105 movl (%1), %0
106 subl $4, %2
107 jbe 2f
108 addl 4(%1), %0
109 adcl 8(%1), %0
110 adcl 12(%1), %0
111 1: adcl 16(%1), %0
112 lea 4(%1), %1
113 decl %2
114 jne 1b
115 adcl $0, %0
116 movl %0, %2
117 shrl $16, %0
118 addw %w2, %w0
119 adcl $0, %0
120 notl %0
121 2:
122 "
123 /* Since the input registers which are loaded with iph and ipl
124 are modified, we must also specify them as outputs, or gcc
125 will assume they contain their original values. */
126 : "=r" (sum), "=r" (iph), "=r" (ihl)
127 : "1" (iph), "2" (ihl));
128 return sum;
129 }
130 #else
131 static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl)
132 {
133 return ip_csum(iph,ihl*4);
134 }
135 #endif
136
137 struct iphdr {
138 #if defined (WORDS_BIGENDIAN)
139 uint8_t version:4,
140 ihl:4;
141 #else
142 uint8_t ihl:4,
143 version:4;
144 #endif
145 uint8_t tos;
146 uint16_t tot_len;
147 uint16_t id;
148 uint16_t frag_off;
149 uint8_t ttl;
150 uint8_t protocol;
151 uint16_t check;
152 uint32_t saddr;
153 uint32_t daddr;
154 /* The options start here. */
155 };
156
157 struct icmphdr {
158 struct iphdr iph;
159 uint8_t type;
160 uint8_t code;
161 uint16_t check;
162 union {
163 uint32_t unused;
164 struct {
165 uint8_t pointer;
166 uint8_t unused1;
167 uint16_t unused2;
168 } pprob;
169 uint32_t gwaddr;
170 struct {
171 uint16_t id;
172 uint16_t seq;
173 } echo;
174 } d;
175 };
176
177 static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf);
178
179 static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
180 uint32_t dest,uint16_t len)
181 {
182 struct icmphdr *h;
183
184 BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
185 buffer_init(&st->icmp,st->max_start_pad);
186 h=buf_append(&st->icmp,sizeof(*h));
187
188 h->iph.version=4;
189 h->iph.ihl=5;
190 h->iph.tos=0;
191 h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
192 h->iph.id=0;
193 h->iph.frag_off=0;
194 h->iph.ttl=255;
195 h->iph.protocol=1;
196 h->iph.saddr=htonl(st->secnet_address);
197 h->iph.daddr=htonl(dest);
198 h->iph.check=0;
199 h->iph.check=ip_fast_csum((uint8_t *)&h->iph,h->iph.ihl);
200 h->check=0;
201 h->d.unused=0;
202
203 return h;
204 }
205
206 /* Fill in the ICMP checksum field correctly */
207 static void netlink_icmp_csum(struct icmphdr *h)
208 {
209 uint32_t len;
210
211 len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
212 h->check=0;
213 h->check=ip_csum(&h->type,len);
214 }
215
216 /* RFC1122:
217 * An ICMP error message MUST NOT be sent as the result of
218 * receiving:
219 *
220 * * an ICMP error message, or
221 *
222 * * a datagram destined to an IP broadcast or IP multicast
223 * address, or
224 *
225 * * a datagram sent as a link-layer broadcast, or
226 *
227 * * a non-initial fragment, or
228 *
229 * * a datagram whose source address does not define a single
230 * host -- e.g., a zero address, a loopback address, a
231 * broadcast address, a multicast address, or a Class E
232 * address.
233 */
234 static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
235 {
236 struct iphdr *iph;
237 uint32_t source;
238
239 iph=(struct iphdr *)buf->start;
240 if (iph->protocol==1) return False; /* Overly-broad; we may reply to
241 eg. icmp echo-request */
242 /* How do we spot broadcast destination addresses? */
243 if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */
244 source=ntohl(iph->saddr);
245 if (source==0) return False;
246 if ((source&0xff000000)==0x7f000000) return False;
247 /* How do we spot broadcast source addresses? */
248 if ((source&0xf0000000)==0xe0000000) return False; /* Multicast */
249 if ((source&0xf0000000)==0xf0000000) return False; /* Class E */
250 return True;
251 }
252
253 /* How much of the original IP packet do we include in its ICMP
254 response? The header plus up to 64 bits. */
255 static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
256 {
257 struct iphdr *iph=(struct iphdr *)buf->start;
258 uint16_t hlen,plen;
259
260 hlen=iph->ihl*4;
261 /* We include the first 8 bytes of the packet data, provided they exist */
262 hlen+=8;
263 plen=ntohs(iph->tot_len);
264 return (hlen>plen?plen:hlen);
265 }
266
267 static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
268 uint8_t type, uint8_t code)
269 {
270 struct iphdr *iph=(struct iphdr *)buf->start;
271 struct icmphdr *h;
272 uint16_t len;
273
274 if (netlink_icmp_may_reply(buf)) {
275 len=netlink_icmp_reply_len(buf);
276 h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len);
277 h->type=type; h->code=code;
278 memcpy(buf_append(&st->icmp,len),buf->start,len);
279 netlink_icmp_csum(h);
280 netlink_packet_deliver(st,&st->icmp);
281 BUF_ASSERT_FREE(&st->icmp);
282 }
283 }
284
285 /*
286 * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
287 * checksum.
288 *
289 * Is the datagram acceptable?
290 *
291 * 1. Length at least the size of an ip header
292 * 2. Version of 4
293 * 3. Checksums correctly.
294 * 4. Doesn't have a bogus length
295 */
296 static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
297 {
298 struct iphdr *iph=(struct iphdr *)buf->start;
299 uint32_t len;
300
301 if (iph->ihl < 5 || iph->version != 4) {
302 printf("ihl/version check failed\n");
303 return False;
304 }
305 if (buf->size < iph->ihl*4) {
306 printf("buffer size check failed\n");
307 return False;
308 }
309 if (ip_fast_csum((uint8_t *)iph, iph->ihl)!=0) {
310 printf("checksum failed\n");
311 return False;
312 }
313 len=ntohs(iph->tot_len);
314 /* There should be no padding */
315 if (buf->size!=len || len<(iph->ihl<<2)) {
316 printf("length check failed buf->size=%d len=%d\n",buf->size,len);
317 return False;
318 }
319
320 /* XXX check that there's no source route specified */
321 return True;
322 }
323
324 static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf)
325 {
326 struct iphdr *iph=(struct iphdr *)buf->start;
327 uint32_t dest=ntohl(iph->daddr);
328 struct netlink_client *c;
329
330 BUF_ASSERT_USED(buf);
331
332 if (dest==st->secnet_address) {
333 Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
334 BUF_FREE(buf);
335 return;
336 }
337
338 for (c=st->clients; c; c=c->next) {
339 if (subnet_match(c->networks,dest)) {
340 if (c->can_deliver) {
341 c->deliver(c->dst,c,buf);
342 BUF_ASSERT_FREE(buf);
343 } else {
344 /* Generate ICMP destination unreachable */
345 netlink_icmp_simple(st,buf,3,0);
346 BUF_FREE(buf);
347 }
348 return;
349 }
350 }
351 if (subnet_match(&st->networks,dest)) {
352 st->deliver_to_host(st->dst,NULL,buf);
353 BUF_ASSERT_FREE(buf);
354 return;
355 }
356 Message(M_ERROR,"%s: failed to deliver a packet (bad destination address)"
357 "\nXXX make this message clearer\n");
358 BUF_FREE(buf);
359 }
360
361 static void netlink_packet_forward(struct netlink *st, struct buffer_if *buf)
362 {
363 struct iphdr *iph=(struct iphdr *)buf->start;
364
365 BUF_ASSERT_USED(buf);
366
367 /* Packet has already been checked */
368 if (iph->ttl<=1) {
369 /* Generate ICMP time exceeded */
370 netlink_icmp_simple(st,buf,11,0);
371 BUF_FREE(buf);
372 return;
373 }
374 iph->ttl--;
375 iph->check=0;
376 iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
377
378 netlink_packet_deliver(st,buf);
379 BUF_ASSERT_FREE(buf);
380 }
381
382 /* Someone has been foolish enough to address a packet to us. I
383 suppose we should reply to it, just to be polite. */
384 static void netlink_packet_local(struct netlink *st, struct buffer_if *buf)
385 {
386 struct icmphdr *h;
387
388 h=(struct icmphdr *)buf->start;
389
390 if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
391 Message(M_WARNING,"%s: fragmented packet addressed to us\n",st->name);
392 BUF_FREE(buf);
393 return;
394 }
395
396 if (h->iph.protocol==1) {
397 /* It's ICMP */
398 if (h->type==8 && h->code==0) {
399 /* ICMP echo-request. Special case: we re-use the buffer
400 to construct the reply. */
401 h->type=0;
402 h->iph.daddr=h->iph.saddr;
403 h->iph.saddr=htonl(st->secnet_address);
404 h->iph.ttl=255; /* Be nice and bump it up again... */
405 h->iph.check=0;
406 h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
407 netlink_icmp_csum(h);
408 netlink_packet_deliver(st,buf);
409 return;
410 }
411 Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
412 } else {
413 /* Send ICMP protocol unreachable */
414 netlink_icmp_simple(st,buf,3,2);
415 BUF_FREE(buf);
416 return;
417 }
418
419 BUF_FREE(buf);
420 }
421
422 /* Called by site code when remote packet is available */
423 /* buf is allocated on entry and free on return */
424 static void netlink_from_tunnel(void *sst, void *cst, struct buffer_if *buf)
425 {
426 struct netlink *st=sst;
427 struct netlink_client *client=cst;
428 uint32_t source,dest;
429 struct iphdr *iph;
430
431 BUF_ASSERT_USED(buf);
432 if (!netlink_check(st,buf)) {
433 Message(M_WARNING,"%s: bad IP packet from tunnel %s\n",
434 st->name,client->name);
435 BUF_FREE(buf);
436 return;
437 }
438 iph=(struct iphdr *)buf->start;
439
440 source=ntohl(iph->saddr);
441 dest=ntohl(iph->daddr);
442
443 /* Check that the packet source is in 'nets' and its destination is
444 in client->networks */
445 if (!subnet_match(client->networks,source)) {
446 string_t s,d;
447 s=ipaddr_to_string(source);
448 d=ipaddr_to_string(dest);
449 Message(M_WARNING,"%s: packet from tunnel %s with bad source address "
450 "(s=%s,d=%s)\n",st->name,client->name,s,d);
451 free(s); free(d);
452 BUF_FREE(buf);
453 return;
454 }
455 /* (st->secnet_address needs checking before matching against
456 st->networks because secnet's IP address may not be in the
457 range the host is willing to deal with) */
458 if (dest==st->secnet_address) {
459 netlink_packet_local(st,buf);
460 BUF_ASSERT_FREE(buf);
461 return;
462 }
463 if (!subnet_match(&st->networks,dest)) {
464 string_t s,d;
465 s=ipaddr_to_string(source);
466 d=ipaddr_to_string(dest);
467 Message(M_WARNING,"%s: incoming packet from tunnel %s "
468 "with bad destination address "
469 "(s=%s,d=%s)\n",st->name,client->name,s,d);
470 free(s); free(d);
471 BUF_FREE(buf);
472 return;
473 }
474
475 netlink_packet_forward(st,buf);
476
477 BUF_ASSERT_FREE(buf);
478 }
479
480 /* Called by driver code when packet is received from kernel */
481 /* cid should be NULL */
482 /* buf should be allocated on entry, and is free on return */
483 static void netlink_from_host(void *sst, void *cid, struct buffer_if *buf)
484 {
485 struct netlink *st=sst;
486 uint32_t source,dest;
487 struct iphdr *iph;
488
489 BUF_ASSERT_USED(buf);
490 if (!netlink_check(st,buf)) {
491 Message(M_WARNING,"%s: bad IP packet from host\n",
492 st->name);
493 BUF_FREE(buf);
494 return;
495 }
496 iph=(struct iphdr *)buf->start;
497
498 source=ntohl(iph->saddr);
499 dest=ntohl(iph->daddr);
500
501 if (!subnet_match(&st->networks,source)) {
502 string_t s,d;
503 s=ipaddr_to_string(source);
504 d=ipaddr_to_string(dest);
505 Message(M_WARNING,"%s: outgoing packet with bad source address "
506 "(s=%s,d=%s)\n",st->name,s,d);
507 free(s); free(d);
508 BUF_FREE(buf);
509 return;
510 }
511 if (dest==st->secnet_address) {
512 netlink_packet_local(st,buf);
513 BUF_ASSERT_FREE(buf);
514 return;
515 }
516 netlink_packet_forward(st,buf);
517 BUF_ASSERT_FREE(buf);
518 }
519
520 static void netlink_set_delivery(void *sst, void *cid, bool_t can_deliver)
521 {
522 struct netlink_client *c=cid;
523
524 c->can_deliver=can_deliver;
525 }
526
527 static void *netlink_regnets(void *sst, struct subnet_list *nets,
528 netlink_deliver_fn *deliver, void *dst,
529 uint32_t max_start_pad, uint32_t max_end_pad,
530 string_t client_name)
531 {
532 struct netlink *st=sst;
533 struct netlink_client *c;
534
535 Message(M_DEBUG_CONFIG,"netlink_regnets: request for %d networks, "
536 "max_start_pad=%d, max_end_pad=%d\n",
537 nets->entries,max_start_pad,max_end_pad);
538
539 c=safe_malloc(sizeof(*c),"netlink_regnets");
540 c->networks=nets;
541 c->deliver=deliver;
542 c->dst=dst;
543 c->name=client_name; /* XXX copy it? */
544 c->can_deliver=False;
545 c->next=st->clients;
546 st->clients=c;
547 if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
548 if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
549
550 return c;
551 }
552
553 static netlink_deliver_fn *netlink_init(struct netlink *st,
554 void *dst, struct cloc loc,
555 dict_t *dict, string_t description,
556 netlink_deliver_fn *to_host)
557 {
558 st->dst=dst;
559 st->cl.description=description;
560 st->cl.type=CL_NETLINK;
561 st->cl.apply=NULL;
562 st->cl.interface=&st->ops;
563 st->ops.st=st;
564 st->ops.regnets=netlink_regnets;
565 st->ops.deliver=netlink_from_tunnel;
566 st->ops.set_delivery=netlink_set_delivery;
567 st->max_start_pad=0;
568 st->max_end_pad=0;
569 st->clients=NULL;
570 st->deliver_to_host=to_host;
571
572 st->name=dict_read_string(dict,"name",False,"netlink",loc);
573 if (!st->name) st->name=description;
574 dict_read_subnet_list(dict, "networks", True, "netlink", loc,
575 &st->networks);
576 st->local_address=string_to_ipaddr(
577 dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
578 st->secnet_address=string_to_ipaddr(
579 dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink");
580 if (!subnet_match(&st->networks,st->local_address)) {
581 cfgfatal(loc,"netlink","local-address must be in local networks\n");
582 }
583 st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
584 buffer_new(&st->icmp,ICMP_BUFSIZE);
585
586 return netlink_from_host;
587 }
588
589 /* Connection to the kernel through userv-ipif */
590
591 struct userv {
592 struct netlink nl;
593 int txfd; /* We transmit to userv */
594 int rxfd; /* We receive from userv */
595 string_t userv_path;
596 string_t service_user;
597 string_t service_name;
598 uint32_t txbuflen;
599 struct buffer_if *buff; /* We unstuff received packets into here
600 and send them to the site code. */
601 bool_t pending_esc;
602 netlink_deliver_fn *netlink_to_tunnel;
603 };
604
605 static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
606 int *timeout_io, const struct timeval *tv_now,
607 uint64_t *now)
608 {
609 struct userv *st=sst;
610 *nfds_io=2;
611 fds[0].fd=st->txfd;
612 fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */
613 fds[1].fd=st->rxfd;
614 fds[1].events=POLLIN|POLLERR|POLLHUP;
615 return 0;
616 }
617
618 static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds,
619 const struct timeval *tv_now, uint64_t *now)
620 {
621 struct userv *st=sst;
622 uint8_t rxbuf[DEFAULT_BUFSIZE];
623 int l,i;
624
625 if (fds[1].revents&POLLERR) {
626 printf("userv_afterpoll: hup!\n");
627 }
628 if (fds[1].revents&POLLIN) {
629 l=read(st->rxfd,rxbuf,DEFAULT_BUFSIZE);
630 if (l<0) {
631 fatal_perror("userv_afterpoll: read(rxfd)");
632 }
633 if (l==0) {
634 fatal("userv_afterpoll: read(rxfd)=0; userv gone away?\n");
635 }
636 /* XXX really crude unstuff code */
637 /* XXX check for buffer overflow */
638 BUF_ASSERT_USED(st->buff);
639 for (i=0; i<l; i++) {
640 if (st->pending_esc) {
641 st->pending_esc=False;
642 switch(rxbuf[i]) {
643 case SLIP_ESCEND:
644 *(uint8_t *)buf_append(st->buff,1)=SLIP_END;
645 break;
646 case SLIP_ESCESC:
647 *(uint8_t *)buf_append(st->buff,1)=SLIP_ESC;
648 break;
649 default:
650 fatal("userv_afterpoll: bad SLIP escape character\n");
651 }
652 } else {
653 switch (rxbuf[i]) {
654 case SLIP_END:
655 if (st->buff->size>0) {
656 st->netlink_to_tunnel(&st->nl,NULL,
657 st->buff);
658 BUF_ALLOC(st->buff,"userv_afterpoll");
659 }
660 buffer_init(st->buff,st->nl.max_start_pad);
661 break;
662 case SLIP_ESC:
663 st->pending_esc=True;
664 break;
665 default:
666 *(uint8_t *)buf_append(st->buff,1)=rxbuf[i];
667 break;
668 }
669 }
670 }
671 }
672 }
673
674 /* Send buf to the kernel. Free buf before returning. */
675 static void userv_deliver_to_kernel(void *sst, void *cid,
676 struct buffer_if *buf)
677 {
678 struct userv *st=sst;
679 uint8_t txbuf[DEFAULT_BUFSIZE];
680 uint8_t *i;
681 uint32_t j;
682
683 BUF_ASSERT_USED(buf);
684
685 /* Spit the packet at userv-ipif: SLIP start marker, then
686 bytestuff the packet, then SLIP end marker */
687 /* XXX crunchy bytestuff code */
688 j=0;
689 txbuf[j++]=SLIP_END;
690 for (i=buf->start; i<(buf->start+buf->size); i++) {
691 switch (*i) {
692 case SLIP_END:
693 txbuf[j++]=SLIP_ESC;
694 txbuf[j++]=SLIP_ESCEND;
695 break;
696 case SLIP_ESC:
697 txbuf[j++]=SLIP_ESC;
698 txbuf[j++]=SLIP_ESCESC;
699 break;
700 default:
701 txbuf[j++]=*i;
702 break;
703 }
704 }
705 txbuf[j++]=SLIP_END;
706 if (write(st->txfd,txbuf,j)<0) {
707 fatal_perror("userv_deliver_to_kernel: write()");
708 }
709 BUF_FREE(buf);
710 }
711
712 static void userv_phase_hook(void *sst, uint32_t newphase)
713 {
714 struct userv *st=sst;
715 pid_t child;
716 int c_stdin[2];
717 int c_stdout[2];
718 string_t addrs;
719 string_t nets;
720 string_t s;
721 struct netlink_client *c;
722 int i;
723
724 /* This is where we actually invoke userv - all the networks we'll
725 be using should already have been registered. */
726
727 addrs=safe_malloc(512,"userv_phase_hook:addrs");
728 snprintf(addrs,512,"%s,%s,%d,slip",ipaddr_to_string(st->nl.local_address),
729 ipaddr_to_string(st->nl.secnet_address),st->nl.mtu);
730
731 nets=safe_malloc(1024,"userv_phase_hook:nets");
732 *nets=0;
733 for (c=st->nl.clients; c; c=c->next) {
734 for (i=0; i<c->networks->entries; i++) {
735 s=subnet_to_string(&c->networks->list[i]);
736 strcat(nets,s);
737 strcat(nets,",");
738 free(s);
739 }
740 }
741 nets[strlen(nets)-1]=0;
742
743 Message(M_INFO,"\nuserv_phase_hook: %s %s %s %s %s\n",st->userv_path,
744 st->service_user,st->service_name,addrs,nets);
745
746 /* Allocate buffer, plus space for padding. Make sure we end up
747 with the start of the packet well-aligned. */
748 /* ALIGN(st->max_start_pad,16); */
749 /* ALIGN(st->max_end_pad,16); */
750
751 st->pending_esc=False;
752
753 /* Invoke userv */
754 if (pipe(c_stdin)!=0) {
755 fatal_perror("userv_phase_hook: pipe(c_stdin)");
756 }
757 if (pipe(c_stdout)!=0) {
758 fatal_perror("userv_phase_hook: pipe(c_stdout)");
759 }
760 st->txfd=c_stdin[1];
761 st->rxfd=c_stdout[0];
762
763 child=fork();
764 if (child==-1) {
765 fatal_perror("userv_phase_hook: fork()");
766 }
767 if (child==0) {
768 char **argv;
769
770 /* We are the child. Modify our stdin and stdout, then exec userv */
771 dup2(c_stdin[0],0);
772 dup2(c_stdout[1],1);
773 close(c_stdin[1]);
774 close(c_stdout[0]);
775
776 /* The arguments are:
777 userv
778 service-user
779 service-name
780 local-addr,secnet-addr,mtu,protocol
781 route1,route2,... */
782 argv=malloc(sizeof(*argv)*6);
783 argv[0]=st->userv_path;
784 argv[1]=st->service_user;
785 argv[2]=st->service_name;
786 argv[3]=addrs;
787 argv[4]=nets;
788 argv[5]=NULL;
789 execvp(st->userv_path,argv);
790 perror("netlink-userv-ipif: execvp");
791
792 exit(1);
793 }
794 /* We are the parent... */
795
796 /* Register for poll() */
797 register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, st->nl.name);
798 }
799
800 static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context,
801 list_t *args)
802 {
803 struct userv *st;
804 item_t *item;
805 dict_t *dict;
806
807 st=safe_malloc(sizeof(*st),"userv_apply");
808
809 /* First parameter must be a dict */
810 item=list_elem(args,0);
811 if (!item || item->type!=t_dict)
812 cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n");
813
814 dict=item->data.dict;
815
816 st->netlink_to_tunnel=
817 netlink_init(&st->nl,st,loc,dict,
818 "netlink-userv-ipif",userv_deliver_to_kernel);
819
820 st->userv_path=dict_read_string(dict,"userv-path",False,"userv-netlink",
821 loc);
822 st->service_user=dict_read_string(dict,"service-user",False,
823 "userv-netlink",loc);
824 st->service_name=dict_read_string(dict,"service-name",False,
825 "userv-netlink",loc);
826 if (!st->userv_path) st->userv_path="userv";
827 if (!st->service_user) st->service_user="root";
828 if (!st->service_name) st->service_name="ipif";
829 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"userv-netlink",loc);
830 BUF_ALLOC(st->buff,"netlink:userv_apply");
831
832 st->rxfd=-1; st->txfd=-1;
833 add_hook(PHASE_DROPPRIV,userv_phase_hook,st);
834
835 return new_closure(&st->nl.cl);
836 }
837
838 /* Connection to the kernel through the universal TUN/TAP driver */
839
840 struct tun {
841 struct netlink nl;
842 int fd;
843 string_t device_path;
844 string_t interface_name;
845 string_t ifconfig_path;
846 string_t route_path;
847 struct buffer_if *buff; /* We receive packets into here
848 and send them to the netlink code. */
849 netlink_deliver_fn *netlink_to_tunnel;
850 };
851
852 static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
853 int *timeout_io, const struct timeval *tv_now,
854 uint64_t *now)
855 {
856 struct tun *st=sst;
857 *nfds_io=1;
858 fds[0].fd=st->fd;
859 fds[0].events=POLLIN|POLLERR|POLLHUP;
860 return 0;
861 }
862
863 static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
864 const struct timeval *tv_now, uint64_t *now)
865 {
866 struct tun *st=sst;
867 int l;
868
869 if (fds[0].revents&POLLERR) {
870 printf("tun_afterpoll: hup!\n");
871 }
872 if (fds[0].revents&POLLIN) {
873 BUF_ALLOC(st->buff,"tun_afterpoll");
874 buffer_init(st->buff,st->nl.max_start_pad);
875 l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad);
876 if (l<0) {
877 fatal_perror("tun_afterpoll: read()");
878 }
879 if (l==0) {
880 fatal("tun_afterpoll: read()=0; device gone away?\n");
881 }
882 if (l>0) {
883 st->buff->size=l;
884 st->netlink_to_tunnel(&st->nl,NULL,st->buff);
885 BUF_ASSERT_FREE(st->buff);
886 }
887 }
888 }
889
890 static void tun_deliver_to_kernel(void *sst, void *cid,
891 struct buffer_if *buf)
892 {
893 struct tun *st=sst;
894
895 BUF_ASSERT_USED(buf);
896
897 /* No error checking, because we'd just throw the packet away anyway */
898 write(st->fd,buf->start,buf->size);
899 BUF_FREE(buf);
900 }
901
902 static void tun_phase_hook(void *sst, uint32_t newphase)
903 {
904 struct tun *st=sst;
905 string_t hostaddr,secnetaddr;
906 uint8_t mtu[6];
907 string_t network,mask;
908 struct netlink_client *c;
909 int i;
910
911 /* All the networks we'll be using have been registered. Invoke ifconfig
912 to set the TUN device's address, and route to add routes to all
913 our networks. */
914
915 hostaddr=ipaddr_to_string(st->nl.local_address);
916 secnetaddr=ipaddr_to_string(st->nl.secnet_address);
917 snprintf(mtu,6,"%d",st->nl.mtu);
918 mtu[5]=0;
919
920 sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
921 hostaddr,"netmask","255.255.255.255","-broadcast",
922 "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
923
924 for (c=st->nl.clients; c; c=c->next) {
925 for (i=0; i<c->networks->entries; i++) {
926 network=ipaddr_to_string(c->networks->list[i].prefix);
927 mask=ipaddr_to_string(c->networks->list[i].mask);
928 sys_cmd(st->route_path,"route","add","-net",network,
929 "netmask",mask,"gw",secnetaddr,(char *)0);
930 }
931 }
932
933 /* Register for poll() */
934 register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
935 }
936
937 #ifdef HAVE_LINUX_IF_H
938 static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
939 list_t *args)
940 {
941 struct tun *st;
942 item_t *item;
943 dict_t *dict;
944 struct ifreq ifr;
945
946 st=safe_malloc(sizeof(*st),"tun_apply");
947
948 /* First parameter must be a dict */
949 item=list_elem(args,0);
950 if (!item || item->type!=t_dict)
951 cfgfatal(loc,"tun","parameter must be a dictionary\n");
952
953 dict=item->data.dict;
954
955 st->netlink_to_tunnel=
956 netlink_init(&st->nl,st,loc,dict,
957 "netlink-tun",tun_deliver_to_kernel);
958
959 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
960 st->interface_name=dict_read_string(dict,"interface",False,
961 "tun-netlink",loc);
962 st->ifconfig_path=dict_read_string(dict,"ifconfig-path",
963 False,"tun-netlink",loc);
964 st->route_path=dict_read_string(dict,"route-path",
965 False,"tun-netlink",loc);
966
967 if (!st->device_path) st->device_path="/dev/net/tun";
968 if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
969 if (!st->route_path) st->route_path="route";
970 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
971
972 /* New TUN interface: open the device, then do ioctl TUNSETIFF
973 to set or find out the network interface name. */
974 st->fd=open(st->device_path,O_RDWR);
975 if (st->fd==-1) {
976 fatal_perror("%s: can't open device file %s",st->nl.name,
977 st->device_path);
978 }
979 memset(&ifr,0,sizeof(ifr));
980 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
981 no extra headers */
982 if (st->interface_name)
983 strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
984 if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
985 fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
986 }
987 if (!st->interface_name) {
988 st->interface_name=safe_malloc(strlen(ifr.ifr_name)+1,"tun_apply");
989 strcpy(st->interface_name,ifr.ifr_name);
990 Message(M_INFO,"%s: allocated network interface %s\n",st->nl.name,
991 st->interface_name);
992 }
993
994 add_hook(PHASE_DROPPRIV,tun_phase_hook,st);
995
996 return new_closure(&st->nl.cl);
997 }
998 #endif /* HAVE_LINUX_IF_H */
999
1000 static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context,
1001 list_t *args)
1002 {
1003 struct tun *st;
1004 item_t *item;
1005 dict_t *dict;
1006 bool_t search_for_if;
1007
1008 st=safe_malloc(sizeof(*st),"tun_old_apply");
1009
1010 Message(M_WARNING,"the tun-old code has never been tested. Please report "
1011 "success or failure to steve@greenend.org.uk\n");
1012
1013 /* First parameter must be a dict */
1014 item=list_elem(args,0);
1015 if (!item || item->type!=t_dict)
1016 cfgfatal(loc,"tun","parameter must be a dictionary\n");
1017
1018 dict=item->data.dict;
1019
1020 st->netlink_to_tunnel=
1021 netlink_init(&st->nl,st,loc,dict,
1022 "netlink-tun",tun_deliver_to_kernel);
1023
1024 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
1025 st->interface_name=dict_read_string(dict,"interface",False,
1026 "tun-netlink",loc);
1027 search_for_if=dict_read_bool(dict,"interface-search",False,"tun-netlink",
1028 loc,st->device_path==NULL);
1029 st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
1030 "tun-netlink",loc);
1031 st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
1032
1033 if (!st->device_path) st->device_path="/dev/tun";
1034 if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
1035 if (!st->route_path) st->route_path="route";
1036 st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
1037
1038 /* Old TUN interface: the network interface name depends on which
1039 /dev/tunX file we open. If 'interface-search' is set to true, treat
1040 'device' as the prefix and try numbers from 0--255. If it's set
1041 to false, treat 'device' as the whole name, and require than an
1042 appropriate interface name be specified. */
1043 if (search_for_if) {
1044 string_t dname;
1045 int i;
1046
1047 if (st->interface_name) {
1048 cfgfatal(loc,"tun-old","you may not specify an interface name "
1049 "in interface-search mode\n");
1050 }
1051 dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
1052 st->interface_name=safe_malloc(8,"tun_old_apply");
1053
1054 for (i=0; i<255; i++) {
1055 sprintf(dname,"%s%d",st->device_path,i);
1056 if ((st->fd=open(dname,O_RDWR))>0) {
1057 sprintf(st->interface_name,"tun%d",i);
1058 Message(M_INFO,"%s: allocated network interface %s "
1059 "through %s\n",st->nl.name,st->interface_name,dname);
1060 break;
1061 }
1062 }
1063 if (st->fd==-1) {
1064 fatal("%s: unable to open any TUN device (%s...)\n",
1065 st->nl.name,st->device_path);
1066 }
1067 } else {
1068 if (!st->interface_name) {
1069 cfgfatal(loc,"tun-old","you must specify an interface name "
1070 "when you explicitly specify a TUN device file\n");
1071 }
1072 st->fd=open(st->device_path,O_RDWR);
1073 if (st->fd==-1) {
1074 fatal_perror("%s: unable to open TUN device file %s",
1075 st->nl.name,st->device_path);
1076 }
1077 }
1078
1079 add_hook(PHASE_DROPPRIV,tun_phase_hook,st);
1080
1081 return new_closure(&st->nl.cl);
1082 }
1083
1084 /* No connection to the kernel at all... */
1085
1086 struct null {
1087 struct netlink nl;
1088 };
1089
1090 static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
1091 {
1092 return;
1093 }
1094
1095 static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
1096 list_t *args)
1097 {
1098 struct null *st;
1099 item_t *item;
1100 dict_t *dict;
1101
1102 st=safe_malloc(sizeof(*st),"null_apply");
1103
1104 item=list_elem(args,0);
1105 if (!item || item->type!=t_dict)
1106 cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
1107
1108 dict=item->data.dict;
1109
1110 netlink_init(&st->nl,st,loc,dict,"null-netlink",null_deliver);
1111
1112 return new_closure(&st->nl.cl);
1113 }
1114
1115 init_module netlink_module;
1116 void netlink_module(dict_t *dict)
1117 {
1118 add_closure(dict,"userv-ipif",userv_apply);
1119 #ifdef HAVE_LINUX_IF_H
1120 add_closure(dict,"tun",tun_apply);
1121 #endif
1122 add_closure(dict,"tun-old",tun_old_apply);
1123 add_closure(dict,"null-netlink",null_apply);
1124 #if 0
1125 /* TODO */
1126 add_closure(dict,"pty-slip",ptyslip_apply);
1127 add_closure(dict,"slipd",slipd_apply);
1128 #endif /* 0 */
1129 }