123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
-
- /* This file is part of Netsukuku
- * (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
- *
- * This source code is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This source code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * Please refer to the GNU Public License for more details.
- *
- * You should have received a copy of the GNU Public License along with
- * this source code; if not, write to:
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * --
- * This code derives from iproute2/iprule.c, it was modified to fit in
- * Netsukuku.
- *
- * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- * Changes:
- * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
- * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
- * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag
- */
-
- #include "includes.h"
-
- #include "inet.h"
- #include <linux/ip.h>
- #include <linux/if_tunnel.h>
-
- #include "libnetlink.h"
- #include "libnetlink.h"
- #include "ll_map.h"
- #include "krnl_route.h"
- #include "route.h"
- #include "iptunnel.h"
- #include "common.h"
-
- static int do_add(int cmd, inet_prefix * remote, inet_prefix * local,
- char *dev, char *tunl_prefix, int tunl_number);
- int do_del(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number);
-
- int
- tunnel_add(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number)
- {
- return do_add(SIOCADDTUNNEL, remote, local, dev, tunl_prefix,
- tunl_number);
- }
-
- int
- tunnel_change(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number)
- {
- return do_add(SIOCGETTUNNEL, remote, local, dev, tunl_prefix,
- tunl_number);
- }
-
- int
- tunnel_del(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number)
- {
- return do_del(remote, local, dev, tunl_prefix, tunl_number);
- }
-
- static int
- do_ioctl_get_ifindex(const char *dev)
- {
- struct ifreq ifr;
- int fd;
- int err;
-
- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- err = ioctl(fd, SIOCGIFINDEX, &ifr);
- if (err) {
- error(ERROR_MSG "ioctl: %s", ERROR_POS, strerror(errno));
- return 0;
- }
- close(fd);
- return ifr.ifr_ifindex;
- }
-
- #if 0
- static int
- do_ioctl_get_iftype(const char *dev)
- {
- struct ifreq ifr;
- int fd;
- int err;
-
- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- err = ioctl(fd, SIOCGIFHWADDR, &ifr);
- if (err) {
- error(ERROR_MSG "ioctl: %s", ERROR_POS, strerror(errno));
- return -1;
- }
- close(fd);
- return ifr.ifr_addr.sa_family;
- }
-
- static char *
- do_ioctl_get_ifname(int idx)
- {
- static struct ifreq ifr;
- int fd;
- int err;
-
- ifr.ifr_ifindex = idx;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- err = ioctl(fd, SIOCGIFNAME, &ifr);
- if (err) {
- error(ERROR_MSG "ioctl: %s", ERROR_POS, strerror(errno));
- return NULL;
- }
- close(fd);
- return ifr.ifr_name;
- }
- #endif
-
- static int
- do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
- {
- struct ifreq ifr;
- int fd;
- int err;
-
- strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
- ifr.ifr_ifru.ifru_data = (void *) p;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- err = ioctl(fd, SIOCGETTUNNEL, &ifr);
- /*
- * if (err)
- * error(ERROR_MSG "ioctl: %s",ERROR_POS, strerror(errno));
- */
- close(fd);
- return err;
- }
-
- static int
- do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
- {
- struct ifreq ifr;
- int fd;
- int err;
-
- if (cmd == SIOCCHGTUNNEL && p->name[0])
- strncpy(ifr.ifr_name, p->name, IFNAMSIZ);
- else
- strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
- ifr.ifr_ifru.ifru_data = (void *) p;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- err = ioctl(fd, cmd, &ifr);
- error
- ("Socket File Descriptor Is: %i cmd is: %i err is: %i ifr is: %s Errno is: %d",
- fd, cmd, err, &ifr, errno);
- if (err)
- error(ERROR_MSG "ioctl: %s", ERROR_POS, strerror(errno));
- close(fd);
- return err;
- }
-
- static int
- do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
- {
- struct ifreq ifr;
- int fd;
- int err;
-
- if (p->name[0])
- strncpy(ifr.ifr_name, p->name, IFNAMSIZ);
- else
- strncpy(ifr.ifr_name, basedev, IFNAMSIZ);
- ifr.ifr_ifru.ifru_data = (void *) p;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- err = ioctl(fd, SIOCDELTUNNEL, &ifr);
- if (err)
- error(ERROR_MSG "ioctl: %s", ERROR_POS, strerror(errno));
- close(fd);
- return err;
- }
-
- /*
- * fill_tunnel_parm: fills the `p' struct.
- * `remote' and `local' must be in host order
- */
- static int
- fill_tunnel_parm(int cmd, inet_prefix * remote, inet_prefix * local,
- char *dev, char *tunl_prefix, int tunl_number,
- struct ip_tunnel_parm *p)
- {
- char medium[IFNAMSIZ];
-
- memset(p, 0, sizeof(*p));
- memset(&medium, 0, sizeof(medium));
-
- p->iph.version = 4;
- p->iph.ihl = 5;
- #ifndef IP_DF
- #define IP_DF 0x4000 /* Flag: "Don't Fragment" */
- #endif
- p->iph.frag_off = htons(IP_DF);
- p->iph.protocol = IPPROTO_IPIP;
-
- if (remote)
- p->iph.daddr = htonl(remote->data[0]);
- if (local)
- p->iph.saddr = htonl(local->data[0]);
- if (dev)
- strncpy(medium, dev, IFNAMSIZ - 1);
-
- sprintf(p->name, TUNL_STRING, TUNL_N(tunl_prefix, tunl_number));
- if (cmd == SIOCCHGTUNNEL) {
- /* Change the old tunnel */
- struct ip_tunnel_parm old_p;
- memset(&old_p, 0, sizeof(old_p));
- if (do_get_ioctl(p->name, &old_p))
- return -1;
- *p = old_p;
- }
-
- if (p->iph.protocol == IPPROTO_IPIP)
- if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY))
- fatal("Keys are not allowed with ipip and sit.");
-
- if (medium[0]) {
- p->link = do_ioctl_get_ifindex(medium);
- if (p->link == 0)
- return -1;
- }
-
- if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr)
- fatal("Broadcast tunnel requires a source address.");
-
- return 0;
- }
-
- /*
- * do_get: returns 1 if the tunnel named `dev' exists.
- */
- int
- do_get(char *dev)
- {
- struct ip_tunnel_parm old_p;
- memset(&old_p, 0, sizeof(old_p));
-
- if (do_get_ioctl(dev, &old_p))
- return 0;
-
- return 1;
- }
-
- static int
- do_add(int cmd, inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number)
- {
- struct ip_tunnel_parm p;
-
- if (fill_tunnel_parm(cmd, remote, local, dev, tunl_prefix,
- tunl_number, &p) < 0)
- return -1;
-
- if (p.iph.ttl && p.iph.frag_off == 0)
- fatal("ttl != 0 and noptmudisc are incompatible");
-
- switch (p.iph.protocol) {
- case IPPROTO_IPIP:
- return do_add_ioctl(cmd, DEFAULT_TUNL_IF, &p);
- default:
- fatal("cannot determine tunnel mode (ipip, gre or sit)\n");
- }
- return -1;
- }
-
- int
- do_del(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number)
- {
- struct ip_tunnel_parm p;
-
- if (fill_tunnel_parm(SIOCDELTUNNEL, remote, local, dev, tunl_prefix,
- tunl_number, &p) < 0)
- return -1;
-
- switch (p.iph.protocol) {
- case IPPROTO_IPIP:
- return do_del_ioctl(DEFAULT_TUNL_IF, &p);
- default:
- return do_del_ioctl(p.name, &p);
- }
- return -1;
- }
-
- /*
- * tun_add_tunl: it adds in the `ifs' array a new struct which refers to
- * the tunnel "tunlX", where X is a number equal to `tunl'.
- */
- int
- tun_add_tunl(interface * ifs, char *tunl_prefix, u_char tunl_number)
- {
- char tunl_name[IFNAMSIZ];
-
- sprintf(tunl_name, TUNL_STRING, TUNL_N(tunl_prefix, tunl_number));
- strncpy(ifs->dev_name, tunl_name, IFNAMSIZ);
- if (!(ifs->dev_idx = do_ioctl_get_ifindex(tunl_name)))
- return -1;
-
- return 0;
- }
-
- /*
- * tun_del_tunl: it removes from the `ifs' array, which must have at least
- * MAX_TUNNEL_IFS members, the struct which refers the tunnel "tunlX", where X
- * is a number equal to `tunl'.
- * If no such struct is found, -1 is returned.
- */
- int
- tun_del_tunl(interface * ifs, char *tunl_prefix, u_char tunl_number)
- {
- char tunl_name[IFNAMSIZ];
- int i;
-
- sprintf(tunl_name, TUNL_STRING, TUNL_N(tunl_prefix, tunl_number));
-
- for (i = 0; i < MAX_TUNNEL_IFS; i++)
- if (!strncmp(ifs[i].dev_name, tunl_name, IFNAMSIZ)) {
- memset(&ifs[i], 0, sizeof(interface));
- return 0;
- }
-
- return -1;
- }
-
-
-
- void
- init_tunnels_ifs(void)
- {
- memset(tunnel_ifs, 0, sizeof(interface) * MAX_TUNNEL_IFS);
- }
-
- /*
- * first_free_tunnel_if: returns the position of the first member of the
- * `tunnel_ifs' array which isn't used yet.
- * If the whole array is full, -1 is returned.
- */
- int
- first_free_tunnel_if(void)
- {
- int i;
-
- for (i = 0; i < MAX_TUNNEL_IFS; i++)
- if (!*tunnel_ifs[i].dev_name && !tunnel_ifs[i].dev_idx)
- return i;
- return -1;
- }
-
- /*
- * set_tunnel_ip: it brings down and up and set the `tunl_ip' IP to the
- * "tunl`tunl_number'" tunnel device
- */
- int
- set_tunnel_ip(char *tunl_prefix, int tunl_number, inet_prefix * tunl_ip)
- {
- const char *ntop;
- ntop = inet_to_str(*tunl_ip);
-
- set_all_ifs(&tunnel_ifs[tunl_number], 1, set_dev_down);
- set_all_ifs(&tunnel_ifs[tunl_number], 1, set_dev_up);
- if (set_all_dev_ip(*tunl_ip, &tunnel_ifs[tunl_number], 1) < 0) {
- error("Cannot set the %s ip to " TUNL_STRING,
- ntop, TUNL_N(tunl_prefix, tunl_number));
- return -1;
- }
- return 0;
- }
-
- /*
- * add_tunnel_if: creates a new tunnel, adds it in the `tunnel_ifs' array, and
- * if `tunl_ip' isn't null, sets to the tunnel the IP `tunl_ip'.
- */
- int
- add_tunnel_if(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number, inet_prefix * tunl_ip)
- {
- char tunl_name[IFNAMSIZ];
-
- /*
- * tunl0 zero is a special tunnel, it cannot be created nor destroyed.
- * It's pure energy.
- */
- if (!strcmp(tunl_prefix, DEFAULT_TUNL_PREFIX) && !tunl_number)
- goto skip_krnl_add_tunl;
-
- if (tunnel_add(remote, local, dev, tunl_prefix, tunl_number) < 0) {
- error("Cannot add the \"" TUNL_STRING "\" tunnel",
- TUNL_N(tunl_prefix, tunl_number));
- return -1;
- }
-
- skip_krnl_add_tunl:
-
- if (tun_add_tunl(&tunnel_ifs[tunl_number], tunl_prefix, tunl_number) <
- 0)
- return -1;
-
- if (tunl_ip) {
-
- /*
- * ifconfig tunnel `tunl_ip' up
- */
- if (set_tunnel_ip(tunl_prefix, tunl_number, tunl_ip) < 0)
- return -1;
-
-
- /*
- * ip route append tunl_ip_subnet dev tunnel proto kernel \
- * scope link src `tunl_ip'
- */
- sprintf(tunl_name, TUNL_STRING, TUNL_N(tunl_prefix, tunl_number));
- rt_append_subnet_src(tunl_ip, tunl_name);
-
- if (route_rp_filter_all_dev(my_family, &tunnel_ifs[tunl_number],
- 1, 0) < 0)
- return -1;
- }
-
- return 0;
- }
-
- /*
- * del_tunnel_if: the inverse of add_tunnel_if() (see above)
- */
- int
- del_tunnel_if(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix, int tunl_number)
- {
- /* tunl0 is a highlander */
- if (!strcmp(tunl_prefix, DEFAULT_TUNL_PREFIX) && !tunl_number)
- goto skip_krnl_del_tunl;
-
- if (tunnel_del(remote, local, dev, tunl_prefix, tunl_number) < 0) {
- error("Cannot delete the \"" TUNL_STRING "\" tunnel",
- TUNL_N(tunl_prefix, tunl_number));
- return -1;
- }
-
- skip_krnl_del_tunl:
-
- tun_del_tunl(tunnel_ifs, tunl_prefix, tunl_number);
- return 0;
- }
-
- void
- del_all_tunnel_ifs(inet_prefix * remote, inet_prefix * local, char *dev,
- char *tunl_prefix)
- {
- char tunl_name[IFNAMSIZ];
- int i;
-
- for (i = 0; i < MAX_TUNNEL_IFS; i++) {
- sprintf(tunl_name, TUNL_STRING, TUNL_N(tunl_prefix, i));
- if (do_get(tunl_name))
- del_tunnel_if(remote, local, 0, tunl_prefix, i);
- else
- break;
- }
- }
|