7d32e21cad1287908acb24f4fbc131bee22bd5ca
[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.45 2003/07/06 22:11:32 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 <arpa/inet.h>
37
38 #include <utils.h>
39 #include <xalloc.h>
40
41 #include "errno.h"
42 #include "conf.h"
43 #include "net.h"
44 #include "netutl.h"
45 #include "logger.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                 logger(DEBUG_ALWAYS, LOG_WARNING, _("Error looking up %s port %s: %s\n"), address,
71                                    service, gai_strerror(err));
72                 return NULL;
73         }
74
75         return ai;
76 }
77
78 sockaddr_t str2sockaddr(char *address, char *port)
79 {
80         struct addrinfo hint, *ai;
81         sockaddr_t result;
82         int err;
83
84         cp();
85
86         memset(&hint, 0, sizeof(hint));
87
88         hint.ai_family = AF_UNSPEC;
89         hint.ai_flags = AI_NUMERICHOST;
90         hint.ai_socktype = SOCK_STREAM;
91
92         err = getaddrinfo(address, port, &hint, &ai);
93
94         if(err || !ai) {
95                 logger(DEBUG_ALWAYS, LOG_ERR, _("Error looking up %s port %s: %s\n"), address, port,
96                            gai_strerror(err));
97                 cp_trace();
98                 raise(SIGFPE);
99                 exit(0);
100         }
101
102         result = *(sockaddr_t *) ai->ai_addr;
103         freeaddrinfo(ai);
104
105         return result;
106 }
107
108 void sockaddr2str(sockaddr_t *sa, char **addrstr, char **portstr)
109 {
110         char address[NI_MAXHOST];
111         char port[NI_MAXSERV];
112         char *scopeid;
113         int err;
114
115         cp();
116
117         err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
118
119         if(err) {
120                 logger(DEBUG_ALWAYS, LOG_ERR, _("Error while translating addresses: %s"),
121                            gai_strerror(err));
122                 cp_trace();
123                 raise(SIGFPE);
124                 exit(0);
125         }
126
127         scopeid = strchr(address, '%');
128
129         if(scopeid)
130                 *scopeid = '\0';                /* Descope. */
131
132         *addrstr = xstrdup(address);
133         *portstr = xstrdup(port);
134 }
135
136 char *sockaddr2hostname(sockaddr_t *sa)
137 {
138         char *str;
139         char address[NI_MAXHOST] = "unknown";
140         char port[NI_MAXSERV] = "unknown";
141         int err;
142
143         cp();
144
145         err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
146                                         hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
147         if(err) {
148                 logger(DEBUG_ALWAYS, LOG_ERR, _("Error while looking up hostname: %s"),
149                            gai_strerror(err));
150         }
151
152         asprintf(&str, _("%s port %s"), address, port);
153
154         return str;
155 }
156
157 int sockaddrcmp(sockaddr_t *a, sockaddr_t *b)
158 {
159         int result;
160
161         cp();
162
163         result = a->sa.sa_family - b->sa.sa_family;
164
165         if(result)
166                 return result;
167
168         switch (a->sa.sa_family) {
169                 case AF_UNSPEC:
170                         return 0;
171
172                 case AF_INET:
173                         result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
174
175                         if(result)
176                                 return result;
177
178                         return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
179
180                 case AF_INET6:
181                         result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
182
183                         if(result)
184                                 return result;
185
186                         return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
187
188                 default:
189                         logger(DEBUG_ALWAYS, LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
190                                    a->sa.sa_family);
191                         cp_trace();
192                         raise(SIGFPE);
193                         exit(0);
194         }
195 }
196
197 void sockaddrunmap(sockaddr_t *sa)
198 {
199         if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
200                 sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
201                 sa->in.sin_family = AF_INET;
202         }
203 }
204
205 /* Subnet mask handling */
206
207 int maskcmp(void *va, void *vb, int masklen, int len)
208 {
209         int i, m, result;
210         char *a = va;
211         char *b = vb;
212
213         cp();
214
215         for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
216                 result = a[i] - b[i];
217                 if(result)
218                         return result;
219         }
220
221         if(m)
222                 return (a[i] & (0x100 - (1 << (8 - m)))) -
223                         (b[i] & (0x100 - (1 << (8 - m))));
224
225         return 0;
226 }
227
228 void mask(void *va, int masklen, int len)
229 {
230         int i;
231         char *a = va;
232
233         cp();
234
235         i = masklen / 8;
236         masklen %= 8;
237
238         if(masklen)
239                 a[i++] &= (0x100 - (1 << masklen));
240
241         for(; i < len; i++)
242                 a[i] = 0;
243 }
244
245 void maskcpy(void *va, void *vb, int masklen, int len)
246 {
247         int i, m;
248         char *a = va;
249         char *b = vb;
250
251         cp();
252
253         for(m = masklen, i = 0; m >= 8; m -= 8, i++)
254                 a[i] = b[i];
255
256         if(m) {
257                 a[i] = b[i] & (0x100 - (1 << m));
258                 i++;
259         }
260
261         for(; i < len; i++)
262                 a[i] = 0;
263 }
264
265 int maskcheck(void *va, int masklen, int len)
266 {
267         int i;
268         char *a = va;
269
270         cp();
271
272         i = masklen / 8;
273         masklen %= 8;
274
275         if(masklen && a[i++] & (0xff >> masklen))
276                 return -1;
277
278         for(; i < len; i++)
279                 if(a[i] != 0)
280                         return -2;
281
282         return 0;
283 }