Annotation of embedaddon/coova-chilli/src/tun.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Tunnel Interface Functions.
3: * Copyright (C) 2002, 2003, 2004 Mondru AB.
4: * Copyright (c) 2006-2007 David Bird <david@coova.com>
5: *
6: * The contents of this file may be used under the terms of the GNU
7: * General Public License Version 2, provided that the above copyright
8: * notice and this permission notice is included in all copies or
9: * substantial portions of the software.
10: *
11: */
12:
13: /*
14: * A tunnel is the back-haul link which chilli sends traffic. Typically,
15: * this is a single tun/tap interface allowing chilli to simply pass on
16: * packets to the kernel for processing (iptables) and routing. Without the
17: * tun/tap interface, chilli must decide for itself how to route traffic,
18: * maintaining a socket into each back-haul interface. One or more tunnels
19: * are required.
20: *
21: */
22:
23: #include "system.h"
24: #include "tun.h"
25: #include "ippool.h"
26: #include "radius.h"
27: #include "radius_wispr.h"
28: #include "radius_chillispot.h"
29: #include "redir.h"
30: #include "syserr.h"
31: #include "dhcp.h"
32: #include "cmdline.h"
33: #include "chilli.h"
34: #include "options.h"
35: #include "net.h"
36:
37: #define inaddr(x) (((struct sockaddr_in *)&ifr->x)->sin_addr)
38: #define inaddr2(p,x) (((struct sockaddr_in *)&(p)->x)->sin_addr)
39:
40: int tun_discover(struct tun_t *this) {
41: net_interface netif;
42: struct ifconf ic;
43: int fd, len, i;
44:
45: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
46: log_err(errno, "socket() failed");
47: return -1;
48: }
49:
50: ic.ifc_buf=0;
51: ic.ifc_len=0;
52:
53: if (ioctl(fd, SIOCGIFCONF, &ic) < 0) {
54: log_err(errno, "ioctl(SIOCGIFCONF)");
55: close(fd);
56: return -1;
57: }
58:
59: ic.ifc_buf = calloc((size_t)ic.ifc_len, 1);
60: if (ioctl(fd, SIOCGIFCONF, &ic) < 0) {
61: log_err(errno, "ioctl(SIOCGIFCONF)");
62: close(fd);
63: return -1;
64: }
65:
66: len = (ic.ifc_len/sizeof(struct ifreq));
67:
68: for (i=0; i<len; ++i) {
69: struct ifreq *ifr = (struct ifreq *)&ic.ifc_req[i];
70: memset(&netif, 0, sizeof(netif));
71:
72:
73: /* device name and address */
74: strncpy(netif.devname, ifr->ifr_name, sizeof(netif.devname));
75: netif.address = inaddr(ifr_addr);
76:
77: log_dbg("Interface: %s", ifr->ifr_name);
78: log_dbg("\tIP Address:\t%s", inet_ntoa(inaddr(ifr_addr)));
79:
80:
81: /* netmask */
82: if (-1 < ioctl(fd, SIOCGIFNETMASK, (caddr_t)ifr)) {
83:
84: netif.netmask = inaddr(ifr_addr);
85: log_dbg("\tNetmask:\t%s", inet_ntoa(inaddr(ifr_addr)));
86:
87: } else log_err(errno, "ioctl(SIOCGIFNETMASK)");
88:
89:
90: /* hardware address */
91: #ifdef SIOCGIFHWADDR
92: if (-1 < ioctl(fd, SIOCGIFHWADDR, (caddr_t)ifr)) {
93: switch (ifr->ifr_hwaddr.sa_family) {
94: case ARPHRD_NETROM:
95: case ARPHRD_ETHER:
96: case ARPHRD_PPP:
97: case ARPHRD_EETHER:
98: case ARPHRD_IEEE802:
99: {
100: unsigned char *u = (unsigned char *)&ifr->ifr_addr.sa_data;
101:
102: memcpy(netif.hwaddr, u, 6);
103:
104: log_dbg("\tHW Address:\t%2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2x",
105: u[0], u[1], u[2], u[3], u[4], u[5]);
106: }
107: break;
108: }
109: } else log_err(errno, "ioctl(SIOCGIFHWADDR)");
110: #else
111: #ifdef SIOCGENADDR
112: if (-1 < ioctl(fd, SIOCGENADDR, (caddr_t)ifr)) {
113: unsigned char *u = (unsigned char *)&ifr->ifr_enaddr;
114:
115: memcpy(netif.hwaddr, u, 6);
116:
117: log_dbg("\tHW Address:\t%2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2x",
118: u[0], u[1], u[2], u[3], u[4], u[5]);
119: } else log_err(errno, "ioctl(SIOCGENADDR)");
120: #else
121: #warning Do not know how to find interface hardware address
122: #endif /* SIOCGENADDR */
123: #endif /* SIOCGIFHWADDR */
124:
125:
126: /* flags */
127: if (-1 < ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr)) {
128:
129: netif.devflags = ifr->ifr_flags;
130:
131: } else log_err(errno, "ioctl(SIOCGIFFLAGS)");
132:
133:
134: /* point-to-point gateway */
135: if (netif.devflags & IFF_POINTOPOINT) {
136: if (-1 < ioctl(fd, SIOCGIFDSTADDR, (caddr_t)ifr)) {
137:
138: netif.gateway = inaddr(ifr_addr);
139: log_dbg("\tPoint-to-Point:\t%s", inet_ntoa(inaddr(ifr_dstaddr)));
140:
141: } else log_err(errno, "ioctl(SIOCGIFDSTADDR)");
142: }
143:
144:
145: /* broadcast address */
146: if (netif.devflags & IFF_BROADCAST) {
147: if (-1 < ioctl(fd, SIOCGIFBRDADDR, (caddr_t)ifr)) {
148:
149: netif.broadcast = inaddr(ifr_addr);
150: log_dbg("\tBroadcast:\t%s", inet_ntoa(inaddr(ifr_addr)));
151:
152: } else log_err(errno, "ioctl(SIOCGIFBRDADDR)");
153: }
154:
155:
156: /* mtu */
157: if (-1 < ioctl(fd, SIOCGIFMTU, (caddr_t)ifr)) {
158:
159: netif.mtu = ifr->ifr_mtu;
160: log_dbg("\tMTU: \t%u", ifr->ifr_mtu);
161:
162: } else log_err(errno, "ioctl(SIOCGIFMTU)");
163:
164:
165: /* if (0 == ioctl(fd, SIOCGIFMETRIC, ifr)) */
166:
167: if (netif.address.s_addr == htonl(INADDR_LOOPBACK) ||
168: netif.address.s_addr == INADDR_ANY ||
169: netif.address.s_addr == INADDR_NONE)
170: continue;
171:
172: else {
173: net_interface *newif = tun_nextif(tun);
174: if (newif) {
175: memcpy(newif, &netif, sizeof(netif));
176: net_open(newif);
177:
178: if (!strcmp(options.routeif, netif.devname))
179: tun->routeidx = newif->idx;
180: } else {
181: log_dbg("no room for interface %s", netif.devname);
182: }
183: }
184: }
185:
186: close(fd);
187: return 0;
188: }
189:
190: net_interface * tun_nextif(struct tun_t *tun) {
191: net_interface *netif;
192:
193: if (tun->_interface_count == TUN_MAX_INTERFACES)
194: return 0;
195:
196: netif = &tun->_interfaces[tun->_interface_count];
197: netif->idx = tun->_interface_count;
198:
199: tun->_interface_count++;
200:
201: return netif;
202: }
203:
204: int tun_name2idx(struct tun_t *tun, char *name) {
205: int i;
206:
207: for (i=0; i<tun->_interface_count; i++)
208: if (!strcmp(name, tun->_interfaces[i].devname))
209: return i;
210:
211: return 0; /* tun/tap index */
212: }
213:
214: #if defined(__linux__)
215:
216: int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, size_t dlen) {
217: size_t len = RTA_LENGTH(dlen);
218: size_t alen = NLMSG_ALIGN(n->nlmsg_len);
219: struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
220: if (alen + len > nsize)
221: return -1;
222: rta->rta_len = len;
223: rta->rta_type = type;
224: memcpy(RTA_DATA(rta), d, dlen);
225: n->nlmsg_len = alen + len;
226: return 0;
227: }
228:
229: int tun_gifindex(struct tun_t *this, int *index) {
230: struct ifreq ifr;
231: int fd;
232:
233: memset (&ifr, '\0', sizeof (ifr));
234: ifr.ifr_addr.sa_family = AF_INET;
235: ifr.ifr_dstaddr.sa_family = AF_INET;
236: ifr.ifr_netmask.sa_family = AF_INET;
237: strncpy(ifr.ifr_name, tuntap(this).devname, IFNAMSIZ);
238: ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
239: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
240: log_err(errno, "socket() failed");
241: }
242: if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
243: log_err(errno,"ioctl() failed");
244: close(fd);
245: return -1;
246: }
247: close(fd);
248: *index = ifr.ifr_ifindex;
249: return 0;
250: }
251: #endif
252:
253: int tun_addaddr(struct tun_t *this, struct in_addr *addr,
254: struct in_addr *dstaddr, struct in_addr *netmask) {
255:
256: #if defined(__linux__)
257: struct {
258: struct nlmsghdr n;
259: struct ifaddrmsg i;
260: char buf[TUN_NLBUFSIZE];
261: } req;
262:
263: struct sockaddr_nl local;
264: size_t addr_len;
265: int fd;
266: int status;
267:
268: struct sockaddr_nl nladdr;
269: struct iovec iov;
270: struct msghdr msg;
271:
272: if (!this->addrs) /* Use ioctl for first addr to make ping work */
273: return tun_setaddr(this, addr, dstaddr, netmask);
274:
275: memset(&req, 0, sizeof(req));
276: req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
277: req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
278: req.n.nlmsg_type = RTM_NEWADDR;
279: req.i.ifa_family = AF_INET;
280: req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
281: req.i.ifa_flags = 0;
282: req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
283:
284: if (tun_gifindex(this, &req.i.ifa_index)) {
285: log_err(errno,"tun_gifindex() failed");
286: return -1;
287: }
288:
289: tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
290: tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
291:
292: if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
293: log_err(errno,"socket() failed");
294: return -1;
295: }
296:
297: memset(&local, 0, sizeof(local));
298: local.nl_family = AF_NETLINK;
299: local.nl_groups = 0;
300:
301: if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
302: log_err(errno, "bind() failed");
303: close(fd);
304: return -1;
305: }
306:
307: addr_len = sizeof(local);
308: if (getsockname(fd, (struct sockaddr*)&local, (socklen_t *) &addr_len) < 0) {
309: log_err(errno, "getsockname() failed");
310: close(fd);
311: return -1;
312: }
313:
314: if (addr_len != sizeof(local)) {
315: log_err(0, "Wrong address length %d", addr_len);
316: close(fd);
317: return -1;
318: }
319:
320: if (local.nl_family != AF_NETLINK) {
321: log_err(0, "Wrong address family %d", local.nl_family);
322: close(fd);
323: return -1;
324: }
325:
326: iov.iov_base = (void*)&req.n;
327: iov.iov_len = req.n.nlmsg_len;
328:
329: msg.msg_name = (void*)&nladdr;
330: msg.msg_namelen = sizeof(nladdr),
331: msg.msg_iov = &iov;
332: msg.msg_iovlen = 1;
333: msg.msg_control = NULL;
334: msg.msg_controllen = 0;
335: msg.msg_flags = 0;
336:
337: memset(&nladdr, 0, sizeof(nladdr));
338: nladdr.nl_family = AF_NETLINK;
339: nladdr.nl_pid = 0;
340: nladdr.nl_groups = 0;
341:
342: req.n.nlmsg_seq = 0;
343: req.n.nlmsg_flags |= NLM_F_ACK;
344:
345: status = sendmsg(fd, &msg, 0);
346:
347: dev_set_flags(tuntap(this).devname, IFF_UP | IFF_RUNNING);
348:
349: close(fd);
350: this->addrs++;
351:
352: return 0;
353:
354: #elif defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
355:
356: int fd;
357: struct ifaliasreq areq;
358:
359: /* TODO: Is this needed on FreeBSD? */
360: if (!this->addrs) /* Use ioctl for first addr to make ping work */
361: return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
362:
363: memset(&areq, 0, sizeof(areq));
364:
365: /* Set up interface name */
366: strncpy(areq.ifra_name, tuntap(this).devname, IFNAMSIZ);
367: areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
368:
369: ((struct sockaddr_in*) &areq.ifra_addr)->sin_family = AF_INET;
370: ((struct sockaddr_in*) &areq.ifra_addr)->sin_len = sizeof(areq.ifra_addr);
371: ((struct sockaddr_in*) &areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
372:
373: ((struct sockaddr_in*) &areq.ifra_mask)->sin_family = AF_INET;
374: ((struct sockaddr_in*) &areq.ifra_mask)->sin_len = sizeof(areq.ifra_mask);
375: ((struct sockaddr_in*) &areq.ifra_mask)->sin_addr.s_addr = netmask->s_addr;
376:
377: /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
378: ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_family = AF_INET;
379: ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_len = sizeof(areq.ifra_broadaddr);
380: ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_addr.s_addr = dstaddr->s_addr;
381:
382: /* Create a channel to the NET kernel. */
383: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
384: log_err(errno,
385: "socket() failed");
386: return -1;
387: }
388:
389: if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
390: log_err(errno,
391: "ioctl(SIOCAIFADDR) failed");
392: close(fd);
393: return -1;
394: }
395:
396: close(fd);
397: this->addrs++;
398: return 0;
399:
400: #elif defined (__sun__)
401:
402: if (!this->addrs) /* Use ioctl for first addr to make ping work */
403: return tun_setaddr(this, addr, dstaddr, netmask);
404:
405: log_err(errno, "Setting multiple addresses not possible on Solaris");
406: return -1;
407:
408: #else
409: #error "Unknown platform!"
410: #endif
411:
412: }
413:
414:
415: int tun_setaddr(struct tun_t *this, struct in_addr *addr, struct in_addr *dstaddr, struct in_addr *netmask) {
416: net_set_address(&tuntap(this), addr, dstaddr, netmask);
417:
418: #if defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
419: net_add_route(dstaddr, addr, netmask);
420: this->routes = 1;
421: #endif
422:
423: return 0;
424: }
425:
426: static int tuntap_interface(struct _net_interface *netif) {
427: #if defined(__linux__)
428: struct ifreq ifr;
429:
430: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
431: char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
432: int devnum;
433: struct ifaliasreq areq;
434: int fd;
435:
436: #elif defined(__sun__)
437: int if_fd, ppa = -1;
438: static int ip_fd = 0;
439: int muxid;
440: struct ifreq ifr;
441:
442: #else
443: #error "Unknown platform!"
444: #endif
445:
446:
447: #if defined(__linux__)
448: /* Open the actual tun device */
449: if ((netif->fd = open("/dev/net/tun", O_RDWR)) < 0) {
450: log_err(errno, "open() failed");
451: return -1;
452: }
453:
454: /* Set device flags. For some weird reason this is also the method
455: used to obtain the network interface name */
456: memset(&ifr, 0, sizeof(ifr));
457: ifr.ifr_flags = (options.usetap ? IFF_TAP : IFF_TUN) | IFF_NO_PI; /* Tun device, no packet info */
458: #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
459: ifr.ifr_flags |= IFF_ONE_QUEUE;
460: #endif
461:
462: if (options.tundev && *options.tundev &&
463: strcmp(options.tundev, "tap") && strcmp(options.tundev, "tun"))
464: strncpy(ifr.ifr_name, options.tundev, IFNAMSIZ);
465:
466: if (ioctl(netif->fd, TUNSETIFF, (void *) &ifr) < 0) {
467: log_err(errno, "ioctl() failed");
468: close(netif->fd);
469: return -1;
470: }
471:
472: #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
473: {
474: struct ifreq nifr;
475: int nfd;
476: memset(&nifr, 0, sizeof(nifr));
477: if ((nfd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) {
478: strncpy(nifr.ifr_name, ifr.ifr_name, IFNAMSIZ);
479: nifr.ifr_qlen = options.txqlen;
480:
481: if (ioctl(nfd, SIOCSIFTXQLEN, (void *) &nifr) >= 0)
482: log_info("TX queue length set to %d", options.txqlen);
483: else
484: log_err(errno, "Cannot set tx queue length on %s", ifr.ifr_name);
485:
486: close (nfd);
487: } else {
488: log_err(errno, "Cannot open socket on %s", ifr.ifr_name);
489: }
490: }
491: #endif
492:
493: strncpy(netif->devname, ifr.ifr_name, IFNAMSIZ);
494: netif->devname[IFNAMSIZ-1] = 0;
495:
496: ioctl(netif->fd, TUNSETNOCSUM, 1); /* Disable checksums */
497:
498: /* Get the MAC address of our tap interface */
499: if (options.usetap) {
500: int fd;
501: netif->flags |= NET_ETHHDR;
502: if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) {
503: memset(&ifr, 0, sizeof(ifr));
504: strncpy(ifr.ifr_name, netif->devname, IFNAMSIZ);
505: if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
506: log_err(errno, "ioctl(d=%d, request=%d) failed", fd, SIOCGIFHWADDR);
507: }
508: memcpy(netif->hwaddr, ifr.ifr_hwaddr.sa_data, PKT_ETH_ALEN);
509: log_dbg("tap-mac: %s %.2X-%.2X-%.2X-%.2X-%.2X-%.2X", ifr.ifr_name,
510: netif->hwaddr[0],netif->hwaddr[1],netif->hwaddr[2],
511: netif->hwaddr[3],netif->hwaddr[4],netif->hwaddr[5]);
512: close(fd);
513: }
514: }
515:
516: return 0;
517:
518: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
519:
520: /* Find suitable device */
521: for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
522: snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
523: devname[sizeof(devname)] = 0;
524: if ((netif->fd = open(devname, O_RDWR)) >= 0) break;
525: if (errno != EBUSY) break;
526: }
527: if (netif->fd < 0) {
528: log_err(errno, "Can't find tunnel device");
529: return -1;
530: }
531:
532: snprintf(netif->devname, sizeof(netif->devname), "tun%d", devnum);
533: netif->devname[sizeof(netif->devname)-1] = 0;
534:
535: /* The tun device we found might have "old" IP addresses allocated */
536: /* We need to delete those. This problem is not present on Linux */
537:
538: memset(&areq, 0, sizeof(areq));
539:
540: /* Set up interface name */
541: strncpy(areq.ifra_name, netif->devname, IFNAMSIZ);
542: areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
543:
544: /* Create a channel to the NET kernel. */
545: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
546: log_err(errno,
547: "socket() failed");
548: return -1;
549: }
550:
551: /* Delete any IP addresses until SIOCDIFADDR fails */
552: while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
553:
554: close(fd);
555: return 0;
556:
557: #elif defined(__sun__)
558:
559: if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
560: log_err(errno, "Can't open /dev/udp");
561: return -1;
562: }
563:
564: if( (netif->fd = open("/dev/tun", O_RDWR, 0)) < 0){
565: log_err(errno, "Can't open /dev/tun");
566: return -1;
567: }
568:
569: /* Assign a new PPA and get its unit number. */
570: if( (ppa = ioctl(netif->fd, TUNNEWPPA, -1)) < 0){
571: log_err(errno, "Can't assign new interface");
572: return -1;
573: }
574:
575: if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
576: log_err(errno, "Can't open /dev/tun (2)");
577: return -1;
578: }
579: if(ioctl(if_fd, I_PUSH, "ip") < 0){
580: log_err(errno, "Can't push IP module");
581: return -1;
582: }
583:
584: /* Assign ppa according to the unit number returned by tun device */
585: if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
586: log_err(errno, "Can't set PPA %d", ppa);
587: return -1;
588: }
589:
590: /* Link the two streams */
591: if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
592: log_err(errno, "Can't link TUN device to IP");
593: return -1;
594: }
595:
596: close (if_fd);
597:
598: snprintf(netif->devname, sizeof(netif->devname), "tun%d", ppa);
599: netif->devname[sizeof(netif->devname)-1] = 0;
600:
601: memset(&ifr, 0, sizeof(ifr));
602: strcpy(ifr.ifr_name, netif->devname);
603: ifr.ifr_ip_muxid = muxid;
604:
605: if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
606: ioctl(ip_fd, I_PUNLINK, muxid);
607: log_err(errno, "Can't set multiplexor id");
608: return -1;
609: }
610:
611: /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
612: msg (M_ERR, "Set file descriptor to non-blocking failed"); */
613:
614: return 0;
615:
616: #else
617: #error "Unknown platform!"
618: #endif
619:
620: }
621:
622: int tun_new(struct tun_t **ptun) {
623: struct tun_t *tun;
624:
625: if (!(tun = *ptun = calloc(1, sizeof(struct tun_t)))) {
626: log_err(errno, "calloc() failed");
627: return EOF;
628: }
629:
630: tuntap_interface(tun_nextif(tun));
631:
632: if (options.routeif) {
633: tun_discover(tun);
634: }
635:
636: return 0;
637: }
638:
639: int tun_free(struct tun_t *tun) {
640:
641: if (tun->routes) {
642: #warning fix this
643: /*XXX: todo! net_delete_route(&tuntap(tun)); */
644: }
645:
646: tun_close(tun);
647:
648: /* TODO: For solaris we need to unlink streams */
649:
650: free(tun);
651: return 0;
652: }
653:
654: int tun_set_cb_ind(struct tun_t *this,
655: int (*cb_ind) (struct tun_t *tun, void *pack, size_t len, int idx)) {
656: this->cb_ind = cb_ind;
657: return 0;
658: }
659:
660: int tun_decaps(struct tun_t *this, int idx) {
661:
662: #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
663: unsigned char buffer[PACKET_MAX];
664: ssize_t status;
665:
666: if ((status = net_read(&tun(this, idx), buffer, sizeof(buffer))) <= 0) {
667: log_err(errno, "read() failed");
668: return -1;
669: }
670:
671: if (this->debug)
672: log_dbg("tun_decaps(%d) %s",status,tun(tun,idx).devname);
673:
674: if (0) { /* if we wanted to do nat'ing, it would could be done here */
675: struct in_addr a;
676: struct pkt_iphdr_t *iph = (struct pkt_iphdr_t *)buffer;
677: inet_aton("10.1.0.1", &a);
678: iph->daddr = a.s_addr;
679: chksum(iph);
680: }
681:
682: if (this->cb_ind)
683: #if defined (__OpenBSD__)
684: /* tun interface adds 4 bytes to front of packet under OpenBSD */
685: return this->cb_ind(this, buffer+4, status, idx);
686: #else
687: return this->cb_ind(this, buffer, status, idx);
688: #endif
689:
690: return 0;
691:
692: #elif defined (__sun__)
693: unsigned char buffer[PACKET_MAX];
694: struct strbuf sbuf;
695: int f = 0;
696:
697: sbuf.maxlen = PACKET_MAX;
698: sbuf.buf = buffer;
699: if (getmsg(tun(this, idx).fd, NULL, &sbuf, &f) < 0) {
700: log_err(errno, "getmsg() failed");
701: return -1;
702: }
703:
704: if (this->cb_ind)
705: return this->cb_ind(this, &packet, sbuf.len);
706:
707: return 0;
708:
709: #endif
710: }
711:
712: static uint32_t dnatip[1024];
713: static uint16_t dnatport[1024];
714:
715: int tun_encaps(struct tun_t *tun, void *pack, size_t len, int idx) {
716:
717: if (tun(tun, idx).flags & NET_ETHHDR) {
718:
719: struct pkt_ethhdr_t *ethh = (struct pkt_ethhdr_t *)pack;
720: /*memcpy(ethh->src, tun->tap_hwaddr, PKT_ETH_ALEN); */
721:
722: /** XXX **/
723: if (1) {
724: ethh->src[0]=0x00;
725: ethh->src[1]=0x17;
726: ethh->src[2]=0x3f;
727: ethh->src[3]=0x99;
728: ethh->src[4]=0xf4;
729: ethh->src[5]=0x46;
730:
731: ethh->dst[0]=0x00;
732: ethh->dst[1]=0x14;
733: ethh->dst[2]=0xBF;
734: ethh->dst[3]=0xE2;
735: ethh->dst[4]=0xC1;
736: ethh->dst[5]=0x75;
737: }
738:
739: log_dbg("writing to tun/tap src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
740: ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
741: ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5]);
742: } else {
743: pack += PKT_ETH_HLEN;
744: len -= PKT_ETH_HLEN;
745: }
746:
747: if (tun->debug)
748: log_dbg("tun_encaps(%d) %s",len,tun(tun,idx).devname);
749:
750: #if defined (__OpenBSD__)
751:
752: unsigned char buffer[PACKET_MAX+4];
753:
754: /* Can we user writev here to be more efficient??? */
755: *((uint32_t *)(&buffer))=htonl(AF_INET);
756: memcpy(&buffer[4], pack, PACKET_MAX);
757:
758: return net_write(&tun(tun, idx), buffer, len+4);
759:
760: #elif defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__) || defined (__NetBSD__)
761:
762: if (0) { /* if we wanted to do nat'ing we could do it here */
763: struct in_addr a;
764: struct pkt_iphdr_t *iph = (struct pkt_iphdr_t *)pack;
765: inet_aton("172.30.97.2", &a);
766: iph->saddr = a.s_addr;
767: chksum(iph);
768: }
769:
770: return net_write(&tun(tun, idx), pack, len);
771:
772: #elif defined (__sun__)
773:
774: struct strbuf sbuf;
775: sbuf.len = len;
776: sbuf.buf = pack;
777: return putmsg(tun(tun, idx).fd, NULL, &sbuf, 0);
778:
779: #endif
780: }
781:
782: int tun_runscript(struct tun_t *tun, char* script) {
783: char saddr[TUN_ADDRSIZE];
784: char smask[TUN_ADDRSIZE];
785: char b[TUN_ADDRSIZE];
786: struct in_addr net;
787: int status;
788:
789: net.s_addr = tuntap(tun).address.s_addr & tuntap(tun).netmask.s_addr;
790:
791: if ((status = fork()) < 0) {
792: log_err(errno, "fork() returned -1!");
793: return 0;
794: }
795:
796: if (status > 0) { /* Parent */
797: return 0;
798: }
799:
800: /*
801: #ifdef HAVE_CLEARENV
802: if (clearenv() != 0) {
803: log_err(errno,
804: "clearenv() did not return 0!");
805: exit(0);
806: }
807: #endif
808: */
809:
810: if (setenv("DEV", tuntap(tun).devname, 1) != 0) {
811: log_err(errno, "setenv() did not return 0!");
812: exit(0);
813: }
814:
815: strncpy(saddr, inet_ntoa(tuntap(tun).address), sizeof(saddr));
816: saddr[sizeof(saddr)-1] = 0;
817: if (setenv("ADDR", saddr, 1 ) != 0) {
818: log_err(errno, "setenv() did not return 0!");
819: exit(0);
820: }
821:
822: strncpy(smask, inet_ntoa(tuntap(tun).netmask), sizeof(smask));
823: smask[sizeof(smask)-1] = 0;
824: if (setenv("MASK", smask, 1) != 0) {
825: log_err(errno, "setenv() did not return 0!");
826: exit(0);
827: }
828:
829: strncpy(b, inet_ntoa(net), sizeof(b));
830: b[sizeof(b)-1] = 0;
831: if (setenv("NET", b, 1 ) != 0) {
832: log_err(errno, "setenv() did not return 0!");
833: exit(0);
834: }
835:
836: snprintf(b, sizeof(b), "%d", options.uamport);
837: if (setenv("UAMPORT", b, 1 ) != 0) {
838: log_err(errno, "setenv() did not return 0!");
839: exit(0);
840: }
841:
842: snprintf(b, sizeof(b), "%d", options.uamuiport);
843: if (setenv("UAMUIPORT", b, 1 ) != 0) {
844: log_err(errno, "setenv() did not return 0!");
845: exit(0);
846: }
847:
848: if (setenv("DHCPIF", options.dhcpif ? options.dhcpif : "", 1 ) != 0) {
849: log_err(errno, "setenv() did not return 0!");
850: exit(0);
851: }
852:
853: if (execl(script, script, tuntap(tun).devname, saddr, smask, (char *) 0) != 0) {
854: log_err(errno, "execl() did not return 0!");
855: exit(0);
856: }
857:
858: exit(0);
859: }
860:
861:
862: /* Currently unused
863: int tun_addroute2(struct tun_t *this,
864: struct in_addr *dst,
865: struct in_addr *gateway,
866: struct in_addr *mask) {
867:
868: struct {
869: struct nlmsghdr n;
870: struct rtmsg r;
871: char buf[TUN_NLBUFSIZE];
872: } req;
873:
874: struct sockaddr_nl local;
875: int addr_len;
876: int fd;
877: int status;
878: struct sockaddr_nl nladdr;
879: struct iovec iov;
880: struct msghdr msg;
881:
882: memset(&req, 0, sizeof(req));
883: req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
884: req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
885: req.n.nlmsg_type = RTM_NEWROUTE;
886: req.r.rtm_family = AF_INET;
887: req.r.rtm_table = RT_TABLE_MAIN;
888: req.r.rtm_protocol = RTPROT_BOOT;
889: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
890: req.r.rtm_type = RTN_UNICAST;
891: tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
892: tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
893:
894: if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
895: sys_err(LOG_ERR, __FILE__, __LINE__, errno,
896: "socket() failed");
897: return -1;
898: }
899:
900: memset(&local, 0, sizeof(local));
901: local.nl_family = AF_NETLINK;
902: local.nl_groups = 0;
903:
904: if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
905: sys_err(LOG_ERR, __FILE__, __LINE__, errno,
906: "bind() failed");
907: close(fd);
908: return -1;
909: }
910:
911: addr_len = sizeof(local);
912: if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
913: sys_err(LOG_ERR, __FILE__, __LINE__, errno,
914: "getsockname() failed");
915: close(fd);
916: return -1;
917: }
918:
919: if (addr_len != sizeof(local)) {
920: sys_err(LOG_ERR, __FILE__, __LINE__, 0,
921: "Wrong address length %d", addr_len);
922: close(fd);
923: return -1;
924: }
925:
926: if (local.nl_family != AF_NETLINK) {
927: sys_err(LOG_ERR, __FILE__, __LINE__, 0,
928: "Wrong address family %d", local.nl_family);
929: close(fd);
930: return -1;
931: }
932:
933: iov.iov_base = (void*)&req.n;
934: iov.iov_len = req.n.nlmsg_len;
935:
936: msg.msg_name = (void*)&nladdr;
937: msg.msg_namelen = sizeof(nladdr),
938: msg.msg_iov = &iov;
939: msg.msg_iovlen = 1;
940: msg.msg_control = NULL;
941: msg.msg_controllen = 0;
942: msg.msg_flags = 0;
943:
944: memset(&nladdr, 0, sizeof(nladdr));
945: nladdr.nl_family = AF_NETLINK;
946: nladdr.nl_pid = 0;
947: nladdr.nl_groups = 0;
948:
949: req.n.nlmsg_seq = 0;
950: req.n.nlmsg_flags |= NLM_F_ACK;
951:
952: status = sendmsg(fd, &msg, 0); * TODO: Error check *
953: close(fd);
954: return 0;
955: }
956: */
957:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>