1 /* User-kernel network link */
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. */
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. */
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. */
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. */
25 #include <sys/ioctl.h>
31 #ifdef HAVE_LINUX_IF_H
33 #include <linux/if_tun.h>
36 /* XXX where do we find if_tun on other architectures? */
38 #define DEFAULT_BUFSIZE 2048
39 #define DEFAULT_MTU 1000
40 #define ICMP_BUFSIZE 1024
44 #define SLIP_ESCEND 220
45 #define SLIP_ESCESC 221
47 struct netlink_client {
48 struct subnet_list *networks;
49 netlink_deliver_fn *deliver;
53 struct netlink_client *next;
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. */
62 struct netlink_if ops;
63 void *dst; /* Pointer to host interface state */
65 uint32_t max_start_pad;
67 struct subnet_list networks;
68 uint32_t local_address; /* host interface address */
69 uint32_t secnet_address; /* our own address */
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 */
76 /* Generic IP checksum routine */
77 static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
79 register uint32_t sum=0;
82 sum+=ntohs(*(uint16_t *)iph);
89 sum=(sum&0xffff)+(sum>>16);
95 * This is a version of ip_compute_csum() optimized for IP headers,
96 * which always checksum on 4 octet boundaries.
98 * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
101 static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl) {
104 __asm__ __volatile__("
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));
131 static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl)
133 return ip_csum(iph,ihl*4);
138 #if defined (WORDS_BIGENDIAN)
154 /* The options start here. */
177 static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf);
179 static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
180 uint32_t dest,uint16_t len)
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));
191 h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
196 h->iph.saddr=htonl(st->secnet_address);
197 h->iph.daddr=htonl(dest);
199 h->iph.check=ip_fast_csum((uint8_t *)&h->iph,h->iph.ihl);
206 /* Fill in the ICMP checksum field correctly */
207 static void netlink_icmp_csum(struct icmphdr *h)
211 len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
213 h->check=ip_csum(&h->type,len);
217 * An ICMP error message MUST NOT be sent as the result of
220 * * an ICMP error message, or
222 * * a datagram destined to an IP broadcast or IP multicast
225 * * a datagram sent as a link-layer broadcast, or
227 * * a non-initial fragment, or
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
234 static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
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 */
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)
257 struct iphdr *iph=(struct iphdr *)buf->start;
261 /* We include the first 8 bytes of the packet data, provided they exist */
263 plen=ntohs(iph->tot_len);
264 return (hlen>plen?plen:hlen);
267 static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
268 uint8_t type, uint8_t code)
270 struct iphdr *iph=(struct iphdr *)buf->start;
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);
286 * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
289 * Is the datagram acceptable?
291 * 1. Length at least the size of an ip header
293 * 3. Checksums correctly.
294 * 4. Doesn't have a bogus length
296 static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
298 struct iphdr *iph=(struct iphdr *)buf->start;
301 if (iph->ihl < 5 || iph->version != 4) {
302 printf("ihl/version check failed\n");
305 if (buf->size < iph->ihl*4) {
306 printf("buffer size check failed\n");
309 if (ip_fast_csum((uint8_t *)iph, iph->ihl)!=0) {
310 printf("checksum failed\n");
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);
320 /* XXX check that there's no source route specified */
324 static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf)
326 struct iphdr *iph=(struct iphdr *)buf->start;
327 uint32_t dest=ntohl(iph->daddr);
328 struct netlink_client *c;
330 BUF_ASSERT_USED(buf);
332 if (dest==st->secnet_address) {
333 Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
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);
344 /* Generate ICMP destination unreachable */
345 netlink_icmp_simple(st,buf,3,0);
351 if (subnet_match(&st->networks,dest)) {
352 st->deliver_to_host(st->dst,NULL,buf);
353 BUF_ASSERT_FREE(buf);
356 Message(M_ERROR,"%s: failed to deliver a packet (bad destination address)"
357 "\nXXX make this message clearer\n");
361 static void netlink_packet_forward(struct netlink *st, struct buffer_if *buf)
363 struct iphdr *iph=(struct iphdr *)buf->start;
365 BUF_ASSERT_USED(buf);
367 /* Packet has already been checked */
369 /* Generate ICMP time exceeded */
370 netlink_icmp_simple(st,buf,11,0);
376 iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
378 netlink_packet_deliver(st,buf);
379 BUF_ASSERT_FREE(buf);
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)
388 h=(struct icmphdr *)buf->start;
390 if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
391 Message(M_WARNING,"%s: fragmented packet addressed to us\n",st->name);
396 if (h->iph.protocol==1) {
398 if (h->type==8 && h->code==0) {
399 /* ICMP echo-request. Special case: we re-use the buffer
400 to construct the reply. */
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... */
406 h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
407 netlink_icmp_csum(h);
408 netlink_packet_deliver(st,buf);
411 Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
413 /* Send ICMP protocol unreachable */
414 netlink_icmp_simple(st,buf,3,2);
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)
426 struct netlink *st=sst;
427 struct netlink_client *client=cst;
428 uint32_t source,dest;
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);
438 iph=(struct iphdr *)buf->start;
440 source=ntohl(iph->saddr);
441 dest=ntohl(iph->daddr);
443 /* Check that the packet source is in 'nets' and its destination is
444 in client->networks */
445 if (!subnet_match(client->networks,source)) {
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);
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);
463 if (!subnet_match(&st->networks,dest)) {
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);
475 netlink_packet_forward(st,buf);
477 BUF_ASSERT_FREE(buf);
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)
485 struct netlink *st=sst;
486 uint32_t source,dest;
489 BUF_ASSERT_USED(buf);
490 if (!netlink_check(st,buf)) {
491 Message(M_WARNING,"%s: bad IP packet from host\n",
496 iph=(struct iphdr *)buf->start;
498 source=ntohl(iph->saddr);
499 dest=ntohl(iph->daddr);
501 if (!subnet_match(&st->networks,source)) {
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);
511 if (dest==st->secnet_address) {
512 netlink_packet_local(st,buf);
513 BUF_ASSERT_FREE(buf);
516 netlink_packet_forward(st,buf);
517 BUF_ASSERT_FREE(buf);
520 static void netlink_set_delivery(void *sst, void *cid, bool_t can_deliver)
522 struct netlink_client *c=cid;
524 c->can_deliver=can_deliver;
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)
532 struct netlink *st=sst;
533 struct netlink_client *c;
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);
539 c=safe_malloc(sizeof(*c),"netlink_regnets");
543 c->name=client_name; /* XXX copy it? */
544 c->can_deliver=False;
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;
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)
559 st->cl.description=description;
560 st->cl.type=CL_NETLINK;
562 st->cl.interface=&st->ops;
564 st->ops.regnets=netlink_regnets;
565 st->ops.deliver=netlink_from_tunnel;
566 st->ops.set_delivery=netlink_set_delivery;
570 st->deliver_to_host=to_host;
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,
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");
583 st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
584 buffer_new(&st->icmp,ICMP_BUFSIZE);
586 return netlink_from_host;
589 /* Connection to the kernel through userv-ipif */
593 int txfd; /* We transmit to userv */
594 int rxfd; /* We receive from userv */
596 string_t service_user;
597 string_t service_name;
599 struct buffer_if *buff; /* We unstuff received packets into here
600 and send them to the site code. */
602 netlink_deliver_fn *netlink_to_tunnel;
605 static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
606 int *timeout_io, const struct timeval *tv_now,
609 struct userv *st=sst;
612 fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */
614 fds[1].events=POLLIN|POLLERR|POLLHUP;
618 static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds,
619 const struct timeval *tv_now, uint64_t *now)
621 struct userv *st=sst;
622 uint8_t rxbuf[DEFAULT_BUFSIZE];
625 if (fds[1].revents&POLLERR) {
626 printf("userv_afterpoll: hup!\n");
628 if (fds[1].revents&POLLIN) {
629 l=read(st->rxfd,rxbuf,DEFAULT_BUFSIZE);
631 fatal_perror("userv_afterpoll: read(rxfd)");
634 fatal("userv_afterpoll: read(rxfd)=0; userv gone away?\n");
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;
644 *(uint8_t *)buf_append(st->buff,1)=SLIP_END;
647 *(uint8_t *)buf_append(st->buff,1)=SLIP_ESC;
650 fatal("userv_afterpoll: bad SLIP escape character\n");
655 if (st->buff->size>0) {
656 st->netlink_to_tunnel(&st->nl,NULL,
658 BUF_ALLOC(st->buff,"userv_afterpoll");
660 buffer_init(st->buff,st->nl.max_start_pad);
663 st->pending_esc=True;
666 *(uint8_t *)buf_append(st->buff,1)=rxbuf[i];
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)
678 struct userv *st=sst;
679 uint8_t txbuf[DEFAULT_BUFSIZE];
683 BUF_ASSERT_USED(buf);
685 /* Spit the packet at userv-ipif: SLIP start marker, then
686 bytestuff the packet, then SLIP end marker */
687 /* XXX crunchy bytestuff code */
690 for (i=buf->start; i<(buf->start+buf->size); i++) {
694 txbuf[j++]=SLIP_ESCEND;
698 txbuf[j++]=SLIP_ESCESC;
706 if (write(st->txfd,txbuf,j)<0) {
707 fatal_perror("userv_deliver_to_kernel: write()");
712 static void userv_phase_hook(void *sst, uint32_t newphase)
714 struct userv *st=sst;
721 struct netlink_client *c;
724 /* This is where we actually invoke userv - all the networks we'll
725 be using should already have been registered. */
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);
731 nets=safe_malloc(1024,"userv_phase_hook:nets");
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]);
741 nets[strlen(nets)-1]=0;
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);
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); */
751 st->pending_esc=False;
754 if (pipe(c_stdin)!=0) {
755 fatal_perror("userv_phase_hook: pipe(c_stdin)");
757 if (pipe(c_stdout)!=0) {
758 fatal_perror("userv_phase_hook: pipe(c_stdout)");
761 st->rxfd=c_stdout[0];
765 fatal_perror("userv_phase_hook: fork()");
770 /* We are the child. Modify our stdin and stdout, then exec userv */
776 /* The arguments are:
780 local-addr,secnet-addr,mtu,protocol
782 argv=malloc(sizeof(*argv)*6);
783 argv[0]=st->userv_path;
784 argv[1]=st->service_user;
785 argv[2]=st->service_name;
789 execvp(st->userv_path,argv);
790 perror("netlink-userv-ipif: execvp");
794 /* We are the parent... */
796 /* Register for poll() */
797 register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, st->nl.name);
800 static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context,
807 st=safe_malloc(sizeof(*st),"userv_apply");
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");
814 dict=item->data.dict;
816 st->netlink_to_tunnel=
817 netlink_init(&st->nl,st,loc,dict,
818 "netlink-userv-ipif",userv_deliver_to_kernel);
820 st->userv_path=dict_read_string(dict,"userv-path",False,"userv-netlink",
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");
832 st->rxfd=-1; st->txfd=-1;
833 add_hook(PHASE_DROPPRIV,userv_phase_hook,st);
835 return new_closure(&st->nl.cl);
838 /* Connection to the kernel through the universal TUN/TAP driver */
843 string_t device_path;
844 string_t interface_name;
845 string_t ifconfig_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;
852 static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
853 int *timeout_io, const struct timeval *tv_now,
859 fds[0].events=POLLIN|POLLERR|POLLHUP;
863 static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
864 const struct timeval *tv_now, uint64_t *now)
869 if (fds[0].revents&POLLERR) {
870 printf("tun_afterpoll: hup!\n");
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);
877 fatal_perror("tun_afterpoll: read()");
880 fatal("tun_afterpoll: read()=0; device gone away?\n");
884 st->netlink_to_tunnel(&st->nl,NULL,st->buff);
885 BUF_ASSERT_FREE(st->buff);
890 static void tun_deliver_to_kernel(void *sst, void *cid,
891 struct buffer_if *buf)
895 BUF_ASSERT_USED(buf);
897 /* No error checking, because we'd just throw the packet away anyway */
898 write(st->fd,buf->start,buf->size);
902 static void tun_phase_hook(void *sst, uint32_t newphase)
905 string_t hostaddr,secnetaddr;
907 string_t network,mask;
908 struct netlink_client *c;
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
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);
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);
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);
933 /* Register for poll() */
934 register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
937 #ifdef HAVE_LINUX_IF_H
938 static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
946 st=safe_malloc(sizeof(*st),"tun_apply");
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");
953 dict=item->data.dict;
955 st->netlink_to_tunnel=
956 netlink_init(&st->nl,st,loc,dict,
957 "netlink-tun",tun_deliver_to_kernel);
959 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
960 st->interface_name=dict_read_string(dict,"interface",False,
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);
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);
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);
976 fatal_perror("%s: can't open device file %s",st->nl.name,
979 memset(&ifr,0,sizeof(ifr));
980 ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
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);
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,
994 add_hook(PHASE_DROPPRIV,tun_phase_hook,st);
996 return new_closure(&st->nl.cl);
998 #endif /* HAVE_LINUX_IF_H */
1000 static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context,
1006 bool_t search_for_if;
1008 st=safe_malloc(sizeof(*st),"tun_old_apply");
1010 Message(M_WARNING,"the tun-old code has never been tested. Please report "
1011 "success or failure to steve@greenend.org.uk\n");
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");
1018 dict=item->data.dict;
1020 st->netlink_to_tunnel=
1021 netlink_init(&st->nl,st,loc,dict,
1022 "netlink-tun",tun_deliver_to_kernel);
1024 st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
1025 st->interface_name=dict_read_string(dict,"interface",False,
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,
1031 st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
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);
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) {
1047 if (st->interface_name) {
1048 cfgfatal(loc,"tun-old","you may not specify an interface name "
1049 "in interface-search mode\n");
1051 dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
1052 st->interface_name=safe_malloc(8,"tun_old_apply");
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);
1064 fatal("%s: unable to open any TUN device (%s...)\n",
1065 st->nl.name,st->device_path);
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");
1072 st->fd=open(st->device_path,O_RDWR);
1074 fatal_perror("%s: unable to open TUN device file %s",
1075 st->nl.name,st->device_path);
1079 add_hook(PHASE_DROPPRIV,tun_phase_hook,st);
1081 return new_closure(&st->nl.cl);
1084 /* No connection to the kernel at all... */
1090 static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
1095 static list_t *null_apply(closure_t *self, struct cloc loc, dict_t *context,
1102 st=safe_malloc(sizeof(*st),"null_apply");
1104 item=list_elem(args,0);
1105 if (!item || item->type!=t_dict)
1106 cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
1108 dict=item->data.dict;
1110 netlink_init(&st->nl,st,loc,dict,"null-netlink",null_deliver);
1112 return new_closure(&st->nl.cl);
1115 init_module netlink_module;
1116 void netlink_module(dict_t *dict)
1118 add_closure(dict,"userv-ipif",userv_apply);
1119 #ifdef HAVE_LINUX_IF_H
1120 add_closure(dict,"tun",tun_apply);
1122 add_closure(dict,"tun-old",tun_old_apply);
1123 add_closure(dict,"null-netlink",null_apply);
1126 add_closure(dict,"pty-slip",ptyslip_apply);
1127 add_closure(dict,"slipd",slipd_apply);