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

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 #include "crc.h"
28
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 int ip_listen(char *ip_addr,int port,int sock_type,int max_fd,int fd_array[])
358 {
359 struct addrinfo hints,*res,*res0;
360 char port_str[20],*addr;
361 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 addr = (ip_addr && strlen(ip_addr)) ? ip_addr : NULL;
374
375 if ((error = getaddrinfo(addr,port_str,&hints,&res0)) != 0) {
376 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 ((sock_type == SOCK_STREAM) && (listen(fd_array[nsock],5) < 0)))
396 {
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 int ip_listen(char *ip_addr,int port,int sock_type,int max_fd,int fd_array[])
411 {
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 if (ip_addr && strlen(ip_addr))
429 sin.sin_addr.s_addr = inet_addr(ip_addr);
430
431 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 if ((sock_type == SOCK_STREAM) && (listen(sck,5) < 0)) {
439 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
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