ea4839f077b984fc4ddc474dfb41bef32933aee2
[tinc] / src / netutl.c
1 /*
2     netutl.c -- some supporting network utility code
3     Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>
4                   2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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.25 2002/02/20 17:15:33 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 #include <string.h>
31 #include <signal.h>
32 #include <sys/socket.h>
33 #include <syslog.h>
34 #include <arpa/inet.h>
35
36 #include <utils.h>
37 #include <xalloc.h>
38
39 #include "errno.h"
40 #include "conf.h"
41 #include "net.h"
42 #include "netutl.h"
43
44 #include "system.h"
45
46 int hostnames = 0;
47
48 /*
49   Turn a string into a struct addrinfo.
50   Return NULL on failure.
51 */
52 struct addrinfo *str2addrinfo(char *address, char *service, int socktype)
53 {
54   struct addrinfo hint, *ai;
55   int err;
56 cp
57   memset(&hint, 0, sizeof(hint));
58
59   hint.ai_family = addressfamily;
60   hint.ai_socktype = socktype;
61
62   if((err = getaddrinfo(address, service, &hint, &ai)))
63     {
64       if(debug_lvl >= DEBUG_ERROR)
65         syslog(LOG_WARNING, _("Error looking up %s port %s: %s\n"), address, service, gai_strerror(err));
66       cp_trace();
67       return NULL;
68     }
69
70 cp
71   return ai;
72 }
73
74 sockaddr_t str2sockaddr(char *address, char *port)
75 {
76   struct addrinfo hint, *ai;
77   sockaddr_t result;
78   int err;
79 cp
80   memset(&hint, 0, sizeof(hint));
81
82   hint.ai_family = AF_UNSPEC;
83   hint.ai_flags = AI_NUMERICHOST;
84   hint.ai_socktype = SOCK_STREAM;
85
86   if((err = getaddrinfo(address, port, &hint, &ai) || !ai))
87     {
88       syslog(LOG_ERR, _("Error looking up %s port %s: %s\n"), address, port, gai_strerror(err));
89       cp_trace();
90       raise(SIGFPE);
91       exit(0);
92     }
93
94   result = *(sockaddr_t *)ai->ai_addr;
95   freeaddrinfo(ai);
96 cp
97   return result;
98 }
99
100 void sockaddr2str(sockaddr_t *sa, char **addrstr, char **portstr)
101 {
102   char address[NI_MAXHOST];
103   char port[NI_MAXSERV];
104   int err;
105 cp
106   if((err = getnameinfo((struct sockaddr *)sa, sizeof(sockaddr_t), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV)))
107     {
108       syslog(LOG_ERR, _("Error while translating addresses: %s"), gai_strerror(err));
109       cp_trace();
110       raise(SIGFPE);
111       exit(0);
112     }
113
114   *addrstr = xstrdup(address);
115   *portstr = xstrdup(port);
116 cp
117 }
118
119 char *sockaddr2hostname(sockaddr_t *sa)
120 {
121   char *str;
122   char address[NI_MAXHOST] = "unknown";
123   char port[NI_MAXSERV] = "unknown";
124   int err;
125 cp
126   if((err = getnameinfo((struct sockaddr *)sa, sizeof(sockaddr_t), address, sizeof(address), port, sizeof(port), hostnames?0:(NI_NUMERICHOST|NI_NUMERICSERV))))
127     {
128       syslog(LOG_ERR, _("Error while looking up hostname: %s"), gai_strerror(err));
129     }
130
131   asprintf(&str, _("%s port %s"), address, port);
132 cp
133   return str;
134 }
135
136 int sockaddrcmp(sockaddr_t *a, sockaddr_t *b)
137 {
138   int result;
139 cp
140   result = a->sa.sa_family - b->sa.sa_family;
141   
142   if(result)
143     return result;
144   
145   switch(a->sa.sa_family)
146     {
147       case AF_UNSPEC:
148         return 0;
149       case AF_INET:
150         return memcmp(&a->in, &b->in, sizeof(a->in));
151       case AF_INET6:
152         return memcmp(&a->in6, &b->in6, sizeof(a->in6));
153       default:
154         syslog(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"), a->sa.sa_family);
155         cp_trace();
156         raise(SIGFPE);
157         exit(0);
158     }
159 cp
160 }
161
162 /* Subnet mask handling */
163
164 int maskcmp(char *a, char *b, int masklen, int len)
165 {
166   int i, m, result;
167 cp
168   for(m = masklen, i = 0; m >= 8; m -= 8, i++)
169     if((result = a[i] - b[i]))
170       return result;
171
172   if(m)
173     return (a[i] & (0x100 - (m << 1))) - (b[i] & (0x100 - (m << 1)));
174
175   return 0;
176 }
177
178 void mask(char *a, int masklen, int len)
179 {
180   int i;
181 cp
182   i = masklen / 8;
183   masklen %= 8;
184   
185   if(masklen)
186     a[i++] &= (0x100 - (masklen << 1));
187   
188   for(; i < len; i++)
189     a[i] = 0;
190 }
191
192 void maskcpy(char *a, char *b, int masklen, int len)
193 {
194   int i, m;
195 cp
196   for(m = masklen, i = 0; m >= 8; m -= 8, i++)
197     a[i] = b[i];
198
199   if(m)
200     {
201       a[i] = b[i] & (0x100 - (m << 1));
202       i++;
203     }
204
205   for(; i < len; i++)
206     a[i] = 0;
207 }
208
209 int maskcheck(char *a, int masklen, int len)
210 {
211   int i;
212 cp
213   i = masklen / 8;
214   masklen %= 8;
215   
216   if(masklen)
217     if(a[i++] & ~(0x100 - (masklen << 1)))
218       return -1;
219   
220   for(; i < len; i++)
221     if(a[i] != 0)
222       return -1;
223
224   return 0;
225 }