Merge commit '10a89ef04df5669c5cdd02f786150a7ab8454e01'
[sliver-openvswitch.git] / planetlab / exp-tool / tunproxy.c
1 /*\r
2  * tunproxy.c --- small demo program for tunneling over UDP with tun/tap\r
3  *\r
4  * Copyright (C) 2003  Philippe Biondi <phil@secdev.org>\r
5  * Copyright (C) 2013  Felician Nemeth <nemethf@tmit.bme.hu>\r
6  *\r
7  * This program is free software; you can redistribute it and/or modify it\r
8  * under the terms of the GNU Lesser General Public License as published by\r
9  * the Free Software Foundation.\r
10  *\r
11  * This program is distributed in the hope that it will be useful, but\r
12  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
14  * Lesser General Public License for more details.\r
15  *\r
16  * http://www.secdev.org/projects/tuntap_udp/files/tunproxy.c\r
17  */\r
18 \r
19 #ifdef HAVE_CONFIG_H\r
20 #include <config.h>\r
21 #endif\r
22 #include <stdlib.h>\r
23 #include <stdio.h>\r
24 #include <string.h>\r
25 #include <unistd.h>\r
26 #include <sys/stat.h>\r
27 #include <fcntl.h>\r
28 #include <sys/types.h>\r
29 #include <sys/socket.h>\r
30 #include <netinet/in.h>\r
31 #include <arpa/inet.h>\r
32 #include <string.h>\r
33 #include <net/if.h>\r
34 #include <linux/if_tun.h>\r
35 #include <getopt.h>\r
36 #include <sys/ioctl.h>\r
37 #include <errno.h>\r
38 \r
39 #define PERROR(x) do { perror(x); exit(1); } while (0)\r
40 #define ERROR(x, args ...) do { fprintf(stderr,"ERROR:" x, ## args); exit(1); } while (0)\r
41 \r
42 extern void exit(int);\r
43 \r
44 void usage()\r
45 {\r
46         fprintf(stderr, "Usage: tunproxy -t target_ip:port [-p local_port] [-e]\n");\r
47         exit(0);\r
48 }\r
49 \r
50 int main(int argc, char *argv[])\r
51 {\r
52         struct sockaddr_in sin, sout, remote;\r
53         struct ifreq ifr;\r
54         int fd, s, remote_len, remote_port, local_port, l;\r
55         unsigned int soutlen;\r
56         char c, *p, *remote_ip = 0;\r
57         char buf[2000];\r
58         fd_set fdset;\r
59 \r
60         int TUNMODE = IFF_TUN, DEBUG = 0;\r
61 \r
62         while ((c = getopt(argc, argv, "t:p:ehd")) != -1) {\r
63                 switch (c) {\r
64                 case 'h':\r
65                         usage();\r
66                 case 'd':\r
67                         DEBUG++;\r
68                         break;\r
69                 case 'p':\r
70                         local_port = atoi(optarg);\r
71                         break;\r
72                 case 't':\r
73                         p = memchr(optarg,':',16);\r
74                         if (!p) ERROR("invalid argument : [%s]\n",optarg);\r
75                         *p = 0;\r
76                         remote_ip = optarg;\r
77                         remote_port = atoi(p+1);\r
78                         break;\r
79                 case 'e':\r
80                         TUNMODE = IFF_TAP;\r
81                         break;\r
82                 default:\r
83                         usage();\r
84                 }\r
85         }\r
86         if (remote_ip == 0) usage();\r
87 \r
88         if ( (fd = open("/dev/net/tun",O_RDWR)) < 0) PERROR("open");\r
89 \r
90         memset(&ifr, 0, sizeof(ifr));\r
91         ifr.ifr_flags = TUNMODE | IFF_NO_PI;\r
92         strncpy(ifr.ifr_name, "toto%d", IFNAMSIZ);\r
93         if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl");\r
94 \r
95         printf("Allocated interface %s. Configure and use it\n", ifr.ifr_name);\r
96         \r
97         s = socket(PF_INET, SOCK_DGRAM, 0);\r
98         sin.sin_family = AF_INET;\r
99         sin.sin_addr.s_addr = htonl(INADDR_ANY);\r
100         sin.sin_port = htons(local_port);\r
101 \r
102         if ( bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0)\r
103           PERROR("bind");\r
104 \r
105         remote_len = sizeof(remote);\r
106         memset(&remote, 0, remote_len);\r
107         remote.sin_family = AF_INET;\r
108         remote.sin_port = htons(remote_port);\r
109         remote.sin_addr.s_addr=inet_addr(remote_ip);\r
110 \r
111         while (1) {\r
112                 FD_ZERO(&fdset);\r
113                 FD_SET(fd, &fdset);\r
114                 FD_SET(s, &fdset);\r
115                 if (select(fd+s+1, &fdset,NULL,NULL,NULL) < 0) PERROR("select");\r
116                 if (FD_ISSET(fd, &fdset)) {\r
117                         if (DEBUG)\r
118                           if (write(1,">", 1) < 0) PERROR("write");\r
119                         l = read(fd, buf, sizeof(buf));\r
120                         if (l < 0) \r
121                           PERROR("read");\r
122                         if (sendto(s, buf, l, 0, (struct sockaddr *)&remote, remote_len) < 0)\r
123                           PERROR("sendto");\r
124                 }\r
125                 if (FD_ISSET(s, &fdset)) {\r
126                         if (DEBUG) \r
127                           if (write(1,"<", 1) < 0) PERROR("write");\r
128                         soutlen = sizeof(sout);\r
129                         l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&sout, &soutlen);\r
130                         if (l == -1) {\r
131                           if (write(1,"(", 1) < 0) PERROR("write");\r
132                           fprintf(stderr, "[%s,%d]", strerror(errno), l);\r
133                           continue;\r
134                         }\r
135                         if ((sout.sin_addr.s_addr != remote.sin_addr.s_addr) ||\r
136                             (sout.sin_port != remote.sin_port)) {\r
137                           printf("Got packet from  %s:%u instead of %s:%u\n", \r
138                                  inet_ntoa(sout.sin_addr), ntohs(sout.sin_port),\r
139                                  inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));\r
140                         }\r
141                         if (write(fd, buf, l) < 0) PERROR("write");\r
142                 }\r
143         }\r
144 }\r