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 <bob....@collabora.com> 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),