📄 ifrename.c
字号:
/* * Wireless Tools * * Jean II - HPL 04 * * Main code for "ifrename". This is tool allows to rename network * interfaces based on various criteria (not only wireless). * You need to link this code against "iwlib.c" and "-lm". * * This file is released under the GPL license. * Copyright (c) 2004 Jean Tourrilhes <jt@hpl.hp.com> *//* * The changelog for ifrename is in the file CHANGELOG.h ;-) * * This work is a nearly complete rewrite of 'nameif.c'. * Original CopyRight of version of 'nameif' I used is : * ------------------------------------------------------- * Name Interfaces based on MAC address. * Writen 2000 by Andi Kleen. * Subject to the Gnu Public License, version 2. * TODO: make it support token ring etc. * $Id: nameif.c,v 1.3 2003/03/06 23:26:52 ecki Exp $ * Add hotplug compatibility : ifname -i eth0. Jean II - 03.12.03 * Add MAC address wildcard : 01:23:45:*. Jean II - 03.12.03 * Add interface name wildcard : wlan*. Jean II - 03.12.03 * Add interface name probing for modular systems. Jean II - 18.02.03 * ------------------------------------------------------- * * The last 4 patches never made it into the regular version of * 'nameif', and had some 'issues', which is the reason of this rewrite. * Difference with standard 'nameif' : * o 'nameif' has only a single selector, the interface MAC address. * o Modular selector architecture, easily add new selectors. * o hotplug invocation support. * o module loading support. * o MAC address wildcard. * o Interface name wildcard ('eth*' or 'wlan*'). *//***************************** INCLUDES *****************************//* This is needed to enable GNU extensions such as getline & FNM_CASEFOLD */#ifndef _GNU_SOURCE #define _GNU_SOURCE#endif#include <getopt.h> /* getopt_long() */#include <linux/sockios.h> /* SIOCSIFNAME */#include <fnmatch.h> /* fnmatch() *///#include <sys/syslog.h>#include "iwlib.h" /* Wireless Tools library */// This would be cool, unfortunately...//#include <linux/ethtool.h> /* Ethtool stuff -> struct ethtool_drvinfo *//************************ CONSTANTS & MACROS ************************//* Our default configuration file */const char DEFAULT_CONF[] = "/etc/iftab"; /* Debian stuff */const char DEBIAN_CONFIG_FILE[] = "/etc/network/interfaces";/* Backward compatibility */#ifndef ifr_newname#define ifr_newname ifr_ifru.ifru_slave#endif/* Types of selector we support. Must match selector_list */const int SELECT_MAC = 0; /* Select by MAC address */const int SELECT_ETHADDR = 1; /* Select by MAC address */const int SELECT_ARP = 2; /* Select by ARP type */const int SELECT_LINKTYPE = 3; /* Select by ARP type */const int SELECT_DRIVER = 4; /* Select by Driver name */const int SELECT_BUSINFO = 5; /* Select by Bus-Info */const int SELECT_FIRMWARE = 6; /* Select by Firmware revision */const int SELECT_BASEADDR = 7; /* Select by HW Base Address */const int SELECT_IRQ = 8; /* Select by HW Irq line */const int SELECT_INTERRUPT = 9; /* Select by HW Irq line */const int SELECT_IWPROTO = 10; /* Select by Wireless Protocol */const int SELECT_PCMCIASLOT = 11; /* Select by Wireless Protocol */#define SELECT_NUM 12#define HAS_MAC_EXACT 1#define HAS_MAC_FILTER 2const struct ether_addr zero_mac = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};const struct option long_opt[] ={ {"config-file", 1, NULL, 'c' }, {"debian", 0, NULL, 'd' }, {"dry-run", 0, NULL, 'D' }, {"help", 0, NULL, '?' }, {"interface", 1, NULL, 'i' }, {"newname", 1, NULL, 'n' }, {"takeover", 0, NULL, 't' }, {"version", 0, NULL, 'v' }, {"verbose", 0, NULL, 'V' }, {NULL, 0, NULL, '\0' },};/* Pcmcia stab files */#define PCMCIA_STAB1 "/var/lib/pcmcia/stab"#define PCMCIA_STAB2 "/var/run/stab"/****************************** TYPES ******************************//* Cut'n'paste from ethtool.h */#define ETHTOOL_BUSINFO_LEN 32/* these strings are set to whatever the driver author decides... */struct ethtool_drvinfo { __u32 cmd; char driver[32]; /* driver short name, "tulip", "eepro100" */ char version[32]; /* driver version string */ char fw_version[32]; /* firmware version string, if applicable */ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ /* For PCI devices, use pci_dev->slot_name. */ char reserved1[32]; char reserved2[16]; __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */ __u32 testinfo_len; __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */};#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. *//* Description of an interface mapping */typedef struct if_mapping{ /* Linked list */ struct if_mapping * next; /* Name of this interface */ char ifname[IFNAMSIZ+1]; /* Selectors for this interface */ int active[SELECT_NUM]; /* Selectors active */ /* Selector data */ struct ether_addr mac; /* Exact MAC address, hex */ char mac_filter[6*3 + 1]; /* WildCard, ascii */ unsigned short hw_type; /* Link/ARP type */ char driver[32]; /* driver short name */ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ char fw_version[32]; /* Firmware revision */ unsigned short base_addr; /* HW Base I/O address */ unsigned char irq; /* HW irq line */ char iwproto[IFNAMSIZ + 1]; /* Wireless/protocol name */ int pcmcia_slot; /* Pcmcia slot */} if_mapping; /* Prototype for adding a selector to a mapping. Return -1 if invalid value. */typedef int (*mapping_add)(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);/* Prototype for comparing the selector of two mapping. Return 0 if matches. */typedef int (*mapping_cmp)(struct if_mapping * ifnode, struct if_mapping * target);/* Prototype for extracting selector value from live interface */typedef int (*mapping_get)(int skfd, const char * ifname, struct if_mapping * target, int flag);/* How to handle a selector */typedef struct mapping_selector{ char * name; mapping_add add_fn; mapping_cmp cmp_fn; mapping_get get_fn;} mapping_selector;/**************************** PROTOTYPES ****************************/static int mapping_addmac(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpmac(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_getmac(int skfd, const char * ifname, struct if_mapping * target, int flag);static int mapping_addarp(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmparp(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_getarp(int skfd, const char * ifname, struct if_mapping * target, int flag);static int mapping_adddriver(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpdriver(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_addbusinfo(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpbusinfo(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_addfirmware(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpfirmware(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_getdriverbusinfo(int skfd, const char * ifname, struct if_mapping * target, int flag);static int mapping_addbaseaddr(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpbaseaddr(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_addirq(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpirq(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_getbaseaddrirq(int skfd, const char * ifname, struct if_mapping * target, int flag);static int mapping_addiwproto(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmpiwproto(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_getiwproto(int skfd, const char * ifname, struct if_mapping * target, int flag);static int mapping_addpcmciaslot(struct if_mapping * ifnode, int * active, char * pos, size_t len, int linenum);static int mapping_cmppcmciaslot(struct if_mapping * ifnode, struct if_mapping * target);static int mapping_getpcmciaslot(int skfd, const char * ifname, struct if_mapping * target, int flag);/**************************** VARIABLES ****************************//* List of mapping read for config file */struct if_mapping * mapping_list = NULL;/* List of selectors we can handle */const struct mapping_selector selector_list[] ={ /* MAC address and ARP/Link type from ifconfig */ { "mac", &mapping_addmac, &mapping_cmpmac, &mapping_getmac }, { "ethaddr", &mapping_addmac, &mapping_cmpmac, &mapping_getmac }, { "arp", &mapping_addarp, &mapping_cmparp, &mapping_getarp }, { "linktype", &mapping_addarp, &mapping_cmparp, &mapping_getarp }, /* Driver name, Bus-Info and firmware rev from ethtool -i */ { "driver", &mapping_adddriver, &mapping_cmpdriver, &mapping_getdriverbusinfo }, { "businfo", &mapping_addbusinfo, &mapping_cmpbusinfo, &mapping_getdriverbusinfo }, { "firmware", &mapping_addfirmware, &mapping_cmpfirmware, &mapping_getdriverbusinfo }, /* Base Address and IRQ from ifconfig */ { "baseaddress", &mapping_addbaseaddr, &mapping_cmpbaseaddr, &mapping_getbaseaddrirq }, { "irq", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq }, { "interrupt", &mapping_addirq, &mapping_cmpirq, &mapping_getbaseaddrirq }, /* Wireless Protocol from iwconfig */ { "iwproto", &mapping_addiwproto, &mapping_cmpiwproto, &mapping_getiwproto }, /* Pcmcia slot from cardmgr */ { "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot }, /* The Terminator */ { NULL, NULL, NULL, NULL },};const int selector_num = sizeof(selector_list)/sizeof(selector_list[0]);/* List of active selectors */int selector_active[SELECT_NUM]; /* Selectors active *//* Takeover support */int force_takeover = 0; /* Takeover name from other interface */int num_takeover = 0; /* Number of takeover done *//* Dry-run support */int dry_run = 0; /* Just print new name, don't rename *//* Verbose support (i.e. debugging) */int verbose = 0;/******************** INTERFACE NAME MANAGEMENT ********************//* * Bunch of low level function for managing interface names. *//*------------------------------------------------------------------*//* * Compare two interface names, with wildcards. * We can't use fnmatch() because we don't want expansion of '[...]' * expressions, '\' sequences and matching of '.'. * We only want to match a single '*' (converted to a %d at that point) * to a numerical value (no ascii). * Return 0 is matches. */static intif_match_ifname(const char * pattern, const char * value){ const char * p; const char * v; int n; int ret; /* Check for a wildcard (converted from '*' to '%d' in mapping_create()) */ p = strstr(pattern, "%d"); /* No wildcard, simple comparison */ if(p == NULL) return(strcmp(pattern, value)); /* Check is prefixes match */ n = (p - pattern); ret = strncmp(pattern, value, n); if(ret) return(ret); /* Check that value has some digits at this point */ v = value + n; if(!isdigit(*v)) return(-1); /* Skip digits to go to value suffix */ do v++; while(isdigit(*v)); /* Pattern suffix */ p += 2; /* Compare suffixes */ return(strcmp(p, v));}/*------------------------------------------------------------------*//* * Steal interface name from another interface. This enable interface * name swapping. * This will work : * 1) with kernel 2.6.X * 2) if other interface is down * Because of (2), it won't work with hotplug, but we don't need it * with hotplug, only with static ifaces... */static intif_takeover_name(int skfd, const char * victimname){ char autoname[IFNAMSIZ+1]; int len; struct ifreq ifr; int ret; /* Compute name for victim interface */ len = strlen(victimname); memcpy(autoname, victimname, len + 1); if(len > (IFNAMSIZ - 2)) len = IFNAMSIZ - 2; /* Make sure we have at least two char */ len--; /* Convert to index */ while(isdigit(autoname[len])) len--; /* Scrap all trailing digits */ strcpy(autoname + len + 1, "%d"); if(verbose) fprintf(stderr, "Takeover : moving interface `%s' to `%s'.\n", victimname, autoname); /* Prepare request */ bzero(&ifr, sizeof(struct ifreq)); strncpy(ifr.ifr_name, victimname, IFNAMSIZ); strncpy(ifr.ifr_newname, autoname, IFNAMSIZ); /* Rename victim interface */ ret = ioctl(skfd, SIOCSIFNAME, &ifr); if(!ret) num_takeover++; return(ret);}/*------------------------------------------------------------------*//* * Ask the kernel to change the name of an interface. * That's what we want to do. All the rest is to make sure we call this * appropriately. */static intif_set_name(int skfd, const char * oldname, const char * newname, char * retname){ struct ifreq ifr; int ret; /* The kernel doesn't check is the interface already has the correct * name and may return an error, so check ourselves. * In the case of wildcard, the result can be weird : if oldname='eth0' * and newname='eth*', retname would be 'eth1'. * So, if the oldname value matches the newname pattern, just return * success. */ if(!if_match_ifname(newname, oldname)) { if(verbose) fprintf(stderr, "Setting : Interface `%s' already matches `%s'.\n", oldname, newname); strcpy(retname, oldname); return(0); } /* Prepare request */ bzero(&ifr, sizeof(struct ifreq)); strncpy(ifr.ifr_name, oldname, IFNAMSIZ); strncpy(ifr.ifr_newname, newname, IFNAMSIZ); /* Do it */ ret = ioctl(skfd, SIOCSIFNAME, &ifr); /* Takeover support : grab interface name from another interface */ if(ret && (errno == EEXIST) && force_takeover) { /* Push things around */ ret = if_takeover_name(skfd, newname); if(!ret) /* Second try */ ret = ioctl(skfd, SIOCSIFNAME, &ifr); } if(!ret) { /* Get the real new name (in case newname is a wildcard) */ strcpy(retname, ifr.ifr_newname); if(verbose) fprintf(stderr, "Setting : Interface `%s' renamed to `%s'.\n", oldname, retname); } return(ret);}/************************ SELECTOR HANDLING ************************//* * Handle the various selector we support *//*------------------------------------------------------------------*//* * Add a MAC address selector to a mapping */static intmapping_addmac(struct if_mapping * ifnode,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -