Initial Debian packaging; add src/include.mk
[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 version 3 as
24  *  published by the Free Software Foundation.
25  *
26  *  uAnytun is distributed in the hope that it will be useful,
27  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  *  GNU General Public License for more details.
30  *
31  *  You should have received a copy of the GNU General Public License
32  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
33  */
34
35 #include "datatypes.h"
36
37 #include "udp.h"
38
39 #include "log.h"
40
41 #include <errno.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <netdb.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <arpa/inet.h>
49 #include <netinet/in.h>
50
51 int udp_init(udp_socket_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type)
52 {
53   if(!sock || !port) 
54     return -1;
55  
56   sock->fd_ = 0;
57   memset(&(sock->local_end_), 0, sizeof(sock->local_end_));
58   memset(&(sock->remote_end_), 0, sizeof(sock->local_end_));
59   sock->remote_end_set_ = 0;
60
61   struct addrinfo hints, *res;
62
63   res = NULL;
64   memset (&hints, 0, sizeof (hints));
65   hints.ai_socktype = SOCK_DGRAM;
66   hints.ai_flags |= AI_PASSIVE;
67
68   switch(resolv_type) {
69   case IPV4_ONLY: hints.ai_family = PF_INET; break;
70   case IPV6_ONLY: hints.ai_family = PF_INET6; break;
71   default: hints.ai_family = PF_UNSPEC; break;
72   }
73
74   int errcode = getaddrinfo(local_addr, port, &hints, &res);
75   if (errcode != 0) {
76     log_printf(ERROR, "Error resolving local address (%s:%s): %s", (local_addr) ? local_addr : "*", port, gai_strerror(errcode));
77     udp_close(sock);
78     return -1;
79   }
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   memcpy(&(sock->local_end_), res->ai_addr, res->ai_addrlen);
88
89   sock->fd_ = socket(res->ai_family, SOCK_DGRAM, 0);
90   if(sock->fd_ < 0) {
91     log_printf(ERROR, "Error on opening udp socket: %s", strerror(errno));
92     freeaddrinfo(res);
93     udp_close(sock);
94     return -1;
95   }
96
97   errcode = bind(sock->fd_, res->ai_addr, res->ai_addrlen);
98   if(errcode) {
99     log_printf(ERROR, "Error on binding udp socket: %s", strerror(errno));
100     freeaddrinfo(res);
101     udp_close(sock);
102     return -1;
103   }
104   
105 /* this doesn't work on linux ?? */
106 /* #ifdef NO_V4MAPPED */
107 /*   if(res->ai_family == AF_INET6) { */
108 /*     log_printf(NOTICE, "disabling V4-Mapped addresses"); */
109 /*     int on = 1; */
110 /*     if(setsockopt(sock->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) */
111 /*       log_printf(ERROR, "Error on setting IPV6_V6ONLY socket option: %s", strerror(errno)); */
112 /*   } */
113 /* #endif */
114   freeaddrinfo(res);
115
116   return 0;
117 }
118
119 int udp_set_remote(udp_socket_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type)
120 {
121   if(!sock || !remote_addr || !port) 
122     return -1;
123
124   struct addrinfo hints, *res;
125
126   res = NULL;
127   memset (&hints, 0, sizeof (hints));
128   hints.ai_socktype = SOCK_DGRAM;
129
130   switch(resolv_type) {
131   case IPV4_ONLY: hints.ai_family = PF_INET; break;
132   case IPV6_ONLY: hints.ai_family = PF_INET6; break;
133   default: hints.ai_family = PF_UNSPEC; break;
134   }
135
136   int errcode = getaddrinfo(remote_addr, port, &hints, &res);
137   if (errcode != 0) {
138     log_printf(ERROR, "Error resolving remote address (%s:%s): %s", (remote_addr) ? remote_addr : "*", port, gai_strerror(errcode));
139     return -1;
140   }
141   if(!res) {
142     log_printf(ERROR, "getaddrinfo returned no address for %s:%s", remote_addr, port);
143     return -1;
144   }
145   memcpy(&(sock->remote_end_), res->ai_addr, res->ai_addrlen);
146   sock->remote_end_set_ = 1;
147   freeaddrinfo(res);
148
149   return 0;
150 }
151
152 void udp_close(udp_socket_t* sock)
153 {
154   if(!sock)
155     return;
156
157   if(sock->fd_ > 0)
158     close(sock->fd_);
159 }
160
161 char* udp_endpoint_to_string(udp_endpoint_t e)
162 {
163   void* ptr;
164   u_int16_t port;
165   size_t addrstr_len = 0;
166   char* addrstr, *ret;
167   char addrport_sep = ':';
168
169   switch (((struct sockaddr *)&e)->sa_family)
170   {
171   case AF_INET:
172     ptr = &((struct sockaddr_in *)&e)->sin_addr;
173     port = ntohs(((struct sockaddr_in *)&e)->sin_port);
174     addrstr_len = INET_ADDRSTRLEN + 1;
175     addrport_sep = ':';
176     break;
177   case AF_INET6:
178     ptr = &((struct sockaddr_in6 *)&e)->sin6_addr;
179     port = ntohs(((struct sockaddr_in6 *)&e)->sin6_port);
180     addrstr_len = INET6_ADDRSTRLEN + 1;
181     addrport_sep = '.';
182     break;
183   default:
184     asprintf(&ret, "unknown address type");
185     return ;
186   }
187   addrstr = malloc(addrstr_len);
188   if(!addrstr)
189     return NULL;
190   inet_ntop (((struct sockaddr *)&e)->sa_family, ptr, addrstr, addrstr_len);
191   asprintf(&ret, "%s%c%d", addrstr, addrport_sep ,port);
192   free(addrstr);
193   return ret;
194 }
195
196 char* udp_get_local_end_string(udp_socket_t* sock)
197 {
198   if(!sock)
199     return NULL;
200
201   return udp_endpoint_to_string(sock->local_end_);
202 }
203
204 char* udp_get_remote_end_string(udp_socket_t* sock)
205 {
206   if(!sock || !sock->remote_end_set_)
207     return NULL;
208
209   return udp_endpoint_to_string(sock->remote_end_);
210 }
211  
212 int udp_read(udp_socket_t* sock, u_int8_t* buf, u_int32_t len, udp_endpoint_t* remote_end)
213 {
214   if(!sock || !remote_end)
215     return -1;
216
217   socklen_t socklen = sizeof(*remote_end);
218   return recvfrom(sock->fd_, buf, len, 0, (struct sockaddr *)remote_end, &socklen);
219 }
220
221 int udp_write(udp_socket_t* sock, u_int8_t* buf, u_int32_t len)
222 {
223   if(!sock || !sock->remote_end_set_)
224     return -1;
225
226   socklen_t socklen = sizeof(sock->remote_end_);
227 #ifdef NO_V4MAPPED
228   if((((struct sockaddr *)&sock->local_end_)->sa_family) == AF_INET)
229     socklen = sizeof(struct sockaddr_in);
230   else if ((((struct sockaddr *)&sock->local_end_)->sa_family) == AF_INET6)
231     socklen = sizeof(struct sockaddr_in6);
232 #endif
233   return sendto(sock->fd_, buf, len, 0, (struct sockaddr *)&(sock->remote_end_), socklen);;
234 }
235