/[dynamips]/trunk/net.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Sat Oct 6 16:29:14 2007 UTC (12 years ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/net.c
File MIME type: text/plain
File size: 10508 byte(s)
dynamips-0.2.7

1 /*
2 * Copyright (c) 2005,2006 Christophe Fillot.
3 * E-mail: cf@utc.fr
4 *
5 * Network Utility functions.
6 */
7
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <unistd.h>
14 #include <time.h>
15 #include <sys/time.h>
16 #include <sys/ioctl.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <assert.h>
24
25 #include "utils.h"
26 #include "net.h"
27
28 /*
29 * IP mask table, which allows to find quickly a network mask
30 * with a prefix length.
31 */
32 n_ip_addr_t ip_masks[N_IP_ADDR_BITS+1] = {
33 0x0,
34 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
35 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
36 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
37 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
38 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
39 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
40 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
41 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF
42 };
43
44 /*
45 * IPv6 mask table, which allows to find quickly a network mask
46 * with a prefix length. Note this is a particularly ugly way
47 * to do this, since we use statically 2 Kb.
48 */
49 n_ipv6_addr_t ipv6_masks[N_IPV6_ADDR_BITS+1];
50
51 /* Initialize IPv6 masks */
52 void ipv6_init_masks(void)
53 {
54 int i,index;
55
56 /* Set all bits to 1 */
57 memset(ipv6_masks,0xff,sizeof(ipv6_masks));
58
59 for(i=0;i<N_IPV6_ADDR_BITS;i++)
60 {
61 index = i >> 3; /* Compute byte index (divide by 8) */
62
63 /* rotate byte */
64 ipv6_masks[i].ip6.u6_addr8[index++] <<= (8 - (i & 7));
65
66 /* clear following bytes */
67 while(index<N_IPV6_ADDR_LEN)
68 ipv6_masks[i].ip6.u6_addr8[index++] = 0;
69 }
70 }
71
72 /* Convert an IPv4 address into a string */
73 char *n_ip_ntoa(char *buffer,n_ip_addr_t ip_addr)
74 {
75 u_char *p = (u_char *)&ip_addr;
76 sprintf(buffer,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]);
77 return(buffer);
78 }
79
80 #if HAS_RFC2553
81 /* Convert in IPv6 address into a string */
82 char *n_ipv6_ntoa(char *buffer,n_ipv6_addr_t *ipv6_addr)
83 {
84 return((char *)inet_ntop(AF_INET6,ipv6_addr,buffer,INET6_ADDRSTRLEN));
85 }
86 #endif
87
88 /* Convert a string containing an IP address in binary */
89 int n_ip_aton(n_ip_addr_t *ip_addr,char *ip_str)
90 {
91 struct in_addr addr;
92
93 if (inet_aton(ip_str,&addr) == 0)
94 return(-1);
95
96 *ip_addr = ntohl(addr.s_addr);
97 return(0);
98 }
99
100 #if HAS_RFC2553
101 /* Convert an IPv6 address from string into binary */
102 int n_ipv6_aton(n_ipv6_addr_t *ipv6_addr,char *ip_str)
103 {
104 return(inet_pton(AF_INET6,ip_str,ipv6_addr));
105 }
106 #endif
107
108 /* Parse an IPv4 CIDR prefix */
109 int ip_parse_cidr(char *token,n_ip_addr_t *net_addr,n_ip_addr_t *net_mask)
110 {
111 char *sl,*tmp,*err;
112 u_long mask;
113
114 /* Find separator */
115 if ((sl = strchr(token,'/')) == NULL)
116 return(-1);
117
118 /* Get mask */
119 mask = strtoul(sl+1,&err,0);
120 if (*err != 0)
121 return(-1);
122
123 /* Ensure that mask has a correct value */
124 if (mask > N_IP_ADDR_BITS)
125 return(-1);
126
127 if ((tmp = strdup(token)) == NULL)
128 return(-1);
129
130 sl = strchr(tmp,'/');
131 *sl = 0;
132
133 /* Parse IP Address */
134 if (n_ip_aton(net_addr,tmp) == -1) {
135 free(tmp);
136 return(-1);
137 }
138
139 /* Set netmask */
140 *net_mask = ip_masks[mask];
141
142 free(tmp);
143 return(0);
144 }
145
146 #if HAS_RFC2553
147 /* Parse an IPv6 CIDR prefix */
148 int ipv6_parse_cidr(char *token,n_ipv6_addr_t *net_addr,u_int *net_mask)
149 {
150 char *sl,*tmp,*err;
151 u_long mask;
152
153 /* Find separator */
154 if ((sl = strchr(token,'/')) == NULL)
155 return(-1);
156
157 /* Get mask */
158 mask = strtoul(sl+1,&err,0);
159 if (*err != 0)
160 return(-1);
161
162 /* Ensure that mask has a correct value */
163 if (mask > N_IPV6_ADDR_BITS)
164 return(-1);
165
166 if ((tmp = strdup(token)) == NULL)
167 return(-1);
168
169 sl = strchr(tmp,'/');
170 *sl = 0;
171
172 /* Parse IP Address */
173 if (n_ipv6_aton(net_addr,tmp) <= 0) {
174 free(tmp);
175 return(-1);
176 }
177
178 /* Set netmask */
179 *net_mask = (u_int)mask;
180
181 free(tmp);
182 return(0);
183 }
184 #endif
185
186 /* Parse a MAC address */
187 int parse_mac_addr(n_eth_addr_t *addr,char *str)
188 {
189 u_int v[N_ETH_ALEN];
190 int i,res;
191
192 /* First try, standard format (00:01:02:03:04:05) */
193 res = sscanf(str,"%x:%x:%x:%x:%x:%x",&v[0],&v[1],&v[2],&v[3],&v[4],&v[5]);
194
195 if (res == 6) {
196 for(i=0;i<N_ETH_ALEN;i++)
197 addr->eth_addr_byte[i] = v[i];
198 return(0);
199 }
200
201 /* Second try, Cisco format (0001.0002.0003) */
202 res = sscanf(str,"%x.%x.%x",&v[0],&v[1],&v[2]);
203
204 if (res == 3) {
205 addr->eth_addr_byte[0] = (v[0] >> 8) & 0xFF;
206 addr->eth_addr_byte[1] = v[0] & 0xFF;
207 addr->eth_addr_byte[2] = (v[1] >> 8) & 0xFF;
208 addr->eth_addr_byte[3] = v[1] & 0xFF;
209 addr->eth_addr_byte[4] = (v[2] >> 8) & 0xFF;
210 addr->eth_addr_byte[5] = v[2] & 0xFF;
211 }
212
213 return(-1);
214 }
215
216 /* Convert an Ethernet address into a string */
217 char *n_eth_ntoa(char *buffer,n_eth_addr_t *addr,int format)
218 {
219 char *str_format;
220
221 if (format == 0) {
222 str_format = "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x";
223 } else {
224 str_format = "%2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x";
225 }
226
227 sprintf(buffer,str_format,
228 addr->eth_addr_byte[0],addr->eth_addr_byte[1],
229 addr->eth_addr_byte[2],addr->eth_addr_byte[3],
230 addr->eth_addr_byte[4],addr->eth_addr_byte[5]);
231 return(buffer);
232 }
233
234 #if HAS_RFC2553
235 /* Create a new socket to connect to specified host */
236 int udp_connect(int local_port,char *remote_host,int remote_port)
237 {
238 struct addrinfo hints,*res,*res0;
239 struct sockaddr_storage st;
240 int error, sck = -1;
241 char port_str[20];
242
243 memset(&hints,0,sizeof(hints));
244 hints.ai_family = PF_UNSPEC;
245 hints.ai_socktype = SOCK_DGRAM;
246
247 snprintf(port_str,sizeof(port_str),"%d",remote_port);
248
249 if ((error = getaddrinfo(remote_host,port_str,&hints,&res0)) != 0) {
250 fprintf(stderr,"%s\n",gai_strerror(error));
251 return(-1);
252 }
253
254 for(res=res0;res;res=res->ai_next)
255 {
256 /* We want only IPv4 or IPv6 */
257 if ((res->ai_family != PF_INET) && (res->ai_family != PF_INET6))
258 continue;
259
260 /* create new socket */
261 if ((sck = socket(res->ai_family,SOCK_DGRAM,res->ai_protocol)) < 0) {
262 perror("udp_connect: socket");
263 continue;
264 }
265
266 /* bind to the local port */
267 memset(&st,0,sizeof(st));
268
269 switch(res->ai_family) {
270 case PF_INET: {
271 struct sockaddr_in *sin = (struct sockaddr_in *)&st;
272 sin->sin_family = PF_INET;
273 sin->sin_port = htons(local_port);
274 break;
275 }
276
277 case PF_INET6: {
278 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&st;
279 #ifdef SIN6_LEN
280 sin6->sin6_len = res->ai_addrlen;
281 #endif
282 sin6->sin6_family = PF_INET6;
283 sin6->sin6_port = htons(local_port);
284 break;
285 }
286
287 default:
288 /* shouldn't happen */
289 close(sck);
290 sck = -1;
291 continue;
292 }
293
294 /* try to connect to remote host */
295 if (!bind(sck,(struct sockaddr *)&st,res->ai_addrlen) &&
296 !connect(sck,res->ai_addr,res->ai_addrlen))
297 break;
298
299 close(sck);
300 sck = -1;
301 }
302
303 freeaddrinfo(res0);
304 return(sck);
305 }
306 #else
307 /*
308 * Create a new socket to connect to specified host.
309 * Version for old systems that do not support RFC 2553 (getaddrinfo())
310 *
311 * See http://www.faqs.org/rfcs/rfc2553.html for more info.
312 */
313 int udp_connect(int local_port,char *remote_host,int remote_port)
314 {
315 struct sockaddr_in sin;
316 struct hostent *hp;
317 int sck;
318
319 if (!(hp = gethostbyname(remote_host))) {
320 fprintf(stderr,"udp_connect: unable to resolve '%s'\n",remote_host);
321 return(-1);
322 }
323
324 if ((sck = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
325 perror("udp_connect: socket");
326 return(-1);
327 }
328
329 /* bind local port */
330 memset(&sin,0,sizeof(sin));
331 sin.sin_family = PF_INET;
332 sin.sin_port = htons(local_port);
333
334 if (bind(sck,(struct sockaddr *)&sin,sizeof(sin)) < 0) {
335 perror("udp_connect: bind");
336 close(sck);
337 }
338
339 /* try to connect to remote host */
340 memset(&sin,0,sizeof(sin));
341 memcpy(&sin.sin_addr,hp->h_addr_list[0],sizeof(struct in_addr));
342 sin.sin_family = PF_INET;
343 sin.sin_port = htons(remote_port);
344
345 if (connect(sck,(struct sockaddr *)&sin,sizeof(sin)) < 0) {
346 perror("udp_connect: connect");
347 close(sck);
348 }
349
350 return(sck);
351 }
352 #endif /* HAS_RFC2553 */
353
354 #if HAS_RFC2553
355 /* Listen on the specified port */
356 int ip_listen(int port,int sock_type,int max_fd,int fd_array[])
357 {
358 struct addrinfo hints,*res,*res0;
359 char port_str[20];
360 int nsock,error,i;
361 int reuse = 1;
362
363 for(i=0;i<max_fd;i++)
364 fd_array[i] = -1;
365
366 memset(&hints,0,sizeof(hints));
367 hints.ai_family = PF_UNSPEC;
368 hints.ai_socktype = sock_type;
369 hints.ai_flags = AI_PASSIVE;
370
371 snprintf(port_str,sizeof(port_str),"%d",port);
372
373 if ((error = getaddrinfo(NULL,port_str,&hints,&res0)) != 0) {
374 fprintf(stderr,"ip_listen: %s", gai_strerror(error));
375 return(-1);
376 }
377
378 nsock = 0;
379 for(res=res0;(res && (nsock < max_fd));res=res->ai_next)
380 {
381 if ((res->ai_family != PF_INET) && (res->ai_family != PF_INET6))
382 continue;
383
384 fd_array[nsock] = socket(res->ai_family,res->ai_socktype,
385 res->ai_protocol);
386
387 if (fd_array[nsock] < 0)
388 continue;
389
390 setsockopt(fd_array[nsock],SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
391
392 if ((bind(fd_array[nsock],res->ai_addr,res->ai_addrlen) < 0) ||
393 (listen(fd_array[nsock],5) < 0))
394 {
395 close(fd_array[nsock]);
396 fd_array[nsock] = -1;
397 continue;
398 }
399
400 nsock++;
401 }
402
403 freeaddrinfo(res0);
404 return(nsock);
405 }
406 #else
407 /* Listen on the specified port */
408 int ip_listen(int port,int sock_type,int max_fd,int fd_array[])
409 {
410 struct sockaddr_in sin;
411 int i,sck,reuse=1;
412
413 for(i=0;i<max_fd;i++)
414 fd_array[i] = -1;
415
416 if ((sck = socket(AF_INET,sock_type,0)) < 0) {
417 perror("ip_listen: socket");
418 return(-1);
419 }
420
421 /* bind local port */
422 memset(&sin,0,sizeof(sin));
423 sin.sin_family = PF_INET;
424 sin.sin_port = htons(port);
425
426 setsockopt(fd_array[0],SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
427
428 if (bind(sck,(struct sockaddr *)&sin,sizeof(sin)) < 0) {
429 perror("ip_listen: bind");
430 goto error;
431 }
432
433 if (listen(sck,5) < 0) {
434 perror("ip_listen: listen");
435 goto error;
436 }
437
438 fd_array[0] = sck;
439 return(1);
440
441 error:
442 close(sck);
443 return(-1);
444 }
445 #endif

  ViewVC Help
Powered by ViewVC 1.1.26