common.c
来自「IPv6环境下的DHCP实现」· C语言 代码 · 共 1,486 行 · 第 1/3 页
C
1,486 行
/* $KAME: common.c,v 1.63 2002/06/21 10:23:32 jinmei 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 <sys/sockio.h>#include <sys/ioctl.h>#include <sys/queue.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>#include <net/if_types.h>#if defined(__FreeBSD__) && __FreeBSD__ >= 3#include <net/if_var.h>#endif#include <net/if_dl.h>#include <net/if_arp.h>#include <netinet/in.h>#include <netinet6/in6_var.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>#ifdef HAVE_GETIFADDRS # ifdef HAVE_IFADDRS_H# define USE_GETIFADDRS# include <ifaddrs.h># endif#endif#include <dhcp6.h>#include <config.h>#include <common.h>#include <timer.h>int foreground;int debug_thresh;#if 0static unsigned int if_maxindex __P((void));#endifstatic int in6_matchflags __P((struct sockaddr *, char *, int));static ssize_t gethwid __P((char *, int, const char *, u_int16_t *));static int get_delegated_prefixes __P((char *, char *, struct dhcp6_optinfo *));intdhcp6_copy_list(dst, src) struct dhcp6_list *dst, *src;{ struct dhcp6_listval *ent, *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)) { 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_PREFIX6: if (IN6_ARE_ADDR_EQUAL(&lv->val_prefix6.addr, &((struct dhcp6_prefix *)val)->addr) && lv->val_prefix6.plen == ((struct dhcp6_prefix *)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_PREFIX6: lv->val_prefix6 = *(struct dhcp6_prefix *)val; break; default: dprintf(LOG_ERR, "%s" "unexpected list value type (%d)", FNAME, type); exit(1); } 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); } ev->ifp = ifp; ev->state = state; TAILQ_INIT(&ev->data_list); return(ev);}voiddhcp6_remove_event(ev) struct dhcp6_event *ev;{ dprintf(LOG_DEBUG, "%s" "removing an event on %s, state=%d", FNAME, ev->ifp->ifname, ev->state); if (!TAILQ_EMPTY(&ev->data_list)) { dprintf(LOG_ERR, "%s" "assumption failure: " "event data list is not empty", FNAME); exit(1); } duidfree(&ev->serverid); if (ev->timer) dhcp6_remove_timer(&ev->timer); TAILQ_REMOVE(&ev->ifp->event_list, ev, link); free(ev);}#if 0static unsigned intif_maxindex(){ struct if_nameindex *p, *p0; unsigned int max = 0; p0 = if_nameindex(); for (p = p0; p && p->if_index && p->if_name; p++) { if (max < p->if_index) max = p->if_index; } if_freenameindex(p0); return max;}#endifintgetifaddr(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 (ifa->ifa_addr->sa_len > sizeof(sin6)) continue; if (in6_matchflags(ifa->ifa_addr, ifa->ifa_name, ignoreflags)) continue; memcpy(&sin6, ifa->ifa_addr, ifa->ifa_addr->sa_len);#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(sin6.sin6_addr)); 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(sin6.sin6_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[IF_NAMESIZE]; 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 *sa; char *buf; size_t len;{ int error; error = sendto(s, buf, len, 0, sa, sa->sa_len); return (error != len) ? -1 : 0;}longrandom_between(x, y) long x; long y;{ long ratio; ratio = 1 << 16; while ((y - x) * ratio < (y - x)) ratio = ratio / 2; return x + ((y - x) * (ratio - 1) / random() & (ratio - 1));}intprefix6_mask(in6, plen) struct in6_addr *in6; int plen;{ struct sockaddr_in6 mask6; int i; if (sa6_plen2mask(&mask6, plen)) return(-1); for (i = 0; i < 16; i++) in6->s6_addr[i] &= mask6.sin6_addr.s6_addr[i]; return(0);}intsa6_plen2mask(sa6, plen) struct sockaddr_in6 *sa6; int plen;{ u_char *cp; if (plen < 0 || plen > 128) return(-1); memset(sa6, 0, sizeof(*sa6)); sa6->sin6_family = AF_INET6; sa6->sin6_len = sizeof(*sa6); for (cp = (u_char *)&sa6->sin6_addr; plen > 7; plen -= 8) *cp++ = 0xff; *cp = 0xff << (8 - plen); return(0);}char *addr2str(sa) struct sockaddr *sa;{ static char addrbuf[8][NI_MAXHOST]; static int round = 0; char *cp; round = (round + 1) & 7; cp = addrbuf[round]; getnameinfo(sa, sa->sa_len, cp, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); return(cp);}char *in6addr2str(in6, scopeid) struct in6_addr *in6; int scopeid;{ struct sockaddr_in6 sa6; memset(&sa6, 0, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_len = sizeof(sa6); sa6.sin6_addr = *in6; sa6.sin6_scope_id = scopeid; return(addr2str((struct sockaddr *)&sa6));}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?