Hi there,
Please find attached a patch for IPv6 support in netselect. The patch
is against r26676 of
svn://svn.debian.org/svn/collab-maint/deb-maint/netselect/trunk
Regards,
Bob Ham
--
Bob Ham <[email protected]>
Software Engineer
>>>>>>>>
Open First
Collabora is hiring!
Please check out our latest opportunities here:
http://bit.ly/Collabora-Careers
<<<<<<<<
Index: netinet/icmp6.h
===================================================================
--- netinet/icmp6.h (revision 0)
+++ netinet/icmp6.h (working copy)
@@ -0,0 +1,1011 @@
+/* $KAME: icmp6.h,v 1.107 2007/06/14 12:09:42 itojun Exp $ */
+
+/*
+ * Copyright (c) 2002 INRIA. All rights reserved.
+ *
+ * Implementation of Multicast Listener Discovery, Version 2.
+ * Developed by Hitoshi Asaeda, INRIA, February 2002.
+ *
+ * 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 INRIA 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_ICMP6_H_
+#define _NETINET_ICMP6_H_
+#ifdef __APPLE__
+#include <sys/appleapiopts.h>
+#endif /* __APPLE__ */
+
+
+#define ICMPV6_PLD_MAXLEN 1232 /* IPV6_MMTU - sizeof(struct ip6_hdr)
+ - sizeof(struct icmp6_hdr) */
+
+struct icmp6_hdr {
+ u_int8_t icmp6_type; /* type field */
+ u_int8_t icmp6_code; /* code field */
+ u_int16_t icmp6_cksum; /* checksum field */
+ union {
+ u_int32_t icmp6_un_data32[1]; /* type-specific field */
+ u_int16_t icmp6_un_data16[2]; /* type-specific field */
+ u_int8_t icmp6_un_data8[4]; /* type-specific field */
+ } icmp6_dataun;
+} __attribute__((__packed__));
+
+#define icmp6_data32 icmp6_dataun.icmp6_un_data32
+#define icmp6_data16 icmp6_dataun.icmp6_un_data16
+#define icmp6_data8 icmp6_dataun.icmp6_un_data8
+#define icmp6_pptr icmp6_data32[0] /* parameter prob */
+#define icmp6_mtu icmp6_data32[0] /* packet too big */
+#define icmp6_id icmp6_data16[0] /* echo request/reply */
+#define icmp6_seq icmp6_data16[1] /* echo request/reply */
+#define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */
+
+#define ICMP6_DST_UNREACH 1 /* dest unreachable, codes: */
+#define ICMP6_PACKET_TOO_BIG 2 /* packet too big */
+#define ICMP6_TIME_EXCEEDED 3 /* time exceeded, code: */
+#define ICMP6_PARAM_PROB 4 /* ip6 header bad */
+
+#define ICMP6_ECHO_REQUEST 128 /* echo service */
+#define ICMP6_ECHO_REPLY 129 /* echo reply */
+#define MLD_LISTENER_QUERY 130 /* multicast listener query */
+#define MLD_LISTENER_REPORT 131 /* multicast listener report */
+#define MLD_LISTENER_DONE 132 /* multicast listener done */
+#define MLD_LISTENER_REDUCTION MLD_LISTENER_DONE /* RFC3542 definition */
+
+/* RFC2292 decls */
+#define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */
+#define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */
+#define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination */
+
+#if (!defined(__APPLE__) && !defined(_KERNEL)) || defined(__APPLE__)
+/* the followings are for backward compatibility to old KAME apps. */
+#define MLD6_LISTENER_QUERY MLD_LISTENER_QUERY
+#define MLD6_LISTENER_REPORT MLD_LISTENER_REPORT
+#define MLD6_LISTENER_DONE MLD_LISTENER_DONE
+#endif
+
+#define ND_ROUTER_SOLICIT 133 /* router solicitation */
+#define ND_ROUTER_ADVERT 134 /* router advertisement */
+#define ND_NEIGHBOR_SOLICIT 135 /* neighbor solicitation */
+#define ND_NEIGHBOR_ADVERT 136 /* neighbor advertisement */
+#define ND_REDIRECT 137 /* redirect */
+
+#define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */
+
+#define ICMP6_WRUREQUEST 139 /* who are you request */
+#define ICMP6_WRUREPLY 140 /* who are you reply */
+#define ICMP6_FQDN_QUERY 139 /* FQDN query */
+#define ICMP6_FQDN_REPLY 140 /* FQDN reply */
+#define ICMP6_NI_QUERY 139 /* node information request */
+#define ICMP6_NI_REPLY 140 /* node information reply */
+
+/* The belows are not yet defined in 2292bis. They will be renamed */
+#define IND_SOLICIT 141 /* inverse neighbor solicitation */
+#define IND_ADVERT 142 /* inverse neighbor advertisement */
+#define MLDV2_LISTENER_REPORT 143 /* MLDv2 report */
+
+/* Folloing numbers are defined in the mobile-ip draft. */
+#define MIP6_HA_DISCOVERY_REQUEST 144 /* home agent address discovery request */
+#define MIP6_HA_DISCOVERY_REPLY 145 /* home agent address discovery reply */
+#define MIP6_PREFIX_SOLICIT 146 /* mobile prefix solicitation */
+#define MIP6_PREFIX_ADVERT 147 /* mobile prefix advertisement */
+
+/* The definitions below are experimental. TBA */
+#define MLD_MTRACE_RESP 200 /* mtrace resp (to sender) */
+#define MLD_MTRACE 201 /* mtrace messages */
+
+/* backward compatibility for applications using old macro names */
+#if (!defined(__APPLE__) && !defined(_KERNEL)) || defined(__APPLE__)
+#define MLD6_MTRACE_RESP MLD_MTRACE_RESP
+#define MLD6_MTRACE MLD_MTRACE
+#define MLD6V2_LISTENER_REPORT MLDV2_LISTENER_REPORT
+#endif
+
+#define ICMP6_MAXTYPE 201
+
+#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
+#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
+#define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor(obsolete) */
+#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */
+#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */
+#define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */
+
+#define ICMP6_TIME_EXCEED_TRANSIT 0 /* ttl==0 in transit */
+#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* ttl==0 in reass */
+
+#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */
+#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized next header */
+#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized option */
+
+#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
+
+#define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an IPv6 address */
+#define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */
+#define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */
+
+#define ICMP6_NI_SUCCESS 0 /* node information successful reply */
+#define ICMP6_NI_REFUSED 1 /* node information request is refused */
+#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
+
+#define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */
+#define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */
+#define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 /* rr seq num reset */
+
+/* Used in kernel only */
+#define ND_REDIRECT_ONLINK 0 /* redirect to an on-link node */
+#define ND_REDIRECT_ROUTER 1 /* redirect to a better router */
+
+/*
+ * Multicast Listener Discovery
+ */
+struct mld_hdr {
+ struct icmp6_hdr mld_icmp6_hdr;
+ struct in6_addr mld_addr; /* multicast address */
+} __attribute__((__packed__));
+
+/* definitions to provide backward compatibility to old KAME applications */
+#if (!defined(__APPLE__) && !defined(_KERNEL)) || defined(__APPLE__)
+#define mld6_hdr mld_hdr
+#define mld6_type mld_type
+#define mld6_code mld_code
+#define mld6_cksum mld_cksum
+#define mld6_maxdelay mld_maxdelay
+#define mld6_reserved mld_reserved
+#define mld6_addr mld_addr
+#endif
+
+/* shortcut macro definitions */
+#define mld_type mld_icmp6_hdr.icmp6_type
+#define mld_code mld_icmp6_hdr.icmp6_code
+#define mld_cksum mld_icmp6_hdr.icmp6_cksum
+#define mld_maxdelay mld_icmp6_hdr.icmp6_data16[0]
+#define mld_reserved mld_icmp6_hdr.icmp6_data16[1]
+
+/*
+ * Multicast Listener Discovery Version 2
+ */
+struct mldv2_hdr {
+ struct icmp6_hdr mld_icmp6_hdr;
+ struct in6_addr mld_addr; /* multicast address */
+ u_int8_t mld_rtval; /* Reserved, S Flag and QRV */
+ u_int8_t mld_qqi; /* querier's query interval (QQI) */
+ u_int16_t mld_numsrc; /* number of sources (0 for general */
+ /* and group-specific queries) */
+ struct in6_addr mld_src[1]; /* source address list */
+} __attribute__((__packed__));
+
+#define MLD_MRC_EXP(x) ((ntohs(x) >> 12) & 0x0007)
+#define MLD_MRC_MANT(x) (ntohs(x) & 0x0fff)
+#define MLD_QQIC_EXP(x) (((x) >> 4) & 0x07)
+#define MLD_QQIC_MANT(x) ((x) & 0x0f)
+#define MLD_QRESV(x) (((x) >> 4) & 0x0f)
+#define MLD_SFLAG(x) (((x) >> 3) & 0x01)
+#define MLD_QRV(x) ((x) & 0x07) /* querier's robustness variable */
+
+/*
+ * MLDv2 Membership Report Message header.
+ */
+struct mld_report_hdr {
+ struct icmp6_hdr mld_icmp6_hdr; /* version & type of MLD message */
+} __attribute__((__packed__));
+
+/* shortcut macro definition */
+#define mld_grpnum mld_icmp6_hdr.icmp6_data16[1]
+
+/*
+ * MLDv2 Group Record header.
+ */
+struct mld_group_record_hdr {
+ u_int8_t record_type; /* record types for membership report */
+ u_int8_t auxlen; /* aux data length (must be zero) */
+ u_int16_t numsrc; /* number of sources */
+ struct in6_addr group; /* group address */
+ struct in6_addr src[1]; /* source address list */
+} __attribute__((__packed__));
+
+#define MLD_V1_QUERY 0
+#define MLD_V2_GENERAL_QUERY 1
+#define MLD_V2_GROUP_QUERY 2
+#define MLD_V2_GROUP_SOURCE_QUERY 3
+
+#define MLD_MINLEN 24
+#define MLD_V2_QUERY_MINLEN 28
+
+
+/*
+ * Group Record Types in the MLD Membership Report
+ */
+#ifndef MODE_IS_INCLUDE
+#define MODE_IS_INCLUDE 1
+#define MODE_IS_EXCLUDE 2
+#define CHANGE_TO_INCLUDE_MODE 3
+#define CHANGE_TO_EXCLUDE_MODE 4
+#define ALLOW_NEW_SOURCES 5
+#define BLOCK_OLD_SOURCES 6
+#endif
+
+/*
+ * Neighbor Discovery
+ */
+
+struct nd_router_solicit { /* router solicitation */
+ struct icmp6_hdr nd_rs_hdr;
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_rs_type nd_rs_hdr.icmp6_type
+#define nd_rs_code nd_rs_hdr.icmp6_code
+#define nd_rs_cksum nd_rs_hdr.icmp6_cksum
+#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0]
+
+struct nd_router_advert { /* router advertisement */
+ struct icmp6_hdr nd_ra_hdr;
+ u_int32_t nd_ra_reachable; /* reachable time */
+ u_int32_t nd_ra_retransmit; /* retransmit timer */
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_ra_type nd_ra_hdr.icmp6_type
+#define nd_ra_code nd_ra_hdr.icmp6_code
+#define nd_ra_cksum nd_ra_hdr.icmp6_cksum
+#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0]
+#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1]
+#define ND_RA_FLAG_MANAGED 0x80
+#define ND_RA_FLAG_OTHER 0x40
+#define ND_RA_FLAG_HOME_AGENT 0x20
+
+/*
+ * Router preference values based on draft-draves-ipngwg-router-selection-01.
+ * These are non-standard definitions.
+ */
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+
+#define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */
+#define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */
+#define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */
+#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
+
+#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1]
+
+struct nd_neighbor_solicit { /* neighbor solicitation */
+ struct icmp6_hdr nd_ns_hdr;
+ struct in6_addr nd_ns_target; /*target address */
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_ns_type nd_ns_hdr.icmp6_type
+#define nd_ns_code nd_ns_hdr.icmp6_code
+#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
+#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
+
+struct nd_neighbor_advert { /* neighbor advertisement */
+ struct icmp6_hdr nd_na_hdr;
+ struct in6_addr nd_na_target; /* target address */
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_na_type nd_na_hdr.icmp6_type
+#define nd_na_code nd_na_hdr.icmp6_code
+#define nd_na_cksum nd_na_hdr.icmp6_cksum
+#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0]
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_NA_FLAG_ROUTER 0x80000000
+#define ND_NA_FLAG_SOLICITED 0x40000000
+#define ND_NA_FLAG_OVERRIDE 0x20000000
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ND_NA_FLAG_ROUTER 0x80
+#define ND_NA_FLAG_SOLICITED 0x40
+#define ND_NA_FLAG_OVERRIDE 0x20
+#endif
+#endif
+
+struct nd_redirect { /* redirect */
+ struct icmp6_hdr nd_rd_hdr;
+ struct in6_addr nd_rd_target; /* target address */
+ struct in6_addr nd_rd_dst; /* destination address */
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define nd_rd_type nd_rd_hdr.icmp6_type
+#define nd_rd_code nd_rd_hdr.icmp6_code
+#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
+#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
+
+struct ind_neighbor_solicit { /* inverse neighbor solicitation */
+ struct icmp6_hdr ind_ns_hdr;
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define ind_ns_type ind_ns_hdr.icmp6_type
+#define ind_ns_code ind_ns_hdr.icmp6_code
+#define ind_ns_cksum ind_ns_hdr.icmp6_cksum
+#define ind_ns_reserved ind_ns_hdr.icmp6_data32[0]
+
+struct ind_neighbor_advert { /* inverse neighbor advertisement */
+ struct icmp6_hdr ind_na_hdr;
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+#define ind_na_type ind_na_hdr.icmp6_type
+#define ind_na_code ind_na_hdr.icmp6_code
+#define ind_na_cksum ind_na_hdr.icmp6_cksum
+#define ind_na_flags_reserved ind_na_hdr.icmp6_data32[0]
+
+struct mip6_dhaad_req { /* HA Address Discovery Request */
+ struct icmp6_hdr mip6_dhreq_hdr;
+} __attribute__((__packed__));
+
+#define mip6_dhreq_type mip6_dhreq_hdr.icmp6_type
+#define mip6_dhreq_code mip6_dhreq_hdr.icmp6_code
+#define mip6_dhreq_cksum mip6_dhreq_hdr.icmp6_cksum
+#define mip6_dhreq_id mip6_dhreq_hdr.icmp6_data16[0]
+#define mip6_dhreq_reserved mip6_dhreq_hdr.icmp6_data16[1]
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_DHREQ_FLAG_MR 0x8000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_DHREQ_FLAG_MR 0x0080
+#endif /* LITTLE_ENDIAN */
+
+
+struct mip6_dhaad_rep { /* HA Address Discovery Reply */
+ struct icmp6_hdr mip6_dhrep_hdr;
+ /* could be followed by home agent addresses */
+} __attribute__((__packed__));
+
+#define mip6_dhrep_type mip6_dhrep_hdr.icmp6_type
+#define mip6_dhrep_code mip6_dhrep_hdr.icmp6_code
+#define mip6_dhrep_cksum mip6_dhrep_hdr.icmp6_cksum
+#define mip6_dhrep_id mip6_dhrep_hdr.icmp6_data16[0]
+#define mip6_dhrep_reserved mip6_dhrep_hdr.icmp6_data16[1]
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_DHREP_FLAG_MR 0x8000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_DHREP_FLAG_MR 0x0080
+#endif /* LITTLE_ENDIAN */
+
+struct mip6_prefix_solicit { /* Mobile Prefix Solicitation */
+ struct icmp6_hdr mip6_ps_hdr;
+} __attribute__((__packed__));
+
+#define mip6_ps_type mip6_ps_hdr.icmp6_type
+#define mip6_ps_code mip6_ps_hdr.icmp6_code
+#define mip6_ps_cksum mip6_ps_hdr.icmp6_cksum
+#define mip6_ps_id mip6_ps_hdr.icmp6_data16[0]
+#define mip6_ps_reserved mip6_ps_hdr.icmp6_data16[1]
+
+struct mip6_prefix_advert { /* Mobile Prefix Advertisement */
+ struct icmp6_hdr mip6_pa_hdr;
+ /* followed by options */
+} __attribute__((__packed__));
+
+#define mip6_pa_type mip6_pa_hdr.icmp6_type
+#define mip6_pa_code mip6_pa_hdr.icmp6_code
+#define mip6_pa_cksum mip6_pa_hdr.icmp6_cksum
+#define mip6_pa_id mip6_pa_hdr.icmp6_data16[0]
+#define mip6_pa_flags_reserved mip6_pa_hdr.icmp6_data16[1]
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_PA_FLAG_MANAGED 0x8000
+#define MIP6_PA_FLAG_OTHER 0x4000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_PA_FLAG_MANAGED 0x0080
+#define MIP6_PA_FLAG_OTHER 0x0040
+#endif /* LITTLE_ENDIAN */
+
+struct nd_opt_hdr { /* Neighbor discovery option header */
+ u_int8_t nd_opt_type;
+ u_int8_t nd_opt_len;
+ /* followed by option specific data*/
+} __attribute__((__packed__));
+
+#define ND_OPT_SOURCE_LINKADDR 1
+#define ND_OPT_TARGET_LINKADDR 2
+#define ND_OPT_PREFIX_INFORMATION 3
+#define ND_OPT_REDIRECTED_HEADER 4
+#define ND_OPT_MTU 5
+#define ND_OPT_ADV_INTERVAL 7 /* RFC3775 */
+#define ND_OPT_HA_INFORMATION 8 /* RFC3775 */
+#define ND_OPT_SOURCE_ADDRLIST 9 /* will be renamed */
+#define ND_OPT_TARGET_ADDRLIST 10 /* will be renamed */
+
+#define ND_OPT_ROUTE_INFO 200 /* draft-ietf-ipngwg-router-preference, not officially assigned yet */
+
+struct nd_opt_prefix_info { /* prefix information */
+ u_int8_t nd_opt_pi_type;
+ u_int8_t nd_opt_pi_len;
+ u_int8_t nd_opt_pi_prefix_len;
+ u_int8_t nd_opt_pi_flags_reserved;
+ u_int32_t nd_opt_pi_valid_time;
+ u_int32_t nd_opt_pi_preferred_time;
+ u_int32_t nd_opt_pi_reserved2;
+ struct in6_addr nd_opt_pi_prefix;
+} __attribute__((__packed__));
+
+#define ND_OPT_PI_FLAG_ONLINK 0x80
+#define ND_OPT_PI_FLAG_AUTO 0x40
+#define ND_OPT_PI_FLAG_ROUTER 0x20 /* RFC3775 */
+
+struct nd_opt_rd_hdr { /* redirected header */
+ u_int8_t nd_opt_rh_type;
+ u_int8_t nd_opt_rh_len;
+ u_int16_t nd_opt_rh_reserved1;
+ u_int32_t nd_opt_rh_reserved2;
+ /* followed by IP header and data */
+} __attribute__((__packed__));
+
+struct nd_opt_mtu { /* MTU option */
+ u_int8_t nd_opt_mtu_type;
+ u_int8_t nd_opt_mtu_len;
+ u_int16_t nd_opt_mtu_reserved;
+ u_int32_t nd_opt_mtu_mtu;
+} __attribute__((__packed__));
+
+struct nd_opt_adv_interval { /* Advertisement interval option */
+ u_int8_t nd_opt_ai_type;
+ u_int8_t nd_opt_ai_len;
+ u_int16_t nd_opt_ai_reserved;
+ u_int32_t nd_opt_ai_interval;
+} __attribute__((__packed__));
+
+struct nd_opt_homeagent_info { /* Home Agent info */
+ u_int8_t nd_opt_hai_type;
+ u_int8_t nd_opt_hai_len;
+ u_int16_t nd_opt_hai_reserved;
+ u_int16_t nd_opt_hai_preference;
+ u_int16_t nd_opt_hai_lifetime;
+} __attribute__((__packed__));
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP6_HAINFO_FLAG_MR 0x8000
+#endif /* BIG_ENDIAN */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define MIP6_HAINFO_FLAG_MR 0x0080
+#endif /* LITTLE_ENDIAN */
+
+struct nd_opt_route_info { /* route info */
+ u_int8_t nd_opt_rti_type;
+ u_int8_t nd_opt_rti_len;
+ u_int8_t nd_opt_rti_prefixlen;
+ u_int8_t nd_opt_rti_flags;
+ u_int32_t nd_opt_rti_lifetime;
+ /* prefix follows */
+} __attribute__((__packed__));
+
+/*
+ * icmp6 namelookup
+ */
+
+struct icmp6_namelookup {
+ struct icmp6_hdr icmp6_nl_hdr;
+ u_int8_t icmp6_nl_nonce[8];
+ int32_t icmp6_nl_ttl;
+#if 0
+ u_int8_t icmp6_nl_len;
+ u_int8_t icmp6_nl_name[3];
+#endif
+ /* could be followed by options */
+} __attribute__((__packed__));
+
+/*
+ * icmp6 node information
+ */
+struct icmp6_nodeinfo {
+ struct icmp6_hdr icmp6_ni_hdr;
+ u_int8_t icmp6_ni_nonce[8];
+ /* could be followed by reply data */
+} __attribute__((__packed__));
+
+#define ni_type icmp6_ni_hdr.icmp6_type
+#define ni_code icmp6_ni_hdr.icmp6_code
+#define ni_cksum icmp6_ni_hdr.icmp6_cksum
+#define ni_qtype icmp6_ni_hdr.icmp6_data16[0]
+#define ni_flags icmp6_ni_hdr.icmp6_data16[1]
+
+#define NI_QTYPE_NOOP 0 /* NOOP */
+#define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */
+#define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */
+#define NI_QTYPE_DNSNAME 2 /* DNS Name (draft 05-07) */
+#define NI_QTYPE_NODENAME 2 /* Node Name (draft 08) */
+#define NI_QTYPE_NODEADDR 3 /* Node Addresses */
+#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS 0x1
+#define NI_FQDN_FLAG_VALIDTTL 0x1
+#define NI_NODENAME_FLAG_VALIDTTL 0x1
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS 0x0100
+#define NI_FQDN_FLAG_VALIDTTL 0x0100
+#define NI_NODENAME_FLAG_VALIDTTL 0x0100
+#endif
+
+#ifdef NAME_LOOKUPS_04
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x1
+#define NI_NODEADDR_FLAG_SITELOCAL 0x2
+#define NI_NODEADDR_FLAG_GLOBAL 0x4
+#define NI_NODEADDR_FLAG_ALL 0x8
+#define NI_NODEADDR_FLAG_TRUNCATE 0x10
+#define NI_NODEADDR_FLAG_ANYCAST 0x20 /* just experimental. not in spec */
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x0100
+#define NI_NODEADDR_FLAG_SITELOCAL 0x0200
+#define NI_NODEADDR_FLAG_GLOBAL 0x0400
+#define NI_NODEADDR_FLAG_ALL 0x0800
+#define NI_NODEADDR_FLAG_TRUNCATE 0x1000
+#define NI_NODEADDR_FLAG_ANYCAST 0x2000 /* just experimental. not in spec */
+#endif
+#else /* draft-ietf-ipngwg-icmp-name-lookups-05 (and later?) */
+#if BYTE_ORDER == BIG_ENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE 0x1
+#define NI_NODEADDR_FLAG_ALL 0x2
+#define NI_NODEADDR_FLAG_COMPAT 0x4
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x8
+#define NI_NODEADDR_FLAG_SITELOCAL 0x10
+#define NI_NODEADDR_FLAG_GLOBAL 0x20
+#define NI_NODEADDR_FLAG_ANYCAST 0x40 /* just experimental. not in spec */
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE 0x0100
+#define NI_NODEADDR_FLAG_ALL 0x0200
+#define NI_NODEADDR_FLAG_COMPAT 0x0400
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x0800
+#define NI_NODEADDR_FLAG_SITELOCAL 0x1000
+#define NI_NODEADDR_FLAG_GLOBAL 0x2000
+#define NI_NODEADDR_FLAG_ANYCAST 0x4000 /* just experimental. not in spec */
+#endif
+#endif
+
+struct ni_reply_fqdn {
+ u_int32_t ni_fqdn_ttl; /* TTL */
+ u_int8_t ni_fqdn_namelen; /* length in octets of the FQDN */
+ u_int8_t ni_fqdn_name[3]; /* XXX: alignment */
+} __attribute__((__packed__));
+#define ni_reply_nodename ni_reply_fqdn
+#define ni_nodename_ttl ni_fqdn_ttl
+#define ni_nodename_namelen ni_fqdn_namelen
+#define ni_nodename_name ni_fqdn_name
+
+/*
+ * Router Renumbering. as router-renum-08.txt
+ */
+struct icmp6_router_renum { /* router renumbering header */
+ struct icmp6_hdr rr_hdr;
+ u_int8_t rr_segnum;
+ u_int8_t rr_flags;
+ u_int16_t rr_maxdelay;
+ u_int32_t rr_reserved;
+} __attribute__((__packed__));
+
+#define ICMP6_RR_FLAGS_TEST 0x80
+#define ICMP6_RR_FLAGS_REQRESULT 0x40
+#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20
+#define ICMP6_RR_FLAGS_SPECSITE 0x10
+#define ICMP6_RR_FLAGS_PREVDONE 0x08
+
+#define rr_type rr_hdr.icmp6_type
+#define rr_code rr_hdr.icmp6_code
+#define rr_cksum rr_hdr.icmp6_cksum
+#define rr_seqnum rr_hdr.icmp6_data32[0]
+
+struct rr_pco_match { /* match prefix part */
+ u_int8_t rpm_code;
+ u_int8_t rpm_len;
+ u_int8_t rpm_ordinal;
+ u_int8_t rpm_matchlen;
+ u_int8_t rpm_minlen;
+ u_int8_t rpm_maxlen;
+ u_int16_t rpm_reserved;
+ struct in6_addr rpm_prefix;
+} __attribute__((__packed__));
+
+#define RPM_PCO_ADD 1
+#define RPM_PCO_CHANGE 2
+#define RPM_PCO_SETGLOBAL 3
+#define RPM_PCO_MAX 4
+
+struct rr_pco_use { /* use prefix part */
+ u_int8_t rpu_uselen;
+ u_int8_t rpu_keeplen;
+ u_int8_t rpu_ramask;
+ u_int8_t rpu_raflags;
+ u_int32_t rpu_vltime;
+ u_int32_t rpu_pltime;
+ u_int32_t rpu_flags;
+ struct in6_addr rpu_prefix;
+} __attribute__((__packed__));
+#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80
+#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000
+#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80
+#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40
+#endif
+
+struct rr_result { /* router renumbering result message */
+ u_int16_t rrr_flags;
+ u_int8_t rrr_ordinal;
+ u_int8_t rrr_matchedlen;
+ u_int32_t rrr_ifid;
+ struct in6_addr rrr_prefix;
+} __attribute__((__packed__));
+#if BYTE_ORDER == BIG_ENDIAN
+#define ICMP6_RR_RESULT_FLAGS_OOB 0x0002
+#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ICMP6_RR_RESULT_FLAGS_OOB 0x0200
+#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100
+#endif
+
+/*
+ * icmp6 filter structures.
+ */
+
+struct icmp6_filter {
+ u_int32_t icmp6_filt[8];
+};
+
+#ifdef _KERNEL
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+do { \
+ int i; u_char *p; \
+ p = (u_char *)filterp; \
+ for (i = 0; i < sizeof(struct icmp6_filter); i++) \
+ p[i] = 0xff; \
+} while (/*CONSTCOND*/ 0)
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+ bzero(filterp, sizeof(struct icmp6_filter))
+#else /* _KERNEL */
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+ memset(filterp, 0xff, sizeof(struct icmp6_filter))
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+ memset(filterp, 0x00, sizeof(struct icmp6_filter))
+#endif /* _KERNEL */
+
+#define ICMP6_FILTER_SETPASS(type, filterp) \
+ (((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31)))
+#define ICMP6_FILTER_SETBLOCK(type, filterp) \
+ (((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31)))
+#define ICMP6_FILTER_WILLPASS(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
+#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
+
+/*
+ * Variables related to this implementation
+ * of the internet control message protocol version 6.
+ */
+struct icmp6errstat {
+ u_quad_t icp6errs_dst_unreach_noroute;
+ u_quad_t icp6errs_dst_unreach_admin;
+ u_quad_t icp6errs_dst_unreach_beyondscope;
+ u_quad_t icp6errs_dst_unreach_addr;
+ u_quad_t icp6errs_dst_unreach_noport;
+ u_quad_t icp6errs_packet_too_big;
+ u_quad_t icp6errs_time_exceed_transit;
+ u_quad_t icp6errs_time_exceed_reassembly;
+ u_quad_t icp6errs_paramprob_header;
+ u_quad_t icp6errs_paramprob_nextheader;
+ u_quad_t icp6errs_paramprob_option;
+ u_quad_t icp6errs_redirect; /* we regard redirect as an error here */
+ u_quad_t icp6errs_unknown;
+};
+
+struct icmp6stat {
+/* statistics related to icmp6 packets generated */
+ u_quad_t icp6s_error; /* # of calls to icmp6_error */
+ u_quad_t icp6s_canterror; /* no error 'cuz old was icmp */
+ u_quad_t icp6s_toofreq; /* no error 'cuz rate limitation */
+ u_quad_t icp6s_outhist[256];
+/* statistics related to input message processed */
+ u_quad_t icp6s_badcode; /* icmp6_code out of range */
+ u_quad_t icp6s_tooshort; /* packet < sizeof(struct icmp6_hdr) */
+ u_quad_t icp6s_checksum; /* bad checksum */
+ u_quad_t icp6s_badlen; /* calculated bound mismatch */
+ /*
+ * number of responses: this member is inherited from netinet code, but
+ * for netinet6 code, it is already available in icp6s_outhist[].
+ */
+ u_quad_t icp6s_reflect;
+ u_quad_t icp6s_inhist[256];
+ u_quad_t icp6s_nd_toomanyopt; /* too many ND options */
+ struct icmp6errstat icp6s_outerrhist;
+#define icp6s_odst_unreach_noroute \
+ icp6s_outerrhist.icp6errs_dst_unreach_noroute
+#define icp6s_odst_unreach_admin icp6s_outerrhist.icp6errs_dst_unreach_admin
+#define icp6s_odst_unreach_beyondscope \
+ icp6s_outerrhist.icp6errs_dst_unreach_beyondscope
+#define icp6s_odst_unreach_addr icp6s_outerrhist.icp6errs_dst_unreach_addr
+#define icp6s_odst_unreach_noport icp6s_outerrhist.icp6errs_dst_unreach_noport
+#define icp6s_opacket_too_big icp6s_outerrhist.icp6errs_packet_too_big
+#define icp6s_otime_exceed_transit \
+ icp6s_outerrhist.icp6errs_time_exceed_transit
+#define icp6s_otime_exceed_reassembly \
+ icp6s_outerrhist.icp6errs_time_exceed_reassembly
+#define icp6s_oparamprob_header icp6s_outerrhist.icp6errs_paramprob_header
+#define icp6s_oparamprob_nextheader \
+ icp6s_outerrhist.icp6errs_paramprob_nextheader
+#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
+#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
+#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
+ u_quad_t icp6s_pmtuchg; /* path MTU changes */
+ u_quad_t icp6s_nd_badopt; /* bad ND options */
+ u_quad_t icp6s_badns; /* bad neighbor solicitation */
+ u_quad_t icp6s_badna; /* bad neighbor advertisement */
+ u_quad_t icp6s_badrs; /* bad router advertisement */
+ u_quad_t icp6s_badra; /* bad router advertisement */
+ u_quad_t icp6s_badredirect; /* bad redirect message */
+};
+
+/*
+ * Names for ICMP sysctl objects
+ */
+#define ICMPV6CTL_STATS 1
+#define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */
+#define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */
+#if 0 /*obsoleted*/
+#define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */
+#endif
+#define ICMPV6CTL_ND6_PRUNE 6
+#define ICMPV6CTL_ND6_DELAY 8
+#define ICMPV6CTL_ND6_UMAXTRIES 9
+#define ICMPV6CTL_ND6_MMAXTRIES 10
+#define ICMPV6CTL_ND6_USELOOPBACK 11
+/*#define ICMPV6CTL_ND6_PROXYALL 12 obsoleted, do not reuse here */
+#define ICMPV6CTL_NODEINFO 13
+#define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */
+#define ICMPV6CTL_ND6_MAXNUDHINT 15
+#define ICMPV6CTL_MTUDISC_HIWAT 16
+#define ICMPV6CTL_MTUDISC_LOWAT 17
+#define ICMPV6CTL_ND6_DEBUG 18
+#define ICMPV6CTL_ND6_DRLIST 19
+#define ICMPV6CTL_ND6_PRLIST 20
+#define ICMPV6CTL_MLD_MAXSRCFILTER 21
+#define ICMPV6CTL_MLD_SOMAXSRC 22
+#define ICMPV6CTL_MLD_VERSION 23
+#define ICMPV6CTL_ND6_MAXQLEN 24
+#define ICMPV6CTL_MAXID 25
+
+#if !defined(__APPLE__) || (defined(__APPLE__) && defined(KERNEL_PRIVATE))
+#define ICMPV6CTL_NAMES { \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "rediraccept", CTLTYPE_INT }, \
+ { "redirtimeout", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "nd6_prune", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { "nd6_delay", CTLTYPE_INT }, \
+ { "nd6_umaxtries", CTLTYPE_INT }, \
+ { "nd6_mmaxtries", CTLTYPE_INT }, \
+ { "nd6_useloopback", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { "nodeinfo", CTLTYPE_INT }, \
+ { "errppslimit", CTLTYPE_INT }, \
+ { "nd6_maxnudhint", CTLTYPE_INT }, \
+ { "mtudisc_hiwat", CTLTYPE_INT }, \
+ { "mtudisc_lowat", CTLTYPE_INT }, \
+ { "nd6_debug", CTLTYPE_INT }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "mldmaxsrcfilter", CTLTYPE_INT }, \
+ { "mldsomaxsrc", CTLTYPE_INT }, \
+ { "mldalwaysv2", CTLTYPE_INT }, \
+ { "nd6_maxqueuelen", CTLTYPE_INT }, \
+}
+
+#define RTF_PROBEMTU RTF_PROTO1
+
+#ifdef _KERNEL
+# ifdef __STDC__
+struct rtentry;
+struct rttimer;
+struct in6_multi;
+# endif
+void icmp6_init(void);
+void icmp6_paramerror(struct mbuf *, int);
+void icmp6_error(struct mbuf *, int, int, int);
+#ifdef __APPLE__
+int icmp6_input(struct mbuf **, int *);
+void icmp6_fasttimo(void);
+#else
+void icmp6_error2(struct mbuf *, int, int, int, struct ifnet *);
+int icmp6_input(struct mbuf **, int *, int);
+#endif
+void icmp6_reflect(struct mbuf *, size_t);
+void icmp6_prepare(struct mbuf *);
+#ifdef __APPLE__
+void icmp6_redirect_input(struct mbuf *, int);
+#else
+void icmp6_redirect_input(struct mbuf *, int, int);
+#endif
+void icmp6_redirect_output(struct mbuf *, struct rtentry *);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int icmp6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+#endif
+
+struct ip6ctlparam;
+#ifdef __APPLE__
+void icmp6_mtudisc_update(struct ip6ctlparam *, int);
+#else /* __APPLE__ */
+void icmp6_mtudisc_update(struct ip6ctlparam *, struct sockaddr_in6 *, int);
+#endif /* __APPLE__ */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+void icmp6_mtudisc_callback_register(void (*)(struct in6_addr *));
+#endif
+
+/* XXX: is this the right place for these macros? */
+#ifdef __APPLE__
+#define icmp6_ifstat_inc(ifp, tag) \
+do { \
+ if ((ifp) && (ifp)->if_index <= if_index \
+ && (ifp)->if_index < icmp6_ifstatmax \
+ && icmp6_ifstat && icmp6_ifstat[(ifp)->if_index]) { \
+ icmp6_ifstat[(ifp)->if_index]->tag++; \
+ } \
+} while (0)
+#else
+#define icmp6_ifstat_inc(ifp, tag) \
+do { \
+ if (ifp) \
+ ((struct in6_ifextra *)((ifp)->if_afdata[AF_INET6]))->icmp6_ifstat->tag++; \
+} while (/*CONSTCOND*/ 0)
+#endif
+
+#define icmp6_ifoutstat_inc(ifp, type, code) \
+do { \
+ icmp6_ifstat_inc(ifp, ifs6_out_msg); \
+ switch(type) { \
+ case ICMP6_DST_UNREACH: \
+ icmp6_ifstat_inc(ifp, ifs6_out_dstunreach); \
+ if (code == ICMP6_DST_UNREACH_ADMIN) \
+ icmp6_ifstat_inc(ifp, ifs6_out_adminprohib); \
+ break; \
+ case ICMP6_PACKET_TOO_BIG: \
+ icmp6_ifstat_inc(ifp, ifs6_out_pkttoobig); \
+ break; \
+ case ICMP6_TIME_EXCEEDED: \
+ icmp6_ifstat_inc(ifp, ifs6_out_timeexceed); \
+ break; \
+ case ICMP6_PARAM_PROB: \
+ icmp6_ifstat_inc(ifp, ifs6_out_paramprob); \
+ break; \
+ case ICMP6_ECHO_REQUEST: \
+ icmp6_ifstat_inc(ifp, ifs6_out_echo); \
+ break; \
+ case ICMP6_ECHO_REPLY: \
+ icmp6_ifstat_inc(ifp, ifs6_out_echoreply); \
+ break; \
+ case MLD_LISTENER_QUERY: \
+ icmp6_ifstat_inc(ifp, ifs6_out_mldquery); \
+ break; \
+ case MLD_LISTENER_REPORT: \
+ case MLDV2_LISTENER_REPORT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_mldreport); \
+ break; \
+ case MLD_LISTENER_DONE: \
+ icmp6_ifstat_inc(ifp, ifs6_out_mlddone); \
+ break; \
+ case ND_ROUTER_SOLICIT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_routersolicit); \
+ break; \
+ case ND_ROUTER_ADVERT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_routeradvert); \
+ break; \
+ case ND_NEIGHBOR_SOLICIT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); \
+ break; \
+ case ND_NEIGHBOR_ADVERT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); \
+ break; \
+ case ND_REDIRECT: \
+ icmp6_ifstat_inc(ifp, ifs6_out_redirect); \
+ break; \
+ } \
+} while (/*CONSTCOND*/ 0)
+
+extern int icmp6_rediraccept; /* accept/process redirects */
+extern int icmp6_redirtimeout; /* cache time for redirect routes */
+
+#define ICMP6_NODEINFO_FQDNOK 0x1
+#define ICMP6_NODEINFO_NODEADDROK 0x2
+#define ICMP6_NODEINFO_TMPADDROK 0x4
+#define ICMP6_NODEINFO_GLOBALOK 0x8
+#endif /* _KERNEL */
+#endif /* !__APPLE__ || (__APPLE__ && KERNEL_PRIVATE) */
+
+#endif /* not _NETINET_ICMP6_H_ */
Index: netinet/ip6.h
===================================================================
--- netinet/ip6.h (revision 0)
+++ netinet/ip6.h (working copy)
@@ -0,0 +1,380 @@
+/* $KAME: ip6.h,v 1.59 2004/07/09 09:15:19 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)ip.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IP6_H_
+#define _NETINET_IP6_H_
+
+/*
+ * Definition for internet protocol version 6.
+ * RFC 2460
+ */
+
+struct ip6_hdr {
+ union {
+ struct ip6_hdrctl {
+ u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */
+ u_int16_t ip6_un1_plen; /* payload length */
+ u_int8_t ip6_un1_nxt; /* next header */
+ u_int8_t ip6_un1_hlim; /* hop limit */
+ } ip6_un1;
+ u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
+ } ip6_ctlun;
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+} __attribute__((__packed__));
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define IPV6_VERSION 0x60
+#define IPV6_VERSION_MASK 0xf0
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */
+#define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */
+#define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */
+#endif /* LITTLE_ENDIAN */
+#endif
+#if 1
+/* ECN bits proposed by Sally Floyd */
+#define IP6TOS_CE 0x01 /* congestion experienced */
+#define IP6TOS_ECT 0x02 /* ECN-capable transport */
+#endif
+
+#ifdef _KERNEL
+/*
+ * for IPv6 pseudo header checksum
+ * XXX nonstandard
+ */
+struct ip6_hdr_pseudo {
+ struct in6_addr ip6ph_src;
+ struct in6_addr ip6ph_dst;
+ u_int32_t ip6ph_len;
+ u_int8_t ip6ph_zero[3];
+ u_int8_t ip6ph_nxt;
+} __packed;
+#endif
+
+/*
+ * Extension Headers
+ */
+
+struct ip6_ext {
+ u_int8_t ip6e_nxt;
+ u_int8_t ip6e_len;
+} __attribute__((__packed__));
+
+/* Hop-by-Hop options header */
+/* XXX should we pad it to force alignment on an 8-byte boundary? */
+struct ip6_hbh {
+ u_int8_t ip6h_nxt; /* next header */
+ u_int8_t ip6h_len; /* length in units of 8 octets */
+ /* followed by options */
+} __attribute__((__packed__));
+
+/* Destination options header */
+/* XXX should we pad it to force alignment on an 8-byte boundary? */
+struct ip6_dest {
+ u_int8_t ip6d_nxt; /* next header */
+ u_int8_t ip6d_len; /* length in units of 8 octets */
+ /* followed by options */
+} __attribute__((__packed__));
+
+/* Option types and related macros */
+#define IP6OPT_PAD1 0x00 /* 00 0 00000 */
+#define IP6OPT_PADN 0x01 /* 00 0 00001 */
+#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */
+#define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */
+#define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */
+#ifndef _KERNEL
+#define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */
+#endif
+#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 (RFC3542, recommended) */
+
+#define IP6OPT_RTALERT_LEN 4
+#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */
+#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */
+#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */
+#define IP6OPT_MINLEN 2
+
+#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */
+#define IP6OPT_EID 0x8a /* 10 0 01010 */
+
+#define IP6OPT_TYPE(o) ((o) & 0xC0)
+#define IP6OPT_TYPE_SKIP 0x00
+#define IP6OPT_TYPE_DISCARD 0x40
+#define IP6OPT_TYPE_FORCEICMP 0x80
+#define IP6OPT_TYPE_ICMP 0xC0
+
+#define IP6OPT_MUTABLE 0x20
+
+/* IPv6 options: common part */
+struct ip6_opt {
+ u_int8_t ip6o_type;
+ u_int8_t ip6o_len;
+} __attribute__((__packed__));
+
+/* Jumbo Payload Option */
+struct ip6_opt_jumbo {
+ u_int8_t ip6oj_type;
+ u_int8_t ip6oj_len;
+ u_int8_t ip6oj_jumbo_len[4];
+} __attribute__((__packed__));
+#define IP6OPT_JUMBO_LEN 6
+
+/* NSAP Address Option */
+struct ip6_opt_nsap {
+ u_int8_t ip6on_type;
+ u_int8_t ip6on_len;
+ u_int8_t ip6on_src_nsap_len;
+ u_int8_t ip6on_dst_nsap_len;
+ /* followed by source NSAP */
+ /* followed by destination NSAP */
+} __attribute__((__packed__));
+
+/* Tunnel Limit Option */
+struct ip6_opt_tunnel {
+ u_int8_t ip6ot_type;
+ u_int8_t ip6ot_len;
+ u_int8_t ip6ot_encap_limit;
+} __attribute__((__packed__));
+
+/* Router Alert Option */
+struct ip6_opt_router {
+ u_int8_t ip6or_type;
+ u_int8_t ip6or_len;
+ u_int8_t ip6or_value[2];
+} __attribute__((__packed__));
+/* Router alert values (in network byte order) */
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6_ALERT_MLD 0x0000
+#define IP6_ALERT_RSVP 0x0001
+#define IP6_ALERT_AN 0x0002
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IP6_ALERT_MLD 0x0000
+#define IP6_ALERT_RSVP 0x0100
+#define IP6_ALERT_AN 0x0200
+#endif /* LITTLE_ENDIAN */
+#endif
+
+/* Home Address Option */
+struct ip6_opt_home_address {
+ u_int8_t ip6oh_type;
+ u_int8_t ip6oh_len;
+ u_int8_t ip6oh_addr[16];/* Home Address */
+ /* followed by sub-options */
+} __attribute__((__packed__));
+
+/* Routing header */
+struct ip6_rthdr {
+ u_int8_t ip6r_nxt; /* next header */
+ u_int8_t ip6r_len; /* length in units of 8 octets */
+ u_int8_t ip6r_type; /* routing type */
+ u_int8_t ip6r_segleft; /* segments left */
+ /* followed by routing type specific data */
+} __attribute__((__packed__));
+
+/* Type 0 Routing header */
+struct ip6_rthdr0 {
+ u_int8_t ip6r0_nxt; /* next header */
+ u_int8_t ip6r0_len; /* length in units of 8 octets */
+ u_int8_t ip6r0_type; /* always zero */
+ u_int8_t ip6r0_segleft; /* segments left */
+ u_int32_t ip6r0_reserved; /* reserved field */
+ /* followed by up to 127 struct in6_addr */
+} __attribute__((__packed__));
+
+/* Type 2 Routing header for Mobile IPv6 */
+struct ip6_rthdr2 {
+ u_int8_t ip6r2_nxt; /* next header */
+ u_int8_t ip6r2_len; /* always 2 */
+ u_int8_t ip6r2_type; /* always 2 */
+ u_int8_t ip6r2_segleft; /* 0 or 1 */
+ u_int32_t ip6r2_reserved; /* reserved field */
+ /* followed by one struct in6_addr */
+} __attribute__((__packed__));
+
+/* Fragment header */
+struct ip6_frag {
+ u_int8_t ip6f_nxt; /* next header */
+ u_int8_t ip6f_reserved; /* reserved field */
+ u_int16_t ip6f_offlg; /* offset, reserved, and flag */
+ u_int32_t ip6f_ident; /* identification */
+} __attribute__((__packed__));
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Internet implementation parameters.
+ */
+#define IPV6_MAXHLIM 255 /* maximum hoplimit */
+#define IPV6_DEFHLIM 64 /* default hlim */
+#define IPV6_FRAGTTL 120 /* ttl for fragment packets, in slowtimo tick */
+#define IPV6_HLIMDEC 1 /* subtracted when forwarding */
+
+#define IPV6_MMTU 1280 /* minimal MTU and reassembly. 1024 + 256 */
+#define IPV6_MAXPACKET 65535 /* ip6 max packet size without Jumbo payload*/
+#define IPV6_MAXOPTHDR 2048 /* max option header size, 256 64-bit words */
+
+#ifdef _KERNEL
+/*
+ * IP6_EXTHDR_CHECK ensures that region between the IP6 header and the
+ * target header (including IPv6 itself, extension headers and
+ * TCP/UDP/ICMP6 headers) are continuous. KAME requires drivers
+ * to store incoming data into one internal mbuf or one or more external
+ * mbufs(never into two or more internal mbufs). Thus, the third case is
+ * supposed to never be matched but is prepared just in case.
+ */
+
+#define IP6_EXTHDR_CHECK(m, off, hlen, ret) \
+do { \
+ if ((m)->m_next != NULL) { \
+ if ((m)->m_len < (off) + (hlen)) { \
+ ip6stat.ip6s_exthdrtoolong++; \
+ m_freem(m); \
+ return ret; \
+ } \
+ } else { \
+ if ((m)->m_len < (off) + (hlen)) { \
+ ip6stat.ip6s_tooshort++; \
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); \
+ m_freem(m); \
+ return ret; \
+ } \
+ } \
+} while (/*CONSTCOND*/ 0)
+
+#ifdef PULLDOWN_STAT
+#define IP6_EXTHDR_STAT(x) x
+#else
+#define IP6_EXTHDR_STAT(x)
+#endif
+
+/*
+ * IP6_EXTHDR_GET ensures that intermediate protocol header (from "off" to
+ * "len") is located in single mbuf, on contiguous memory region.
+ * The pointer to the region will be returned to pointer variable "val",
+ * with type "typ".
+ * IP6_EXTHDR_GET0 does the same, except that it aligns the structure at the
+ * very top of mbuf. GET0 is likely to make memory copy than GET.
+ */
+#define IP6_EXTHDR_GET(val, typ, m, off, len) \
+do { \
+ struct mbuf *t; \
+ int tmp; \
+ IP6_EXTHDR_STAT(mbstat.m_exthdrget++); \
+ if ((m)->m_len >= (off) + (len)) \
+ (val) = (typ)(mtod((m), caddr_t) + (off)); \
+ else { \
+ t = m_pulldown((m), (off), (len), &tmp); \
+ if (t) { \
+ if (t->m_len < tmp + (len)) \
+ panic("m_pulldown malfunction"); \
+ (val) = (typ)(mtod(t, caddr_t) + tmp); \
+ } else { \
+ (val) = (typ)NULL; \
+ (m) = NULL; \
+ } \
+ } \
+} while (/*CONSTCOND*/ 0)
+
+#define IP6_EXTHDR_GET0(val, typ, m, off, len) \
+do { \
+ struct mbuf *t; \
+ IP6_EXTHDR_STAT(mbstat.m_exthdrget0++); \
+ if ((off) == 0 && (m)->m_len >= len) \
+ (val) = (typ)mtod((m), caddr_t); \
+ else { \
+ t = m_pulldown((m), (off), (len), NULL); \
+ if (t) { \
+ if (t->m_len < (len)) \
+ panic("m_pulldown malfunction"); \
+ (val) = (typ)mtod(t, caddr_t); \
+ } else { \
+ (val) = (typ)NULL; \
+ (m) = NULL; \
+ } \
+ } \
+} while (/*CONSTCOND*/ 0)
+#endif /*_KERNEL*/
+
+#endif /* not _NETINET_IP6_H_ */
Index: netselect.c
===================================================================
--- netselect.c (revision 26675)
+++ netselect.c (working copy)
@@ -59,6 +59,8 @@
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -100,7 +102,26 @@
struct timeval tv; /* time packet left */
}__attribute__((packed)) IPacket;
+/*
+ * format of a (headerless udp) probe packet.
+ */
+typedef struct
+{
+ struct udphdr udp;
+ u_char seq; /* sequence number of this packet */
+ u_char ttl; /* ttl packet left with */
+ struct timeval tv; /* time packet left */
+} OPacket6;
+/*
+ * format of a (icmpv6) probe packet.
+ */
+typedef struct
+{
+ struct icmp6_hdr icmp6; /* icmp6 contains seq (id) and ttl (seq)
+ * fields already */
+ struct timeval tv; /* time packet left */
+}__attribute__((packed)) I6Packet;
/*
* currently-known information about a host
@@ -114,7 +135,7 @@
char *dnsname; /* DNS name of the host, matches hostname
* unless a host resolves to multiple IP
* addresses */
- struct sockaddr_in addr; /* remote address */
+ struct sockaddr_storage addr; /* remote address */
int invalid; /* !=0 if we discard this host */
int done; /* !=0 if host testing is done */
@@ -132,23 +153,30 @@
/* prototypes for functions in this file */
static HostData *add_host(HostData *host, int *numhosts,
- char *hostname, struct sockaddr_in *addr,
+ char *hostname, struct sockaddr *addr,
char *dnsname, int max_ttl);
static char *un_url(char *orig);
-static char *fix_url(char *orig, char *hostname);
+static char *fix_url(char *orig, struct sockaddr *addr);
static HostData *name_resolver(int *numhosts, int numnames, char **names,
int max_ttl);
static void send_probe(int seq, int ttl, OPacket *op,
HostData *host);
+static void send_probe6(int seq, int ttl, OPacket6 *op,
+ HostData *host);
static void send_icmp_probe(int seq, int ttl, IPacket *op,
HostData *host);
+static void send_icmp6_probe(int seq, int ttl, I6Packet *op,
+ HostData *host);
static time_t deltaT(struct timeval *t1p, struct timeval *t2p);
static HostData *wait_for_reply(HostData *hosts, int numhosts,
- int sock, int msec_timeout);
+ int msec_timeout);
static HostData *packet_ok(HostData *hosts, int numhosts,
u_char *buf, int cc,
struct sockaddr_in *from);
+static HostData *packet6_ok(HostData *hosts, int numhosts,
+ u_char *buf, int cc,
+ struct sockaddr_in6 *from);
static int choose_ttl(HostData *host);
static void usage();
static int results(HostData *hosts, int numhosts, int num_score, int use_dns);
@@ -159,7 +187,9 @@
/* global variables */
static int rcvsock; /* receive (icmp) socket file descriptor */
+static int rcvsock6; /* IPv6 receive (icmp) socket file descriptor */
static int sndsock; /* send (udp) socket file descriptor */
+static int sndsock6; /* IPv6 send socket file descriptor */
static int verbose = 0;
static u_short ident;
@@ -167,6 +197,8 @@
static int validhosts;
+static int addr_fam = AF_UNSPEC;
+
int main(int argc, char **argv)
{
extern char *optarg;
@@ -173,15 +205,18 @@
extern int optind;
int hostcount, startcount, endcount = 0, sent_one, lag, min_lag = 100;
int ch, seq, ttl, max_ttl = 30, num_score = 1;
- int use_icmp, use_dns, found = 0;
+ int use_icmp = 0, use_dns = 0, found = 0;
+ int sock_v6_only = 1;
unsigned int min_tries = 10;
struct timeval now;
struct timezone tz;
OPacket udppacket; /* last output (udp) packet */
- IPacket icmppacket; /* last output (udp) packet */
+ IPacket icmppacket; /* last output (icmp) packet */
+ OPacket6 udppacket6; /* last output (headerless udp) packet */
+ I6Packet icmp6packet; /* last output (icmp6) packet */
HostData *host, *hosts;
- int numhosts, delay, must_continue, count;
+ int numhosts, delay, must_continue, count, port_unreachable, other_unreachable;
int socket_errno = 0;
/* we might have cap_net_raw on linux, instead print a tip if and when
@@ -190,8 +225,9 @@
fprintf (stderr, "%s: root privileges required\n", argv[0]);
*/
- if ((rcvsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0
- || (sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW )) < 0)
+ if ((rcvsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0
+ || (sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW )) < 0
+ || (rcvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
{
/* Capture errno so that command-line options can be parsed.
We delay reporting an error until this has happened. */
@@ -206,7 +242,7 @@
#ifdef __EMX__
_response(&argc,&argv);
#endif
- while ((ch = getopt(argc, argv, "s:t:m:IDv?")) != EOF)
+ while ((ch = getopt(argc, argv, "s:t:m:IDv?46")) != EOF)
{
switch (ch)
{
@@ -240,6 +276,14 @@
use_dns = 1;
break;
+ case '4':
+ addr_fam = AF_INET;
+ break;
+
+ case '6':
+ addr_fam = AF_INET6;
+ break;
+
case 'v':
verbose++;
break;
@@ -272,6 +316,19 @@
return 5;
}
+ if (addr_fam == AF_INET)
+ {
+ close(rcvsock6);
+ rcvsock6 = -1;
+ }
+ else if (addr_fam == AF_INET6)
+ {
+ close(rcvsock);
+ rcvsock = -1;
+ }
+
+ ident = (getpid() & 0xffff) | 0x8000;
+
if ( use_icmp )
{
memset(&icmppacket, 0, sizeof(IPacket));
@@ -278,6 +335,8 @@
icmppacket.ip.ip_tos = 0;
icmppacket.ip.ip_v = IPVERSION;
icmppacket.ip.ip_id = 0;
+
+ sndsock6 = rcvsock6;
}
else
{
@@ -285,10 +344,41 @@
udppacket.ip.ip_tos = 0;
udppacket.ip.ip_v = IPVERSION;
udppacket.ip.ip_id = 0;
+
+ if (addr_fam != AF_INET)
+ {
+ struct sockaddr_in6 source;
+
+ if ((sndsock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ {
+ perror("netselect: socket");
+ if (errno == EPERM) {
+ fprintf(stderr, "You should be root to run netselect.\n");
+ return 6;
+ }
+ return 5;
+ }
+
+ if (setsockopt(sndsock6, IPPROTO_IPV6, IPV6_V6ONLY,
+ &sock_v6_only, sizeof(int)) < 0)
+ {
+ perror("setsockopt with IPV6_V6ONLY");
+ return 1;
+ }
+
+ memset(&source, 0, sizeof(struct sockaddr_in6));
+ source.sin6_family = AF_INET6;
+ source.sin6_port = htons(ident);
+ memcpy(&source.sin6_addr, &in6addr_any, sizeof(struct in6_addr));
+
+ if (bind(sndsock6, (struct sockaddr *)&source, sizeof(source)) < 0)
+ {
+ perror("bind");
+ return 1;
+ }
+ }
}
- ident = (getpid() & 0xffff) | 0x8000;
-
validhosts = numhosts = 0;
hosts = name_resolver(&numhosts, argc, argv, max_ttl);
@@ -350,12 +440,26 @@
host->retries++;
host->num_out++;
- if ( use_icmp )
- send_icmp_probe(host->seq, ttl, &icmppacket, host);
- else
- send_probe(host->seq, ttl, &udppacket, host);
- endcount = hostcount;
- sent_one = 1;
+ if (host->addr.ss_family == AF_INET
+ || host->addr.ss_family == AF_INET6)
+ {
+ if (host->addr.ss_family == AF_INET)
+ {
+ if ( use_icmp )
+ send_icmp_probe(host->seq, ttl, &icmppacket, host);
+ else
+ send_probe(host->seq, ttl, &udppacket, host);
+ }
+ else
+ {
+ if ( use_icmp )
+ send_icmp6_probe(host->seq, ttl, &icmp6packet, host);
+ else
+ send_probe6(host->seq, ttl, &udppacket6, host);
+ }
+ endcount = hostcount;
+ sent_one = 1;
+ }
}
}
else if (host->hops_less_than - host->hops_more_than > 2)
@@ -374,7 +478,7 @@
} while (hostcount != startcount);
delay = min_lag/2; /* transmit time must be <= min_lag / 2 */
- if ((host = wait_for_reply(hosts, numhosts, rcvsock, delay)) != NULL)
+ if ((host = wait_for_reply(hosts, numhosts, delay)) != NULL)
{
gettimeofday(&now, &tz);
delay = 0;
@@ -383,10 +487,11 @@
fprintf(stderr, "%-35s %5u ms %3d hops - ", host->shortname,
(unsigned)deltaT(&host->send_time, &now),
choose_ttl(host));
-
- switch (host->code - 1)
+
+ port_unreachable = 0;
+ other_unreachable = 0;
+ if (host->code == -1)
{
- case -2:
if (verbose >= 3)
fprintf(stderr, "HIGHER");
else if (verbose >= 1)
@@ -396,9 +501,51 @@
host->hops_more_than = choose_ttl(host);
host->retries = 0;
host->num_out--;
- break;
-
- case ICMP_UNREACH_PORT:
+ }
+ else if (host->addr.ss_family == AF_INET)
+ {
+ switch (host->code - 1)
+ {
+ case ICMP_UNREACH_PORT:
+ port_unreachable = 1;
+ break;
+
+ case ICMP_UNREACH_NET:
+ case ICMP_UNREACH_HOST:
+ case ICMP_UNREACH_PROTOCOL:
+ case ICMP_UNREACH_NEEDFRAG:
+ case ICMP_UNREACH_SRCFAIL:
+ case ICMP_UNREACH_FILTER_PROHIB:
+ case ICMP_UNREACH_NET_PROHIB: /* misuse */
+ case ICMP_UNREACH_HOST_PROHIB:
+ case ICMP_UNREACH_NET_UNKNOWN:
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ case ICMP_UNREACH_ISOLATED:
+ case ICMP_UNREACH_TOSNET:
+ case ICMP_UNREACH_TOSHOST:
+ other_unreachable = 1;
+ break;
+ }
+ }
+ else if (host->addr.ss_family == AF_INET6)
+ {
+ switch (host->code - 1)
+ {
+ case ICMP6_DST_UNREACH_NOPORT:
+ port_unreachable = 1;
+ break;
+
+ case ICMP6_DST_UNREACH_NOROUTE:
+ case ICMP6_DST_UNREACH_ADMIN:
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ case ICMP6_DST_UNREACH_ADDR:
+ other_unreachable = 1;
+ break;
+ }
+ }
+
+ if (port_unreachable)
+ {
if (verbose >= 3)
fprintf(stderr, "OK");
else if (verbose >= 1)
@@ -414,27 +561,14 @@
fprintf(stderr, "\nmin_lag is now %d", min_lag);
}
host->total_lag += lag;
- break;
-
- case ICMP_UNREACH_NET:
- case ICMP_UNREACH_HOST:
- case ICMP_UNREACH_PROTOCOL:
- case ICMP_UNREACH_NEEDFRAG:
- case ICMP_UNREACH_SRCFAIL:
- case ICMP_UNREACH_FILTER_PROHIB:
- case ICMP_UNREACH_NET_PROHIB: /* misuse */
- case ICMP_UNREACH_HOST_PROHIB:
- case ICMP_UNREACH_NET_UNKNOWN:
- case ICMP_UNREACH_HOST_UNKNOWN:
- case ICMP_UNREACH_ISOLATED:
- case ICMP_UNREACH_TOSNET:
- case ICMP_UNREACH_TOSHOST:
+ }
+ else if (other_unreachable)
+ {
if (verbose >= 3)
fprintf(stderr, "unreachable! (blocking probes?)\n");
if (!host->invalid)
validhosts--;
host->invalid = 1;
- break;
}
if (verbose >= 3)
@@ -463,6 +597,10 @@
return 0;
}
+static inline int in6_addr_cmp(struct in6_addr *a, struct in6_addr *b)
+{
+ return memcmp(&a->s6_addr, &b->s6_addr, 16);
+}
/*
* when the newly-created objects are freed, we try to free(hostname)...
@@ -470,7 +608,7 @@
* function!
*/
static HostData *add_host(HostData *hosts, int *numhosts,
- char *hostname, struct sockaddr_in *addr,
+ char *hostname, struct sockaddr *addr,
char *dnsname, int max_ttl)
{
HostData *host;
@@ -477,14 +615,51 @@
if (addr)
{
- int hcount;
- for (hcount = 0, host = hosts; hcount < *numhosts; hcount++, host++)
- if (host->addr.sin_addr.s_addr == addr->sin_addr.s_addr)
+ int hcount;
+ sa_family_t family = ((struct sockaddr_storage *)addr)->ss_family;
+ struct in_addr *addr4, *haddr4;
+ struct in6_addr *addr6, *haddr6;
+
+
+ if ((family != AF_INET && family != AF_INET6)
+ || (family == AF_INET && addr_fam == AF_INET6)
+ || (family == AF_INET6 && addr_fam == AF_INET ))
+ {
+ if (verbose >= 1)
+ fprintf(stderr, "\nUnsupported address family %hu for host %s address\n",
+ family, hostname);
+ return hosts;
+ }
+
+ if (family == AF_INET)
+ addr4 = &((struct sockaddr_in *)addr)->sin_addr;
+ else
+ addr6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
+
+ for (hcount = 0, host = hosts; hcount < *numhosts; hcount++, host++)
{
- if (verbose >= 1)
- fprintf(stderr, "\nDuplicate address %s (%s, %s); keeping only under first name.\n",
- inet_ntoa(addr->sin_addr), host->hostname, hostname);
- return hosts;
+ if (host->invalid || host->addr.ss_family != family)
+ continue;
+
+ if (family == AF_INET)
+ haddr4 = &((struct sockaddr_in *)&host->addr)->sin_addr;
+ else
+ haddr6 = &((struct sockaddr_in6 *)&host->addr)->sin6_addr;
+
+ if ((family == AF_INET && haddr4->s_addr == addr4->s_addr)
+ || (family == AF_INET6 && in6_addr_cmp(haddr6, addr6) == 0))
+ {
+ if (verbose >= 1)
+ {
+ char txt[INET6_ADDRSTRLEN];
+ fprintf(stderr, "\nDuplicate address %s (%s, %s); keeping only under first name.\n",
+ inet_ntop(family,
+ family == AF_INET ? (void *)addr4 : (void *)addr6,
+ txt, sizeof(txt)),
+ host->hostname, hostname);
+ }
+ return hosts;
+ }
}
}
@@ -502,7 +677,7 @@
host->dnsname = dnsname;
host->shortname = un_url(hostname);
if (addr)
- memcpy(&host->addr, addr, sizeof(*addr));
+ memcpy(&host->addr, addr, sizeof(struct sockaddr_storage));
else
host->invalid = 1;
host->hops_less_than = max_ttl;
@@ -513,62 +688,132 @@
static char *un_url(char *orig)
{
- char *sptr, *eptr, *newbuf;
+ char *sptr, *eptr = NULL, *newbuf;
if ((sptr = strstr(orig, "://")) != NULL)
{
/* URL formatted, like: http://hostname:port/dir/file */
sptr += 3; /* skip :// */
- eptr = strchr(sptr, ':');
+ if (*sptr == '[') /* v6 literal address */
+ {
+ eptr = strchr(sptr, ']');
+ if (eptr)
+ ++sptr;
+ }
+ if (!eptr) eptr = strchr(sptr, ':');
if (!eptr) eptr = strchr(sptr, '/');
if (!eptr) eptr = strchr(sptr, 0);
-
+ }
+ else
+ {
+ if (*orig == '[')
+ {
+ /* quoted v6 literal address in non-URL format */
+ eptr = strchr(orig, ']');
+ if (eptr)
+ sptr = orig + 1;
+ }
+
+ if (!sptr && (eptr = strchr(orig, ':')) != NULL)
+ {
+ /* Could be an IPv6 address */
+ struct sockaddr_storage ss;
+ if (inet_pton(AF_INET6, orig, &ss) != 1)
+ {
+ /* FTP formatted, like: ftp.debian.org:/debian/foo */
+ sptr = orig;
+ }
+ }
+ }
+
+ if (sptr)
+ {
newbuf = (char *)malloc(eptr-sptr+1);
strncpy(newbuf, sptr, eptr-sptr);
newbuf[eptr-sptr] = 0;
return newbuf;
}
- else if ((sptr = strchr(orig, ':')) != NULL)
- {
- /* FTP formatted, like: ftp.debian.org:/debian/foo */
- newbuf = (char *)malloc(sptr-orig+1);
- strncpy(newbuf, orig, sptr-orig);
- newbuf[sptr-orig] = 0;
- return newbuf;
- }
else /* just plain */
return strdup(orig);
}
+static char *fix_url(char *orig, struct sockaddr *addr)
+{
+ char *pree = NULL, *posts = NULL;
+ char addrstr[INET6_ADDRSTRLEN + 2];
+ void *src;
-static char *fix_url(char *orig, char *hostname)
-{
- char *sptr, *eptr, *newbuf;
-
- if ((sptr = strstr(orig, "://")) != NULL)
+ if ((pree = strstr(orig, "://")) != NULL)
{
/* URL formatted, like: http://hostname:port/dir/file */
- sptr += 3; /* skip :// */
- eptr = strchr(sptr, ':');
- if (!eptr) eptr = strchr(sptr, '/');
- if (!eptr) eptr = strchr(sptr, 0);
+ pree += 3; /* skip :// */
+ if (*pree == '[') /* v6 literal address */
+ {
+ posts = strchr(pree, ']');
+ if (posts)
+ ++posts;
+ }
+ if (!posts) posts = strchr(pree, ':');
+ if (!posts) posts = strchr(pree, '/');
+ if (!posts) posts = strchr(pree, 0);
+ }
+ else
+ {
+ pree = orig;
+ if (*pree == '[')
+ {
+ /* quoted v6 literal address in non-URL format */
+ posts = strchr(pree, ']');
+ if (posts)
+ ++posts;
+ }
- newbuf = (char *)malloc(strlen(orig) + strlen(hostname) + 1);
- strncpy(newbuf, orig, sptr-orig);
- strcpy(newbuf+(sptr-orig), hostname);
- strcat(newbuf, eptr);
- return newbuf;
+ if (!posts)
+ {
+ struct sockaddr_storage ss;
+ if (inet_pton(AF_INET6, orig, &ss) != 1)
+ {
+ /* FTP formatted, like: ftp.debian.org:/debian/foo */
+ posts = strchr(orig, ':');
+ }
+ }
}
- else if ((sptr = strchr(orig, ':')) != NULL)
+
+ if (addr->sa_family == AF_INET)
+ src = &((struct sockaddr_in *)addr)->sin_addr;
+ else
+ src = &((struct sockaddr_in6 *)addr)->sin6_addr;
+
+ inet_ntop(addr->sa_family, src, addrstr, sizeof(addrstr));
+
+ if (posts)
{
- /* FTP formatted, like: ftp.debian.org:/debian/foo */
- newbuf = (char *)malloc(strlen(orig) + strlen(hostname) + 1);
- strcpy(newbuf, hostname);
- strcat(newbuf, sptr);
+ char *newbuf;
+ size_t addrlen;
+ size_t prelen = pree - orig;
+ size_t postlen = strlen(posts);
+
+ /* We want to quote a v6 address in this case */
+ if (addr->sa_family == AF_INET6)
+ {
+ char quoted_addr[sizeof(addrstr)];
+ sprintf(quoted_addr, "[%s]", addrstr);
+ strcpy(addrstr, quoted_addr);
+ }
+
+ addrlen = strlen(addrstr);
+
+ newbuf = (char *)malloc(prelen + addrlen + postlen + 1);
+
+ if (prelen > 0)
+ strncpy(newbuf, orig, prelen);
+ strncpy(newbuf + prelen, addrstr, addrlen);
+ strncpy(newbuf + prelen + addrlen, posts, postlen);
+
return newbuf;
}
else /* just plain */
- return strdup(hostname);
+ return strdup(addrstr);
}
@@ -582,7 +827,7 @@
struct {
char *hostname;
int broken, multi;
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
} result;
HostData *hosts = NULL;
@@ -591,8 +836,9 @@
time_t start = time(NULL);
fd_set rfd, wfd, efd;
struct timeval tv;
- struct hostent *hp;
+ struct addrinfo *hp, hints;
pid_t pid;
+ int err;
if (pipe(pipes))
{
@@ -605,6 +851,10 @@
setmode(pipes[0],O_BINARY);
setmode(pipes[1],O_BINARY);
#endif
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = addr_fam;
+ hints.ai_flags = AI_ADDRCONFIG;
while (time(NULL) < start + 20)
{
@@ -628,45 +878,52 @@
result.multi = result.broken = 0;
/* child task -- actually do name lookup */
- result.addr.sin_family = AF_INET;
- result.addr.sin_addr.s_addr = inet_addr(names[count]);
+
+ /* try simple IPv4 dotted-quad conversion */
+ if (addr_fam != AF_INET6)
+ {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *) &result.addr;
+ addr4->sin_family = AF_INET;
+ addr4->sin_addr.s_addr = inet_addr(names[count]);
- if (result.addr.sin_addr.s_addr != INADDR_NONE)
- {
- write(pipes[1], &result, sizeof(result));
+ if (addr4->sin_addr.s_addr != INADDR_NONE)
+ {
+ write(pipes[1], &result, sizeof(result));
+ /* Use this as a flag to not do a lookup */
+ result.multi = 1;
+ }
}
- else
+
+ if (result.multi == 0);
{
/* must actually do the name lookup */
char *simplename = un_url(result.hostname);
- hp = gethostbyname(simplename);
+ err = getaddrinfo(simplename, NULL, &hints, &hp);
free(simplename);
- if (hp)
+ if (!err)
{
- if (hp->h_addrtype != AF_INET
- || hp->h_length != sizeof(struct in_addr))
+ struct addrinfo *ptr;
+ int already_seen_one = 0;
+
+ result.broken = 0;
+ for (ptr = hp; ptr; ptr = ptr->ai_next)
{
- result.broken = 1;
+ if ((ptr->ai_family != AF_INET && ptr->ai_family != AF_INET6)
+ || (ptr->ai_family == AF_INET && addr_fam == AF_INET6)
+ || (ptr->ai_family == AF_INET6 && addr_fam == AF_INET))
+ continue;
+
+ if (already_seen_one)
+ result.multi = 1;
+
+ memcpy(&result.addr, ptr->ai_addr, ptr->ai_addrlen);
write(pipes[1], &result, sizeof(result));
+ if (!already_seen_one)
+ already_seen_one = 1;
}
- else
- {
- char **ptr = hp->h_addr_list;
-
- result.broken = 0;
- if (ptr[1])
- result.multi = 1;
- result.addr.sin_family = AF_INET;
-
- while (*ptr)
- {
- memcpy(&result.addr.sin_addr,
- *ptr, hp->h_length);
- write(pipes[1], &result, sizeof(result));
- ptr++;
- }
- }
+
+ freeaddrinfo(hp);
}
else
{
@@ -747,12 +1004,12 @@
if (result.multi)
newhostname = fix_url(result.hostname,
- inet_ntoa(result.addr.sin_addr));
+ (struct sockaddr *)&result.addr);
else
newhostname = strdup(result.hostname);
hosts = add_host(hosts, numhosts, newhostname,
- &result.addr, dnsname, max_ttl);
+ (struct sockaddr *)&result.addr, dnsname, max_ttl);
}
}
}
@@ -779,6 +1036,35 @@
return hosts;
}
+static void do_sendto(int sockfd, const void *buf, size_t len, HostData *host)
+{
+ int i;
+ i = sendto(sockfd, buf, len, 0, (struct sockaddr *)&host->addr,
+ sizeof(struct sockaddr_storage));
+ if (i < 0 || i != len)
+ {
+ if (i < 0)
+ {
+ switch (errno)
+ {
+ case ENETDOWN:
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ if (verbose >= 3)
+ fprintf(stderr, "unreachable or down!\n");
+ if (!host->invalid)
+ validhosts--;
+ host->invalid = 1;
+ break;
+
+ default:
+ perror("sendto");
+ }
+ }
+ fflush(stdout);
+ }
+}
static void send_probe(int seq, int ttl, OPacket *op, HostData *host)
{
@@ -785,9 +1071,8 @@
struct ip *ip = &op->ip;
struct udphdr *up = &op->udp;
struct timezone tz;
- int i;
- op->ip.ip_dst = host->addr.sin_addr;
+ op->ip.ip_dst = ((struct sockaddr_in *)&host->addr)->sin_addr;
op->seq = seq;
op->ttl = ttl;
gettimeofday(&op->tv, &tz);
@@ -808,31 +1093,30 @@
if (verbose >= 4)
fprintf(stderr, "%-35s(UDP)>>\n", host->shortname);
- i = sendto(sndsock, op, sizeof(OPacket), 0,
- (struct sockaddr *)&host->addr, sizeof(host->addr));
- if (i < 0 || i != sizeof(OPacket))
+ do_sendto(sndsock, op, sizeof(OPacket), host);
+}
+
+static void send_probe6(int seq, int ttl, OPacket6 *op, HostData *host)
+{
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&host->addr;
+ struct timezone tz;
+
+ op->seq = seq;
+ op->ttl = ttl;
+ gettimeofday(&op->tv, &tz);
+
+ addr->sin6_port = htons(port + seq);
+
+ if (verbose >= 4)
+ fprintf(stderr, "%-35s(UDP6)>>\n", host->shortname);
+
+ if (setsockopt(sndsock6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0)
{
- if (i < 0)
- {
- switch (errno)
- {
- case ENETDOWN:
- case ENETUNREACH:
- case EHOSTDOWN:
- case EHOSTUNREACH:
- if (verbose >= 3)
- fprintf(stderr, "unreachable or down!\n");
- if (!host->invalid)
- validhosts--;
- host->invalid = 1;
- break;
-
- default:
- perror("sendto");
- }
- }
- fflush(stdout);
+ perror("setsockopt with IPV6_UNICAST_HOPS");
+ return;
}
+
+ do_sendto(sndsock6, op, sizeof(OPacket6), host);
}
uint16_t
@@ -852,9 +1136,8 @@
struct ip *ip = &op->ip;
struct icmp *icmp = &op->icmp;
struct timezone tz;
- int i;
- op->ip.ip_dst = host->addr.sin_addr;
+ op->ip.ip_dst = ((struct sockaddr_in *)&host->addr)->sin_addr;
op->seq = seq;
op->ttl = ttl;
gettimeofday(&op->tv, &tz);
@@ -879,31 +1162,34 @@
if (verbose >= 5)
fprintf(stderr, "ICMP sequence: %i, identifier: %i\n", icmp->icmp_seq, icmp->icmp_id);
- i = sendto(sndsock, op, sizeof(IPacket), 0,
- (struct sockaddr *)&host->addr, sizeof(host->addr));
- if (i < 0 || i != sizeof(IPacket))
+ do_sendto(sndsock, op, sizeof(IPacket), host);
+}
+
+static void send_icmp6_probe(int seq, int ttl, I6Packet *op, HostData *host)
+{
+ struct icmp6_hdr *icmp = &op->icmp6;
+ struct timezone tz;
+
+ gettimeofday(&op->tv, &tz);
+
+ icmp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icmp->icmp6_code = 0;
+ icmp->icmp6_cksum = 0;
+ icmp->icmp6_id = htons (ident);
+ icmp->icmp6_seq = htons (seq);
+
+ if (verbose >= 4)
+ fprintf(stderr, "%-35s(ICMP6)>>\n", host->shortname);
+ if (verbose >= 5)
+ fprintf(stderr, "ICMP6 sequence: %i, identifier: %i\n", icmp->icmp6_seq, icmp->icmp6_id);
+
+ if (setsockopt(sndsock6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0)
{
- if (i < 0)
- {
- switch (errno)
- {
- case ENETDOWN:
- case ENETUNREACH:
- case EHOSTDOWN:
- case EHOSTUNREACH:
- if (verbose >= 3)
- fprintf(stderr, "unreachable or down!\n");
- if (!host->invalid)
- validhosts--;
- host->invalid = 1;
- break;
-
- default:
- perror("sendto");
- }
- }
- fflush(stdout);
+ perror("setsockopt with IPV6_UNICAST_HOPS");
+ return;
}
+
+ do_sendto(sndsock6, op, sizeof(I6Packet), host);
}
@@ -913,27 +1199,59 @@
+ (t2p->tv_usec - t1p->tv_usec) / 1000;
}
+static HostData * receive(HostData *hosts, int numhosts, int sock)
+{
+ u_char inpacket[INPACKET_SIZE];
+ struct sockaddr_storage from;
+ int cc = 0;
+ HostData *host = NULL;
+#if !defined(__GLIBC__)
+ int fromlen = sizeof(from);
+#else /* __GLIBC__ */
+ socklen_t fromlen = sizeof(from);
+#endif /* __GLIBC__ */
+
+ cc = recvfrom(sock, inpacket, INPACKET_SIZE, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (cc > 0 &&
+ (addr_fam == AF_UNSPEC || from.ss_family == addr_fam))
+ {
+ if (from.ss_family == AF_INET)
+ host = packet_ok(hosts, numhosts, inpacket, cc,
+ (struct sockaddr_in *)&from);
+ else
+ host = packet6_ok(hosts, numhosts, inpacket, cc,
+ (struct sockaddr_in6 *)&from);
+ }
+
+ return host;
+}
+
static HostData *wait_for_reply(HostData *hosts, int numhosts,
- int sock, int msec_timeout)
+ int msec_timeout)
{
fd_set fds;
struct timeval wait, start_time;
struct timezone tz;
- u_char inpacket[INPACKET_SIZE];
- struct sockaddr_in from;
- int cc = 0;
time_t msec_used;
HostData *host;
+ int nfds = -1;
+ int sock;
-#if !defined(__GLIBC__)
- int fromlen = sizeof(from);
-#else /* __GLIBC__ */
- socklen_t fromlen = sizeof(from);
-#endif /* __GLIBC__ */
-
FD_ZERO(&fds);
- FD_SET(sock, &fds);
+ if (addr_fam != AF_INET6)
+ {
+ FD_SET(rcvsock, &fds);
+ nfds = rcvsock;
+ }
+ if (addr_fam != AF_INET)
+ {
+ FD_SET(rcvsock6, &fds);
+ if (nfds < rcvsock6)
+ nfds = rcvsock6;
+ }
+ ++nfds;
gettimeofday(&start_time, &tz);
@@ -947,16 +1265,19 @@
wait.tv_usec = (msec_timeout - msec_used) * 1000;
wait.tv_sec = 0;
- if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
+ if (select(nfds, &fds, NULL, NULL, &wait) > 0)
{
- cc = recvfrom(rcvsock, inpacket, INPACKET_SIZE, 0,
- (struct sockaddr *) &from, &fromlen);
- if (cc > 0)
- {
- if ((host = packet_ok(hosts, numhosts, inpacket, cc, &from))
- != NULL)
- return host;
- }
+ if (addr_fam == AF_INET)
+ sock = rcvsock;
+ else if (addr_fam == AF_INET6)
+ sock = rcvsock6;
+ else if (FD_ISSET(rcvsock, &fds))
+ sock = rcvsock;
+ else
+ sock = rcvsock6;
+
+ if ((host = receive(hosts, numhosts, sock)) != NULL)
+ return host;
}
}
@@ -974,6 +1295,7 @@
struct icmp *icp;
HostData *host;
int hcount;
+ struct sockaddr_in *haddr;
ip = (struct ip *) buf;
hlen = ip->ip_hl << 2;
@@ -1001,11 +1323,13 @@
for (hcount = 0, host = hosts; hcount < numhosts; hcount++, host++)
{
- if (host->invalid) continue;
+ if (host->invalid || host->addr.ss_family != AF_INET) continue;
+ haddr = (struct sockaddr_in *)&host->addr;
+
/* Valid ICMP echo reply packet */
if ( type == ICMP_ECHOREPLY &&
- ip->ip_src.s_addr == host->addr.sin_addr.s_addr &&
+ ip->ip_src.s_addr == haddr->sin_addr.s_addr &&
icp->icmp_id == htons(ident) &&
icp->icmp_seq == htons(host->seq) )
{
@@ -1014,7 +1338,7 @@
}
/* Time exceeded reply to an ICMP echo request */
if ( type == ICMP_TIMXCEED &&
- hip->ip_dst.s_addr == host->addr.sin_addr.s_addr &&
+ hip->ip_dst.s_addr == haddr->sin_addr.s_addr &&
hip->ip_id == htons(ident+host->seq) )
{
host->code = -1;
@@ -1025,7 +1349,7 @@
if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
up->uh_sport == htons(ident) &&
up->uh_dport == htons(port + host->seq) &&
- hip->ip_dst.s_addr == host->addr.sin_addr.s_addr)
+ hip->ip_dst.s_addr == haddr->sin_addr.s_addr)
{
host->code = (type == ICMP_TIMXCEED ? -1 : code + 1);
return host;
@@ -1038,7 +1362,106 @@
return NULL;
}
+static HostData *packet6_ok(HostData *hosts, int numhosts,
+ u_char * buf, int cc,
+ struct sockaddr_in6 *from)
+{
+ u_char type, code;
+ struct icmp6_hdr *icp;
+ HostData *host;
+ int hcount;
+ if (cc < sizeof(struct icmp6_hdr))
+ return NULL;
+
+ icp = (struct icmp6_hdr *) buf;
+
+ type = icp->icmp6_type;
+ code = icp->icmp6_code;
+
+ if (verbose >= 5)
+ {
+ char txt[INET6_ADDRSTRLEN];
+ fprintf(stderr, "Received ICMP6 type: %i, code: %i, from %s\n", type, code,
+ inet_ntop(AF_INET6, &from->sin6_addr, txt, sizeof(txt)) );
+ }
+
+ if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
+ || type == ICMP6_DST_UNREACH || type == ICMP6_ECHO_REPLY )
+ {
+ struct ip6_hdr *hip;
+ int invoke_len;
+
+ hip = (struct ip6_hdr *) (icp + 1);
+
+ if (type != ICMP6_ECHO_REPLY)
+ {
+ if (cc < (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)))
+ return NULL;
+
+ /* Check packet is as big as the following code assumes */
+ switch (hip->ip6_nxt)
+ {
+ case IPPROTO_ICMPV6:
+ invoke_len = sizeof(struct icmp6_hdr);
+ break;
+ case IPPROTO_UDP:
+ invoke_len = sizeof(struct udphdr);
+ break;
+ default:
+ return NULL;
+ };
+
+ if (cc < (sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + invoke_len))
+ return NULL;
+ }
+
+
+ for (hcount = 0, host = hosts; hcount < numhosts; hcount++, host++)
+ {
+ struct sockaddr_in6 *haddr;
+
+ if (host->invalid || host->addr.ss_family != AF_INET6) continue;
+
+ haddr = (struct sockaddr_in6 *)&host->addr;
+
+ /* Valid ICMP echo reply packet */
+ if ( type == ICMP6_ECHO_REPLY &&
+ in6_addr_cmp(&from->sin6_addr, &haddr->sin6_addr) == 0 &&
+ icp->icmp6_id == htons(ident) &&
+ icp->icmp6_seq == htons(host->seq) )
+ {
+ host->code = ICMP6_DST_UNREACH_NOPORT + 1; /* Behave like if a UDP packet was received even though we used ICMP */
+ return host;
+ }
+ /* Time exceeded reply to an ICMP echo request */
+ if ( type == ICMP6_TIME_EXCEEDED &&
+ hip->ip6_nxt == IPPROTO_ICMPV6 &&
+ in6_addr_cmp(&hip->ip6_dst, &haddr->sin6_addr) == 0 &&
+ ((struct icmp6_hdr *)(hip + 1))->icmp6_id == htons(ident+host->seq) )
+ {
+ host->code = -1;
+ return host;
+ }
+
+ /* Valid reply to an UDP probe packet */
+ if ( hip->ip6_nxt == IPPROTO_UDP &&
+ in6_addr_cmp(&hip->ip6_dst, &haddr->sin6_addr) == 0 &&
+ ((struct udphdr *)(hip + 1))->uh_sport == htons(ident) &&
+ ((struct udphdr *)(hip + 1))->uh_dport == htons(port + host->seq) )
+ {
+ host->code = (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
+ return host;
+ }
+ }
+ }
+
+ if (verbose >= 3)
+ fprintf(stderr, "received an unknown v6 packet!\n");
+ return NULL;
+}
+
+
static int choose_ttl(HostData *host)
{
if (!host || host->invalid)
Index: netselect.1
===================================================================
--- netselect.1 (revision 26675)
+++ netselect.1 (working copy)
@@ -17,6 +17,7 @@
.IR PACKETS\|
.RB [ \|\-I ]
.RB [ \|\-D ]
+.RB [ \|\-4 | \|\-6 ]
.IR host \ ...
.SH DESCRIPTION
@@ -248,7 +249,14 @@
to present the final server list using the original DNS name instead
of the IP address if the DNS name resolves to more than one IP address.
+.TP
+.BI \-4
+Restrict address lookups to IPv4 only.
+.TP
+.BI \-6
+Restrict address lookups to IPv6 only.
+
.SH SEE ALSO
.BR ping (8),
.BR traceroute (8),