📄 common.c
字号:
/* $Id: common.c,v 1.19 2004/02/04 23:30:17 shemminger Exp $ *//* ported from KAME: common.c,v 1.65 2002/12/06 01:41:29 suz Exp *//* * Copyright (C) 1998 and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include <sys/types.h>#include <sys/socket.h>#include <linux/sockios.h>#include <sys/ioctl.h>#if TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include <net/if.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <net/if_arp.h>#include <netinet/in.h>#include <errno.h>#include <limits.h>#include <stdio.h>#include <stdarg.h>#include <syslog.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <err.h>#include <netdb.h>#include <ifaddrs.h>#include <resolv.h>#ifdef HAVE_GETIFADDRS # ifdef HAVE_IFADDRS_H# define USE_GETIFADDRS# include <ifaddrs.h># endif#endif#include "queue.h"#include "dhcp6.h"#include "config.h"#include "common.h"#include "timer.h"#include "lease.h"int foreground;int debug_thresh;struct dhcp6_if *dhcp6_if;struct dns_list dnslist;static struct host_conf *host_conflist;static int in6_matchflags __P((struct sockaddr *, char *, int));ssize_t gethwid __P((char *, int, const char *, u_int16_t *));static int get_assigned_ipv6addrs __P((char *, char *, struct dhcp6_optinfo *));struct dhcp6_if *find_ifconfbyname(const char *ifname){ struct dhcp6_if *ifp; for (ifp = dhcp6_if; ifp; ifp = ifp->next) { if (strcmp(ifp->ifname, ifname) == 0) return (ifp); } return (NULL);}struct dhcp6_if *find_ifconfbyid(unsigned int id){ struct dhcp6_if *ifp; for (ifp = dhcp6_if; ifp; ifp = ifp->next) { if (ifp->ifid == id) return (ifp); } return (NULL);}struct host_conf *find_hostconf(const struct duid *duid){ struct host_conf *host; for (host = host_conflist; host; host = host->next) { if (host->duid.duid_len == duid->duid_len && memcmp(host->duid.duid_id, duid->duid_id, host->duid.duid_len) == 0) { return (host); } } return (NULL);}voidifinit(const char *ifname){ struct dhcp6_if *ifp; if ((ifp = find_ifconfbyname(ifname)) != NULL) { dprintf(LOG_NOTICE, "%s" "duplicated interface: %s", FNAME, ifname); return; } if ((ifp = malloc(sizeof(*ifp))) == NULL) { dprintf(LOG_ERR, "%s" "malloc failed", FNAME); goto die; } memset(ifp, 0, sizeof(*ifp)); TAILQ_INIT(&ifp->event_list); if ((ifp->ifname = strdup(ifname)) == NULL) { dprintf(LOG_ERR, "%s" "failed to copy ifname", FNAME); goto die; } if ((ifp->ifid = if_nametoindex(ifname)) == 0) { dprintf(LOG_ERR, "%s" "invalid interface(%s): %s", FNAME, ifname, strerror(errno)); goto die; }#ifdef HAVE_SCOPELIB if (inet_zoneid(AF_INET6, 2, ifname, &ifp->linkid)) { dprintf(LOG_ERR, "%s" "failed to get link ID for %s", FNAME, ifname); goto die; }#else ifp->linkid = ifp->ifid; /* XXX */#endif if (get_linklocal(ifname, &ifp->linklocal) < 0) goto die; ifp->next = dhcp6_if; dhcp6_if = ifp; return; die: exit(1);}intdhcp6_copy_list(struct dhcp6_list *dst, const struct dhcp6_list *src){ const struct dhcp6_listval *ent; struct dhcp6_listval *dent; for (ent = TAILQ_FIRST(src); ent; ent = TAILQ_NEXT(ent, link)) { if ((dent = malloc(sizeof(*dent))) == NULL) goto fail; memset(dent, 0, sizeof(*dent)); memcpy(&dent->uv, &ent->uv, sizeof(ent->uv)); TAILQ_INSERT_TAIL(dst, dent, link); } return 0; fail: dhcp6_clear_list(dst); return -1;}voiddhcp6_clear_list(head) struct dhcp6_list *head;{ struct dhcp6_listval *v; while ((v = TAILQ_FIRST(head)) != NULL) { TAILQ_REMOVE(head, v, link); free(v); } return;}intdhcp6_count_list(head) struct dhcp6_list *head;{ struct dhcp6_listval *v; int i; for (i = 0, v = TAILQ_FIRST(head); v; v = TAILQ_NEXT(v, link)) i++; return i;}struct dhcp6_listval *dhcp6_find_listval(head, val, type) struct dhcp6_list *head; void *val; dhcp6_listval_type_t type;{ struct dhcp6_listval *lv; for (lv = TAILQ_FIRST(head); lv; lv = TAILQ_NEXT(lv, link)) { switch(type) { case DHCP6_LISTVAL_NUM: if (lv->val_num == *(int *)val) return (lv); break; case DHCP6_LISTVAL_ADDR6: if (IN6_ARE_ADDR_EQUAL(&lv->val_addr6, (struct in6_addr *)val)) { return (lv); } break; case DHCP6_LISTVAL_DHCP6ADDR: if (IN6_ARE_ADDR_EQUAL(&lv->val_dhcp6addr.addr, &((struct dhcp6_addr *)val)->addr) && (lv->val_dhcp6addr.plen == ((struct dhcp6_addr *)val)->plen)) { return (lv); } break; } } return (NULL);}struct dhcp6_listval *dhcp6_add_listval(head, val, type) struct dhcp6_list *head; void *val; dhcp6_listval_type_t type;{ struct dhcp6_listval *lv; if ((lv = malloc(sizeof(*lv))) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate memory for list " "entry", FNAME); return (NULL); } memset(lv, 0, sizeof(*lv)); switch(type) { case DHCP6_LISTVAL_NUM: lv->val_num = *(int *)val; break; case DHCP6_LISTVAL_ADDR6: lv->val_addr6 = *(struct in6_addr *)val; break; case DHCP6_LISTVAL_DHCP6ADDR: lv->val_dhcp6addr = *(struct dhcp6_addr *)val; break; default: dprintf(LOG_ERR, "%s" "unexpected list value type (%d)", FNAME, type); return (NULL); } TAILQ_INSERT_TAIL(head, lv, link); return (lv);}struct dhcp6_event *dhcp6_create_event(ifp, state) struct dhcp6_if *ifp; int state;{ struct dhcp6_event *ev; if ((ev = malloc(sizeof(*ev))) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate memory for an event", FNAME); return (NULL); } /* for safety */ memset(ev, 0, sizeof(*ev)); ev->serverid.duid_id = NULL; ev->ifp = ifp; ev->state = state; TAILQ_INIT(&ev->data_list); dprintf(LOG_DEBUG, "%s" "create an event %p xid %d for state %d", FNAME, ev, ev->xid, ev->state); return (ev);}voiddhcp6_remove_event(ev) struct dhcp6_event *ev;{ dprintf(LOG_DEBUG, "%s" "removing an event %p on %s, state=%d, xid=%x", FNAME, ev, ev->ifp->ifname, ev->state, ev->xid); if (!TAILQ_EMPTY(&ev->data_list)) { dprintf(LOG_ERR, "%s" "assumption failure: " "event data list is not empty", FNAME); exit(1); } if (ev->serverid.duid_id != NULL) duidfree(&ev->serverid); if (ev->timer) dhcp6_remove_timer(ev->timer); TAILQ_REMOVE(&ev->ifp->event_list, ev, link); free(ev); /* XXX: for safety */ ev = NULL;}intgetifaddr(addr, ifnam, prefix, plen, strong, ignoreflags) struct in6_addr *addr; char *ifnam; struct in6_addr *prefix; int plen; int strong; /* if strong host model is required or not */ int ignoreflags;{ struct ifaddrs *ifap, *ifa; struct sockaddr_in6 sin6; int error = -1; if (getifaddrs(&ifap) != 0) { err(1, "getifaddr: getifaddrs"); /*NOTREACHED*/ } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { int s1, s2; if (strong && strcmp(ifnam, ifa->ifa_name) != 0) continue; /* in any case, ignore interfaces in different scope zones. */ if ((s1 = in6_addrscopebyif(prefix, ifnam)) < 0 || (s2 = in6_addrscopebyif(prefix, ifa->ifa_name)) < 0 || s1 != s2) continue; if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (sizeof(*(ifa->ifa_addr)) > sizeof(sin6)) continue; if (in6_matchflags(ifa->ifa_addr, ifa->ifa_name, ignoreflags)) continue; memcpy(&sin6, ifa->ifa_addr, sizeof(sin6));#ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { sin6.sin6_addr.s6_addr[2] = 0; sin6.sin6_addr.s6_addr[3] = 0; }#endif if (plen % 8 == 0) { if (memcmp(&sin6.sin6_addr, prefix, plen / 8) != 0) continue; } else { struct in6_addr a, m; int i; memcpy(&a, &sin6.sin6_addr, sizeof(a)); memset(&m, 0, sizeof(m)); memset(&m, 0xff, plen / 8); m.s6_addr[plen / 8] = (0xff00 >> (plen % 8)) & 0xff; for (i = 0; i < sizeof(a); i++) a.s6_addr[i] &= m.s6_addr[i]; if (memcmp(&a, prefix, plen / 8) != 0 || a.s6_addr[plen / 8] != (prefix->s6_addr[plen / 8] & m.s6_addr[plen / 8])) continue; } memcpy(addr, &sin6.sin6_addr, sizeof(*addr));#ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(addr)) addr->s6_addr[2] = addr->s6_addr[3] = 0; #endif error = 0; break; } freeifaddrs(ifap); return (error);}intin6_addrscopebyif(addr, ifnam) struct in6_addr *addr; char *ifnam;{ u_int ifindex; if ((ifindex = if_nametoindex(ifnam)) == 0) return (-1); if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) return (ifindex); if (IN6_IS_ADDR_SITELOCAL(addr) || IN6_IS_ADDR_MC_SITELOCAL(addr)) return (1); /* XXX */ if (IN6_IS_ADDR_MC_ORGLOCAL(addr)) return (1); /* XXX */ return (1); /* treat it as global */}/* XXX: this code assumes getifaddrs(3) */const char *getdev(addr) struct sockaddr_in6 *addr;{ struct ifaddrs *ifap, *ifa; struct sockaddr_in6 *a6; static char ret_ifname[IFNAMSIZ]; if (getifaddrs(&ifap) != 0) { err(1, "getdev: getifaddrs"); /* NOTREACHED */ } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; a6 = (struct sockaddr_in6 *)ifa->ifa_addr; if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &addr->sin6_addr) || a6->sin6_scope_id != addr->sin6_scope_id) continue; break; } if (ifa) strlcpy(ret_ifname, ifa->ifa_name, sizeof(ret_ifname)); freeifaddrs(ifap); return (ifa ? ret_ifname : NULL);}inttransmit_sa(s, sa, buf, len) int s; struct sockaddr_in6 *sa; char *buf; size_t len;{ int error; error = sendto(s, buf, len, MSG_DONTROUTE, (struct sockaddr *)sa, sizeof(*sa)); return (error != len) ? -1 : 0;}longrandom_between(x, y) long x; long y;{ long ratio; ratio = 1 << 16; while ((y - x) * ratio < (y - x))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -