Imported Upstream version 0.3.3
[debian/uanytun.git] / src / udp.c
1 /*
2  *  uAnytun
3  *
4  *  uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full
5  *  featured implementation uAnytun has no support for multiple connections
6  *  or synchronisation. It is a small single threaded implementation intended
7  *  to act as a client on small platforms.
8  *  The secure anycast tunneling protocol (satp) defines a protocol used
9  *  for communication between any combination of unicast and anycast
10  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
11  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
12  *  ethernet, ip, arp ...). satp directly includes cryptography and
13  *  message authentication based on the methodes used by SRTP.  It is
14  *  intended to deliver a generic, scaleable and secure solution for
15  *  tunneling and relaying of packets of any protocol.
16  *  
17  *
18  *  Copyright (C) 2007-2010 Christian Pointner <equinox@anytun.org>
19  *
20  *  This file is part of uAnytun.
21  *
22  *  uAnytun is free software: you can redistribute it and/or modify
23  *  it under the terms of the GNU General Public License as published by
24  *  the Free Software Foundation, either version 3 of the License, or
25  *  any later version.
26  *
27  *  uAnytun is distributed in the hope that it will be useful,
28  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  *  GNU General Public License for more details.
31  *
32  *  You should have received a copy of the GNU General Public License
33  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
34  */
35
36 #include "datatypes.h"
37
38 #include "udp.h"
39
40 #include "log.h"
41
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <netdb.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <arpa/inet.h>
50 #include <netinet/in.h>
51
52 int udp_init(udp_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type)
53 {
54   if(!sock || !port) 
55     return -1;
56
57   sock->socks_ = NULL;
58   sock->active_sock_ = NULL;
59   memset(&(sock->remote_end_), 0, sizeof(sock->remote_end_));
60   sock->remote_end_set_ = 0;
61
62   struct addrinfo hints, *res;
63
64   res = NULL;
65   memset (&hints, 0, sizeof (hints));
66   hints.ai_socktype = SOCK_DGRAM;
67   hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
68
69   switch(resolv_type) {
70   case IPV4_ONLY: hints.ai_family = AF_INET; break;
71   case IPV6_ONLY: hints.ai_family = AF_INET6; break;
72   default: hints.ai_family = AF_UNSPEC; break;
73   }
74
75   int errcode = getaddrinfo(local_addr, port, &hints, &res);
76   if (errcode != 0) {
77     log_printf(ERROR, "Error resolving local address (%s:%s): %s", (local_addr) ? local_addr : "*", port, gai_strerror(errcode));
78     udp_close(sock);
79     return -1;
80   }
81   if(!res) {
82     udp_close(sock);
83     log_printf(ERROR, "getaddrinfo returned no address for %s:%s", local_addr, port);
84     return -1;
85   }
86
87   struct addrinfo* r = res;
88   udp_socket_t* prev_sock = NULL;
89   while(r) {
90     udp_socket_t* new_sock = malloc(sizeof(udp_socket_t));
91     if(!new_sock) {
92       log_printf(ERROR, "memory error at udp_init");
93       freeaddrinfo(res);
94       udp_close(sock);
95       return -2;
96     }
97     memset(&(new_sock->local_end_), 0, sizeof(new_sock->local_end_));
98     new_sock->next_ = NULL;
99
100     if(!sock->socks_) {
101       sock->socks_ = new_sock;
102       prev_sock = new_sock;
103     }
104     else {
105       prev_sock->next_ = new_sock;
106       prev_sock = new_sock;
107     }
108     
109     memcpy(&(new_sock->local_end_), r->ai_addr, r->ai_addrlen);
110     new_sock->fd_ = socket(r->ai_family, SOCK_DGRAM, 0);
111     if(new_sock->fd_ < 0) {
112       log_printf(ERROR, "Error on opening udp socket: %s", strerror(errno));
113       freeaddrinfo(res);
114       udp_close(sock);
115       return -1;
116     }
117
118     if(r->ai_family == AF_INET6) {
119       int on = 1;
120       if(setsockopt(new_sock->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)))
121         log_printf(ERROR, "Error on setting IPV6_V6ONLY socket option: %s", strerror(errno));
122     }
123
124     errcode = bind(new_sock->fd_, r->ai_addr, r->ai_addrlen);
125     if(errcode) {
126       log_printf(ERROR, "Error on binding udp socket: %s", strerror(errno));
127       freeaddrinfo(res);
128       udp_close(sock);
129       return -1;
130     }
131   
132     char* local_string = udp_endpoint_to_string(new_sock->local_end_);
133     if(local_string) {
134       log_printf(NOTICE, "listening on: %s", local_string);
135       free(local_string);
136     }
137
138     r = r->ai_next;
139   }
140
141   freeaddrinfo(res);
142
143   return 0;
144 }
145
146 int udp_init_fd_set(udp_t* sock, fd_set* set)
147 {
148   int max_fd = 0;
149
150   udp_socket_t* s = sock->socks_;
151   while(s) {
152     FD_SET(s->fd_, set);
153     max_fd = s->fd_ > max_fd ? s->fd_ : max_fd;
154     s = s->next_;
155   }
156
157   return max_fd;
158 }
159
160 int udp_set_remote(udp_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type)
161 {
162   if(!sock || !remote_addr || !port) 
163     return -1;
164
165   struct addrinfo hints, *res;
166
167   res = NULL;
168   memset (&hints, 0, sizeof (hints));
169   hints.ai_socktype = SOCK_DGRAM;
170
171   switch(resolv_type) {
172   case IPV4_ONLY: hints.ai_family = PF_INET; break;
173   case IPV6_ONLY: hints.ai_family = PF_INET6; break;
174   default: hints.ai_family = PF_UNSPEC; break;
175   }
176
177   int errcode = getaddrinfo(remote_addr, port, &hints, &res);
178   if (errcode != 0) {
179     log_printf(ERROR, "Error resolving remote address (%s:%s): %s", (remote_addr) ? remote_addr : "*", port, gai_strerror(errcode));
180     return -1;
181   }
182   if(!res) {
183     log_printf(ERROR, "getaddrinfo returned no address for %s:%s", remote_addr, port);
184     return -1;
185   }
186   memcpy(&(sock->remote_end_), res->ai_addr, res->ai_addrlen);
187   sock->remote_end_set_ = 1;
188
189   if(!sock->active_sock_) {
190     udp_socket_t* s = sock->socks_;
191     while(s) {
192       if((((struct sockaddr *)&s->local_end_)->sa_family) == res->ai_family) {
193         sock->active_sock_ = s;
194         break;
195       }
196       s = s->next_;
197     }
198   }
199
200   freeaddrinfo(res);
201
202   return 0;
203 }
204
205 void udp_set_active_sock(udp_t* sock, int fd)
206 {
207   if(!sock || (sock->active_sock_ && sock->active_sock_->fd_ == fd))
208     return;
209
210   udp_socket_t* s = sock->socks_;
211   while(s) {
212     if(s->fd_ == fd) {
213       sock->active_sock_ = s;
214       return;
215     }
216     s = s->next_;
217   }
218 }
219
220 void udp_close(udp_t* sock)
221 {
222   if(!sock)
223     return;
224
225   while(sock->socks_) {
226     if(sock->socks_->fd_ > 0)
227       close(sock->socks_->fd_);
228     
229     udp_socket_t*s = sock->socks_;
230     sock->socks_ = sock->socks_->next_;
231     
232     free(s);
233   }
234   sock->socks_ = NULL;
235 }
236
237 char* udp_endpoint_to_string(udp_endpoint_t e)
238 {
239   void* ptr;
240   u_int16_t port;
241   size_t addrstr_len = 0;
242   char* addrstr, *ret;
243   char addrport_sep = ':';
244
245   switch (((struct sockaddr *)&e)->sa_family)
246   {
247   case AF_INET:
248     ptr = &((struct sockaddr_in *)&e)->sin_addr;
249     port = ntohs(((struct sockaddr_in *)&e)->sin_port);
250     addrstr_len = INET_ADDRSTRLEN + 1;
251     addrport_sep = ':';
252     break;
253   case AF_INET6:
254     ptr = &((struct sockaddr_in6 *)&e)->sin6_addr;
255     port = ntohs(((struct sockaddr_in6 *)&e)->sin6_port);
256     addrstr_len = INET6_ADDRSTRLEN + 1;
257     addrport_sep = '.';
258     break;
259   default:
260     asprintf(&ret, "unknown address type");
261     return ;
262   }
263   addrstr = malloc(addrstr_len);
264   if(!addrstr)
265     return NULL;
266   inet_ntop (((struct sockaddr *)&e)->sa_family, ptr, addrstr, addrstr_len);
267   asprintf(&ret, "%s%c%d", addrstr, addrport_sep ,port);
268   free(addrstr);
269   return ret;
270 }
271
272 char* udp_get_remote_end_string(udp_t* sock)
273 {
274   if(!sock || !sock->remote_end_set_)
275     return NULL;
276
277   return udp_endpoint_to_string(sock->remote_end_);
278 }
279  
280 int udp_read(udp_t* sock, int fd, u_int8_t* buf, u_int32_t len, udp_endpoint_t* remote_end)
281 {
282   if(!sock || !remote_end)
283     return -1;
284
285   socklen_t socklen = sizeof(*remote_end);
286   return recvfrom(fd, buf, len, 0, (struct sockaddr *)remote_end, &socklen);
287 }
288
289 int udp_write(udp_t* sock, u_int8_t* buf, u_int32_t len)
290 {
291   if(!sock || !sock->remote_end_set_ || !sock->active_sock_)
292     return 0;
293
294   socklen_t socklen = sizeof(sock->remote_end_);
295   if((((struct sockaddr *)&sock->active_sock_->local_end_)->sa_family) == AF_INET)
296     socklen = sizeof(struct sockaddr_in);
297   else if ((((struct sockaddr *)&sock->active_sock_->local_end_)->sa_family) == AF_INET6)
298     socklen = sizeof(struct sockaddr_in6);
299
300   return sendto(sock->active_sock_->fd_, buf, len, 0, (struct sockaddr *)&(sock->remote_end_), socklen);
301 }
302