rrenum.c revision 71333
10Sstevel@tonic-gate/* $FreeBSD: head/usr.sbin/rtadvd/rrenum.c 71333 2001-01-21 15:25:46Z itojun $ */ 20Sstevel@tonic-gate/* $KAME: rrenum.c,v 1.3 2000/05/16 13:34:14 itojun Exp $ */ 30Sstevel@tonic-gate 40Sstevel@tonic-gate/* 52522Sraf * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 62522Sraf * All rights reserved. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 90Sstevel@tonic-gate * modification, are permitted provided that the following conditions 100Sstevel@tonic-gate * are met: 110Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 120Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 130Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 140Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 150Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 160Sstevel@tonic-gate * 3. Neither the name of the project nor the names of its contributors 170Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 180Sstevel@tonic-gate * without specific prior written permission. 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 210Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222522Sraf * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 230Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 240Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 250Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 260Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 270Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 280Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 290Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 302522Sraf * SUCH DAMAGE. 312522Sraf */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate#include <sys/param.h> 340Sstevel@tonic-gate#include <sys/ioctl.h> 350Sstevel@tonic-gate#include <sys/socket.h> 360Sstevel@tonic-gate#include <sys/sysctl.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate#include <net/if.h> 390Sstevel@tonic-gate#if defined(__FreeBSD__) && __FreeBSD__ >= 3 400Sstevel@tonic-gate#include <net/if_var.h> 410Sstevel@tonic-gate#endif /* __FreeBSD__ >= 3 */ 420Sstevel@tonic-gate#include <net/route.h> 430Sstevel@tonic-gate#include <netinet/in.h> 440Sstevel@tonic-gate#include <netinet/in_var.h> 450Sstevel@tonic-gate#include <netinet/icmp6.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate#include <arpa/inet.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate#include <errno.h> 500Sstevel@tonic-gate#include <string.h> 510Sstevel@tonic-gate#include <stdlib.h> 520Sstevel@tonic-gate#include <syslog.h> 530Sstevel@tonic-gate#include "rrenum.h" 540Sstevel@tonic-gate#include "if.h" 550Sstevel@tonic-gate 560Sstevel@tonic-gate#define RR_ISSET_SEGNUM(segnum_bits, segnum) \ 570Sstevel@tonic-gate ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) 580Sstevel@tonic-gate#define RR_SET_SEGNUM(segnum_bits, segnum) \ 590Sstevel@tonic-gate (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) 600Sstevel@tonic-gate 610Sstevel@tonic-gatestruct rr_operation { 620Sstevel@tonic-gate u_long rro_seqnum; 630Sstevel@tonic-gate u_long rro_segnum_bits[8]; 640Sstevel@tonic-gate}; 650Sstevel@tonic-gate 660Sstevel@tonic-gatestatic struct rr_operation rro; 670Sstevel@tonic-gatestatic int rr_rcvifindex; 680Sstevel@tonic-gatestatic int rrcmd2pco[RPM_PCO_MAX] = { 690Sstevel@tonic-gate 0, 700Sstevel@tonic-gate SIOCAIFPREFIX_IN6, 710Sstevel@tonic-gate SIOCCIFPREFIX_IN6, 720Sstevel@tonic-gate SIOCSGIFPREFIX_IN6 730Sstevel@tonic-gate}; 740Sstevel@tonic-gatestatic int s = -1; 750Sstevel@tonic-gate 760Sstevel@tonic-gate/* 770Sstevel@tonic-gate * Check validity of a Prefix Control Operation(PCO). 780Sstevel@tonic-gate * Return 0 on success, 1 on failure. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gatestatic int 810Sstevel@tonic-gaterr_pco_check(int len, struct rr_pco_match *rpm) 820Sstevel@tonic-gate{ 830Sstevel@tonic-gate struct rr_pco_use *rpu, *rpulim; 842522Sraf int checklen; 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ 870Sstevel@tonic-gate if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ 880Sstevel@tonic-gate (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ 890Sstevel@tonic-gate syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", 900Sstevel@tonic-gate __FUNCTION__, rpm->rpm_len); 910Sstevel@tonic-gate return 1; 920Sstevel@tonic-gate } 930Sstevel@tonic-gate /* rpm->rpm_code must be valid value */ 940Sstevel@tonic-gate switch(rpm->rpm_code) { 950Sstevel@tonic-gate case RPM_PCO_ADD: 960Sstevel@tonic-gate case RPM_PCO_CHANGE: 970Sstevel@tonic-gate case RPM_PCO_SETGLOBAL: 980Sstevel@tonic-gate break; 990Sstevel@tonic-gate default: 1000Sstevel@tonic-gate syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __FUNCTION__, 1010Sstevel@tonic-gate rpm->rpm_code); 1020Sstevel@tonic-gate return 1; 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate /* rpm->rpm_matchlen must be 0 to 128 inclusive */ 1050Sstevel@tonic-gate if (rpm->rpm_matchlen > 128) { 1060Sstevel@tonic-gate syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", 1070Sstevel@tonic-gate __FUNCTION__, rpm->rpm_matchlen); 1080Sstevel@tonic-gate return 1; 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be 1130Sstevel@tonic-gate * between 0 and 128 inclusive 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate for (rpu = (struct rr_pco_use *)(rpm + 1), 1160Sstevel@tonic-gate rpulim = (struct rr_pco_use *)((char *)rpm + len); 1170Sstevel@tonic-gate rpu < rpulim; 1182522Sraf rpu += 1) { 1190Sstevel@tonic-gate checklen = rpu->rpu_uselen; 1200Sstevel@tonic-gate checklen += rpu->rpu_keeplen; 1210Sstevel@tonic-gate /* 1222522Sraf * omit these check, because either of rpu_uselen 1230Sstevel@tonic-gate * and rpu_keeplen is unsigned char 1240Sstevel@tonic-gate * (128 > rpu_uselen > 0) 1250Sstevel@tonic-gate * (128 > rpu_keeplen > 0) 1260Sstevel@tonic-gate * (rpu_uselen + rpu_keeplen > 0) 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate if (checklen > 128) { 1290Sstevel@tonic-gate syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" 1300Sstevel@tonic-gate " rpu_keeplen %d is %d(over 128)", 1310Sstevel@tonic-gate __FUNCTION__, rpu->rpu_uselen, 1320Sstevel@tonic-gate rpu->rpu_keeplen, 1330Sstevel@tonic-gate rpu->rpu_uselen + rpu->rpu_keeplen); 1340Sstevel@tonic-gate return 1; 135 } 136 } 137 return 0; 138} 139 140static void 141do_use_prefix(int len, struct rr_pco_match *rpm, struct in6_rrenumreq *irr) { 142 struct rr_pco_use *rpu, *rpulim; 143 144 rpu = (struct rr_pco_use *)(rpm + 1); 145 rpulim = (struct rr_pco_use *)((char *)rpm + len); 146 147 if (rpu == rpulim) { 148 if (rpm->rpm_code == RPM_PCO_ADD) 149 return; 150 151 irr->irr_u_uselen = 0; 152 irr->irr_u_keeplen = 0; 153 irr->irr_raf_mask_onlink = 0; 154 irr->irr_raf_mask_auto = 0; 155 irr->irr_vltime = 0; 156 irr->irr_pltime = 0; 157 memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); 158 irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ 159 irr->irr_useprefix.sin6_family = 0; 160 irr->irr_useprefix.sin6_addr = in6addr_any; 161 if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 162 errno != EADDRNOTAVAIL) 163 syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, 164 strerror(errno)); 165 return; 166 } 167 168 for (rpu = (struct rr_pco_use *)(rpm + 1), 169 rpulim = (struct rr_pco_use *)((char *)rpm + len); 170 rpu < rpulim; 171 rpu += 1) { 172 /* init in6_rrenumreq fields */ 173 irr->irr_u_uselen = rpu->rpu_uselen; 174 irr->irr_u_keeplen = rpu->rpu_keeplen; 175 irr->irr_raf_mask_onlink = 176 (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 177 irr->irr_raf_mask_auto = 178 (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 179 irr->irr_vltime = rpu->rpu_vltime; 180 irr->irr_pltime = rpu->rpu_pltime; 181 irr->irr_raf_onlink = 182 (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); 183 irr->irr_raf_auto = 184 (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); 185 irr->irr_rrf_decrvalid = 186 (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME); 187 irr->irr_rrf_decrprefd = 188 (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME); 189 irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); 190 irr->irr_useprefix.sin6_family = AF_INET6; 191 irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; 192 193 if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && 194 errno != EADDRNOTAVAIL) 195 syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, 196 strerror(errno)); 197 } 198} 199 200/* 201 * process a Prefix Control Operation(PCO). 202 * return 0 on success, 1 on failure 203 */ 204static int 205do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) 206{ 207 int ifindex = 0; 208 struct in6_rrenumreq irr; 209 210 if ((rr_pco_check(len, rpm) != NULL)) 211 return 1; 212 213 if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 214 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 215 strerror(errno)); 216 exit(1); 217 } 218 219 memset(&irr, 0, sizeof(irr)); 220 irr.irr_origin = PR_ORIG_RR; 221 irr.irr_m_len = rpm->rpm_matchlen; 222 irr.irr_m_minlen = rpm->rpm_minlen; 223 irr.irr_m_maxlen = rpm->rpm_maxlen; 224 irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); 225 irr.irr_matchprefix.sin6_family = AF_INET6; 226 irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; 227 228 while (if_indextoname(++ifindex, irr.irr_name)) { 229 /* 230 * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off, 231 * the interface is not applied 232 */ 233 if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && 234 (iflist[ifindex]->ifm_flags & IFF_UP) == 0) 235 continue; 236 /* TODO: interface scope check */ 237 do_use_prefix(len, rpm, &irr); 238 } 239 if (errno == ENXIO) 240 return 0; 241 else if (errno) { 242 syslog(LOG_ERR, "<%s> if_indextoname: %s", __FUNCTION__, 243 strerror(errno)); 244 return 1; 245 } 246 return 0; 247} 248 249/* 250 * call do_pco() for each Prefix Control Operations(PCOs) in a received 251 * Router Renumbering Command packet. 252 * return 0 on success, 1 on failure 253 */ 254static int 255do_rr(int len, struct icmp6_router_renum *rr) 256{ 257 struct rr_pco_match *rpm; 258 char *cp, *lim; 259 260 lim = (char *)rr + len; 261 cp = (char *)(rr + 1); 262 len -= sizeof(struct icmp6_router_renum); 263 264 /* get iflist block from kernel again, to get up-to-date information */ 265 init_iflist(); 266 267 while (cp < lim) { 268 int rpmlen; 269 270 rpm = (struct rr_pco_match *)cp; 271 if (len < sizeof(struct rr_pco_match)) { 272 tooshort: 273 syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " 274 "gabage at end of pkt?", __FUNCTION__, len); 275 return 1; 276 } 277 rpmlen = rpm->rpm_len << 3; 278 if (len < rpmlen) 279 goto tooshort; 280 281 if (do_pco(rr, rpmlen, rpm)) { 282 syslog(LOG_WARNING, "<%s> invalid PCO", __FUNCTION__); 283 goto next; 284 } 285 286 next: 287 cp += rpmlen; 288 len -= rpmlen; 289 } 290 291 return 0; 292} 293 294/* 295 * check validity of a router renumbering command packet 296 * return 0 on success, 1 on failure 297 */ 298static int 299rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, 300 struct in6_addr *dst) 301{ 302 u_char ntopbuf[INET6_ADDRSTRLEN]; 303 304 /* omit rr minimal length check. hope kernel have done it. */ 305 /* rr_command length check */ 306 if (len < (sizeof(struct icmp6_router_renum) + 307 sizeof(struct rr_pco_match))) { 308 syslog(LOG_ERR, "<%s> rr_command len %d is too short", 309 __FUNCTION__, len); 310 return 1; 311 } 312 313 /* destination check. only for multicast. omit unicast check. */ 314 if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && 315 !IN6_IS_ADDR_MC_SITELOCAL(dst)) { 316 syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", 317 __FUNCTION__, 318 inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); 319 return 1; 320 } 321 322 /* seqnum and segnum check */ 323 if (rro.rro_seqnum > rr->rr_seqnum) { 324 syslog(LOG_WARNING, 325 "<%s> rcvd old seqnum %d from %s", 326 __FUNCTION__, (u_int32_t)ntohl(rr->rr_seqnum), 327 inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); 328 return 1; 329 } 330 if (rro.rro_seqnum == rr->rr_seqnum && 331 (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && 332 RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { 333 if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) 334 syslog(LOG_WARNING, 335 "<%s> rcvd duped segnum %d from %s", 336 __FUNCTION__, rr->rr_segnum, 337 inet_ntop(AF_INET6, from, ntopbuf, 338 INET6_ADDRSTRLEN)); 339 return 0; 340 } 341 342 /* update seqnum */ 343 if (rro.rro_seqnum != rr->rr_seqnum) { 344 /* then must be "<" */ 345 346 /* init rro_segnum_bits */ 347 memset(rro.rro_segnum_bits, 0, 348 sizeof(rro.rro_segnum_bits)); 349 } 350 rro.rro_seqnum = rr->rr_seqnum; 351 352 return 0; 353} 354 355static void 356rr_command_input(int len, struct icmp6_router_renum *rr, 357 struct in6_addr *from, struct in6_addr *dst) 358{ 359 /* rr_command validity check */ 360 if (rr_command_check(len, rr, from, dst)) 361 goto failed; 362 if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == 363 ICMP6_RR_FLAGS_TEST) 364 return; 365 366 /* do router renumbering */ 367 if (do_rr(len, rr)) { 368 goto failed; 369 } 370 371 /* update segnum */ 372 RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); 373 374 return; 375 376 failed: 377 syslog(LOG_ERR, "<%s> received RR was invalid", __FUNCTION__); 378 return; 379} 380 381void 382rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, 383 struct sockaddr_in6 *from, struct in6_addr *dst) 384{ 385 u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 386 387 syslog(LOG_DEBUG, 388 "<%s> RR received from %s to %s on %s", 389 __FUNCTION__, 390 inet_ntop(AF_INET6, &from->sin6_addr, 391 ntopbuf[0], INET6_ADDRSTRLEN), 392 inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), 393 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 394 395 rr_rcvifindex = pi->ipi6_ifindex; 396 397 /* TODO: some consistency check. */ 398 399 switch (rr->rr_code) { 400 case ICMP6_ROUTER_RENUMBERING_COMMAND: 401 rr_command_input(len, rr, &from->sin6_addr, dst); 402 /* TODO: send reply msg */ 403 break; 404 case ICMP6_ROUTER_RENUMBERING_RESULT: 405 /* RESULT will be processed by rrenumd */ 406 break; 407 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 408 /* TODO: sequence number reset */ 409 break; 410 default: 411 syslog(LOG_ERR, "<%s> received unknown code %d", 412 __FUNCTION__, rr->rr_code); 413 break; 414 415 } 416 417 return; 418} 419