comparison src/common.c @ 0:65c01f57bdce V2.1.2

Initial commit
author ivo <ivo@UFO-Net.nl>
date Thu, 07 Oct 2010 15:53:01 +0200
parents
children b2c7c83a1dda
comparison
equal deleted inserted replaced
-1:000000000000 0:65c01f57bdce
1 /* Copyright 2010 Ivo Smits <Ivo@UCIS.nl>. All rights reserved.
2 Redistribution and use in source and binary forms, with or without modification, are
3 permitted provided that the following conditions are met:
4
5 1. Redistributions of source code must retain the above copyright notice, this list of
6 conditions and the following disclaimer.
7
8 2. Redistributions in binary form must reproduce the above copyright notice, this list
9 of conditions and the following disclaimer in the documentation and/or other materials
10 provided with the distribution.
11
12 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
14 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
15 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
19 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
20 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
22 The views and conclusions contained in the software and documentation are those of the
23 authors and should not be interpreted as representing official policies, either expressed
24 or implied, of Ivo Smits.*/
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #ifndef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
32 #endif
33 #include <sys/ioctl.h>
34 #include <linux/if.h>
35 #include <linux/if_tun.h>
36 #include <linux/if_ether.h>
37 #include <poll.h>
38 #include <netdb.h>
39 #include <stdlib.h>
40
41 #define MAX_PACKET_LEN (ETH_FRAME_LEN+4) //Some space for optional packet information
42
43 struct qtsession;
44 struct qtproto {
45 int encrypted;
46 int buffersize_raw;
47 int buffersize_enc;
48 int offset_raw;
49 int offset_enc;
50 int (*encode)(struct qtsession* sess, char* raw, char* enc, int len);
51 int (*decode)(struct qtsession* sess, char* enc, char* raw, int len);
52 int (*init)(struct qtsession* sess);
53 int protocol_data_size;
54 };
55 struct qtsession {
56 struct qtproto protocol;
57 void* protocol_data;
58 int fd_socket;
59 int fd_dev;
60 int remote_float;
61 struct sockaddr_in remote_addr;
62 };
63
64 #ifdef COMBINED_BINARY
65 extern char* (*getconf)(const char*);
66 extern int errorexit(const char*);
67 extern int errorexitp(const char*);
68 extern void print_header();
69 extern void hex2bin(unsigned char*, unsigned char*, int);
70 #else
71
72 char* (*getconf)(const char*) = getenv;
73
74 int errorexit(const char* text) {
75 fprintf(stderr, "%s\n", text);
76 return -1;
77 }
78 int errorexitp(const char* text) {
79 perror(text);
80 return -1;
81 }
82
83 void print_header() {
84 printf("UCIS QuickTun (c) 2010 Ivo Smits <Ivo@UCIS.nl>\n");
85 printf("More information: http://wiki.qontrol.nl/QuickTun\n");
86 }
87
88 int init_udp(struct qtsession* session) {
89 char* envval;
90 printf("Initializing UDP socket...\n");
91 int sfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
92 if (sfd < 0) return errorexitp("Could not create UDP socket");
93 struct sockaddr_in udpaddr;
94 struct hostent *he;
95 udpaddr.sin_family = AF_INET;
96 udpaddr.sin_addr.s_addr = INADDR_ANY;
97 udpaddr.sin_port = htons(2998);
98 if (envval = getconf("LOCAL_ADDRESS")) {
99 he = gethostbyname(envval);
100 if (!he) return errorexit("bind address lookup failed");
101 else if (!he->h_addr_list[0]) return errorexit("no address to bind to");
102 udpaddr.sin_addr.s_addr = *((unsigned long*)he->h_addr_list[0]);
103 udpaddr.sin_family = he->h_addrtype;
104 }
105 if (envval = getconf("LOCAL_PORT")) {
106 udpaddr.sin_port = htons(atoi(envval));
107 }
108 if (bind(sfd, (struct sockaddr*)&udpaddr, sizeof(struct sockaddr_in))) return errorexitp("Could not bind socket");
109 if (!(envval = getconf("REMOTE_ADDRESS"))) {
110 session->remote_float = 1;
111 //return errorexit("Missing REMOTE_ADDRESS");
112 } else {
113 session->remote_float = 0;
114 he = gethostbyname(envval);
115 if (!he) return errorexit("remote address lookup failed");
116 else if (!he->h_addr_list[0]) return errorexit("no address to connect to");
117 udpaddr.sin_family = he->h_addrtype;
118 udpaddr.sin_addr.s_addr = *((unsigned long*)he->h_addr_list[0]);
119 if (envval = getconf("REMOTE_PORT")) {
120 udpaddr.sin_port = htons(atoi(envval));
121 }
122 if (connect(sfd, (struct sockaddr*)&udpaddr, sizeof(struct sockaddr_in))) return errorexitp("Could not connect socket");
123 session->remote_addr = udpaddr;
124 }
125 session->fd_socket = sfd;
126 return sfd;
127 }
128
129 int init_tuntap() {
130 char* envval;
131 printf("Initializing tap device...\n");
132 int ttfd; //Tap device file descriptor
133 struct ifreq ifr; //required for tun/tap setup
134 memset(&ifr, 0, sizeof(ifr));
135 if ((ttfd = open("/dev/net/tun", O_RDWR)) < 0) return errorexitp("Could not open tap device file");
136 if (envval = getconf("INTERFACE")) strcpy(ifr.ifr_name, envval);
137 ifr.ifr_flags = getconf("TUN_MODE") ? IFF_TUN : IFF_TAP;
138 ifr.ifr_flags |= getconf("USE_PI") ? 0 : IFF_NO_PI;
139 if (ioctl(ttfd, TUNSETIFF, (void *)&ifr) < 0) return errorexitp("TUNSETIFF ioctl failed");
140 return ttfd;
141 }
142
143 void hex2bin(unsigned char* dest, unsigned char* src, int count) {
144 int i;
145 for (i = 0; i < count; i++) {
146 if (*src >= '0' && *src <= '9') *dest = *src - '0';
147 else if (*src >= 'a' && * src <='f') *dest = *src - 'a' + 10;
148 else if (*src >= 'A' && * src <='F') *dest = *src - 'A' + 10;
149 src++; *dest = *dest << 4;
150 if (*src >= '0' && *src <= '9') *dest += *src - '0';
151 else if (*src >= 'a' && *src <= 'f') *dest += *src - 'a' + 10;
152 else if (*src >= 'A' && *src <= 'F') *dest += *src - 'A' + 10;
153 src++; dest++;
154 }
155 }
156
157 int qtrun(struct qtproto* p) {
158 struct qtsession session;
159 session.protocol = *p;
160 init_udp(&session);
161 session.fd_dev = init_tuntap();
162
163 char protocol_data[p->protocol_data_size];
164 session.protocol_data = &protocol_data;
165 if (p->init) p->init(&session);
166
167 int sfd = session.fd_socket;
168 int ttfd = session.fd_dev;
169 if (sfd == -1) return -1;
170 if (ttfd == -1) return -1;
171 printf("The tunnel is now operational!\n");
172
173 struct pollfd fds[2];
174 fds[0].fd = ttfd;
175 fds[0].events = POLLIN;
176 fds[1].fd = sfd;
177 fds[1].events = POLLIN;
178
179 struct sockaddr_in recvaddr;
180
181 char buffer_raw_a[p->buffersize_raw];
182 char buffer_enc_a[p->buffersize_enc];
183 char* buffer_raw = buffer_raw_a;
184 char* buffer_enc = buffer_enc_a;
185
186 while (1) {
187 int len = poll(fds, 2, -1);
188 if (len < 0) return errorexitp("poll error");
189 else if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) return errorexit("poll error on tap device");
190 else if (fds[1].revents & (POLLHUP | POLLNVAL)) return errorexit("poll error on udp socket");
191 if (fds[0].revents & POLLIN) {
192 if (session.remote_float == 0 || session.remote_float == 2) {
193 len = read(ttfd, buffer_raw + p->offset_raw, p->buffersize_raw);
194 len = p->encode(&session, buffer_raw, buffer_enc, len);
195 if (len < 0) return len;
196 if (session.remote_float == 0) {
197 write(sfd, buffer_enc + p->offset_enc, len);
198 } else {
199 sendto(sfd, buffer_enc + p->offset_enc, len, 0, (struct sockaddr*)&session.remote_addr, sizeof(session.remote_addr));
200 }
201 }
202 }
203 if (fds[1].revents & POLLIN) {
204 socklen_t recvaddr_len = sizeof(recvaddr);
205 if (session.remote_float == 0) {
206 len = read(sfd, buffer_enc + p->offset_enc, p->buffersize_enc);
207 } else {
208 len = recvfrom(sfd, buffer_enc + p->offset_enc, p->buffersize_enc, 0, (struct sockaddr*)&recvaddr, &recvaddr_len);
209 }
210 if (len < 0) {
211 int out;
212 len = 4;
213 getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len);
214 fprintf(stderr, "End of file on udp socket");
215 } else {
216 len = p->decode(&session, buffer_enc, buffer_raw, len);
217 if (len != 0 && session.remote_float != 0 && (session.remote_addr.sin_addr.s_addr != recvaddr.sin_addr.s_addr || session.remote_addr.sin_port != recvaddr.sin_port)) {
218 fprintf(stderr, "Remote endpoint has changed to %s:%d", inet_ntoa(recvaddr.sin_addr), ntohs(recvaddr.sin_port));
219 session.remote_addr = recvaddr;
220 session.remote_float = 2;
221 }
222 if (len < 0) return len;
223 write(ttfd, buffer_raw + p->offset_raw, len);
224 }
225 }
226 }
227 return 0;
228 }
229 #endif