/[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

Annotation of /trunk/net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Sat Oct 6 16:05:34 2007 UTC (12 years ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC2/net.c
File MIME type: text/plain
File size: 10508 byte(s)
dynamips-0.2.6-RC2

1 dpavlin 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