Updated daemonize () function, added parameter as interface - tunnel; pid file is...
[ndprouter.git] / main.c
blob188008620a67d3990cb437fbc01fc062121cd159
1 /*
2 * ZeX/OS
3 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <pcap.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <net/if.h>
29 #include <sys/stat.h>
30 #include <arpa/inet.h>
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <net/if_arp.h>
35 #include <netinet/in.h>
36 #include <netinet/ip6.h> /* ip6_hdr */
37 #include <net/ethernet.h>
40 #define SNAP_LEN BUFSIZ
41 #define SIZE_ETHERNET 14 /* Ethernet headers are always exactly 14 bytes */
42 #define ETHERTYPE_IPV6 0xdd86
43 #define SIZE_IP6 40 /* IPv6 headers are always exactly 40 bytes */
45 /* MAC address structure */
46 typedef unsigned char s_mac_addr[6];
48 /* Ethernet header structure */
49 struct s_ethernet {
50 s_mac_addr dest; /* 48 b; destination host (MAC) address */
51 s_mac_addr src; /* 48 b; source host (MAC) address */
52 unsigned short type; /* 16 b; IP/ARP/RARP/... */
55 /* IPv6 header structure */
56 struct s_ip6 {
57 unsigned char ver; /* 8 b; version */
58 unsigned char traffic_class; /* 8 b; traffic class */
59 unsigned short flow_label; /* 16 b; flow label (qos) */
60 unsigned short len; /* 16 b; payload length */
61 unsigned char next_header; /* 8 b; next header */
62 unsigned char hop_limit; /* 8 b; hop limit (replaces ttl) */
63 struct in6_addr ip_src; /* 128 b; source address */
64 struct in6_addr ip_dest; /* 128 b; destination address */
67 struct s_conf {
68 struct in6_addr prefix;
69 unsigned char len;
70 unsigned char daemon;
73 struct s_conf config;
75 typedef struct ipv6_context {
76 struct ipv6_context *next, *prev;
78 struct in6_addr addr;
79 } ipv6_t;
81 ipv6_t ipv6_list;
83 unsigned ipv6_find (struct in6_addr *addr)
85 ipv6_t *ipv6;
87 for (ipv6 = ipv6_list.next; ipv6 != &ipv6_list; ipv6 = ipv6->next) {
88 if (!memcmp (&ipv6->addr, addr, sizeof (struct in6_addr)))
89 return 1;
92 return 0;
95 unsigned ipv6_add (struct in6_addr *addr)
97 if (ipv6_find (addr))
98 return 0;
100 /* alloc and init context */
101 ipv6_t *ipv6 = (ipv6_t *) malloc (sizeof (ipv6_t));
103 if (!ipv6)
104 return 0;
106 memcpy (&ipv6->addr, addr, sizeof (struct in6_addr));
108 /* add into list */
109 ipv6->next = &ipv6_list;
110 ipv6->prev = ipv6_list.prev;
111 ipv6->prev->next = ipv6;
112 ipv6->next->prev = ipv6;
114 char str[64];
115 char addr_src[INET6_ADDRSTRLEN];
116 inet_ntop (AF_INET6, addr, addr_src, INET6_ADDRSTRLEN);
118 if (config.daemon)
119 printf ("> new ipv6: %s\n", addr_src);
121 sprintf (str, "ip -6 neigh add proxy %s dev eth0", addr_src);
123 system (str);
125 return 1;
128 void handle_ipv6 (struct s_ethernet *eth, unsigned char *packet)
130 /* define/compute IP header offset */
131 struct s_ip6 *ip = (struct s_ip6 *) packet;
133 /* DEBUG: print source and destination IP addresses */
134 #ifdef DEBUG
135 char addr_src[INET6_ADDRSTRLEN];
136 char addr_dest[INET6_ADDRSTRLEN];
137 inet_ntop (AF_INET6, &ip->ip_src, addr_src, INET6_ADDRSTRLEN);
138 inet_ntop (AF_INET6, &ip->ip_dest, addr_dest, INET6_ADDRSTRLEN);
140 printf("> From: %s\n", addr_src);
141 printf("> To: %s\n", addr_dest);
142 #endif
143 if (!memcmp (&ip->ip_src, &config.prefix, config.len/8))
144 ipv6_add (&ip->ip_src);
147 void handle_packet (unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet)
149 /* define ethernet header */
150 struct s_ethernet *eth = (struct s_ethernet *) packet;
151 unsigned char *payload = (unsigned char *) (packet);
153 /* it could be actually whatever packet, but we assume its tunnel interface */
154 return handle_ipv6 (eth, payload);
157 void daemonize (char *dev)
159 #ifndef __WIN32__
160 int i, lockfd;
161 char pid[16];
162 char spid[64];
164 int ipid = getpid ();
166 /* detach if asked */
167 if (ipid == 1)
168 return; /* already a daemon */
170 /* fork to guarantee we are not process group leader */
171 i = fork ();
173 if (i < 0)
174 exit (1); /* fork error */
175 if (i > 0)
176 exit (0); /* parent exits */
178 /* child (daemon) continues */
179 setsid (); /* obtain a new process group */
180 ipid = getpid ()+1;
182 printf ("> started with pid -> %d\n", ipid);
183 /* fork again so we become process group leader
184 * and cannot regain a controlling tty
186 i = fork ();
188 if (i < 0)
189 exit (1); /* fork error */
190 else if (i > 0)
191 exit (0); /* parent exits */
193 /* close all fds */
194 for (i = getdtablesize (); i >= 0; --i)
195 close (i); /* close all descriptors */
197 /* close parent fds and send output to fds 0, 1 and 2 to bitbucket */
198 i = open ("/dev/null", O_RDWR);
200 if (i < 0)
201 exit (1);
203 dup (i);
204 dup (i); /* handle standart I/O */
206 sprintf (spid, "%s.pid", dev);
208 /* create local lock */
209 lockfd = open (spid, O_RDWR | O_CREAT, 0640);
211 if (lockfd < 0) {
212 perror ("lock: open");
213 exit (1);
215 #ifndef __CYGWIN__
216 /* lock the file */
217 if (lockf (lockfd, F_TLOCK, 0) < 0) {
218 perror ("lock: lockf");
219 printf ("> ndprouter is already running.\n");
220 exit (0);
222 #else
223 /* lock the file */
225 struct flock lock;
226 lock.l_type = F_RDLCK;
227 lock.l_start = 0;
228 lock.l_whence = SEEK_SET;
229 lock.l_len = 0;
231 if (fcntl (lockfd, F_SETLK, &lock) < 0) {
232 printf ("> ndprouter is already running.\n");
233 exit (0);
236 #endif
237 /* write to pid to lockfile */
238 snprintf (pid, 16, "%d\n", getpid ());
239 write (lockfd, pid, strlen (pid));
241 /* restrict created files to 0750 */
242 umask (027);
243 #endif
246 int main (int argc, char **argv)
248 char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
250 if (argc != 3 && argc != 4) {
251 printf ("syntax: <interface> <prefix/len> [-d]\n");
252 return -1;
255 char *dev = argv[1]; /* captured device */
256 char *prefix = argv[2];
258 if (argc == 4) {
259 if (argv[3][0] == '-' && argv[3][1] == 'd')
260 config.daemon = 1;
261 } else
262 config.daemon = 0;
264 unsigned i;
265 unsigned len = 0;
266 for (i = 0; prefix[i]; i ++) {
267 if (prefix[i] == '/') {
268 prefix[i] = '\0';
269 len = i;
270 break;
274 if (!len) {
275 printf ("ERROR -> Prefix length must be specified, example: 2001:abc:def::/64\n");
276 return -1;
279 char *plen = prefix + len + 1;
281 config.len = atoi (plen);
283 if (config.len < 16 || config.len > 128) {
284 printf ("ERROR -> Prefix length is wrong length: 16-128 are allowed");
285 return -1;
288 inet_pton (AF_INET6, prefix, &config.prefix);
290 ipv6_list.next = &ipv6_list;
291 ipv6_list.prev = &ipv6_list;
293 if (!config.daemon) {
294 printf ("> init\n");
296 /* print capture info */
297 printf ("> interface: %s\n", dev);
298 printf ("> ipv6 prefix: %s/%d\n", prefix, config.len);
299 } else
300 daemonize (dev);
302 /* open capture device */
303 pcap_t *handle = pcap_open_live (dev, SNAP_LEN, 1, 1, errbuf);
305 if (!handle) {
306 fprintf (stderr, "ERROR -> Couldn't open device %s: %s\n", dev, errbuf);
307 return -1;
310 /* now we can set our callback function */
311 pcap_loop (handle, 0, handle_packet, NULL);
313 /* free memory of pcap */
314 pcap_close (handle);
316 return 0;