Mercurial > hg > quicktun
comparison src/common.c @ 47:e896392f7e03
Added support for connecting over IPv6
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Fri, 24 May 2013 17:14:10 +0200 |
parents | 54d28a81ca99 |
children | b4de2326e9f7 |
comparison
equal
deleted
inserted
replaced
46:3f04a72ce035 | 47:e896392f7e03 |
---|---|
49 #endif | 49 #endif |
50 #endif | 50 #endif |
51 | 51 |
52 #define MAX_PACKET_LEN (ETH_FRAME_LEN+4) //Some space for optional packet information | 52 #define MAX_PACKET_LEN (ETH_FRAME_LEN+4) //Some space for optional packet information |
53 | 53 |
54 typedef union { | |
55 struct sockaddr any; | |
56 struct sockaddr_in ip4; | |
57 struct sockaddr_in6 ip6; | |
58 } sockaddr_any; | |
59 | |
54 struct qtsession; | 60 struct qtsession; |
55 struct qtproto { | 61 struct qtproto { |
56 int encrypted; | 62 int encrypted; |
57 int buffersize_raw; | 63 int buffersize_raw; |
58 int buffersize_enc; | 64 int buffersize_enc; |
68 struct qtproto protocol; | 74 struct qtproto protocol; |
69 void* protocol_data; | 75 void* protocol_data; |
70 int fd_socket; | 76 int fd_socket; |
71 int fd_dev; | 77 int fd_dev; |
72 int remote_float; | 78 int remote_float; |
73 struct sockaddr_in remote_addr; | 79 sockaddr_any remote_addr; |
74 int use_pi; | 80 int use_pi; |
75 int poll_timeout; | 81 int poll_timeout; |
76 void (*sendnetworkpacket)(struct qtsession* sess, char* msg, int len); | 82 void (*sendnetworkpacket)(struct qtsession* sess, char* msg, int len); |
77 }; | 83 }; |
78 | 84 |
102 void print_header() { | 108 void print_header() { |
103 fprintf(stderr, "UCIS QuickTun "QT_VERSION" (c) 2010-2013 Ivo Smits <Ivo@UCIS.nl>\n"); | 109 fprintf(stderr, "UCIS QuickTun "QT_VERSION" (c) 2010-2013 Ivo Smits <Ivo@UCIS.nl>\n"); |
104 fprintf(stderr, "More information: http://wiki.ucis.nl/QuickTun\n"); | 110 fprintf(stderr, "More information: http://wiki.ucis.nl/QuickTun\n"); |
105 } | 111 } |
106 | 112 |
113 static int is_all_zero(void* buf, int size) { | |
114 int i; | |
115 char* bb = (char*)buf; | |
116 for (i = 0; i < size; i++) if (bb[i] != 0) return 0; | |
117 return 1; | |
118 } | |
119 static int sockaddr_is_zero_address(sockaddr_any* sa) { | |
120 int af = sa->any.sa_family; | |
121 if (af == AF_INET) return is_all_zero(&sa->ip4.sin_addr, sizeof(struct in_addr)); | |
122 if (af == AF_INET6) return is_all_zero(&sa->ip6.sin6_addr, sizeof(struct in6_addr)); | |
123 return is_all_zero(sa, sizeof(sockaddr_any)); | |
124 } | |
125 static int sockaddr_set_port(sockaddr_any* sa, int port) { | |
126 port = htons(port); | |
127 int af = sa->any.sa_family; | |
128 if (af == AF_INET) sa->ip4.sin_port = port; | |
129 else if (af == AF_INET6) sa->ip6.sin6_port = port; | |
130 else return errorexit("Unknown address family"); | |
131 return 0; | |
132 } | |
133 static int sockaddr_equal(sockaddr_any* a, sockaddr_any* b) { | |
134 if (a->any.sa_family != b->any.sa_family) return 0; | |
135 if (a->any.sa_family == AF_INET) return a->ip4.sin_port == b->ip4.sin_port && a->ip4.sin_addr.s_addr == b->ip4.sin_addr.s_addr; | |
136 if (a->any.sa_family == AF_INET6) return a->ip6.sin6_port == b->ip6.sin6_port && memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(struct in6_addr)) == 0 && a->ip6.sin6_scope_id == b->ip6.sin6_scope_id; | |
137 return memcmp(a, b, sizeof(sockaddr_any)) == 0; | |
138 } | |
139 static void sockaddr_to_string(sockaddr_any* sa, char* str, int strbuflen) { | |
140 if (sa->any.sa_family == AF_INET) { | |
141 if (!inet_ntop(AF_INET, &sa->ip4.sin_addr, str, strbuflen)) str[0] = 0; | |
142 int i = strlen(str); | |
143 snprintf(str + i, strbuflen - i, ":%u", ntohs(sa->ip4.sin_port)); | |
144 } else if (sa->any.sa_family == AF_INET6) { | |
145 if (!inet_ntop(AF_INET6, &sa->ip6.sin6_addr, str, strbuflen)) str[0] = 0; | |
146 int i = strlen(str); | |
147 snprintf(str + i, strbuflen - i, "%%%d:%u", sa->ip6.sin6_scope_id, ntohs(sa->ip6.sin6_port)); | |
148 } else { | |
149 strncpy(str, "Unknown AF", strbuflen); | |
150 } | |
151 str[strbuflen - 1] = 0; | |
152 } | |
153 | |
107 static int init_udp(struct qtsession* session) { | 154 static int init_udp(struct qtsession* session) { |
108 char* envval; | 155 char* envval; |
109 fprintf(stderr, "Initializing UDP socket...\n"); | 156 fprintf(stderr, "Initializing UDP socket...\n"); |
110 int sfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | 157 struct addrinfo *ai_local = NULL, *ai_remote = NULL; |
158 unsigned short af = 0; | |
159 if (envval = getconf("LOCAL_ADDRESS")) { | |
160 if (getaddrinfo(envval, NULL, NULL, &ai_local)) return errorexitp("getaddrinfo(LOCAL_ADDRESS)"); | |
161 if (!ai_local) return errorexit("LOCAL_ADDRESS lookup failed"); | |
162 if (ai_local->ai_addrlen > sizeof(sockaddr_any)) return errorexit("Resolved LOCAL_ADDRESS is too big"); | |
163 af = ai_local->ai_family; | |
164 } | |
165 if (envval = getconf("REMOTE_ADDRESS")) { | |
166 if (getaddrinfo(envval, NULL, NULL, &ai_remote)) return errorexitp("getaddrinfo(REMOTE_ADDRESS)"); | |
167 if (!ai_remote) return errorexit("REMOTE_ADDRESS lookup failed"); | |
168 if (ai_remote->ai_addrlen > sizeof(sockaddr_any)) return errorexit("Resolved REMOTE_ADDRESS is too big"); | |
169 if (af && af != ai_remote->ai_family) return errorexit("Address families do not match"); | |
170 af = ai_remote->ai_family; | |
171 } | |
172 if (!af) af = AF_INET; | |
173 int sfd = socket(af, SOCK_DGRAM, IPPROTO_UDP); | |
111 if (sfd < 0) return errorexitp("Could not create UDP socket"); | 174 if (sfd < 0) return errorexitp("Could not create UDP socket"); |
112 struct sockaddr_in udpaddr; | 175 sockaddr_any udpaddr; |
113 struct hostent *he; | 176 memset(&udpaddr, 0, sizeof(udpaddr)); |
114 udpaddr.sin_family = AF_INET; | 177 udpaddr.any.sa_family = af; |
115 udpaddr.sin_addr.s_addr = INADDR_ANY; | 178 if (ai_local) memcpy(&udpaddr, ai_local->ai_addr, ai_local->ai_addrlen); |
116 udpaddr.sin_port = htons(2998); | 179 int port = 2998; |
117 if (envval = getconf("LOCAL_ADDRESS")) { | 180 if (envval = getconf("LOCAL_PORT")) port = atoi(envval); |
118 he = gethostbyname(envval); | 181 if (sockaddr_set_port(&udpaddr, port)) return -1; |
119 if (!he) return errorexit("bind address lookup failed"); | 182 if (bind(sfd, (struct sockaddr*)&udpaddr, sizeof(udpaddr))) return errorexitp("Could not bind socket"); |
120 else if (!he->h_addr_list[0]) return errorexit("no address to bind to"); | 183 memset(&udpaddr, 0, sizeof(udpaddr)); |
121 udpaddr.sin_addr.s_addr = *((unsigned long*)he->h_addr_list[0]); | 184 udpaddr.any.sa_family = af; |
122 udpaddr.sin_family = he->h_addrtype; | 185 if (ai_remote) memcpy(&udpaddr, ai_remote->ai_addr, ai_remote->ai_addrlen); |
123 } | 186 if (!ai_remote || sockaddr_is_zero_address(&udpaddr)) { |
124 if (envval = getconf("LOCAL_PORT")) { | |
125 udpaddr.sin_port = htons(atoi(envval)); | |
126 } | |
127 if (bind(sfd, (struct sockaddr*)&udpaddr, sizeof(struct sockaddr_in))) return errorexitp("Could not bind socket"); | |
128 if (!(envval = getconf("REMOTE_ADDRESS"))) { | |
129 session->remote_float = 1; | 187 session->remote_float = 1; |
130 //return errorexit("Missing REMOTE_ADDRESS"); | |
131 } else { | 188 } else { |
132 session->remote_float = getconf("REMOTE_FLOAT") ? 1 : 0; | 189 session->remote_float = getconf("REMOTE_FLOAT") ? 1 : 0; |
133 he = gethostbyname(envval); | 190 port = 2998; |
134 if (!he) return errorexit("remote address lookup failed"); | 191 if (envval = getconf("REMOTE_PORT")) port = atoi(envval); |
135 else if (!he->h_addr_list[0]) return errorexit("no address to connect to"); | 192 if (sockaddr_set_port(&udpaddr, port)) return -1; |
136 udpaddr.sin_family = he->h_addrtype; | 193 session->remote_addr = udpaddr; |
137 udpaddr.sin_addr.s_addr = *((unsigned long*)he->h_addr_list[0]); | 194 if (session->remote_float) { |
138 if (udpaddr.sin_addr.s_addr == 0) { | 195 session->remote_float = 2; |
139 session->remote_float = 1; | |
140 } else { | 196 } else { |
141 if (envval = getconf("REMOTE_PORT")) { | 197 if (connect(sfd, (struct sockaddr*)&udpaddr, sizeof(udpaddr))) return errorexitp("Could not connect socket"); |
142 udpaddr.sin_port = htons(atoi(envval)); | |
143 } | |
144 if (connect(sfd, (struct sockaddr*)&udpaddr, sizeof(struct sockaddr_in))) return errorexitp("Could not connect socket"); | |
145 session->remote_addr = udpaddr; | |
146 } | 198 } |
147 } | 199 } |
200 if (ai_local) freeaddrinfo(ai_local); | |
201 if (ai_remote) freeaddrinfo(ai_remote); | |
148 session->fd_socket = sfd; | 202 session->fd_socket = sfd; |
149 return sfd; | 203 return sfd; |
150 } | 204 } |
151 | 205 |
152 static int init_tuntap(struct qtsession* session) { | 206 static int init_tuntap(struct qtsession* session) { |
221 | 275 |
222 static void qtsendnetworkpacket(struct qtsession* session, char* msg, int len) { | 276 static void qtsendnetworkpacket(struct qtsession* session, char* msg, int len) { |
223 if (session->remote_float == 0) { | 277 if (session->remote_float == 0) { |
224 len = write(session->fd_socket, msg, len); | 278 len = write(session->fd_socket, msg, len); |
225 } else if (session->remote_float == 2) { | 279 } else if (session->remote_float == 2) { |
226 len = sendto(session->fd_socket, msg, len, 0, (struct sockaddr*)&session->remote_addr, sizeof(struct sockaddr_in)); | 280 len = sendto(session->fd_socket, msg, len, 0, (struct sockaddr*)&session->remote_addr, sizeof(sockaddr_any)); |
227 } | 281 } |
228 } | 282 } |
229 | 283 |
230 int qtrun(struct qtproto* p) { | 284 int qtrun(struct qtproto* p) { |
231 if (getconf("DEBUG")) debug = 1; | 285 if (getconf("DEBUG")) debug = 1; |
253 struct pollfd fds[2]; | 307 struct pollfd fds[2]; |
254 fds[0].fd = ttfd; | 308 fds[0].fd = ttfd; |
255 fds[0].events = POLLIN; | 309 fds[0].events = POLLIN; |
256 fds[1].fd = sfd; | 310 fds[1].fd = sfd; |
257 fds[1].events = POLLIN; | 311 fds[1].events = POLLIN; |
258 | |
259 struct sockaddr_in recvaddr; | |
260 | 312 |
261 int pi_length = 0; | 313 int pi_length = 0; |
262 if (session.use_pi == 2) pi_length = 4; | 314 if (session.use_pi == 2) pi_length = 4; |
263 | 315 |
264 char buffer_raw_a[p->buffersize_raw + pi_length]; | 316 char buffer_raw_a[p->buffersize_raw + pi_length]; |
287 len = sizeof(out); | 339 len = sizeof(out); |
288 getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len); | 340 getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len); |
289 fprintf(stderr, "Received error %d on udp socket\n", out); | 341 fprintf(stderr, "Received error %d on udp socket\n", out); |
290 } | 342 } |
291 if (fds[1].revents & POLLIN) { | 343 if (fds[1].revents & POLLIN) { |
344 sockaddr_any recvaddr; | |
292 socklen_t recvaddr_len = sizeof(recvaddr); | 345 socklen_t recvaddr_len = sizeof(recvaddr); |
293 if (session.remote_float == 0) { | 346 if (session.remote_float == 0) { |
294 len = read(sfd, buffer_enc + p->offset_enc, p->buffersize_enc); | 347 len = read(sfd, buffer_enc + p->offset_enc, p->buffersize_enc); |
295 } else { | 348 } else { |
296 len = recvfrom(sfd, buffer_enc + p->offset_enc, p->buffersize_enc, 0, (struct sockaddr*)&recvaddr, &recvaddr_len); | 349 len = recvfrom(sfd, buffer_enc + p->offset_enc, p->buffersize_enc, 0, (struct sockaddr*)&recvaddr, &recvaddr_len); |
301 getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len); | 354 getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len); |
302 fprintf(stderr, "Received end of file on udp socket (error %lld)\n", out); | 355 fprintf(stderr, "Received end of file on udp socket (error %lld)\n", out); |
303 } else { | 356 } else { |
304 len = p->decode(&session, buffer_enc, buffer_raw + pi_length, len); | 357 len = p->decode(&session, buffer_enc, buffer_raw + pi_length, len); |
305 if (len < 0) continue; | 358 if (len < 0) continue; |
306 if (session.remote_float != 0 && (session.remote_addr.sin_addr.s_addr != recvaddr.sin_addr.s_addr || session.remote_addr.sin_port != recvaddr.sin_port)) { | 359 if (session.remote_float != 0 && !sockaddr_equal(&session.remote_addr, &recvaddr)) { |
307 fprintf(stderr, "Remote endpoint has changed to %08X:%d\n", ntohl(recvaddr.sin_addr.s_addr), ntohs(recvaddr.sin_port)); | 360 char epname[INET6_ADDRSTRLEN + 1 + 2 + 1 + 5]; //addr%scope:port |
361 sockaddr_to_string(&recvaddr, epname, sizeof(epname)); | |
362 fprintf(stderr, "Remote endpoint has changed to %s\n", epname); | |
308 session.remote_addr = recvaddr; | 363 session.remote_addr = recvaddr; |
309 session.remote_float = 2; | 364 session.remote_float = 2; |
310 } | 365 } |
311 if (len > 0 && session.use_pi == 2) { | 366 if (len > 0 && session.use_pi == 2) { |
312 int ipver = (buffer_raw[p->offset_raw + pi_length] >> 4) & 0xf; | 367 int ipver = (buffer_raw[p->offset_raw + pi_length] >> 4) & 0xf; |