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