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