178064Sume/* $KAME: rrenumd.c,v 1.20 2000/11/08 02:40:53 itojun Exp $ */ 262638Skris 355505Sshin/* 455505Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555505Sshin * All rights reserved. 655505Sshin * 755505Sshin * Redistribution and use in source and binary forms, with or without 855505Sshin * modification, are permitted provided that the following conditions 955505Sshin * are met: 1055505Sshin * 1. Redistributions of source code must retain the above copyright 1155505Sshin * notice, this list of conditions and the following disclaimer. 1255505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355505Sshin * notice, this list of conditions and the following disclaimer in the 1455505Sshin * documentation and/or other materials provided with the distribution. 1555505Sshin * 3. Neither the name of the project nor the names of its contributors 1655505Sshin * may be used to endorse or promote products derived from this software 1755505Sshin * without specific prior written permission. 1855505Sshin * 1955505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955505Sshin * SUCH DAMAGE. 3055505Sshin * 3155505Sshin * $FreeBSD$ 3255505Sshin */ 3355505Sshin 3455505Sshin#include <sys/param.h> 3555505Sshin#include <sys/socket.h> 3655505Sshin#include <sys/uio.h> 3755505Sshin#include <sys/time.h> 3855505Sshin 3955505Sshin#include <string.h> 4055505Sshin 4155505Sshin#include <net/route.h> 4255505Sshin 4355505Sshin#include <netinet/in_systm.h> 4455505Sshin#include <netinet/in.h> 4555505Sshin#include <netinet/ip.h> 4655505Sshin#include <netinet/ip6.h> 4755505Sshin#include <netinet/icmp6.h> 4855505Sshin 4962638Skris#include <arpa/inet.h> 5062638Skris 5155505Sshin#ifdef IPSEC 52171135Sgnn#include <netipsec/ipsec.h> 5355505Sshin#endif 5455505Sshin 5555505Sshin#include <stdio.h> 5662638Skris#include <err.h> 5755505Sshin#include <errno.h> 5855505Sshin#include <stdlib.h> 5955505Sshin#include <unistd.h> 6055505Sshin#include <syslog.h> 6155505Sshin 6255505Sshin#include "rrenumd.h" 6355505Sshin 6462638Skris#define LL_ALLROUTERS "ff02::2" 6562638Skris#define SL_ALLROUTERS "ff05::2" 6655505Sshin 6778064Sume#define RR_MCHLIM_DEFAULT 64 6878064Sume 6955505Sshin#ifndef IN6_IS_SCOPE_LINKLOCAL 7062638Skris#define IN6_IS_SCOPE_LINKLOCAL(a) \ 7155505Sshin ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 7255505Sshin (IN6_IS_ADDR_MC_LINKLOCAL(a))) 7355505Sshin#endif /* IN6_IS_SCOPE_LINKLOCAL */ 7455505Sshin 7555505Sshinstruct flags { 7662638Skris u_long debug : 1; 7762638Skris u_long fg : 1; 7855505Sshin#ifdef IPSEC 7955505Sshin#ifdef IPSEC_POLICY_IPSEC 8062638Skris u_long policy : 1; 8162638Skris#else /* IPSEC_POLICY_IPSEC */ 8262638Skris u_long auth : 1; 8362638Skris u_long encrypt : 1; 8455505Sshin#endif /* IPSEC_POLICY_IPSEC */ 8555505Sshin#endif /*IPSEC*/ 8655505Sshin}; 8755505Sshin 8862638Skrisstruct msghdr sndmhdr; 8962638Skrisstruct msghdr rcvmhdr; 9062638Skrisstruct sockaddr_in6 from; 9162638Skrisstruct sockaddr_in6 sin6_ll_allrouters; 9255505Sshin 9362638Skrisint s4, s6; 9462638Skrisint with_v4dest, with_v6dest; 9562638Skrisstruct in6_addr prefix; /* ADHOC */ 9662638Skrisint prefixlen = 64; /* ADHOC */ 9755505Sshin 98173412Skevloextern int parse(FILE **); 9955505Sshin 100173412Skevlostatic void show_usage(void); 101173412Skevlostatic void init_sin6(struct sockaddr_in6 *, const char *); 10278064Sume#if 0 103173412Skevlostatic void join_multi(const char *); 10478064Sume#endif 105173412Skevlostatic void init_globals(void); 106173412Skevlostatic void config(FILE **); 10778064Sume#ifdef IPSEC_POLICY_IPSEC 108173412Skevlostatic void sock6_open(struct flags *, char *); 109173412Skevlostatic void sock4_open(struct flags *, char *); 11078064Sume#else 111173412Skevlostatic void sock6_open(struct flags *); 112173412Skevlostatic void sock4_open(struct flags *); 11378064Sume#endif 114173412Skevlostatic void rrenum_output(struct payload_list *, struct dst_list *); 115173412Skevlostatic void rrenum_snd_eachdst(struct payload_list *); 11678064Sume#if 0 117173412Skevlostatic void rrenum_snd_fullsequence(void); 11878064Sume#endif 119173412Skevlostatic void rrenum_input(int); 120173412Skevloint main(int, char *[]); 12178064Sume 12278064Sume 12355505Sshin/* Print usage. Don't call this after daemonized. */ 12455505Sshinstatic void 12555505Sshinshow_usage() 12655505Sshin{ 12755505Sshin fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" 12855505Sshin#ifdef IPSEC 12955505Sshin#ifdef IPSEC_POLICY_IPSEC 13055505Sshin "] [-P policy" 13162638Skris#else /* IPSEC_POLICY_IPSEC */ 13262638Skris "AE" 13355505Sshin#endif /* IPSEC_POLICY_IPSEC */ 13455505Sshin#endif /* IPSEC */ 13555505Sshin "]\n"); 13655505Sshin exit(1); 13755505Sshin} 13855505Sshin 13978064Sumestatic void 14055505Sshininit_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) 14155505Sshin{ 14255505Sshin memset(sin6, 0, sizeof(*sin6)); 14355505Sshin sin6->sin6_len = sizeof(*sin6); 14455505Sshin sin6->sin6_family = AF_INET6; 14555505Sshin if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) 14655505Sshin ; /* XXX do something */ 14755505Sshin} 14855505Sshin 14962638Skris#if 0 /* XXX: not necessary ?? */ 15078064Sumestatic void 15162638Skrisjoin_multi(const char *addrname) 15262638Skris{ 15362638Skris struct ipv6_mreq mreq; 15462638Skris 15562638Skris if (inet_pton(AF_INET6, addrname, &mreq.ipv6mr_multiaddr.s6_addr) 15662638Skris != 1) { 15762638Skris syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 158136057Sstefanf __func__); 15962638Skris exit(1); 16062638Skris } 16162638Skris /* ADHOC: currently join only one */ 16262638Skris { 16362638Skris if ((mreq.ipv6mr_interface = if_nametoindex(ifname)) == 0) { 16462638Skris syslog(LOG_ERR, "<%s> ifname %s should be invalid: %s", 165136057Sstefanf __func__, ifname, strerror(errno)); 16662638Skris exit(1); 16762638Skris } 16862638Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, 16962638Skris &mreq, 17062638Skris sizeof(mreq)) < 0) { 17162638Skris syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 172136057Sstefanf __func__, ifname, strerror(errno)); 17362638Skris exit(1); 17462638Skris } 17562638Skris } 17662638Skris} 17762638Skris#endif 17862638Skris 17978064Sumestatic void 18055505Sshininit_globals() 18155505Sshin{ 18255505Sshin static struct iovec rcviov; 18355505Sshin static u_char rprdata[4500]; /* maximal MTU of connected links */ 18462638Skris static u_char *rcvcmsgbuf = NULL; 18562638Skris static u_char *sndcmsgbuf = NULL; 18662638Skris int sndcmsglen, rcvcmsglen; 18755505Sshin 18855505Sshin /* init ll_allrouters */ 18955505Sshin init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); 19055505Sshin 19155505Sshin /* initialize msghdr for receiving packets */ 19255505Sshin rcviov.iov_base = (caddr_t)rprdata; 19355505Sshin rcviov.iov_len = sizeof(rprdata); 19455505Sshin rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); 19555505Sshin rcvmhdr.msg_iov = &rcviov; 19655505Sshin rcvmhdr.msg_iovlen = 1; 19762638Skris rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 19862638Skris CMSG_SPACE(sizeof(int)); 19962638Skris if (rcvcmsgbuf == NULL && 20062638Skris (rcvcmsgbuf = (u_char *)malloc(rcvcmsglen)) == NULL) { 201136057Sstefanf syslog(LOG_ERR, "<%s>: malloc failed", __func__); 20262638Skris exit(1); 20362638Skris } 20455505Sshin rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; 20562638Skris rcvmhdr.msg_controllen = rcvcmsglen; 20655505Sshin 20755505Sshin /* initialize msghdr for sending packets */ 20855505Sshin sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 20955505Sshin sndmhdr.msg_iovlen = 1; 21062638Skris sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 21162638Skris CMSG_SPACE(sizeof(int)); 21262638Skris if (sndcmsgbuf == NULL && 21362638Skris (sndcmsgbuf = (u_char *)malloc(sndcmsglen)) == NULL) { 214136057Sstefanf syslog(LOG_ERR, "<%s>: malloc failed", __func__); 21562638Skris exit(1); 21662638Skris } 21755505Sshin sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 21862638Skris sndmhdr.msg_controllen = sndcmsglen; 21955505Sshin} 22055505Sshin 22178064Sumestatic void 22255505Sshinconfig(FILE **fpp) 22355505Sshin{ 22455505Sshin struct payload_list *pl; 22555505Sshin struct iovec *iov; 22655505Sshin struct icmp6_router_renum *irr; 22755505Sshin struct rr_pco_match *rpm; 22855505Sshin 22955505Sshin if (parse(fpp) < 0) { 230136057Sstefanf syslog(LOG_ERR, "<%s> parse failed", __func__); 23155505Sshin exit(1); 23255505Sshin } 23355505Sshin 23455505Sshin /* initialize fields not configured by parser */ 23555505Sshin for (pl = pl_head; pl; pl = pl->pl_next) { 23655505Sshin iov = (struct iovec *)&pl->pl_sndiov; 23755505Sshin irr = (struct icmp6_router_renum *)&pl->pl_irr; 23855505Sshin rpm = (struct rr_pco_match *)&pl->pl_rpm; 23955505Sshin 24055505Sshin irr->rr_type = ICMP6_ROUTER_RENUMBERING; 24155505Sshin irr->rr_code = 0; 24255505Sshin /* 24355505Sshin * now we don't support multiple PCOs in a rr message. 24455505Sshin * so segment number is not supported. 24555505Sshin */ 24655505Sshin /* TODO: rr flags config in parser */ 24755505Sshin irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; 24855505Sshin /* TODO: max delay config in parser */ 24955505Sshin 25055505Sshin /* 25155505Sshin * means only 1 use_prefix is contained as router-renum-05.txt. 25255505Sshin * now we don't support multiple PCOs in a rr message, 25355505Sshin * nor multiple use_prefix in one PCO. 25455505Sshin */ 25555505Sshin rpm->rpm_len = 4*1 +3; 25655505Sshin rpm->rpm_ordinal = 0; 25755505Sshin iov->iov_base = (caddr_t)irr; 25855505Sshin iov->iov_len = sizeof(struct icmp6_router_renum) 25955505Sshin + sizeof(struct rr_pco_match) 26055505Sshin + sizeof(struct rr_pco_use); 26155505Sshin } 26255505Sshin} 26355505Sshin 26478064Sumestatic void 26555505Sshinsock6_open(struct flags *flags 26655505Sshin#ifdef IPSEC_POLICY_IPSEC 26755505Sshin , char *policy 26855505Sshin#endif /* IPSEC_POLICY_IPSEC */ 26955505Sshin ) 27055505Sshin{ 27155505Sshin struct icmp6_filter filt; 27262638Skris int on; 27362638Skris#ifdef IPSEC 27462638Skris#ifndef IPSEC_POLICY_IPSEC 27562638Skris int optval; 27662638Skris#endif 27762638Skris#endif 27855505Sshin 27955505Sshin if (with_v6dest == 0) 28055505Sshin return; 28155505Sshin if (with_v6dest && 28255505Sshin (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 283136057Sstefanf syslog(LOG_ERR, "<%s> socket(v6): %s", __func__, 28455505Sshin strerror(errno)); 28555505Sshin exit(1); 28655505Sshin } 28755505Sshin 28862638Skris /* 28962638Skris * join all routers multicast addresses. 29062638Skris */ 29162638Skris#if 0 /* XXX: not necessary ?? */ 29262638Skris join_multi(LL_ALLROUTERS); 29362638Skris join_multi(SL_ALLROUTERS); 29462638Skris#endif 29555505Sshin 29655505Sshin /* set icmpv6 filter */ 29755505Sshin ICMP6_FILTER_SETBLOCKALL(&filt); 29855505Sshin ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 29955505Sshin if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 30055505Sshin sizeof(filt)) < 0) { 30155505Sshin syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 302136057Sstefanf __func__, strerror(errno)); 30355505Sshin exit(1); 30455505Sshin } 30555505Sshin 30655505Sshin /* specify to tell receiving interface */ 30755505Sshin on = 1; 308121561Sume if (setsockopt(s6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 30955505Sshin sizeof(on)) < 0) { 310121568Sume syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", 311136057Sstefanf __func__, strerror(errno)); 31255505Sshin exit(1); 31355505Sshin } 31455505Sshin 31555505Sshin#ifdef IPSEC 31655505Sshin#ifdef IPSEC_POLICY_IPSEC 31755505Sshin if (flags->policy) { 31855505Sshin char *buf; 31955505Sshin buf = ipsec_set_policy(policy, strlen(policy)); 32055505Sshin if (buf == NULL) 32168905Skris errx(1, "%s", ipsec_strerror()); 32255505Sshin /* XXX should handle in/out bound policy. */ 32355505Sshin if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 32455505Sshin buf, ipsec_get_policylen(buf)) < 0) 32578064Sume err(1, "setsockopt(IPV6_IPSEC_POLICY)"); 32655505Sshin free(buf); 32755505Sshin } 32862638Skris#else /* IPSEC_POLICY_IPSEC */ 32962638Skris if (flags->auth) { 33062638Skris optval = IPSEC_LEVEL_REQUIRE; 33162638Skris if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 33262638Skris &optval, sizeof(optval)) == -1) { 33362638Skris syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", 334136057Sstefanf __func__, strerror(errno)); 33562638Skris exit(1); 33662638Skris } 33762638Skris } 33862638Skris if (flags->encrypt) { 33962638Skris optval = IPSEC_LEVEL_REQUIRE; 34062638Skris if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 34162638Skris &optval, sizeof(optval)) == -1) { 34262638Skris syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", 343136057Sstefanf __func__, strerror(errno)); 34462638Skris exit(1); 34562638Skris } 34662638Skris } 34755505Sshin#endif /* IPSEC_POLICY_IPSEC */ 34855505Sshin#endif /* IPSEC */ 34955505Sshin 35055505Sshin return; 35155505Sshin} 35255505Sshin 35378064Sumestatic void 35462638Skrissock4_open(struct flags *flags 35562638Skris#ifdef IPSEC_POLICY_IPSEC 35662638Skris , char *policy 35762638Skris#endif /* IPSEC_POLICY_IPSEC */ 35862638Skris ) 35962638Skris{ 36062638Skris#ifdef IPSEC 36162638Skris#ifndef IPSEC_POLICY_IPSEC 36262638Skris int optval; 36362638Skris#endif 36462638Skris#endif 36562638Skris 36662638Skris if (with_v4dest == 0) 36762638Skris return; 36862638Skris if ((s4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 369136057Sstefanf syslog(LOG_ERR, "<%s> socket(v4): %s", __func__, 37062638Skris strerror(errno)); 37162638Skris exit(1); 37262638Skris } 37362638Skris 37462638Skris#if 0 /* XXX: not necessary ?? */ 37562638Skris /* 37662638Skris * join all routers multicast addresses. 37762638Skris */ 37862638Skris some_join_function(); 37962638Skris#endif 38062638Skris 38162638Skris#ifdef IPSEC 38262638Skris#ifdef IPSEC_POLICY_IPSEC 38362638Skris if (flags->policy) { 38462638Skris char *buf; 38562638Skris buf = ipsec_set_policy(policy, strlen(policy)); 38662638Skris if (buf == NULL) 38768905Skris errx(1, "%s", ipsec_strerror()); 38862638Skris /* XXX should handle in/out bound policy. */ 38962638Skris if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, 39062638Skris buf, ipsec_get_policylen(buf)) < 0) 39178064Sume err(1, "setsockopt(IP_IPSEC_POLICY)"); 39262638Skris free(buf); 39362638Skris } 39462638Skris#else /* IPSEC_POLICY_IPSEC */ 39562638Skris if (flags->auth) { 39662638Skris optval = IPSEC_LEVEL_REQUIRE; 39762638Skris if (setsockopt(s4, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, 39862638Skris &optval, sizeof(optval)) == -1) { 39962638Skris syslog(LOG_ERR, "<%s> IP_AUTH_TRANS_LEVEL: %s", 400136057Sstefanf __func__, strerror(errno)); 40162638Skris exit(1); 40262638Skris } 40362638Skris } 40462638Skris if (flags->encrypt) { 40562638Skris optval = IPSEC_LEVEL_REQUIRE; 40662638Skris if (setsockopt(s4, IPPROTO_IP, IP_ESP_TRANS_LEVEL, 40762638Skris &optval, sizeof(optval)) == -1) { 40862638Skris syslog(LOG_ERR, "<%s> IP_ESP_TRANS_LEVEL: %s", 409136057Sstefanf __func__, strerror(errno)); 41062638Skris exit(1); 41162638Skris } 41262638Skris } 41362638Skris#endif /* IPSEC_POLICY_IPSEC */ 41462638Skris#endif /* IPSEC */ 41562638Skris 41662638Skris return; 41762638Skris} 41862638Skris 41978064Sumestatic void 42055505Sshinrrenum_output(struct payload_list *pl, struct dst_list *dl) 42155505Sshin{ 42255505Sshin int i, msglen = 0; 42355505Sshin struct cmsghdr *cm; 42455505Sshin struct in6_pktinfo *pi; 42555505Sshin struct sockaddr_in6 *sin6 = NULL; 42655505Sshin 42755505Sshin sndmhdr.msg_name = (caddr_t)dl->dl_dst; 42855505Sshin if (dl->dl_dst->sa_family == AF_INET6) 42955505Sshin sin6 = (struct sockaddr_in6 *)dl->dl_dst; 43055505Sshin 43155505Sshin if (sin6 != NULL && 43278064Sume IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 43378064Sume int hoplimit = RR_MCHLIM_DEFAULT; 43455505Sshin 43555505Sshin cm = CMSG_FIRSTHDR(&sndmhdr); 43655505Sshin /* specify the outgoing interface */ 43755505Sshin cm->cmsg_level = IPPROTO_IPV6; 43855505Sshin cm->cmsg_type = IPV6_PKTINFO; 43955505Sshin cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 44055505Sshin pi = (struct in6_pktinfo *)CMSG_DATA(cm); 44155505Sshin memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 44255505Sshin pi->ipi6_ifindex = sin6->sin6_scope_id; 44362638Skris msglen += CMSG_LEN(sizeof(struct in6_pktinfo)); 44455505Sshin 44555505Sshin /* specify the hop limit of the packet if dest is link local */ 44655505Sshin /* not defined by router-renum-05.txt, but maybe its OK */ 44755505Sshin cm = CMSG_NXTHDR(&sndmhdr, cm); 44855505Sshin cm->cmsg_level = IPPROTO_IPV6; 44955505Sshin cm->cmsg_type = IPV6_HOPLIMIT; 45055505Sshin cm->cmsg_len = CMSG_LEN(sizeof(int)); 45155505Sshin memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 45262638Skris msglen += CMSG_LEN(sizeof(int)); 45355505Sshin } 45455505Sshin sndmhdr.msg_controllen = msglen; 45555505Sshin if (sndmhdr.msg_controllen == 0) 45655505Sshin sndmhdr.msg_control = 0; 45755505Sshin 45855505Sshin sndmhdr.msg_iov = &pl->pl_sndiov; 45962638Skris i = sendmsg(dl->dl_dst->sa_family == AF_INET ? s4 : s6, &sndmhdr, 0); 46055505Sshin 46155505Sshin if (i < 0 || i != sndmhdr.msg_iov->iov_len) 462136057Sstefanf syslog(LOG_ERR, "<%s> sendmsg: %s", __func__, 46355505Sshin strerror(errno)); 46455505Sshin} 46555505Sshin 46678064Sumestatic void 46755505Sshinrrenum_snd_eachdst(struct payload_list *pl) 46855505Sshin{ 46955505Sshin struct dst_list *dl; 47055505Sshin 47155505Sshin for (dl = dl_head; dl; dl = dl->dl_next) { 47255505Sshin rrenum_output(pl, dl); 47355505Sshin } 47455505Sshin} 47555505Sshin 47678064Sume#if 0 47778064Sumestatic void 47855505Sshinrrenum_snd_fullsequence() 47955505Sshin{ 48055505Sshin struct payload_list *pl; 48155505Sshin 48255505Sshin for (pl = pl_head; pl; pl = pl->pl_next) { 48355505Sshin rrenum_snd_eachdst(pl); 48455505Sshin } 48555505Sshin} 48678064Sume#endif 48755505Sshin 48878064Sumestatic void 48955505Sshinrrenum_input(int s) 49055505Sshin{ 49155505Sshin int i; 49255505Sshin struct icmp6_router_renum *rr; 49355505Sshin 49455505Sshin /* get message */ 49555505Sshin if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 496136057Sstefanf syslog(LOG_ERR, "<%s> recvmsg: %s", __func__, 49755505Sshin strerror(errno)); 49855505Sshin return; 49955505Sshin } 50062638Skris if (s == s4) 50162638Skris i -= sizeof(struct ip); 50255505Sshin if (i < sizeof(struct icmp6_router_renum)) { 50355505Sshin syslog(LOG_ERR, "<%s> packet size(%d) is too short", 504136057Sstefanf __func__, i); 50555505Sshin return; 50655505Sshin } 50762638Skris if (s == s4) { 50862638Skris struct ip *ip = (struct ip *)rcvmhdr.msg_iov->iov_base; 50955505Sshin 51062638Skris rr = (struct icmp6_router_renum *)(ip + 1); 51162638Skris } else /* s == s6 */ 51262638Skris rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; 51362638Skris 51455505Sshin switch(rr->rr_code) { 51555505Sshin case ICMP6_ROUTER_RENUMBERING_COMMAND: 51655505Sshin /* COMMAND will be processed by rtadvd */ 51755505Sshin break; 51855505Sshin case ICMP6_ROUTER_RENUMBERING_RESULT: 51955505Sshin /* TODO: receiving result message */ 52055505Sshin break; 52155505Sshin default: 52262638Skris syslog(LOG_ERR, "<%s> received unknown code %d", 523136057Sstefanf __func__, rr->rr_code); 52455505Sshin break; 52555505Sshin } 52655505Sshin} 52755505Sshin 52855505Sshinint 52955505Sshinmain(int argc, char *argv[]) 53055505Sshin{ 53155505Sshin FILE *fp = stdin; 53255505Sshin fd_set fdset; 53355505Sshin struct timeval timeout; 53455505Sshin int ch, i, maxfd = 0, send_counter = 0; 53555505Sshin struct flags flags; 53655505Sshin struct payload_list *pl; 53755505Sshin#ifdef IPSEC_POLICY_IPSEC 53855505Sshin char *policy = NULL; 53955505Sshin#endif 54055505Sshin 54155505Sshin memset(&flags, 0, sizeof(flags)); 54262638Skris openlog("rrenumd", LOG_PID, LOG_DAEMON); 54355505Sshin 54455505Sshin /* get options */ 54555505Sshin while ((ch = getopt(argc, argv, "c:sdf" 54655505Sshin#ifdef IPSEC 54755505Sshin#ifdef IPSEC_POLICY_IPSEC 54879101Sume "P:" 54962638Skris#else /* IPSEC_POLICY_IPSEC */ 55062638Skris "AE" 55155505Sshin#endif /* IPSEC_POLICY_IPSEC */ 55255505Sshin#endif /* IPSEC */ 55355505Sshin )) != -1){ 55455505Sshin switch (ch) { 55555505Sshin case 'c': 55655505Sshin if((fp = fopen(optarg, "r")) == NULL) { 55755505Sshin syslog(LOG_ERR, 55855505Sshin "<%s> config file %s open failed", 559136057Sstefanf __func__, optarg); 56055505Sshin exit(1); 56155505Sshin } 56255505Sshin break; 56355505Sshin case 's': 56455505Sshin fp = stdin; 56555505Sshin break; 56655505Sshin case 'd': 56755505Sshin flags.debug = 1; 56855505Sshin break; 56955505Sshin case 'f': 57055505Sshin flags.fg = 1; 57155505Sshin break; 57255505Sshin#ifdef IPSEC 57355505Sshin#ifdef IPSEC_POLICY_IPSEC 57455505Sshin case 'P': 57555505Sshin flags.policy = 1; 57655505Sshin policy = strdup(optarg); 57755505Sshin break; 57862638Skris#else /* IPSEC_POLICY_IPSEC */ 57962638Skris case 'A': 58062638Skris flags.auth = 1; 58162638Skris break; 58262638Skris case 'E': 58362638Skris flags.encrypt = 1; 58462638Skris break; 58555505Sshin#endif /* IPSEC_POLICY_IPSEC */ 58655505Sshin#endif /*IPSEC*/ 58755505Sshin default: 58855505Sshin show_usage(); 58955505Sshin } 59055505Sshin } 59155505Sshin argc -= optind; 59255505Sshin argv += optind; 59355505Sshin 59455505Sshin /* set log level */ 59555505Sshin if (flags.debug == 0) 59655505Sshin (void)setlogmask(LOG_UPTO(LOG_ERR)); 59755505Sshin if (flags.debug == 1) 59855505Sshin (void)setlogmask(LOG_UPTO(LOG_INFO)); 59955505Sshin 60055505Sshin /* init global variables */ 60155505Sshin init_globals(); 60255505Sshin 60355505Sshin config(&fp); 60455505Sshin 60555505Sshin sock6_open(&flags 60655505Sshin#ifdef IPSEC_POLICY_IPSEC 60755505Sshin , policy 60855505Sshin#endif /* IPSEC_POLICY_IPSEC */ 60955505Sshin ); 61062638Skris sock4_open(&flags 61162638Skris#ifdef IPSEC_POLICY_IPSEC 61262638Skris , policy 61362638Skris#endif /* IPSEC_POLICY_IPSEC */ 61462638Skris ); 61555505Sshin 61655505Sshin if (!flags.fg) 61755505Sshin daemon(0, 0); 61855505Sshin 61955505Sshin FD_ZERO(&fdset); 62055505Sshin if (with_v6dest) { 62155505Sshin FD_SET(s6, &fdset); 62255505Sshin if (s6 > maxfd) 62355505Sshin maxfd = s6; 62455505Sshin } 62562638Skris if (with_v4dest) { 62662638Skris FD_SET(s4, &fdset); 62762638Skris if (s4 > maxfd) 62862638Skris maxfd = s4; 62962638Skris } 63055505Sshin 63155505Sshin /* ADHOC: timeout each 30seconds */ 63255505Sshin memset(&timeout, 0, sizeof(timeout)); 63355505Sshin 63478064Sume /* init temporary payload_list and send_counter*/ 63555505Sshin pl = pl_head; 63655505Sshin send_counter = retry + 1; 63755505Sshin while (1) { 63855505Sshin struct fd_set select_fd = fdset; /* reinitialize */ 63955505Sshin 64055505Sshin if ((i = select(maxfd + 1, &select_fd, NULL, NULL, 64155505Sshin &timeout)) < 0){ 64255505Sshin syslog(LOG_ERR, "<%s> select: %s", 643136057Sstefanf __func__, strerror(errno)); 64455505Sshin continue; 64555505Sshin } 64655505Sshin if (i == 0) { /* timeout */ 64755505Sshin if (pl == NULL) 64855505Sshin exit(0); 64955505Sshin rrenum_snd_eachdst(pl); 65055505Sshin send_counter--; 65178064Sume timeout.tv_sec = 30; 65255505Sshin if (send_counter == 0) { 65378064Sume timeout.tv_sec = 0; 65455505Sshin pl = pl->pl_next; 65555505Sshin send_counter = retry + 1; 65655505Sshin } 65755505Sshin } 65862638Skris if (FD_ISSET(s4, &select_fd)) 65962638Skris rrenum_input(s4); 66055505Sshin if (FD_ISSET(s6, &select_fd)) 66155505Sshin rrenum_input(s6); 66255505Sshin } 66355505Sshin} 664