Imported Upstream version 0.3.2
[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-2008 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_socket_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->fd_ = 0;
58   memset(&(sock->local_end_), 0, sizeof(sock->local_end_));
59   memset(&(sock->remote_end_), 0, sizeof(sock->local_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;
68
69   switch(resolv_type) {
70   case IPV4_ONLY: hints.ai_family = PF_INET; break;
71   case IPV6_ONLY: hints.ai_family = PF_INET6; break;
72   default: hints.ai_family = PF_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
82   if(!res) {
83     udp_close(sock);
84     log_printf(ERROR, "getaddrinfo returned no address for %s:%s", local_addr, port);
85     return -1;
86   }
87
88   memcpy(&(sock->local_end_), res->ai_addr, res->ai_addrlen);
89
90   sock->fd_ = socket(res->ai_family, SOCK_DGRAM, 0);
91   if(sock->fd_ < 0) {
92     log_printf(ERROR, "Error on opening udp socket: %s", strerror(errno));
93     freeaddrinfo(res);
94     udp_close(sock);
95     return -1;
96   }
97
98   errcode = bind(sock->fd_, res->ai_addr, res->ai_addrlen);
99   if(errcode) {
100     log_printf(ERROR, "Error on binding udp socket: %s", strerror(errno));
101     freeaddrinfo(res);
102     udp_close(sock);
103     return -1;
104   }
105   
106 /* this doesn't work on linux ?? */
107 /* #ifdef NO_V4MAPPED */
108 /*   if(res->ai_family == AF_INET6) { */
109 /*     log_printf(NOTICE, "disabling V4-Mapped addresses"); */
110 /*     int on = 1; */
111 /*     if(setsockopt(sock->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) */
112 /*       log_printf(ERROR, "Error on setting IPV6_V6ONLY socket option: %s", strerror(errno)); */
113 /*   } */
114 /* #endif */
115   freeaddrinfo(res);
116
117   return 0;
118 }
119
120 int udp_set_remote(udp_socket_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type)
121 {
122   if(!sock || !remote_addr || !port) 
123     return -1;
124
125   struct addrinfo hints, *res;
126
127   res = NULL;
128   memset (&hints, 0, sizeof (hints));
129   hints.ai_socktype = SOCK_DGRAM;
130
131   switch(resolv_type) {
132   case IPV4_ONLY: hints.ai_family = PF_INET; break;
133   case IPV6_ONLY: hints.ai_family = PF_INET6; break;
134   default: hints.ai_family = PF_UNSPEC; break;
135   }
136
137   int errcode = getaddrinfo(remote_addr, port, &hints, &res);
138   if (errcode != 0) {
139     log_printf(ERROR, "Error resolving remote address (%s:%s): %s", (remote_addr) ? remote_addr : "*", port, gai_strerror(errcode));
140     return -1;
141   }
142   if(!res) {
143     log_printf(ERROR, "getaddrinfo returned no address for %s:%s", remote_addr, port);
144     return -1;
145   }
146   memcpy(&(sock->remote_end_), res->ai_addr, res->ai_addrlen);
147   sock->remote_end_set_ = 1;
148   freeaddrinfo(res);
149
150   return 0;
151 }
152
153 void udp_close(udp_socket_t* sock)
154 {
155   if(!sock)
156     return;
157
158   if(sock->fd_ > 0)
159     close(sock->fd_);
160 }
161
162 char* udp_endpoint_to_string(udp_endpoint_t e)
163 {
164   void* ptr;
165   u_int16_t port;
166   size_t addrstr_len = 0;
167   char* addrstr, *ret;
168   char addrport_sep = ':';
169
170   switch (((struct sockaddr *)&e)->sa_family)
171   {
172   case AF_INET:
173     ptr = &((struct sockaddr_in *)&e)->sin_addr;
174     port = ntohs(((struct sockaddr_in *)&e)->sin_port);
175     addrstr_len = INET_ADDRSTRLEN + 1;
176     addrport_sep = ':';
177     break;
178   case AF_INET6:
179     ptr = &((struct sockaddr_in6 *)&e)->sin6_addr;
180     port = ntohs(((struct sockaddr_in6 *)&e)->sin6_port);
181     addrstr_len = INET6_ADDRSTRLEN + 1;
182     addrport_sep = '.';
183     break;
184   default:
185     asprintf(&ret, "unknown address type");
186     return ;
187   }
188   addrstr = malloc(addrstr_len);
189   if(!addrstr)
190     return NULL;
191   inet_ntop (((struct sockaddr *)&e)->sa_family, ptr, addrstr, addrstr_len);
192   asprintf(&ret, "%s%c%d", addrstr, addrport_sep ,port);
193   free(addrstr);
194   return ret;
195 }
196
197 char* udp_get_local_end_string(udp_socket_t* sock)
198 {
199   if(!sock)
200     return NULL;
201
202   return udp_endpoint_to_string(sock->local_end_);
203 }
204
205 char* udp_get_remote_end_string(udp_socket_t* sock)
206 {
207   if(!sock || !sock->remote_end_set_)
208     return NULL;
209
210   return udp_endpoint_to_string(sock->remote_end_);
211 }
212  
213 int udp_read(udp_socket_t* sock, u_int8_t* buf, u_int32_t len, udp_endpoint_t* remote_end)
214 {
215   if(!sock || !remote_end)
216     return -1;
217
218   socklen_t socklen = sizeof(*remote_end);
219   return recvfrom(sock->fd_, buf, len, 0, (struct sockaddr *)remote_end, &socklen);
220 }
221
222 int udp_write(udp_socket_t* sock, u_int8_t* buf, u_int32_t len)
223 {
224   if(!sock || !sock->remote_end_set_)
225     return -1;
226
227   socklen_t socklen = sizeof(sock->remote_end_);
228 #ifdef NO_V4MAPPED
229   if((((struct sockaddr *)&sock->local_end_)->sa_family) == AF_INET)
230     socklen = sizeof(struct sockaddr_in);
231   else if ((((struct sockaddr *)&sock->local_end_)->sa_family) == AF_INET6)
232     socklen = sizeof(struct sockaddr_in6);
233 #endif
234   return sendto(sock->fd_, buf, len, 0, (struct sockaddr *)&(sock->remote_end_), socklen);;
235 }
236