1 /*
2 * tun-loop.c
3 *
4 * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5 *
6 * $Id: tun-loop.c,v 1.5 2002/03/09 04:41:20 dugsong Exp $
7 */
8
9 #include "config.h"
10
11 #include <sys/types.h>
12 #include <sys/time.h>
13
14 #include <err.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <dnet.h>
22 #include <event.h>
23 #include <pcap.h>
24
25 #include "pcaputil.h"
26 #include "tun.h"
27
28 #ifdef __linux__
29 #define LOOPBACK_DEV "lo"
30 #else
31 #define LOOPBACK_DEV "lo0"
32 #endif
33
34 struct tun {
35 intf_t *intf;
36 pcap_t *pcap;
37 route_t *route;
38
39 struct route_entry rtent;
40 struct intf_entry *ifent;
41 u_char buf[1024];
42 int dloff;
43
44 int fd;
45 struct event ev;
46 tun_handler callback;
47 void *arg;
48 };
49
50 tun_t *
tun_open(struct addr * src,struct addr * dst,int mtu)51 tun_open(struct addr *src, struct addr *dst, int mtu)
52 {
53 struct tun *tun;
54 struct arp_entry arpent;
55 struct intf_entry ifent;
56 arp_t *arp;
57
58 if ((tun = calloc(1, sizeof(*tun))) == NULL)
59 return (NULL);
60
61 tun->ifent = (struct intf_entry *)tun->buf;
62 tun->ifent->intf_len = sizeof(tun->buf);
63 strlcpy(tun->ifent->intf_name, LOOPBACK_DEV,
64 sizeof(tun->ifent->intf_name));
65
66 /* Get interface information. */
67 if ((tun->intf = intf_open()) == NULL)
68 return (NULL);
69
70 if (intf_get(tun->intf, tun->ifent) < 0)
71 return (tun_close(tun));
72
73 memcpy(&tun->rtent.route_dst, dst, sizeof(*dst));
74 #ifdef __linux__
75 /* XXX - Linux sets the routed src IP regardless of assigned addr */
76 addr_aton("127.0.0.1", &tun->rtent.route_gw);
77 #else
78 memcpy(&tun->rtent.route_gw, src, sizeof(*src));
79 #endif
80 /* Set interface address and MTU. */
81 memset(&ifent, 0, sizeof(ifent));
82 strcpy(ifent.intf_name, tun->ifent->intf_name);
83 ifent.intf_flags = tun->ifent->intf_flags | INTF_FLAG_UP;
84 ifent.intf_mtu = mtu;
85 memcpy(&ifent.intf_addr, &tun->rtent.route_gw,
86 sizeof(ifent.intf_addr));
87
88 if (intf_set(tun->intf, &ifent) < 0)
89 return (tun_close(tun));
90
91 /* Delete any existing route for destination. */
92 if ((tun->route = route_open()) == NULL)
93 return (tun_close(tun));
94 route_delete(tun->route, &tun->rtent);
95
96 /* Delete any existing ARP entry for destination. */
97 if ((arp = arp_open()) != NULL) {
98 memcpy(&arpent.arp_pa, dst, sizeof(*dst));
99 arp_delete(arp, &arpent);
100 arp_close(arp);
101 }
102 /* Add route for destination via loopback. */
103 if (route_add(tun->route, &tun->rtent) < 0)
104 return (tun_close(tun));
105
106 /* Set up to sniff on loopback. */
107 if ((tun->pcap = pcap_open1(tun->ifent->intf_name)) == NULL)
108 return (tun_close(tun));
109
110 if (pcap_filter(tun->pcap, "ip dst %s", addr_ntoa(dst)) < 0)
111 return (tun_close(tun));
112
113 tun->dloff = pcap_dloff(tun->pcap);
114 tun->fd = pcap_fileno(tun->pcap);
115
116 return (tun);
117 }
118
119 static void
_pcap_recv(u_char * u,const struct pcap_pkthdr * hdr,const u_char * pkt)120 _pcap_recv(u_char *u, const struct pcap_pkthdr *hdr, const u_char *pkt)
121 {
122 tun_t *tun = (tun_t *)u;
123
124 /*
125 * XXX - if we wanted to be a real tunnel device,
126 * we would forcibly rewrite the addresses here...
127 */
128 (*tun->callback)((u_char *)pkt + tun->dloff,
129 hdr->caplen - tun->dloff, tun->arg);
130 }
131
132 static void
_tun_recv(int fd,short event,void * arg)133 _tun_recv(int fd, short event, void *arg)
134 {
135 tun_t *tun = (tun_t *)arg;
136
137 event_add(&tun->ev, NULL);
138 pcap_dispatch(tun->pcap, -1, _pcap_recv, (u_char *)tun);
139 }
140
141 int
tun_register(tun_t * tun,tun_handler callback,void * arg)142 tun_register(tun_t *tun, tun_handler callback, void *arg)
143 {
144 tun->callback = callback;
145 tun->arg = arg;
146
147 event_set(&tun->ev, tun->fd, EV_READ, _tun_recv, tun);
148 event_add(&tun->ev, NULL);
149
150 return (0);
151 }
152
153 tun_t *
tun_close(tun_t * tun)154 tun_close(tun_t *tun)
155 {
156 if (event_initialized(&tun->ev))
157 event_del(&tun->ev);
158
159 /* Stop sniffing. */
160 if (tun->pcap != NULL)
161 pcap_close(tun->pcap);
162
163 /* Delete loopback route. */
164 if (tun->route != NULL) {
165 if (route_delete(tun->route, &tun->rtent) < 0)
166 warnx("couldn't delete loopback route");
167 route_close(tun->route);
168 }
169 /* Restore interface address and MTU. */
170 if (tun->intf != NULL) {
171 if (tun->ifent != NULL) {
172 if (intf_set(tun->intf, tun->ifent) < 0)
173 warnx("couldn't restore loopback settings");
174 }
175 intf_close(tun->intf);
176 }
177 free(tun);
178
179 return (NULL);
180 }
181