123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- /* 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.
- */
-
-
- #include "includes.h"
- #include <fnmatch.h>
-
- #include "common.h"
- #include "inet.h"
- #include "if.h"
- #include "libnetlink.h"
- #include "ll_map.h"
-
- extern int errno;
-
- static struct {
- int ifindex;
- int family;
- int oneline;
- int showqueue;
- inet_prefix pfx;
- int scope, scopemask;
- int flags, flagmask;
- int up;
- char *label;
- int flushed;
- char *flushb;
- int flushp;
- int flushe;
- struct rtnl_handle *rth;
- } filter;
-
- /*
- * ifs_find_idx: returns the pointer to the interface struct of the
- * device which has the index equal to `dev_idx'.
- * `ifs' is the array which keeps the interface list and has `ifs_n' elements.
- */
- interface *
- ifs_find_idx(interface * ifs, int ifs_n, int dev_idx)
- {
- int i;
-
- for (i = 0; i < ifs_n; i++)
- if (ifs[i].dev_idx == dev_idx)
- return &ifs[i];
-
- return 0;
- }
-
- int
- ifs_find_devname(interface * ifs, int ifs_n, char *dev_name)
- {
- int i;
-
- if (!dev_name)
- return -1;
-
- for (i = 0; i < ifs_n; i++)
- if (ifs[i].dev_name &&
- !strncmp(ifs[i].dev_name, dev_name, IFNAMSIZ))
- return i;
-
- return -1;
- }
-
- /*
- * ifs_del: removes from the `ifs' array the device which is at the
- * `if_pos'th position. `*ifs_n' is then decremented.
- */
- void
- ifs_del(interface * ifs, int *ifs_n, int if_pos)
- {
- if (if_pos == (*ifs_n) - 1)
- setzero(&ifs[if_pos], sizeof(interface));
- else {
- memcpy(&ifs[if_pos], &ifs[(*ifs_n) - 1], sizeof(interface));
- setzero(&ifs[(*ifs_n) - 1], sizeof(interface));
- }
-
- (*ifs_n)--;
- }
-
- /*
- * ifs_del_byname: deletes from the `ifs' array the device whose name is equal
- * to `dev_name'
- */
- void
- ifs_del_byname(interface * ifs, int *ifs_n, char *dev_name)
- {
- int if_pos;
-
- if_pos = ifs_find_devname(ifs, *ifs_n, dev_name);
- if (if_pos < 0)
- return;
-
- ifs_del(ifs, ifs_n, if_pos);
- }
-
- /*
- * ifs_del_all_name: deleted from the `ifs' array all the device which have a
- * device name that begins with `dev_name'. For example,
- * ifs_del_all_name(ifs, ifs_n, "tun") deletes all the tunnel iifs
- */
- void
- ifs_del_all_name(interface * ifs, int *ifs_n, char *dev_name)
- {
- int i, dev_len;
-
- if (!dev_name || (dev_len = strlen(dev_name)) > IFNAMSIZ)
- return;
-
- for (i = 0; i < (*ifs_n); i++) {
- if (ifs[i].dev_name &&
- !strncmp(ifs[i].dev_name, dev_name, dev_len)) {
-
- ifs_del(ifs, ifs_n, i);
- if (i <= (*ifs_n) - 1)
- i--;
- }
- }
- }
-
- /*
- * ifs_get_pos: this is a stupid functions which returns the position of the
- * struct in the `ifs' array which has the dev_idx element equal to
- * `dev'->dev_idx. The `ifs' array has `ifs_n' members.
- * If it is not found -1 is returned.
- */
- int
- ifs_get_pos(interface * ifs, int ifs_n, interface * dev)
- {
- int i;
-
- for (i = 0; i < ifs_n; i++)
- if (ifs[i].dev_idx == dev->dev_idx)
- return i;
-
- return -1;
- }
-
- /*
- * get_dev: It returs the first dev it finds up and sets `*dev_ids' to the
- * device's index. On error NULL is returned.
- */
- const char *
- get_dev(int *dev_idx)
- {
- int idx;
-
- if ((idx = ll_first_up_if()) == -1) {
- error("Couldn't find \"up\" devices. Set one dev \"up\", or "
- "specify the device name in the options.");
- return 0;
- }
- if (dev_idx)
- *dev_idx = idx;
- return ll_index_to_name(idx);
- }
-
- /*
- * get_all_ifs: It fills the `ifs' array with all the network interfaces it
- * finds up. The `ifs' array has `ifs_n'# members.
- * It returns the number of filled interfaces.
- */
- int
- get_all_up_ifs(interface * ifs, int ifs_n)
- {
- int i, idx, n;
-
- for (i = 0, n = 0; i < ifs_n; i++) {
- idx = ll_nth_up_if(n + 1);
- if (idx <= 0)
- continue;
-
- ifs[n].dev_idx = idx;
- strncpy(ifs[n].dev_name, ll_index_to_name(idx), IFNAMSIZ);
- loginfo("Network interface \"%s\" detected", ifs[n].dev_name);
- n++;
-
- if ((idx - 1) > i)
- i = idx - 1;
- }
-
- return n;
- }
-
- int
- set_flags(char *dev, u_int flags, u_int mask)
- {
- struct ifreq ifr;
- int s;
-
- strcpy(ifr.ifr_name, dev);
- if ((s = new_socket(AF_INET)) < 0) {
- error("Error while setting \"%s\" flags: Cannot open socket", dev);
- return -1;
- }
-
- if (ioctl(s, SIOCGIFFLAGS, &ifr)) {
- error("Error while setting \"%s\" flags: %s", dev,
- strerror(errno));
- close(s);
- return -1;
- }
-
- ifr.ifr_flags &= ~mask;
- ifr.ifr_flags |= mask & flags;
- if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
- error("Error while setting \"%s\" flags: %s", dev,
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
- }
-
- int
- set_dev_up(char *dev)
- {
- u_int mask = 0, flags = 0;
-
- mask |= IFF_UP;
- flags |= IFF_UP;
- return set_flags(dev, flags, mask);
- }
-
- int
- set_dev_down(char *dev)
- {
- u_int mask = 0, flags = 0;
-
- mask |= IFF_UP;
- flags &= ~IFF_UP;
- return set_flags(dev, flags, mask);
- }
-
- /*
- * set_all_ifs: for all the `ifs_n' interfaces present in the `ifs' array, it
- * calls the `set_func' functions, passing as argument ifs[i].dev_name.
- * (All the above set_* functions can be used as `set_func').
- * It returns the sum of all each return code, of set_func, therefore if it
- * returns a negative value, some `set_func' gave an error.
- */
- int
- set_all_ifs(interface * ifs, int ifs_n, int (*set_func) (char *dev))
- {
- int i, ret = 0;
-
- for (i = 0; i < ifs_n; i++)
- ret += set_func(ifs[i].dev_name);
-
- return ret;
- }
-
- /*
- * if_init_all: it initializes all the `ifs_n'# interfaces present in the
- * `ifs' array. If `ifs_n' is zero it gets all the current up interfaces and
- * stores them in `new_ifs', updating the `new_ifs_n' counter too. Then it
- * initializes them.
- * In the `new_ifs' array, which must be at least big as the `ids' array, it
- * stores all the initialized interfaces, updating the `new_ifs_n' counter.
- * On error -1 is returned.
- */
- int
- if_init_all(char *ifs_name[MAX_INTERFACES], int ifs_n,
- interface * new_ifs, int *new_ifs_n)
- {
- struct rtnl_handle rth;
- int ret = 0, i, j, n, dedup;
-
- if (rtnl_open(&rth, 0) < 0) {
- error("Cannot open the rtnetlink socket to talk to the kernel's "
- "soul");
- return -1;
- }
- ll_init_map(&rth);
-
- if (!ifs_n) {
- ret = get_all_up_ifs(new_ifs, MAX_INTERFACES);
-
- if (!ret)
- return -1;
-
- *new_ifs_n = ret;
- } else {
- for (i = 0, n = 0; i < ifs_n; i++) {
- dedup = 0;
- for(j=0; j < n; j++) {
- if(strcmp(ifs_name[i], new_ifs[j].dev_name) == 0) {
- dedup = 1;
- break;
- }
- }
- if(dedup) {
- continue;
- }
- new_ifs[n].dev_idx = ll_name_to_index(ifs_name[n]);
- if (!new_ifs[n].dev_idx) {
- error("Cannot initialize the %s interface. "
- "Ignoring it", ifs_name[n]);
- continue;
- }
-
- strncpy(new_ifs[n].dev_name, ifs_name[n], IFNAMSIZ);
- n++;
- }
-
- if (!n)
- return -1;
-
- *new_ifs_n = n;
- }
-
- if (set_all_ifs(new_ifs, *new_ifs_n, set_dev_up) < 0)
- return -1;
-
- rtnl_close(&rth);
-
- return ret;
- }
-
- void
- if_close_all(void)
- {
- #if 0
- /* XXX: disabled for now, it is buggy */
- ll_free_index();
- #endif
- }
-
- /*
- * set_dev_ip: Assign the given `ip' to the interface named `dev'
- * On success 0 is returned, -1 otherwise.
- */
- int
- set_dev_ip(inet_prefix ip, char *dev)
- {
- int s = -1;
-
- if (ip.family == AF_INET) {
- struct ifreq req;
-
- if ((s = new_socket(AF_INET)) < 0) {
- error("Error while setting \"%s\" ip: Cannot open socket",
- dev);
- return -1;
- }
-
- strncpy(req.ifr_name, dev, IFNAMSIZ);
- inet_to_sockaddr(&ip, 0, &req.ifr_addr, 0);
-
- if (ioctl(s, SIOCSIFADDR, &req)) {
- error("Error while setting \"%s\" ip: %s", dev,
- strerror(errno));
- close(s);
- return -1;
- }
- } else if (ip.family == AF_INET6) {
- struct in6_ifreq req6;
- struct sockaddr_in6 sin6;
- struct sockaddr *sa = (struct sockaddr *) &sin6;
-
- if ((s = new_socket(AF_INET6)) < 0) {
- error("Error while setting \"%s\" ip: Cannot open socket",
- dev);
- return -1;
- }
-
- req6.ifr6_ifindex = ll_name_to_index(dev);
- req6.ifr6_prefixlen = 0;
- inet_to_sockaddr(&ip, 0, sa, 0);
- memcpy(&req6.ifr6_addr, sin6.sin6_addr.s6_addr32, ip.len);
-
- if (ioctl(s, SIOCSIFADDR, &req6)) {
- error("Error while setting \"%s\" ip: %s", dev,
- strerror(errno));
- close(s);
- return -1;
- }
-
- }
-
- close(s);
- return 0;
- }
-
- /*
- * set_all_dev_ip: it sets the given `ip' to all the `ifs_n'# interfaces
- * present in the `ifs' array.
- * On error -1 is returned.
- */
- int
- set_all_dev_ip(inet_prefix ip, interface * ifs, int ifs_n)
- {
- int i, ret = 0;
-
- for (i = 0; i < ifs_n; i++)
- ret += set_dev_ip(ip, ifs[i].dev_name);
-
- return ret;
- }
-
- /*
- * get_dev_ip: fetches the ip currently assigned to the interface named `dev'
- * and stores it to `ip'.
- * On success 0 is returned, -1 otherwise.
- */
- int
- get_dev_ip(inet_prefix * ip, int family, char *dev)
- {
- int s = -1;
- int ret = 0;
-
- setzero(ip, sizeof(inet_prefix));
-
- if ((s = new_socket(family)) < 0) {
- error("Error while setting \"%s\" ip: Cannot open socket", dev);
- return -1;
- }
-
- if (family == AF_INET) {
- struct ifreq req;
-
- strncpy(req.ifr_name, dev, IFNAMSIZ);
- req.ifr_addr.sa_family = family;
-
- if (ioctl(s, SIOCGIFADDR, &req))
- ERROR_FINISH(ret, -1, finish);
-
- sockaddr_to_inet(&req.ifr_addr, ip, 0);
- } else if (family == AF_INET6) {
- struct in6_ifreq req6;
-
- /*
- * XXX: NOT TESTED
- */
-
- req6.ifr6_ifindex = ll_name_to_index(dev);
- req6.ifr6_prefixlen = 0;
-
- if (ioctl(s, SIOCGIFADDR, &req6))
- ERROR_FINISH(ret, -1, finish);
-
- inet_setip(ip, (u_int *) & req6.ifr6_addr, family);
- }
-
- finish:
- if (s != -1)
- close(s);
- return ret;
- }
-
-
- /*
- * All the code below this point is ripped from iproute2/iproute.c
- * written by Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>.
- *
- * Modified lightly
- */
- static int
- flush_update(void)
- {
- if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
- error("Failed to send flush request: %s", strerror(errno));
- return -1;
- }
- filter.flushp = 0;
- return 0;
- }
-
- int
- print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
- void *arg)
- {
- struct ifaddrmsg *ifa = NLMSG_DATA(n);
- int len = n->nlmsg_len;
- struct rtattr *rta_tb[IFA_MAX + 1];
- char b1[64];
-
- if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
- return 0;
- len -= NLMSG_LENGTH(sizeof(*ifa));
- if (len < 0) {
- error("BUG: wrong nlmsg len %d\n", len);
- return -1;
- }
-
- if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
- return 0;
-
- parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa),
- n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
-
- if (!rta_tb[IFA_LOCAL])
- rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
- if (!rta_tb[IFA_ADDRESS])
- rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
-
- if (filter.ifindex && filter.ifindex != ifa->ifa_index)
- return 0;
- if ((filter.scope ^ ifa->ifa_scope) & filter.scopemask)
- return 0;
- if ((filter.flags ^ ifa->ifa_flags) & filter.flagmask)
- return 0;
- if (filter.label) {
- const char *label;
- if (rta_tb[IFA_LABEL])
- label = RTA_DATA(rta_tb[IFA_LABEL]);
- else
- label = ll_idx_n2a(ifa->ifa_index, b1);
- if (fnmatch(filter.label, label, 0) != 0)
- return 0;
- }
- if (filter.pfx.family) {
- if (rta_tb[IFA_LOCAL]) {
- inet_prefix dst;
- setzero(&dst, sizeof(dst));
- dst.family = ifa->ifa_family;
- memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]),
- RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
- if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bits))
- return 0;
- }
- }
-
- if (filter.flushb) {
- struct nlmsghdr *fn;
- if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
- if (flush_update())
- return -1;
- }
- fn = (struct nlmsghdr *) (filter.flushb +
- NLMSG_ALIGN(filter.flushp));
- memcpy(fn, n, n->nlmsg_len);
- fn->nlmsg_type = RTM_DELADDR;
- fn->nlmsg_flags = NLM_F_REQUEST;
- fn->nlmsg_seq = ++filter.rth->seq;
- filter.flushp = (((char *) fn) + n->nlmsg_len) - filter.flushb;
- filter.flushed++;
- }
-
- return 0;
- }
-
- struct nlmsg_list {
- struct nlmsg_list *next;
- struct nlmsghdr h;
- };
-
- static int
- store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
- {
- struct nlmsg_list **linfo = (struct nlmsg_list **) arg;
- struct nlmsg_list *h;
- struct nlmsg_list **lp;
-
- h = malloc(n->nlmsg_len + sizeof(void *));
- if (h == NULL)
- return -1;
-
- memcpy(&h->h, n, n->nlmsg_len);
- h->next = NULL;
-
- for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */
- ;
- *lp = h;
-
- ll_remember_index((struct sockaddr_nl *) who, n, NULL);
- return 0;
- }
-
- int
- ip_addr_flush(int family, char *dev, int scope)
- {
- struct nlmsg_list *linfo = NULL;
- struct rtnl_handle rth;
- char *filter_dev = NULL;
-
- setzero(&filter, sizeof(filter));
- filter.showqueue = 1;
-
- filter.family = family;
- filter_dev = dev;
-
- if (rtnl_open(&rth, 0) < 0)
- return -1;
-
- if (rtnl_wilddump_request(&rth, family, RTM_GETLINK) < 0) {
- error("Cannot send dump request: %s", strerror(errno));
- return -1;
- }
-
- if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
- error("Dump terminated");
- return -1;
- }
-
- filter.ifindex = ll_name_to_index(filter_dev);
- if (filter.ifindex <= 0) {
- error("Device \"%s\" does not exist.", filter_dev);
- return -1;
- }
-
- int round = 0;
- char flushb[4096 - 512];
-
- filter.flushb = flushb;
- filter.flushp = 0;
- filter.flushe = sizeof(flushb);
- filter.rth = &rth;
- filter.scopemask = -1;
- filter.scope = scope;
-
- for (;;) {
- if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
- error("Cannot send dump request: %s", strerror(errno));
- return -1;
- }
- filter.flushed = 0;
- if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
- error("Flush terminated: %s", errno);
- return -1;
- }
- if (filter.flushed == 0)
- return 0;
-
- round++;
- if (flush_update() < 0)
- return -1;
- }
-
- rtnl_close(&rth);
- }
-
- int
- ip_addr_flush_all_ifs(interface * ifs, int ifs_n, int family, int scope)
- {
- int i, ret = 0;
-
- for (i = 0; i < ifs_n; i++)
- ret += ip_addr_flush(family, ifs[i].dev_name, scope);
-
- return ret;
- }
|