1ae326725SJun-ichiro itojun Hagino /* $FreeBSD$ */ 2fa19f9beSHajimu UMEMOTO /* $KAME: rrenum.c,v 1.12 2002/06/10 19:59:47 itojun Exp $ */ 3b26e03e9SKris Kennaway 49a4365d0SYoshinobu Inoue /* 59a4365d0SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 69a4365d0SYoshinobu Inoue * All rights reserved. 79a4365d0SYoshinobu Inoue * 89a4365d0SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 99a4365d0SYoshinobu Inoue * modification, are permitted provided that the following conditions 109a4365d0SYoshinobu Inoue * are met: 119a4365d0SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 129a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 139a4365d0SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 149a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 159a4365d0SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 169a4365d0SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 179a4365d0SYoshinobu Inoue * may be used to endorse or promote products derived from this software 189a4365d0SYoshinobu Inoue * without specific prior written permission. 199a4365d0SYoshinobu Inoue * 209a4365d0SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 219a4365d0SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 229a4365d0SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 239a4365d0SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 249a4365d0SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 259a4365d0SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 269a4365d0SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 279a4365d0SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 289a4365d0SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 299a4365d0SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 309a4365d0SYoshinobu Inoue * SUCH DAMAGE. 319a4365d0SYoshinobu Inoue */ 3233841545SHajimu UMEMOTO #include <sys/types.h> 339a4365d0SYoshinobu Inoue #include <sys/param.h> 349a4365d0SYoshinobu Inoue #include <sys/ioctl.h> 359a4365d0SYoshinobu Inoue #include <sys/socket.h> 369a4365d0SYoshinobu Inoue #include <sys/sysctl.h> 379a4365d0SYoshinobu Inoue 389a4365d0SYoshinobu Inoue #include <net/if.h> 3937241896SHiroki Sato #include <net/if_dl.h> 409a4365d0SYoshinobu Inoue #include <net/if_var.h> 419a4365d0SYoshinobu Inoue #include <net/route.h> 429a4365d0SYoshinobu Inoue #include <netinet/in.h> 439a4365d0SYoshinobu Inoue #include <netinet/in_var.h> 449a4365d0SYoshinobu Inoue #include <netinet/icmp6.h> 459a4365d0SYoshinobu Inoue 469a4365d0SYoshinobu Inoue #include <arpa/inet.h> 479a4365d0SYoshinobu Inoue 489a4365d0SYoshinobu Inoue #include <errno.h> 49db82af41SHiroki Sato #include <netdb.h> 509a4365d0SYoshinobu Inoue #include <string.h> 519a4365d0SYoshinobu Inoue #include <stdlib.h> 52*7d26db17SHiroki Sato #include <time.h> 539a4365d0SYoshinobu Inoue #include <syslog.h> 5433841545SHajimu UMEMOTO #include "rtadvd.h" 559a4365d0SYoshinobu Inoue #include "rrenum.h" 569a4365d0SYoshinobu Inoue #include "if.h" 579a4365d0SYoshinobu Inoue 589a4365d0SYoshinobu Inoue #define RR_ISSET_SEGNUM(segnum_bits, segnum) \ 599a4365d0SYoshinobu Inoue ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) 609a4365d0SYoshinobu Inoue #define RR_SET_SEGNUM(segnum_bits, segnum) \ 619a4365d0SYoshinobu Inoue (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) 629a4365d0SYoshinobu Inoue 639a4365d0SYoshinobu Inoue struct rr_operation { 649a4365d0SYoshinobu Inoue u_long rro_seqnum; 659a4365d0SYoshinobu Inoue u_long rro_segnum_bits[8]; 669a4365d0SYoshinobu Inoue }; 679a4365d0SYoshinobu Inoue 689a4365d0SYoshinobu Inoue static struct rr_operation rro; 699a4365d0SYoshinobu Inoue static int rr_rcvifindex; 70b26e03e9SKris Kennaway static int rrcmd2pco[RPM_PCO_MAX] = { 71b26e03e9SKris Kennaway 0, 729a4365d0SYoshinobu Inoue SIOCAIFPREFIX_IN6, 739a4365d0SYoshinobu Inoue SIOCCIFPREFIX_IN6, 749a4365d0SYoshinobu Inoue SIOCSGIFPREFIX_IN6 759a4365d0SYoshinobu Inoue }; 76b26e03e9SKris Kennaway static int s = -1; 779a4365d0SYoshinobu Inoue 789a4365d0SYoshinobu Inoue /* 799a4365d0SYoshinobu Inoue * Check validity of a Prefix Control Operation(PCO). 80db82af41SHiroki Sato * return 0 on success, 1 on failure. 819a4365d0SYoshinobu Inoue */ 829a4365d0SYoshinobu Inoue static int 839a4365d0SYoshinobu Inoue rr_pco_check(int len, struct rr_pco_match *rpm) 849a4365d0SYoshinobu Inoue { 859a4365d0SYoshinobu Inoue struct rr_pco_use *rpu, *rpulim; 869a4365d0SYoshinobu Inoue int checklen; 879a4365d0SYoshinobu Inoue 889a4365d0SYoshinobu Inoue /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ 899a4365d0SYoshinobu Inoue if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ 909a4365d0SYoshinobu Inoue (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ 919a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", 921533bed0SHajimu UMEMOTO __func__, rpm->rpm_len); 93db82af41SHiroki Sato return (1); 949a4365d0SYoshinobu Inoue } 959a4365d0SYoshinobu Inoue /* rpm->rpm_code must be valid value */ 969a4365d0SYoshinobu Inoue switch (rpm->rpm_code) { 979a4365d0SYoshinobu Inoue case RPM_PCO_ADD: 989a4365d0SYoshinobu Inoue case RPM_PCO_CHANGE: 999a4365d0SYoshinobu Inoue case RPM_PCO_SETGLOBAL: 1009a4365d0SYoshinobu Inoue break; 1019a4365d0SYoshinobu Inoue default: 1021533bed0SHajimu UMEMOTO syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__, 1039a4365d0SYoshinobu Inoue rpm->rpm_code); 104db82af41SHiroki Sato return (1); 1059a4365d0SYoshinobu Inoue } 1069a4365d0SYoshinobu Inoue /* rpm->rpm_matchlen must be 0 to 128 inclusive */ 1079a4365d0SYoshinobu Inoue if (rpm->rpm_matchlen > 128) { 1089a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", 1091533bed0SHajimu UMEMOTO __func__, rpm->rpm_matchlen); 110db82af41SHiroki Sato return (1); 1119a4365d0SYoshinobu Inoue } 1129a4365d0SYoshinobu Inoue 1139a4365d0SYoshinobu Inoue /* 1149a4365d0SYoshinobu Inoue * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be 1159a4365d0SYoshinobu Inoue * between 0 and 128 inclusive 1169a4365d0SYoshinobu Inoue */ 1179a4365d0SYoshinobu Inoue for (rpu = (struct rr_pco_use *)(rpm + 1), 1189a4365d0SYoshinobu Inoue rpulim = (struct rr_pco_use *)((char *)rpm + len); 1199a4365d0SYoshinobu Inoue rpu < rpulim; 1209a4365d0SYoshinobu Inoue rpu += 1) { 1219a4365d0SYoshinobu Inoue checklen = rpu->rpu_uselen; 1229a4365d0SYoshinobu Inoue checklen += rpu->rpu_keeplen; 1239a4365d0SYoshinobu Inoue /* 1249a4365d0SYoshinobu Inoue * omit these check, because either of rpu_uselen 1259a4365d0SYoshinobu Inoue * and rpu_keeplen is unsigned char 1269a4365d0SYoshinobu Inoue * (128 > rpu_uselen > 0) 1279a4365d0SYoshinobu Inoue * (128 > rpu_keeplen > 0) 1289a4365d0SYoshinobu Inoue * (rpu_uselen + rpu_keeplen > 0) 1299a4365d0SYoshinobu Inoue */ 1309a4365d0SYoshinobu Inoue if (checklen > 128) { 1319a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" 1329a4365d0SYoshinobu Inoue " rpu_keeplen %d is %d(over 128)", 133db82af41SHiroki Sato __func__, rpu->rpu_uselen, rpu->rpu_keeplen, 1349a4365d0SYoshinobu Inoue rpu->rpu_uselen + rpu->rpu_keeplen); 135db82af41SHiroki Sato return (1); 1369a4365d0SYoshinobu Inoue } 1379a4365d0SYoshinobu Inoue } 138db82af41SHiroki Sato return (0); 1399a4365d0SYoshinobu Inoue } 1409a4365d0SYoshinobu Inoue 1419a4365d0SYoshinobu Inoue static void 14233841545SHajimu UMEMOTO do_use_prefix(int len, struct rr_pco_match *rpm, 14333841545SHajimu UMEMOTO struct in6_rrenumreq *irr, int ifindex) 14433841545SHajimu UMEMOTO { 1459a4365d0SYoshinobu Inoue struct rr_pco_use *rpu, *rpulim; 14633841545SHajimu UMEMOTO struct rainfo *rai; 14737241896SHiroki Sato struct ifinfo *ifi; 148db82af41SHiroki Sato struct prefix *pfx; 1499a4365d0SYoshinobu Inoue 1509a4365d0SYoshinobu Inoue rpu = (struct rr_pco_use *)(rpm + 1); 1519a4365d0SYoshinobu Inoue rpulim = (struct rr_pco_use *)((char *)rpm + len); 1529a4365d0SYoshinobu Inoue 15333841545SHajimu UMEMOTO if (rpu == rpulim) { /* no use prefix */ 1549a4365d0SYoshinobu Inoue if (rpm->rpm_code == RPM_PCO_ADD) 1559a4365d0SYoshinobu Inoue return; 1569a4365d0SYoshinobu Inoue 1579a4365d0SYoshinobu Inoue irr->irr_u_uselen = 0; 1589a4365d0SYoshinobu Inoue irr->irr_u_keeplen = 0; 1599a4365d0SYoshinobu Inoue irr->irr_raf_mask_onlink = 0; 1609a4365d0SYoshinobu Inoue irr->irr_raf_mask_auto = 0; 1619a4365d0SYoshinobu Inoue irr->irr_vltime = 0; 1629a4365d0SYoshinobu Inoue irr->irr_pltime = 0; 1639a4365d0SYoshinobu Inoue memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); 1649a4365d0SYoshinobu Inoue irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ 1659a4365d0SYoshinobu Inoue irr->irr_useprefix.sin6_family = 0; 1669a4365d0SYoshinobu Inoue irr->irr_useprefix.sin6_addr = in6addr_any; 1679a4365d0SYoshinobu Inoue if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 1689a4365d0SYoshinobu Inoue errno != EADDRNOTAVAIL) 1691533bed0SHajimu UMEMOTO syslog(LOG_ERR, "<%s> ioctl: %s", __func__, 1709a4365d0SYoshinobu Inoue strerror(errno)); 1719a4365d0SYoshinobu Inoue return; 1729a4365d0SYoshinobu Inoue } 1739a4365d0SYoshinobu Inoue 1749a4365d0SYoshinobu Inoue for (rpu = (struct rr_pco_use *)(rpm + 1), 1759a4365d0SYoshinobu Inoue rpulim = (struct rr_pco_use *)((char *)rpm + len); 1769a4365d0SYoshinobu Inoue rpu < rpulim; 1779a4365d0SYoshinobu Inoue rpu += 1) { 1789a4365d0SYoshinobu Inoue /* init in6_rrenumreq fields */ 1799a4365d0SYoshinobu Inoue irr->irr_u_uselen = rpu->rpu_uselen; 1809a4365d0SYoshinobu Inoue irr->irr_u_keeplen = rpu->rpu_keeplen; 1819a4365d0SYoshinobu Inoue irr->irr_raf_mask_onlink = 1826f74a8c7SWarner Losh !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 1839a4365d0SYoshinobu Inoue irr->irr_raf_mask_auto = 1846f74a8c7SWarner Losh !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 18533841545SHajimu UMEMOTO irr->irr_vltime = ntohl(rpu->rpu_vltime); 18633841545SHajimu UMEMOTO irr->irr_pltime = ntohl(rpu->rpu_pltime); 1879a4365d0SYoshinobu Inoue irr->irr_raf_onlink = 188db82af41SHiroki Sato (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 189db82af41SHiroki Sato 0 : 1; 1909a4365d0SYoshinobu Inoue irr->irr_raf_auto = 191db82af41SHiroki Sato (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 192db82af41SHiroki Sato 0 : 1; 1939a4365d0SYoshinobu Inoue irr->irr_rrf_decrvalid = 194db82af41SHiroki Sato (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 195db82af41SHiroki Sato 0 : 1; 1969a4365d0SYoshinobu Inoue irr->irr_rrf_decrprefd = 197db82af41SHiroki Sato (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 198db82af41SHiroki Sato 0 : 1; 1999a4365d0SYoshinobu Inoue irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); 2009a4365d0SYoshinobu Inoue irr->irr_useprefix.sin6_family = AF_INET6; 2019a4365d0SYoshinobu Inoue irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; 2029a4365d0SYoshinobu Inoue 2039a4365d0SYoshinobu Inoue if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 2049a4365d0SYoshinobu Inoue errno != EADDRNOTAVAIL) 2051533bed0SHajimu UMEMOTO syslog(LOG_ERR, "<%s> ioctl: %s", __func__, 2069a4365d0SYoshinobu Inoue strerror(errno)); 20733841545SHajimu UMEMOTO 20833841545SHajimu UMEMOTO /* very adhoc: should be rewritten */ 20933841545SHajimu UMEMOTO if (rpm->rpm_code == RPM_PCO_CHANGE && 21033841545SHajimu UMEMOTO IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) && 21133841545SHajimu UMEMOTO rpm->rpm_matchlen == rpu->rpu_uselen && 21233841545SHajimu UMEMOTO rpu->rpu_uselen == rpu->rpu_keeplen) { 21337241896SHiroki Sato ifi = if_indextoifinfo(ifindex); 21437241896SHiroki Sato if (ifi == NULL || ifi->ifi_rainfo == NULL) 21533841545SHajimu UMEMOTO continue; /* non-advertising IF */ 21637241896SHiroki Sato rai = ifi->ifi_rainfo; 21733841545SHajimu UMEMOTO 218db82af41SHiroki Sato TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { 219*7d26db17SHiroki Sato struct timespec now; 22033841545SHajimu UMEMOTO 221db82af41SHiroki Sato if (prefix_match(&pfx->pfx_prefix, 222db82af41SHiroki Sato pfx->pfx_prefixlen, &rpm->rpm_prefix, 22333841545SHajimu UMEMOTO rpm->rpm_matchlen)) { 22433841545SHajimu UMEMOTO /* change parameters */ 225db82af41SHiroki Sato pfx->pfx_validlifetime = 226db82af41SHiroki Sato ntohl(rpu->rpu_vltime); 227db82af41SHiroki Sato pfx->pfx_preflifetime = 228db82af41SHiroki Sato ntohl(rpu->rpu_pltime); 22933841545SHajimu UMEMOTO if (irr->irr_rrf_decrvalid) { 230*7d26db17SHiroki Sato clock_gettime(CLOCK_MONOTONIC_FAST, 231*7d26db17SHiroki Sato &now); 232db82af41SHiroki Sato pfx->pfx_vltimeexpire = 233db82af41SHiroki Sato now.tv_sec + 234db82af41SHiroki Sato pfx->pfx_validlifetime; 23533841545SHajimu UMEMOTO } else 236db82af41SHiroki Sato pfx->pfx_vltimeexpire = 0; 23733841545SHajimu UMEMOTO if (irr->irr_rrf_decrprefd) { 238*7d26db17SHiroki Sato clock_gettime(CLOCK_MONOTONIC_FAST, 239*7d26db17SHiroki Sato &now); 240db82af41SHiroki Sato pfx->pfx_pltimeexpire = 241db82af41SHiroki Sato now.tv_sec + 242db82af41SHiroki Sato pfx->pfx_preflifetime; 24333841545SHajimu UMEMOTO } else 244db82af41SHiroki Sato pfx->pfx_pltimeexpire = 0; 24533841545SHajimu UMEMOTO } 24633841545SHajimu UMEMOTO } 24733841545SHajimu UMEMOTO } 2489a4365d0SYoshinobu Inoue } 2499a4365d0SYoshinobu Inoue } 2509a4365d0SYoshinobu Inoue 2519a4365d0SYoshinobu Inoue /* 2529a4365d0SYoshinobu Inoue * process a Prefix Control Operation(PCO). 2539a4365d0SYoshinobu Inoue * return 0 on success, 1 on failure 2549a4365d0SYoshinobu Inoue */ 2559a4365d0SYoshinobu Inoue static int 2569a4365d0SYoshinobu Inoue do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) 2579a4365d0SYoshinobu Inoue { 2589a4365d0SYoshinobu Inoue int ifindex = 0; 2599a4365d0SYoshinobu Inoue struct in6_rrenumreq irr; 26037241896SHiroki Sato struct ifinfo *ifi; 2619a4365d0SYoshinobu Inoue 262c88f8102SBruce Evans if ((rr_pco_check(len, rpm) != 0)) 263db82af41SHiroki Sato return (1); 2649a4365d0SYoshinobu Inoue 265b26e03e9SKris Kennaway if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 2661533bed0SHajimu UMEMOTO syslog(LOG_ERR, "<%s> socket: %s", __func__, 267b26e03e9SKris Kennaway strerror(errno)); 268b26e03e9SKris Kennaway exit(1); 269b26e03e9SKris Kennaway } 270b26e03e9SKris Kennaway 2719a4365d0SYoshinobu Inoue memset(&irr, 0, sizeof(irr)); 2729a4365d0SYoshinobu Inoue irr.irr_origin = PR_ORIG_RR; 2739a4365d0SYoshinobu Inoue irr.irr_m_len = rpm->rpm_matchlen; 2749a4365d0SYoshinobu Inoue irr.irr_m_minlen = rpm->rpm_minlen; 2759a4365d0SYoshinobu Inoue irr.irr_m_maxlen = rpm->rpm_maxlen; 2769a4365d0SYoshinobu Inoue irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); 2779a4365d0SYoshinobu Inoue irr.irr_matchprefix.sin6_family = AF_INET6; 2789a4365d0SYoshinobu Inoue irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; 2799a4365d0SYoshinobu Inoue 2809a4365d0SYoshinobu Inoue while (if_indextoname(++ifindex, irr.irr_name)) { 28137241896SHiroki Sato ifi = if_indextoifinfo(ifindex); 28237241896SHiroki Sato if (ifi == NULL) { 28337241896SHiroki Sato syslog(LOG_ERR, "<%s> ifindex not found.", 28437241896SHiroki Sato __func__); 28537241896SHiroki Sato return (1); 28637241896SHiroki Sato } 2879a4365d0SYoshinobu Inoue /* 288db82af41SHiroki Sato * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and 289db82af41SHiroki Sato * IFF_UP is off, the interface is not applied 2909a4365d0SYoshinobu Inoue */ 2919a4365d0SYoshinobu Inoue if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && 29237241896SHiroki Sato (ifi->ifi_flags & IFF_UP) == 0) 2939a4365d0SYoshinobu Inoue continue; 2949a4365d0SYoshinobu Inoue /* TODO: interface scope check */ 29533841545SHajimu UMEMOTO do_use_prefix(len, rpm, &irr, ifindex); 2969a4365d0SYoshinobu Inoue } 2979a4365d0SYoshinobu Inoue if (errno == ENXIO) 298db82af41SHiroki Sato return (0); 2999a4365d0SYoshinobu Inoue else if (errno) { 3001533bed0SHajimu UMEMOTO syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__, 3019a4365d0SYoshinobu Inoue strerror(errno)); 302db82af41SHiroki Sato return (1); 3039a4365d0SYoshinobu Inoue } 304db82af41SHiroki Sato return (0); 3059a4365d0SYoshinobu Inoue } 3069a4365d0SYoshinobu Inoue 3079a4365d0SYoshinobu Inoue /* 3089a4365d0SYoshinobu Inoue * call do_pco() for each Prefix Control Operations(PCOs) in a received 3099a4365d0SYoshinobu Inoue * Router Renumbering Command packet. 3109a4365d0SYoshinobu Inoue * return 0 on success, 1 on failure 3119a4365d0SYoshinobu Inoue */ 3129a4365d0SYoshinobu Inoue static int 3139a4365d0SYoshinobu Inoue do_rr(int len, struct icmp6_router_renum *rr) 3149a4365d0SYoshinobu Inoue { 3159a4365d0SYoshinobu Inoue struct rr_pco_match *rpm; 3169a4365d0SYoshinobu Inoue char *cp, *lim; 3179a4365d0SYoshinobu Inoue 3189a4365d0SYoshinobu Inoue lim = (char *)rr + len; 3199a4365d0SYoshinobu Inoue cp = (char *)(rr + 1); 3209a4365d0SYoshinobu Inoue len -= sizeof(struct icmp6_router_renum); 3219a4365d0SYoshinobu Inoue 32237241896SHiroki Sato update_ifinfo(&ifilist, UPDATE_IFINFO_ALL); 3239a4365d0SYoshinobu Inoue 3249a4365d0SYoshinobu Inoue while (cp < lim) { 3259a4365d0SYoshinobu Inoue int rpmlen; 3269a4365d0SYoshinobu Inoue 3279a4365d0SYoshinobu Inoue rpm = (struct rr_pco_match *)cp; 328db82af41SHiroki Sato if ((size_t)len < sizeof(struct rr_pco_match)) { 3299a4365d0SYoshinobu Inoue tooshort: 3309a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " 331a32ae730SEitan Adler "garbage at end of pkt?", __func__, len); 332db82af41SHiroki Sato return (1); 3339a4365d0SYoshinobu Inoue } 3349a4365d0SYoshinobu Inoue rpmlen = rpm->rpm_len << 3; 3359a4365d0SYoshinobu Inoue if (len < rpmlen) 3369a4365d0SYoshinobu Inoue goto tooshort; 3379a4365d0SYoshinobu Inoue 3389a4365d0SYoshinobu Inoue if (do_pco(rr, rpmlen, rpm)) { 3391533bed0SHajimu UMEMOTO syslog(LOG_WARNING, "<%s> invalid PCO", __func__); 3409a4365d0SYoshinobu Inoue goto next; 3419a4365d0SYoshinobu Inoue } 3429a4365d0SYoshinobu Inoue 3439a4365d0SYoshinobu Inoue next: 3449a4365d0SYoshinobu Inoue cp += rpmlen; 3459a4365d0SYoshinobu Inoue len -= rpmlen; 3469a4365d0SYoshinobu Inoue } 347b26e03e9SKris Kennaway 348db82af41SHiroki Sato return (0); 3499a4365d0SYoshinobu Inoue } 3509a4365d0SYoshinobu Inoue 3519a4365d0SYoshinobu Inoue /* 3529a4365d0SYoshinobu Inoue * check validity of a router renumbering command packet 3539a4365d0SYoshinobu Inoue * return 0 on success, 1 on failure 3549a4365d0SYoshinobu Inoue */ 3559a4365d0SYoshinobu Inoue static int 3569a4365d0SYoshinobu Inoue rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, 3579a4365d0SYoshinobu Inoue struct in6_addr *dst) 3589a4365d0SYoshinobu Inoue { 3599a4365d0SYoshinobu Inoue u_char ntopbuf[INET6_ADDRSTRLEN]; 3609a4365d0SYoshinobu Inoue 3619a4365d0SYoshinobu Inoue /* omit rr minimal length check. hope kernel have done it. */ 3629a4365d0SYoshinobu Inoue /* rr_command length check */ 363db82af41SHiroki Sato if ((size_t)len < (sizeof(struct icmp6_router_renum) + 3649a4365d0SYoshinobu Inoue sizeof(struct rr_pco_match))) { 3659a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> rr_command len %d is too short", 3661533bed0SHajimu UMEMOTO __func__, len); 367db82af41SHiroki Sato return (1); 3689a4365d0SYoshinobu Inoue } 3699a4365d0SYoshinobu Inoue 3709a4365d0SYoshinobu Inoue /* destination check. only for multicast. omit unicast check. */ 3719a4365d0SYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && 3729a4365d0SYoshinobu Inoue !IN6_IS_ADDR_MC_SITELOCAL(dst)) { 3739a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", 3741533bed0SHajimu UMEMOTO __func__, 375db82af41SHiroki Sato inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf))); 376db82af41SHiroki Sato return (1); 3779a4365d0SYoshinobu Inoue } 3789a4365d0SYoshinobu Inoue 3799a4365d0SYoshinobu Inoue /* seqnum and segnum check */ 3809a4365d0SYoshinobu Inoue if (rro.rro_seqnum > rr->rr_seqnum) { 3819a4365d0SYoshinobu Inoue syslog(LOG_WARNING, 3829a4365d0SYoshinobu Inoue "<%s> rcvd old seqnum %d from %s", 3831533bed0SHajimu UMEMOTO __func__, (u_int32_t)ntohl(rr->rr_seqnum), 384db82af41SHiroki Sato inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf))); 385db82af41SHiroki Sato return (1); 3869a4365d0SYoshinobu Inoue } 3879a4365d0SYoshinobu Inoue if (rro.rro_seqnum == rr->rr_seqnum && 3889a4365d0SYoshinobu Inoue (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && 3899a4365d0SYoshinobu Inoue RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { 3909a4365d0SYoshinobu Inoue if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) 3919a4365d0SYoshinobu Inoue syslog(LOG_WARNING, 3929a4365d0SYoshinobu Inoue "<%s> rcvd duped segnum %d from %s", 393db82af41SHiroki Sato __func__, rr->rr_segnum, inet_ntop(AF_INET6, from, 394db82af41SHiroki Sato ntopbuf, sizeof(ntopbuf))); 395db82af41SHiroki Sato return (0); 3969a4365d0SYoshinobu Inoue } 3979a4365d0SYoshinobu Inoue 3989a4365d0SYoshinobu Inoue /* update seqnum */ 3999a4365d0SYoshinobu Inoue if (rro.rro_seqnum != rr->rr_seqnum) { 4009a4365d0SYoshinobu Inoue /* then must be "<" */ 4019a4365d0SYoshinobu Inoue 4029a4365d0SYoshinobu Inoue /* init rro_segnum_bits */ 4039a4365d0SYoshinobu Inoue memset(rro.rro_segnum_bits, 0, 4049a4365d0SYoshinobu Inoue sizeof(rro.rro_segnum_bits)); 4059a4365d0SYoshinobu Inoue } 4069a4365d0SYoshinobu Inoue rro.rro_seqnum = rr->rr_seqnum; 4079a4365d0SYoshinobu Inoue 408db82af41SHiroki Sato return (0); 4099a4365d0SYoshinobu Inoue } 4109a4365d0SYoshinobu Inoue 4119a4365d0SYoshinobu Inoue static void 4129a4365d0SYoshinobu Inoue rr_command_input(int len, struct icmp6_router_renum *rr, 4139a4365d0SYoshinobu Inoue struct in6_addr *from, struct in6_addr *dst) 4149a4365d0SYoshinobu Inoue { 4159a4365d0SYoshinobu Inoue /* rr_command validity check */ 4169a4365d0SYoshinobu Inoue if (rr_command_check(len, rr, from, dst)) 4179a4365d0SYoshinobu Inoue goto failed; 4189a4365d0SYoshinobu Inoue if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == 4199a4365d0SYoshinobu Inoue ICMP6_RR_FLAGS_TEST) 4209a4365d0SYoshinobu Inoue return; 4219a4365d0SYoshinobu Inoue 4229a4365d0SYoshinobu Inoue /* do router renumbering */ 423db82af41SHiroki Sato if (do_rr(len, rr)) 4249a4365d0SYoshinobu Inoue goto failed; 4259a4365d0SYoshinobu Inoue 4269a4365d0SYoshinobu Inoue /* update segnum */ 4279a4365d0SYoshinobu Inoue RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); 4289a4365d0SYoshinobu Inoue 4299a4365d0SYoshinobu Inoue return; 4309a4365d0SYoshinobu Inoue 4319a4365d0SYoshinobu Inoue failed: 4321533bed0SHajimu UMEMOTO syslog(LOG_ERR, "<%s> received RR was invalid", __func__); 4339a4365d0SYoshinobu Inoue return; 4349a4365d0SYoshinobu Inoue } 4359a4365d0SYoshinobu Inoue 4369a4365d0SYoshinobu Inoue void 4379a4365d0SYoshinobu Inoue rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, 4389a4365d0SYoshinobu Inoue struct sockaddr_in6 *from, struct in6_addr *dst) 4399a4365d0SYoshinobu Inoue { 4409a4365d0SYoshinobu Inoue u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 4419a4365d0SYoshinobu Inoue 4429a4365d0SYoshinobu Inoue syslog(LOG_DEBUG, 4439a4365d0SYoshinobu Inoue "<%s> RR received from %s to %s on %s", 4441533bed0SHajimu UMEMOTO __func__, 445db82af41SHiroki Sato inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])), 446db82af41SHiroki Sato inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), 4479a4365d0SYoshinobu Inoue if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 4489a4365d0SYoshinobu Inoue 44933841545SHajimu UMEMOTO /* packet validation based on Section 4.1 of RFC2894 */ 450db82af41SHiroki Sato if ((size_t)len < sizeof(struct icmp6_router_renum)) { 45133841545SHajimu UMEMOTO syslog(LOG_NOTICE, 45233841545SHajimu UMEMOTO "<%s>: RR short message (size %d) from %s to %s on %s", 4531533bed0SHajimu UMEMOTO __func__, len, 454db82af41SHiroki Sato inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0], 455db82af41SHiroki Sato sizeof(ntopbuf[0])), 456db82af41SHiroki Sato inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])), 45733841545SHajimu UMEMOTO if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 45833841545SHajimu UMEMOTO return; 45933841545SHajimu UMEMOTO } 4609a4365d0SYoshinobu Inoue 46133841545SHajimu UMEMOTO /* 46233841545SHajimu UMEMOTO * If the IPv6 destination address is neither an All Routers multicast 46333841545SHajimu UMEMOTO * address [AARCH] nor one of the receiving router's unicast addresses, 46433841545SHajimu UMEMOTO * the message MUST be discarded and SHOULD be logged to network 46533841545SHajimu UMEMOTO * management. 46633841545SHajimu UMEMOTO * We rely on the kernel input routine for unicast addresses, and thus 46733841545SHajimu UMEMOTO * check multicast destinations only. 46833841545SHajimu UMEMOTO */ 469db82af41SHiroki Sato if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL( 470db82af41SHiroki Sato &sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) { 47133841545SHajimu UMEMOTO syslog(LOG_NOTICE, 47233841545SHajimu UMEMOTO "<%s>: RR message with invalid destination (%s) " 47333841545SHajimu UMEMOTO "from %s on %s", 4741533bed0SHajimu UMEMOTO __func__, 475db82af41SHiroki Sato inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])), 476db82af41SHiroki Sato inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1], 477db82af41SHiroki Sato sizeof(ntopbuf[1])), 47833841545SHajimu UMEMOTO if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 47933841545SHajimu UMEMOTO return; 48033841545SHajimu UMEMOTO } 48133841545SHajimu UMEMOTO 48233841545SHajimu UMEMOTO rr_rcvifindex = pi->ipi6_ifindex; 4839a4365d0SYoshinobu Inoue 4849a4365d0SYoshinobu Inoue switch (rr->rr_code) { 4859a4365d0SYoshinobu Inoue case ICMP6_ROUTER_RENUMBERING_COMMAND: 4869a4365d0SYoshinobu Inoue rr_command_input(len, rr, &from->sin6_addr, dst); 4879a4365d0SYoshinobu Inoue /* TODO: send reply msg */ 4889a4365d0SYoshinobu Inoue break; 4899a4365d0SYoshinobu Inoue case ICMP6_ROUTER_RENUMBERING_RESULT: 4909a4365d0SYoshinobu Inoue /* RESULT will be processed by rrenumd */ 4919a4365d0SYoshinobu Inoue break; 4929a4365d0SYoshinobu Inoue case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 4939a4365d0SYoshinobu Inoue /* TODO: sequence number reset */ 4949a4365d0SYoshinobu Inoue break; 4959a4365d0SYoshinobu Inoue default: 4969a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> received unknown code %d", 4971533bed0SHajimu UMEMOTO __func__, rr->rr_code); 4989a4365d0SYoshinobu Inoue break; 4999a4365d0SYoshinobu Inoue 5009a4365d0SYoshinobu Inoue } 5019a4365d0SYoshinobu Inoue 5029a4365d0SYoshinobu Inoue return; 5039a4365d0SYoshinobu Inoue } 504