]>
git.ipfire.org Git - people/ms/strongswan.git/blob - programs/starter/interfaces.c
1 /* strongSwan IPsec interfaces management
2 * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * RCSID $Id: interfaces.c,v 1.15 2006/02/05 10:51:55 as Exp $
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
26 #include <freeswan/ipsec_tunnel.h>
28 #include "../pluto/constants.h"
29 #include "../pluto/defs.h"
30 #include "../pluto/log.h"
32 #include "interfaces.h"
36 #define MIN(a,b) ( ((a)>(b)) ? (b) : (a) )
46 static struct st_ipsec_if _ipsec_if
[N_IPSEC_IF
];
49 _find_physical_iface(int sock
, char *iface
)
51 static char _if
[IFNAMSIZ
];
57 strncpy(req
.ifr_name
, iface
, IFNAMSIZ
);
58 if (ioctl(sock
, SIOCGIFFLAGS
, &req
)==0)
60 if (req
.ifr_flags
& IFF_UP
)
62 strncpy(_if
, iface
, IFNAMSIZ
);
68 /* If there is a file named /var/run/dynip/<iface>, look if we
69 * can get interface name from there (IP_PHYS)
71 b
= (char *)alloc_bytes(strlen(DYNIP_DIR
) + strlen(iface
) + 10, "iface");
74 sprintf(b
, "%s/%s", DYNIP_DIR
, iface
);
79 memset(_if
, 0, sizeof(_if
));
80 memset(line
, 0, sizeof(line
));
81 while (fgets(line
, sizeof(line
), fd
) != 0)
83 if ((strncmp(line
,"IP_PHYS=\"", 9) == 0)
84 && (line
[strlen(line
) - 2] == '"')
85 && (line
[strlen(line
) - 1] == '\n'))
87 strncpy(_if
, line
+ 9, MIN(strlen(line
) - 11, IFNAMSIZ
));
90 else if ((strncmp(line
,"IP_PHYS=", 8) == 0)
92 && (line
[strlen(line
) - 1] == '\n'))
94 strncpy(_if
, line
+ 8, MIN(strlen(line
) - 9, IFNAMSIZ
));
102 strncpy(req
.ifr_name
, _if
, IFNAMSIZ
);
103 if (ioctl(sock
, SIOCGIFFLAGS
, &req
) == 0)
105 if (req
.ifr_flags
& IFF_UP
)
116 starter_iface_find(char *iface
, int af
, ip_address
*dst
, ip_address
*nh
)
120 struct sockaddr_in
*sa
= (struct sockaddr_in
*)(&req
.ifr_addr
);
126 sock
= socket(af
, SOCK_DGRAM
, 0);
130 phys
= _find_physical_iface(sock
, iface
);
134 strncpy(req
.ifr_name
, phys
, IFNAMSIZ
);
135 if (ioctl(sock
, SIOCGIFFLAGS
, &req
)!=0)
137 if (!(req
.ifr_flags
& IFF_UP
))
140 if ((req
.ifr_flags
& IFF_POINTOPOINT
)
142 && ioctl(sock
, SIOCGIFDSTADDR
, &req
) == 0)
144 if (sa
->sin_family
== af
)
145 initaddr((const void *)&sa
->sin_addr
, sizeof(struct in_addr
), af
, nh
);
147 if ((dst
) && (ioctl(sock
, SIOCGIFADDR
, &req
) == 0))
149 if (sa
->sin_family
== af
)
150 initaddr((const void *)&sa
->sin_addr
, sizeof(struct in_addr
), af
, dst
);
161 valid_str(char *str
, unsigned int *pn
, char **pphys
162 , defaultroute_t
*defaultroute
)
164 if (streq(str
, "%defaultroute"))
166 if (!defaultroute
->defined
)
171 *pphys
= defaultroute
->iface
;
176 || str
[0] != 'i' || str
[1] != 'p' || str
[2] !='s' || str
[3] != 'e'
177 || str
[4] != 'c' || str
[5] < '0' || str
[5] > '9' || str
[6] != '=')
188 _iface_up (int sock
, struct st_ipsec_if
*iface
, char *phys
189 , unsigned int mtu
, bool nat_t
)
192 struct ipsectunnelconf
*shc
=(struct ipsectunnelconf
*)&req
.ifr_data
;
195 /* sscholz@astaro.com: for network mask 32 bit
196 struct sockaddr_in *inp;
199 strncpy(req
.ifr_name
, phys
, IFNAMSIZ
);
200 if (ioctl(sock
, SIOCGIFFLAGS
, &req
) !=0 )
202 phys_flags
= req
.ifr_flags
;
204 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
205 if (ioctl(sock
, SIOCGIFFLAGS
, &req
) != 0)
208 if ((!(req
.ifr_flags
& IFF_UP
)) || (!iface
->up
))
211 DBG_log("attaching interface %s to %s", iface
->name
, phys
)
216 if ((*iface
->phys
) && (strcmp(iface
->phys
, phys
) != 0 ))
218 /* tncfg --detach if phys has changed */
219 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
220 ioctl(sock
, IPSEC_DEL_DEV
, &req
);
225 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
226 strncpy(shc
->cf_name
, phys
, sizeof(shc
->cf_name
));
227 ioctl(sock
, IPSEC_SET_DEV
, &req
);
229 /* set ipsec addr = phys addr */
230 strncpy(req
.ifr_name
, phys
, IFNAMSIZ
);
231 if (ioctl(sock
, SIOCGIFADDR
, &req
) == 0)
233 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
234 ioctl(sock
, SIOCSIFADDR
, &req
);
237 /* set ipsec mask = phys mask */
238 strncpy(req
.ifr_name
, phys
, IFNAMSIZ
);
239 if (ioctl(sock
, SIOCGIFNETMASK
, &req
) == 0)
241 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
242 /* sscholz@astaro.com: changed netmask to 32 bit
243 * in order to prevent network routes from being created
245 inp = (struct sockaddr_in *)&req.ifr_addr;
246 inp->sin_addr.s_addr = 0xFFFFFFFFL;
249 ioctl(sock
, SIOCSIFNETMASK
, &req
);
252 /* set other flags & addr */
253 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
254 if (ioctl(sock
, SIOCGIFFLAGS
, &req
)==0)
256 /* removed by sscholz@astaro.com (caused trouble with DSL/ppp0) */
257 /* if (phys_flags & IFF_POINTOPOINT)
259 req.ifr_flags |= IFF_POINTOPOINT;
260 req.ifr_flags &= ~IFF_BROADCAST;
261 ioctl(sock, SIOCSIFFLAGS, &req);
262 strncpy(req.ifr_name, phys, IFNAMSIZ);
263 if (ioctl(sock, SIOCGIFDSTADDR, &req) == 0)
265 strncpy(req.ifr_name, iface->name, IFNAMSIZ);
266 ioctl(sock, SIOCSIFDSTADDR, &req);
271 if (phys_flags
& IFF_BROADCAST
)
273 req
.ifr_flags
&= ~IFF_POINTOPOINT
;
274 req
.ifr_flags
|= IFF_BROADCAST
;
275 ioctl(sock
, SIOCSIFFLAGS
, &req
);
276 strncpy(req
.ifr_name
, phys
, IFNAMSIZ
);
277 if (ioctl(sock
, SIOCGIFBRDADDR
, &req
) == 0)
279 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
280 ioctl(sock
, SIOCSIFBRDADDR
, &req
);
285 req
.ifr_flags
&= ~IFF_POINTOPOINT
;
286 req
.ifr_flags
&= ~IFF_BROADCAST
;
287 ioctl(sock
, SIOCSIFFLAGS
, &req
);
292 * guess MTU = phys interface MTU - ESP Overhead
294 * ESP overhead : 10+16+7+2+12=57 -> 60 by security
295 * NAT-T overhead : 20
299 strncpy(req
.ifr_name
, phys
, IFNAMSIZ
);
300 ioctl(sock
, SIOCGIFMTU
, &req
);
301 mtu
= req
.ifr_mtu
- 60;
308 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
310 ioctl(sock
, SIOCSIFMTU
, &req
);
313 /* ipsec interface UP */
314 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
315 if (ioctl(sock
, SIOCGIFFLAGS
, &req
) == 0)
317 req
.ifr_flags
|= IFF_UP
;
318 ioctl(sock
, SIOCSIFFLAGS
, &req
);
322 strncpy(iface
->phys
, phys
, IFNAMSIZ
);
327 _iface_down(int sock
, struct st_ipsec_if
*iface
)
334 strncpy(req
.ifr_name
, iface
->name
, IFNAMSIZ
);
335 if (ioctl(sock
, SIOCGIFFLAGS
, &req
)!=0)
338 if (req
.ifr_flags
& IFF_UP
)
341 DBG_log("shutting down interface %s/%s", iface
->name
, iface
->phys
)
343 req
.ifr_flags
&= ~IFF_UP
;
344 ioctl(sock
, SIOCSIFFLAGS
, &req
);
349 memset(&req
.ifr_addr
, 0, sizeof(req
.ifr_addr
));
350 req
.ifr_addr
.sa_family
= AF_INET
;
351 ioctl(sock
, SIOCSIFADDR
, &req
);
354 ioctl(sock
, IPSEC_DEL_DEV
, &req
);
356 memset(iface
->phys
, 0, sizeof(iface
->phys
));
362 starter_ifaces_init(void)
366 memset(_ipsec_if
, 0, sizeof(_ipsec_if
));
367 for (i
= 0; i
< N_IPSEC_IF
; i
++)
368 snprintf(_ipsec_if
[i
].name
, IFNAMSIZ
, "ipsec%d", i
);
372 starter_ifaces_clear (void)
377 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
381 for (i
= 0; i
< N_IPSEC_IF
; i
++)
382 _iface_down (sock
, &(_ipsec_if
[i
]));
386 starter_ifaces_load(char **ifaces
, unsigned int omtu
, bool nat_t
387 , defaultroute_t
*defaultroute
)
389 char *tmp_phys
, *phys
;
395 struct ifreq physreq
, ipsecreq
; // re-attach interface
396 struct sockaddr_in
*inp1
, *inp2
; // re-attach interface
399 DBG_log("starter_ifaces_load()")
402 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
406 for (j
= 0; j
< N_IPSEC_IF
; j
++)
410 for (i
= ifaces
; i
&& *i
; i
++)
412 if (valid_str(*i
, &n
, &tmp_phys
, defaultroute
)
421 plog( "ignoring duplicate entry for interface ipsec%d", j
);
426 phys
= _find_physical_iface(sock
, tmp_phys
);
428 /* Re-attach ipsec interface if IP address changes
433 memset ((void*)&physreq
, 0, sizeof(physreq
));
434 memset ((void*)&ipsecreq
, 0, sizeof(ipsecreq
));
435 strncpy(physreq
.ifr_name
, phys
, IFNAMSIZ
);
436 sprintf(ipsecreq
.ifr_name
, "ipsec%d", j
);
437 ioctl(sock
, SIOCGIFADDR
, &physreq
);
438 ioctl(sock
, SIOCGIFADDR
, &ipsecreq
);
439 inp1
= (struct sockaddr_in
*)&physreq
.ifr_addr
;
440 inp2
= (struct sockaddr_in
*)&ipsecreq
.ifr_addr
;
441 if (inp1
->sin_addr
.s_addr
!= inp2
->sin_addr
.s_addr
)
443 plog("IP address of physical interface changed "
444 "-> reinit of ipsec interface");
445 _iface_down (sock
, &(_ipsec_if
[n
]));
447 ret
+= _iface_up (sock
, &(_ipsec_if
[n
]), phys
, omtu
, nat_t
);
451 ret
+= _iface_down (sock
, &(_ipsec_if
[n
]));
458 /* Only log in the first loop */
459 plog("ignoring invalid interface '%s'", *i
);
463 ret
+= _iface_down (sock
, &(_ipsec_if
[j
]));
467 return ret
; /* = number of changes - 'whack --listen' if > 0 */
471 * initialize a defaultroute_t struct
474 init_defaultroute(defaultroute_t
*defaultroute
)
476 memset(defaultroute
, 0, sizeof(defaultroute_t
));
480 * discover the default route via /proc/net/route
483 get_defaultroute(defaultroute_t
*defaultroute
)
489 init_defaultroute(defaultroute
);
491 fd
= fopen("/proc/net/route", "r");
495 plog("could not open 'proc/net/route'");
499 while (fgets(line
, sizeof(line
), fd
) != 0)
512 /* proc/net/route returns IP addresses in host order */
513 strcpy(gateway
, "0h");
515 /* skip the header line */
522 /* parsing a single line of proc/net/route */
523 items
= sscanf(line
, "%10s\t%8s\t%8s\t%5s\t%d\t%d\t%d\t%8s\t"
524 , iface
, destination
, gateway
+2, flags
, &refcnt
, &use
, &metric
, mask
);
527 plog("parsing error while scanning /proc/net/route");
531 /* check for defaultroute (destination 0.0.0.0 and mask 0.0.0.0) */
532 if (streq(destination
, "00000000") && streq(mask
, "00000000"))
534 if (defaultroute
->defined
)
536 plog("multiple default routes - cannot cope with %%defaultroute!!!");
537 defaultroute
->defined
= FALSE
;
541 ttoaddr(gateway
, strlen(gateway
), AF_INET
, &defaultroute
->nexthop
);
542 strncpy(defaultroute
->iface
, iface
, IFNAMSIZ
);
543 defaultroute
->defined
= TRUE
;
548 if (!defaultroute
->defined
)
550 plog("no default route - cannot cope with %%defaultroute!!!");
554 char addr_buf
[20], nexthop_buf
[20];
555 struct ifreq physreq
;
557 int sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
559 /* determine IP address of iface */
562 plog("could not open SOCK_DGRAM socket");
563 defaultroute
->defined
= FALSE
;
566 memset ((void*)&physreq
, 0, sizeof(physreq
));
567 strncpy(physreq
.ifr_name
, defaultroute
->iface
, IFNAMSIZ
);
568 ioctl(sock
, SIOCGIFADDR
, &physreq
);
570 defaultroute
->addr
.u
.v4
= *((struct sockaddr_in
*)&physreq
.ifr_addr
);
572 addrtot(&defaultroute
->addr
, 0, addr_buf
, sizeof(addr_buf
));
573 addrtot(&defaultroute
->nexthop
, 0, nexthop_buf
, sizeof(nexthop_buf
));
576 DBG_log("Default route found: iface=%s, addr=%s, nexthop=%s"
577 , defaultroute
->iface
, addr_buf
, nexthop_buf
)
580 /* for backwards-compatibility with the awk shell scripts
581 * store the defaultroute in /var/run/ipsec.info
583 fd
= fopen(INFO_FILE
, "w");
587 fprintf(fd
, "defaultroutephys=%s\n", defaultroute
->iface
);
588 fprintf(fd
, "defaultroutevirt=ipsec0\n");
589 fprintf(fd
, "defaultrouteaddr=%s\n", addr_buf
);
590 fprintf(fd
, "defaultroutenexthop=%s\n", nexthop_buf
);