/[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 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 11766 byte(s)
make working copy

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

  ViewVC Help
Powered by ViewVC 1.1.26