- Speed up checksumming
[tinc] / src / netutl.c
1 /*
2     netutl.c -- some supporting network utility code
3     Copyright (C) 1998-2002 Ivo Timmermans <ivo@o2w.nl>
4                   2000-2002 Guus Sliepen <guus@sliepen.eu.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: netutl.c,v 1.12.4.44 2002/09/09 22:32:44 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <fcntl.h>
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_INTTYPES_H
31 #include <inttypes.h>
32 #endif
33 #include <string.h>
34 #include <signal.h>
35 #include <sys/socket.h>
36 #include <syslog.h>
37 #include <arpa/inet.h>
38
39 #include <utils.h>
40 #include <xalloc.h>
41
42 #include "errno.h"
43 #include "conf.h"
44 #include "net.h"
45 #include "netutl.h"
46
47 #include "system.h"
48
49 int hostnames = 0;
50
51 /*
52   Turn a string into a struct addrinfo.
53   Return NULL on failure.
54 */
55 struct addrinfo *str2addrinfo(char *address, char *service, int socktype)
56 {
57         struct addrinfo hint, *ai;
58         int err;
59
60         cp();
61
62         memset(&hint, 0, sizeof(hint));
63
64         hint.ai_family = addressfamily;
65         hint.ai_socktype = socktype;
66
67         err = getaddrinfo(address, service, &hint, &ai);
68
69         if(err) {
70                 if(debug_lvl >= DEBUG_ERROR)
71                         syslog(LOG_WARNING, _("Error looking up %s port %s: %s\n"), address,
72                                    service, gai_strerror(err));
73                 cp_trace();
74                 return NULL;
75         }
76
77         return ai;
78 }
79
80 sockaddr_t str2sockaddr(char *address, char *port)
81 {
82         struct addrinfo hint, *ai;
83         sockaddr_t result;
84         int err;
85
86         cp();
87
88         memset(&hint, 0, sizeof(hint));
89
90         hint.ai_family = AF_UNSPEC;
91         hint.ai_flags = AI_NUMERICHOST;
92         hint.ai_socktype = SOCK_STREAM;
93
94         err = getaddrinfo(address, port, &hint, &ai);
95
96         if(err || !ai) {
97                 syslog(LOG_ERR, _("Error looking up %s port %s: %s\n"), address, port,
98                            gai_strerror(err));
99                 cp_trace();
100                 raise(SIGFPE);
101                 exit(0);
102         }
103
104         result = *(sockaddr_t *) ai->ai_addr;
105         freeaddrinfo(ai);
106
107         return result;
108 }
109
110 void sockaddr2str(sockaddr_t *sa, char **addrstr, char **portstr)
111 {
112         char address[NI_MAXHOST];
113         char port[NI_MAXSERV];
114         char *scopeid;
115         int err;
116
117         cp();
118
119         err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
120
121         if(err) {
122                 syslog(LOG_ERR, _("Error while translating addresses: %s"),
123                            gai_strerror(err));
124                 cp_trace();
125                 raise(SIGFPE);
126                 exit(0);
127         }
128
129         scopeid = strchr(address, '%');
130
131         if(scopeid)
132                 *scopeid = '\0';                /* Descope. */
133
134         *addrstr = xstrdup(address);
135         *portstr = xstrdup(port);
136 }
137
138 char *sockaddr2hostname(sockaddr_t *sa)
139 {
140         char *str;
141         char address[NI_MAXHOST] = "unknown";
142         char port[NI_MAXSERV] = "unknown";
143         int err;
144
145         cp();
146
147         err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
148                                         hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
149         if(err) {
150                 syslog(LOG_ERR, _("Error while looking up hostname: %s"),
151                            gai_strerror(err));
152         }
153
154         asprintf(&str, _("%s port %s"), address, port);
155
156         return str;
157 }
158
159 int sockaddrcmp(sockaddr_t *a, sockaddr_t *b)
160 {
161         int result;
162
163         cp();
164
165         result = a->sa.sa_family - b->sa.sa_family;
166
167         if(result)
168                 return result;
169
170         switch (a->sa.sa_family) {
171                 case AF_UNSPEC:
172                         return 0;
173
174                 case AF_INET:
175                         result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
176
177                         if(result)
178                                 return result;
179
180                         return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
181
182                 case AF_INET6:
183                         result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
184
185                         if(result)
186                                 return result;
187
188                         return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
189
190                 default:
191                         syslog(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
192                                    a->sa.sa_family);
193                         cp_trace();
194                         raise(SIGFPE);
195                         exit(0);
196         }
197 }
198
199 void sockaddrunmap(sockaddr_t *sa)
200 {
201         if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
202                 sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
203                 sa->in.sin_family = AF_INET;
204         }
205 }
206
207 /* Subnet mask handling */
208
209 int maskcmp(void *va, void *vb, int masklen, int len)
210 {
211         int i, m, result;
212         char *a = va;
213         char *b = vb;
214
215         cp();
216
217         for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
218                 result = a[i] - b[i];
219                 if(result)
220                         return result;
221         }
222
223         if(m)
224                 return (a[i] & (0x100 - (1 << (8 - m)))) -
225                         (b[i] & (0x100 - (1 << (8 - m))));
226
227         return 0;
228 }
229
230 void mask(void *va, int masklen, int len)
231 {
232         int i;
233         char *a = va;
234
235         cp();
236
237         i = masklen / 8;
238         masklen %= 8;
239
240         if(masklen)
241                 a[i++] &= (0x100 - (1 << masklen));
242
243         for(; i < len; i++)
244                 a[i] = 0;
245 }
246
247 void maskcpy(void *va, void *vb, int masklen, int len)
248 {
249         int i, m;
250         char *a = va;
251         char *b = vb;
252
253         cp();
254
255         for(m = masklen, i = 0; m >= 8; m -= 8, i++)
256                 a[i] = b[i];
257
258         if(m) {
259                 a[i] = b[i] & (0x100 - (1 << m));
260                 i++;
261         }
262
263         for(; i < len; i++)
264                 a[i] = 0;
265 }
266
267 int maskcheck(void *va, int masklen, int len)
268 {
269         int i;
270         char *a = va;
271
272         cp();
273
274         i = masklen / 8;
275         masklen %= 8;
276
277         if(masklen && a[i++] & (0xff >> masklen))
278                 return -1;
279
280         for(; i < len; i++)
281                 if(a[i] != 0)
282                         return -2;
283
284         return 0;
285 }