1ec6e5a82199548254b3f3c3813082ef7b47e544
[oweals/tinc.git] / src / netutl.c
1 /*
2     netutl.c -- some supporting network utility code
3     Copyright (C) 1998-2003 Ivo Timmermans <ivo@o2w.nl>
4                   2000-2003 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.50 2003/07/29 22:59:00 guus Exp $
21 */
22
23 #include "system.h"
24
25 #include "net.h"
26 #include "netutl.h"
27 #include "logger.h"
28 #include "utils.h"
29 #include "xalloc.h"
30
31 bool hostnames = false;
32
33 /*
34   Turn a string into a struct addrinfo.
35   Return NULL on failure.
36 */
37 struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype)
38 {
39         struct addrinfo *ai;
40         struct addrinfo hint = {
41                 .ai_family = addressfamily,
42                 .ai_socktype = socktype,
43         };
44         int err;
45
46         cp();
47
48         err = getaddrinfo(address, service, &hint, &ai);
49
50         if(err) {
51                 logger(LOG_WARNING, _("Error looking up %s port %s: %s\n"), address,
52                                    service, gai_strerror(err));
53                 return NULL;
54         }
55
56         return ai;
57 }
58
59 sockaddr_t str2sockaddr(const char *address, const char *port)
60 {
61         struct addrinfo *ai;
62         struct addrinfo hint = {
63                 .ai_family = AF_UNSPEC,
64                 .ai_flags = AI_NUMERICHOST,
65                 .ai_socktype = SOCK_STREAM,
66         };
67         sockaddr_t result;
68         int err;
69
70         cp();
71
72         err = getaddrinfo(address, port, &hint, &ai);
73
74         if(err || !ai) {
75                 logger(LOG_ERR, _("Error looking up %s port %s: %s\n"), address, port,
76                            gai_strerror(err));
77                 cp_trace();
78                 raise(SIGFPE);
79                 exit(0);
80         }
81
82         result = *(sockaddr_t *) ai->ai_addr;
83         freeaddrinfo(ai);
84
85         return result;
86 }
87
88 void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
89 {
90         char address[NI_MAXHOST];
91         char port[NI_MAXSERV];
92         char *scopeid;
93         int err;
94
95         cp();
96
97         err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
98
99         if(err) {
100                 logger(LOG_ERR, _("Error while translating addresses: %s"),
101                            gai_strerror(err));
102                 cp_trace();
103                 raise(SIGFPE);
104                 exit(0);
105         }
106
107         scopeid = strchr(address, '%');
108
109         if(scopeid)
110                 *scopeid = '\0';                /* Descope. */
111
112         *addrstr = xstrdup(address);
113         *portstr = xstrdup(port);
114 }
115
116 char *sockaddr2hostname(const sockaddr_t *sa)
117 {
118         char *str;
119         char address[NI_MAXHOST] = "unknown";
120         char port[NI_MAXSERV] = "unknown";
121         int err;
122
123         cp();
124
125         err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
126                                         hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
127         if(err) {
128                 logger(LOG_ERR, _("Error while looking up hostname: %s"),
129                            gai_strerror(err));
130         }
131
132         asprintf(&str, _("%s port %s"), address, port);
133
134         return str;
135 }
136
137 int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
138 {
139         int result;
140
141         cp();
142
143         result = a->sa.sa_family - b->sa.sa_family;
144
145         if(result)
146                 return result;
147
148         switch (a->sa.sa_family) {
149                 case AF_UNSPEC:
150                         return 0;
151
152                 case AF_INET:
153                         result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
154
155                         if(result)
156                                 return result;
157
158                         return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
159
160                 case AF_INET6:
161                         result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
162
163                         if(result)
164                                 return result;
165
166                         return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
167
168                 default:
169                         logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
170                                    a->sa.sa_family);
171                         cp_trace();
172                         raise(SIGFPE);
173                         exit(0);
174         }
175 }
176
177 void sockaddrunmap(sockaddr_t *sa)
178 {
179         if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
180                 sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
181                 sa->in.sin_family = AF_INET;
182         }
183 }
184
185 /* Subnet mask handling */
186
187 int maskcmp(const void *va, const void *vb, int masklen, int len)
188 {
189         int i, m, result;
190         const char *a = va;
191         const char *b = vb;
192
193         cp();
194
195         for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
196                 result = a[i] - b[i];
197                 if(result)
198                         return result;
199         }
200
201         if(m)
202                 return (a[i] & (0x100 - (1 << (8 - m)))) -
203                         (b[i] & (0x100 - (1 << (8 - m))));
204
205         return 0;
206 }
207
208 void mask(void *va, int masklen, int len)
209 {
210         int i;
211         char *a = va;
212
213         cp();
214
215         i = masklen / 8;
216         masklen %= 8;
217
218         if(masklen)
219                 a[i++] &= (0x100 - (1 << masklen));
220
221         for(; i < len; i++)
222                 a[i] = 0;
223 }
224
225 void maskcpy(void *va, const void *vb, int masklen, int len)
226 {
227         int i, m;
228         char *a = va;
229         const char *b = vb;
230
231         cp();
232
233         for(m = masklen, i = 0; m >= 8; m -= 8, i++)
234                 a[i] = b[i];
235
236         if(m) {
237                 a[i] = b[i] & (0x100 - (1 << m));
238                 i++;
239         }
240
241         for(; i < len; i++)
242                 a[i] = 0;
243 }
244
245 bool maskcheck(const void *va, int masklen, int len)
246 {
247         int i;
248         const char *a = va;
249
250         cp();
251
252         i = masklen / 8;
253         masklen %= 8;
254
255         if(masklen && a[i++] & (0xff >> masklen))
256                 return false;
257
258         for(; i < len; i++)
259                 if(a[i] != 0)
260                         return false;
261
262         return true;
263 }