📄 ipv6addr.c
字号:
/* * This program manages IPv6 address. * * Author: Huang Zhen <zhenh@cn.ibm.com> * Copyright (c) 2004 International Business Machines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * It can add an IPv6 address, or remove one. * * Usage: IPv6addr ipv6-address {start|stop|status|monitor} * * The "start" arg adds an IPv6 address. * The "stop" arg removes one. * The "status" arg shows whether the IPv6 address exists * The "monitor" arg shows whether the IPv6 address can be pinged (ICMPv6 ECHO) */ /* * ipv6-address: * * currently the following forms are legal: * address * address/prefix * * E.g. * 3ffe:ffff:0:f101::1 * 3ffe:ffff:0:f101::1/64 * */ /* * start: * 1.IPv6addr will choice a proper interface for the new address. * 2.Then assign the new address to the interface. * 3.Wait until the new address is available (reply ICMPv6 ECHO packet) * 4.Send out the unsolicited advertisements. * * return 0(LSB_EXIT_OK) for success * return 1(LSB_EXIT_GENERIC) for failure * * * stop: * remove the address from the inferface. * * return 0(LSB_EXIT_OK) for success * return 1(LSB_EXIT_GENERIC) for failure * * status: * return the status of the address. only check whether it exists. * * return 0(LSB_STATUS_OK) for existing * return 1(LSB_STATUS_STOPPED) for not existing * * * monitor: * ping the address by ICMPv6 ECHO request. * * return 0(LSB_STATUS_OK) for response correctly. * return 1(LSB_STATUS_STOPPED) for no response. * */ #include <config.h>#include <asm/types.h>#include <libgen.h>#include <syslog.h>#include <clplumbing/cl_log.h>#include <libnet.h>#include <linux/icmpv6.h>#include <clplumbing/lsb_exitcodes.h>#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ < 2# include <sys/uio.h>#endif #define PIDDIR HA_VARRUNDIR#define PIDFILE_BASE PIDDIR "/IPv6addr-"const char* IF_INET6 = "/proc/net/if_inet6";const char* APP_NAME = "IPv6addr";const char* START_CMD = "start";const char* STOP_CMD = "stop";const char* STATUS_CMD = "status";const char* MONITOR_CMD = "monitor";const char* ADVT_CMD = "advt";char BCAST_ADDR[] = "ff02::1";const int UA_REPEAT_COUNT = 5;const int QUERY_COUNT = 5;struct in6_ifreq { struct in6_addr ifr6_addr; __u32 ifr6_prefixlen; unsigned int ifr6_ifindex;};static int start_addr6(struct in6_addr* addr6, int prefix_len);static int stop_addr6(struct in6_addr* addr6, int prefix_len);static int status_addr6(struct in6_addr* addr6, int prefix_len);static int monitor_addr6(struct in6_addr* addr6, int prefix_len);static int advt_addr6(struct in6_addr* addr6, int prefix_len);static void usage(const char* self);int write_pid_file(const char *pid_file);int create_pid_directory(const char *pid_file);static void byebye(int nsig);static char* find_if(struct in6_addr* addr_target, int* plen_target);static char* get_if(struct in6_addr* addr_target, int* plen_target);static int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);static int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);int is_addr6_available(struct in6_addr* addr6);static int send_ua(struct in6_addr* src_ip, char* if_name);intmain(int argc, char* argv[]){ char pid_file[256]; int ret; char* cp; int prefix_len; struct in6_addr addr6; /* Check the count of parameters first */ if (argc < 3) { usage(argv[0]); return EXIT_FAILURE; } /* set termination signal */ siginterrupt(SIGTERM, 1); signal(SIGTERM, byebye); /* open system log */ openlog(APP_NAME, LOG_CONS | LOG_PID, LOG_USER); /* check the first parameter, should be a IPv6 address */ if ((cp = strchr(argv[1], '/'))) { prefix_len = atol(cp + 1); if ((prefix_len < 0) || (prefix_len > 128)) { usage(argv[0]); return EXIT_FAILURE; } *cp=0; } else { prefix_len = 0; } if (inet_pton(AF_INET6, argv[1], &addr6) <= 0) { usage(argv[0]); return EXIT_FAILURE; } /* Check whether this system supports IPv6 */ if (access(IF_INET6, R_OK)) { cl_log(LOG_ERR, "No support for INET6 on this system."); return EXIT_FAILURE; } /* create the pid file so we can make sure that only one IPv6addr * for this address is running */ if (snprintf(pid_file, sizeof(pid_file), "%s%s", PIDFILE_BASE, argv[1]) >= (int)sizeof(pid_file)) { cl_log(LOG_ERR, "Pid file truncated"); return EXIT_FAILURE; } if (write_pid_file(pid_file) < 0) { return EXIT_FAILURE; } /* switch the command */ if (0 == strncmp(START_CMD,argv[2], strlen(START_CMD))) { ret = start_addr6(&addr6, prefix_len); }else if (0 == strncmp(STOP_CMD,argv[2], strlen(STOP_CMD))) { ret = stop_addr6(&addr6, prefix_len); }else if (0 == strncmp(STATUS_CMD,argv[2], strlen(STATUS_CMD))) { ret = status_addr6(&addr6, prefix_len); }else if (0 ==strncmp(MONITOR_CMD,argv[2], strlen(MONITOR_CMD))) { ret = monitor_addr6(&addr6, prefix_len); }else if (0 ==strncmp(ADVT_CMD,argv[2], strlen(MONITOR_CMD))) { ret = advt_addr6(&addr6, prefix_len); }else{ usage(argv[0]); ret = EXIT_FAILURE; } /* release the pid file */ unlink(pid_file); return ret;}intstart_addr6(struct in6_addr* addr6, int prefix_len){ /* First, we need to find a proper device to assign the address */ int i; char* if_name = find_if(addr6, &prefix_len); if (NULL == if_name) { cl_log(LOG_ERR, "no valid mecahnisms"); return LSB_EXIT_GENERIC; } /* Assign the address */ if (0 != assign_addr6(addr6, prefix_len, if_name)) { cl_log(LOG_ERR, "failed to assign the address to %s", if_name); return LSB_EXIT_GENERIC; } /* Check whether the address available */ for (i = 0; i < QUERY_COUNT; i++) { if (0 == is_addr6_available(addr6)) { break; } sleep(1); } if (i == QUERY_COUNT) { cl_log(LOG_ERR, "failed to ping the address"); return LSB_EXIT_GENERIC; } /* Send unsolicited advertisement packet to neighbor */ for (i = 0; i < UA_REPEAT_COUNT; i++) { send_ua(addr6, if_name); sleep(1); } return LSB_EXIT_OK;}intadvt_addr6(struct in6_addr* addr6, int prefix_len){ /* First, we need to find a proper device to assign the address */ char* if_name = get_if(addr6, &prefix_len); int i; if (NULL == if_name) { cl_log(LOG_ERR, "no valid mecahnisms"); return LSB_EXIT_GENERIC; } /* Send unsolicited advertisement packet to neighbor */ for (i = 0; i < UA_REPEAT_COUNT; i++) { send_ua(addr6, if_name); sleep(1); } return LSB_STATUS_OK;} intstop_addr6(struct in6_addr* addr6, int prefix_len){ char* if_name = get_if(addr6, &prefix_len); if (NULL == if_name) { cl_log(LOG_ERR, "no valid mechanisms."); /* I think this should be a success exit according to LSB. */ return LSB_EXIT_GENERIC; } /* Unassign the address */ if (0 != unassign_addr6(addr6, prefix_len, if_name)) { cl_log(LOG_ERR, "failed to assign the address to %s", if_name); return LSB_EXIT_GENERIC; } return LSB_EXIT_OK;}intstatus_addr6(struct in6_addr* addr6, int prefix_len){ char* if_name = get_if(addr6, &prefix_len); if (NULL == if_name) { return LSB_STATUS_STOPPED; } return LSB_STATUS_OK;} intmonitor_addr6(struct in6_addr* addr6, int prefix_len){ if(0 == is_addr6_available(addr6)) { return LSB_STATUS_OK; } return LSB_STATUS_STOPPED;}/* Send an unsolicited advertisement packet * Please refer to rfc2461 */intsend_ua(struct in6_addr* src_ip, char* if_name){ libnet_t *l; char errbuf[LIBNET_ERRBUF_SIZE]; struct libnet_in6_addr dst_ip; struct libnet_ether_addr *mac_address; char payload[24]; if ((l=libnet_init(LIBNET_RAW6, if_name, errbuf)) == NULL) { cl_log(LOG_ERR, "libnet_init failure on %s", if_name); return -1; } mac_address = libnet_get_hwaddr(l); if (!mac_address) { cl_log(LOG_ERR, "libnet_get_hwaddr: %s", errbuf); return -1; } dst_ip = libnet_name2addr6(l, BCAST_ADDR, LIBNET_DONT_RESOLVE); memcpy(payload,src_ip->s6_addr,16); payload[16] = 2; /* 2 for Target Link-layer Address */ payload[17] = 1; /* The length of the option */ memcpy(payload+18,mac_address->ether_addr_octet, 6); libnet_seed_prand(l); /* 0x2000: RSO */ libnet_build_icmpv4_echo(136,0,0,0x2000,0,(unsigned char*)payload,sizeof(payload), l,LIBNET_PTAG_INITIALIZER); libnet_build_ipv6(0,0,LIBNET_ICMPV6_H + sizeof(payload),IPPROTO_ICMP6, 255,*(struct libnet_in6_addr*)src_ip, dst_ip,NULL,0,l,0); if (libnet_write(l) == -1) { cl_log(LOG_ERR, "libnet_write: %s", libnet_geterror(l)); return -1; } return 0;}/* find a proper network interface to assign the address */char*find_if(struct in6_addr* addr_target, int* plen_target){ FILE *f; char addr6[40]; static char devname[20]=""; struct in6_addr addr; struct in6_addr mask; int plen; int scope; int dad_status; int if_idx; char addr6p[8][5]; /* open /proc/net/if_inet6 file */ if ((f = fopen(IF_INET6, "r")) == NULL) { return NULL; } /* Loop for each entry */ while ( fscanf(f,"%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF){ int i; int n; int s; gboolean same = TRUE; sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -