aboutsummaryrefslogtreecommitdiffstats
path: root/network_cmds
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /network_cmds
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'network_cmds')
-rw-r--r--network_cmds/APPLE_LICENSE370
-rw-r--r--network_cmds/arp.tproj/IMPORT_NOTES3
-rw-r--r--network_cmds/arp.tproj/arp.8251
-rw-r--r--network_cmds/arp.tproj/arp.c1163
-rw-r--r--network_cmds/arp.tproj/arp4.4123
-rw-r--r--network_cmds/cfilutil/cfilstat.c341
-rw-r--r--network_cmds/cfilutil/cfilutil.156
-rw-r--r--network_cmds/cfilutil/cfilutil.c987
-rw-r--r--network_cmds/dnctl/dnctl.8508
-rw-r--r--network_cmds/dnctl/dnctl.c1313
-rw-r--r--network_cmds/ecnprobe/base.h57
-rw-r--r--network_cmds/ecnprobe/capture.c204
-rw-r--r--network_cmds/ecnprobe/capture.h58
-rw-r--r--network_cmds/ecnprobe/ecn.c1119
-rw-r--r--network_cmds/ecnprobe/ecn.h49
-rw-r--r--network_cmds/ecnprobe/ecn_probe.c469
-rw-r--r--network_cmds/ecnprobe/ecnprobe.120
-rw-r--r--network_cmds/ecnprobe/gmt2local.c66
-rw-r--r--network_cmds/ecnprobe/gmt2local.h27
-rw-r--r--network_cmds/ecnprobe/history.c211
-rw-r--r--network_cmds/ecnprobe/history.h75
-rw-r--r--network_cmds/ecnprobe/inet.c503
-rw-r--r--network_cmds/ecnprobe/inet.h206
-rw-r--r--network_cmds/ecnprobe/session.c785
-rw-r--r--network_cmds/ecnprobe/session.h183
-rw-r--r--network_cmds/ecnprobe/support.c246
-rw-r--r--network_cmds/ecnprobe/support.h132
-rw-r--r--network_cmds/frame_delay/frame_delay.845
-rw-r--r--network_cmds/frame_delay/frame_delay.c595
-rw-r--r--network_cmds/ifconfig.tproj/af_inet.c316
-rw-r--r--network_cmds/ifconfig.tproj/af_inet6.c753
-rw-r--r--network_cmds/ifconfig.tproj/af_link.c164
-rw-r--r--network_cmds/ifconfig.tproj/if6lowpan.c178
-rw-r--r--network_cmds/ifconfig.tproj/ifbond.c284
-rw-r--r--network_cmds/ifconfig.tproj/ifbridge.c952
-rw-r--r--network_cmds/ifconfig.tproj/ifclone.c170
-rw-r--r--network_cmds/ifconfig.tproj/ifconfig.81109
-rw-r--r--network_cmds/ifconfig.tproj/ifconfig.c2692
-rw-r--r--network_cmds/ifconfig.tproj/ifconfig.h186
-rw-r--r--network_cmds/ifconfig.tproj/iffake.c138
-rw-r--r--network_cmds/ifconfig.tproj/ifmedia.c872
-rw-r--r--network_cmds/ifconfig.tproj/ifvlan.c207
-rw-r--r--network_cmds/ifconfig.tproj/nexus.c98
-rw-r--r--network_cmds/ip6addrctl.tproj/ip6addrctl.8126
-rw-r--r--network_cmds/ip6addrctl.tproj/ip6addrctl.c467
-rw-r--r--network_cmds/ip6addrctl.tproj/ip6addrctl.conf12
-rw-r--r--network_cmds/kdumpd.tproj/com.apple.kdumpd.plist36
-rw-r--r--network_cmds/kdumpd.tproj/kdump.h114
-rwxr-xr-xnetwork_cmds/kdumpd.tproj/kdumpd.883
-rw-r--r--network_cmds/kdumpd.tproj/kdumpd.c726
-rw-r--r--network_cmds/kdumpd.tproj/kdumpsubs.c273
-rw-r--r--network_cmds/kdumpd.tproj/kdumpsubs.h72
-rw-r--r--network_cmds/mnc.tproj/LICENCE37
-rw-r--r--network_cmds/mnc.tproj/README63
-rw-r--r--network_cmds/mnc.tproj/mnc.1101
-rw-r--r--network_cmds/mnc.tproj/mnc.h92
-rw-r--r--network_cmds/mnc.tproj/mnc_error.c95
-rw-r--r--network_cmds/mnc.tproj/mnc_main.c131
-rw-r--r--network_cmds/mnc.tproj/mnc_multicast.c404
-rw-r--r--network_cmds/mnc.tproj/mnc_opts.c182
-rw-r--r--network_cmds/mptcp_client/conn_lib.c233
-rw-r--r--network_cmds/mptcp_client/conn_lib.h53
-rw-r--r--network_cmds/mptcp_client/mptcp_client.121
-rw-r--r--network_cmds/mptcp_client/mptcp_client.c701
-rw-r--r--network_cmds/mtest.tproj/COPYING27
-rw-r--r--network_cmds/mtest.tproj/mtest.8175
-rw-r--r--network_cmds/mtest.tproj/mtest.c825
-rw-r--r--network_cmds/ndp.tproj/gnuc.h2
-rw-r--r--network_cmds/ndp.tproj/ndp.8236
-rw-r--r--network_cmds/ndp.tproj/ndp.c1696
-rw-r--r--network_cmds/netstat.tproj/DERIVED_FILES1
-rw-r--r--network_cmds/netstat.tproj/data.c28
-rw-r--r--network_cmds/netstat.tproj/if.c2259
-rw-r--r--network_cmds/netstat.tproj/inet.c1361
-rw-r--r--network_cmds/netstat.tproj/inet6.c1333
-rw-r--r--network_cmds/netstat.tproj/ipsec.c376
-rw-r--r--network_cmds/netstat.tproj/main.c638
-rw-r--r--network_cmds/netstat.tproj/mbuf.c476
-rw-r--r--network_cmds/netstat.tproj/mcast.c887
-rw-r--r--network_cmds/netstat.tproj/misc.c122
-rw-r--r--network_cmds/netstat.tproj/mptcp.c170
-rw-r--r--network_cmds/netstat.tproj/netstat.1445
-rw-r--r--network_cmds/netstat.tproj/netstat.h170
-rw-r--r--network_cmds/netstat.tproj/route.c795
-rw-r--r--network_cmds/netstat.tproj/systm.c503
-rw-r--r--network_cmds/netstat.tproj/tp_astring.c74
-rw-r--r--network_cmds/netstat.tproj/unix.c231
-rw-r--r--network_cmds/netstat.tproj/vsock.c187
-rw-r--r--network_cmds/network-client-server-entitlements.plist10
-rw-r--r--network_cmds/network_cmds.plist26
-rwxr-xr-xnetwork_cmds/network_cmds.xcodeproj/project.pbxproj5098
-rw-r--r--network_cmds/ping.tproj/ping.8616
-rw-r--r--network_cmds/ping.tproj/ping.c2134
-rw-r--r--network_cmds/ping6.tproj/md5.c308
-rw-r--r--network_cmds/ping6.tproj/md5.h75
-rw-r--r--network_cmds/ping6.tproj/ping6.8625
-rw-r--r--network_cmds/ping6.tproj/ping6.c3340
-rw-r--r--network_cmds/pktapctl/pktapctl.841
-rw-r--r--network_cmds/pktapctl/pktapctl.c189
-rw-r--r--network_cmds/pktmnglr/packet_mangler.c329
-rw-r--r--network_cmds/rarpd.tproj/rarpd.892
-rw-r--r--network_cmds/rarpd.tproj/rarpd.c830
-rwxr-xr-xnetwork_cmds/route.tproj/gen_header.pl15
-rw-r--r--network_cmds/route.tproj/keywords49
-rw-r--r--network_cmds/route.tproj/keywords.h119
-rw-r--r--network_cmds/route.tproj/route.8405
-rw-r--r--network_cmds/route.tproj/route.c1571
-rw-r--r--network_cmds/rtadvd.tproj/advcap.c483
-rw-r--r--network_cmds/rtadvd.tproj/advcap.h45
-rw-r--r--network_cmds/rtadvd.tproj/config.c1313
-rw-r--r--network_cmds/rtadvd.tproj/config.h46
-rw-r--r--network_cmds/rtadvd.tproj/dump.c283
-rw-r--r--network_cmds/rtadvd.tproj/dump.h32
-rw-r--r--network_cmds/rtadvd.tproj/if.c604
-rw-r--r--network_cmds/rtadvd.tproj/if.h64
-rw-r--r--network_cmds/rtadvd.tproj/pathnames.h4
-rw-r--r--network_cmds/rtadvd.tproj/rrenum.c484
-rw-r--r--network_cmds/rtadvd.tproj/rrenum.h33
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.8207
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.c1650
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.conf20
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.conf.5509
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.h205
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd_logging.c45
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd_logging.h24
-rw-r--r--network_cmds/rtadvd.tproj/timer.c205
-rw-r--r--network_cmds/rtadvd.tproj/timer.h64
-rw-r--r--network_cmds/rtsol.tproj/dump.c172
-rw-r--r--network_cmds/rtsol.tproj/if.c501
-rw-r--r--network_cmds/rtsol.tproj/probe.c221
-rw-r--r--network_cmds/rtsol.tproj/rtsock.c179
-rw-r--r--network_cmds/rtsol.tproj/rtsol.8224
-rw-r--r--network_cmds/rtsol.tproj/rtsol.c343
-rw-r--r--network_cmds/rtsol.tproj/rtsold.c791
-rw-r--r--network_cmds/rtsol.tproj/rtsold.h96
-rw-r--r--network_cmds/spray.tproj/spray.874
-rw-r--r--network_cmds/spray.tproj/spray.c247
-rw-r--r--network_cmds/spray.tproj/spray.x24
-rw-r--r--network_cmds/traceroute.tproj/README126
-rw-r--r--network_cmds/traceroute.tproj/as.c242
-rw-r--r--network_cmds/traceroute.tproj/as.h42
-rw-r--r--network_cmds/traceroute.tproj/findsaddr-socket.c246
-rw-r--r--network_cmds/traceroute.tproj/findsaddr.h23
-rw-r--r--network_cmds/traceroute.tproj/gnuc.h43
-rw-r--r--network_cmds/traceroute.tproj/ifaddrlist.c202
-rw-r--r--network_cmds/traceroute.tproj/ifaddrlist.h57
-rw-r--r--network_cmds/traceroute.tproj/mean.awk50
-rw-r--r--network_cmds/traceroute.tproj/median.awk67
-rw-r--r--network_cmds/traceroute.tproj/traceroute.8439
-rw-r--r--network_cmds/traceroute.tproj/traceroute.c1822
-rw-r--r--network_cmds/traceroute.tproj/traceroute.h26
-rw-r--r--network_cmds/traceroute.tproj/version.c1
-rw-r--r--network_cmds/traceroute6.tproj/traceroute6.8178
-rw-r--r--network_cmds/traceroute6.tproj/traceroute6.c1423
154 files changed, 65374 insertions, 0 deletions
diff --git a/network_cmds/APPLE_LICENSE b/network_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..e7aa7d0
--- /dev/null
+++ b/network_cmds/APPLE_LICENSE
@@ -0,0 +1,370 @@
+ APPLE PUBLIC SOURCE LICENSE
+ Version 1.0 - March 16, 1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License. If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+ work which Apple Computer, Inc. ("Apple") publicly announces as
+ subject to this Apple Public Source License and which contains a
+ notice placed by Apple identifying such program or work as "Original
+ Code" and stating that it is subject to the terms of this Apple
+ Public Source License version 1.0 (or subsequent version thereof),
+ as it may be revised from time to time by Apple ("License"). As
+ used in this License:
+
+1.1 "Applicable Patents" mean: (a) in the case where Apple is the
+ grantor of rights, (i) patents or patent applications that are now
+ or hereafter acquired, owned by or assigned to Apple and (ii) whose
+ claims cover subject matter contained in the Original Code, but only
+ to the extent necessary to use, reproduce and/or distribute the
+ Original Code without infringement; and (b) in the case where You
+ are the grantor of rights, (i) patents and patent applications that
+ are now or hereafter acquired, owned by or assigned to You and (ii)
+ whose claims cover subject matter in Your Modifications, taken alone
+ or in combination with Original Code.
+
+1.2 "Covered Code" means the Original Code, Modifications, the
+ combination of Original Code and any Modifications, and/or any
+ respective portions thereof.
+
+1.3 "Deploy" means to use, sublicense or distribute Covered Code other
+ than for Your internal research and development (R&D), and includes
+ without limitation, any and all internal use or distribution of
+ Covered Code within Your business or organization except for R&D
+ use, as well as direct or indirect sublicensing or distribution of
+ Covered Code by You to any third party in any form or manner.
+
+1.4 "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+
+1.5 "Modifications" mean any addition to, deletion from, and/or change
+ to, the substance and/or structure of Covered Code. When code is
+ released as a series of files, a Modification is: (a) any addition
+ to or deletion from the contents of a file containing Covered Code;
+ and/or (b) any new file or other representation of computer program
+ statements that contains any part of Covered Code.
+
+1.6 "Original Code" means the Source Code of a program or other work
+ as originally made available by Apple under this License, including
+ the Source Code of any updates or upgrades to such programs or works
+ made available by Apple under this License, and that has been
+ expressly identified by Apple as such in the header file(s) of such
+ work.
+
+1.7 "Source Code" means the human readable form of a program or other
+ work that is suitable for making modifications to it, including all
+ modules it contains, plus any associated interface definition files,
+ scripts used to control compilation and installation of an
+ executable (object code).
+
+1.8 "You" or "Your" means an individual or a legal entity exercising
+ rights under this License. For legal entities, "You" or "Your"
+ includes any entity which controls, is controlled by, or is under
+ common control with, You, where "control" means (a) the power,
+ direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of fifty
+ percent (50%) or more of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+ and conditions of this License, Apple hereby grants You, effective
+ on the date You accept this License and download the Original Code,
+ a world-wide, royalty-free, non-exclusive license, to the extent of
+ Apple's Applicable Patents and copyrights covering the Original
+ Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+ without Modifications, solely for Your internal research and
+ development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+ instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6. You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) must notify Apple and other third parties of how to obtain Your
+Deployed Modifications by filling out and submitting the required
+information found at
+http://www.apple.com/publicsource/modifications.html; and
+
+(d) if you Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+ licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patents and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patents and other intellectual property rights owned or
+controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+ Code with other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In each such
+ instance, You must make sure the requirements of this License are
+ fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+ Section 2, no other patent rights, express or implied, are granted
+ by Apple herein. Modifications and/or Larger Works may require
+ additional patent licenses from Apple which Apple may grant in its
+ sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee
+ for, warranty, support, indemnity or liability obligations and/or
+ other rights consistent with the scope of the license granted herein
+ ("Additional Terms") to one or more recipients of Covered
+ Code. However, You may do so only on Your own behalf and as Your
+ sole responsibility, and not on behalf of Apple. You must obtain the
+ recipient's agreement that any such Additional Terms are offered by
+ You alone, and You hereby agree to indemnify, defend and hold Apple
+ harmless for any liability incurred by or claims asserted against
+ Apple by reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+ versions of this License from time to time. Each version will be
+ given a distinguishing version number. Once Original Code has been
+ published under a particular version of this License, You may
+ continue to use it under the terms of that version. You may also
+ choose to use such Original Code under the terms of any subsequent
+ version of this License published by Apple. No one other than Apple
+ has the right to modify the terms applicable to Covered Code created
+ under this License.
+
+8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or
+ in part pre-release, untested, or not fully tested works. The
+ Original Code may contain errors that could cause failures or loss
+ of data, and may be incomplete or contain inaccuracies. You
+ expressly acknowledge and agree that use of the Original Code, or
+ any portion thereof, is at Your sole and entire risk. THE ORIGINAL
+ CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT
+ OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF
+ SECTIONS 8 AND 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY
+ REFERRED TO AS "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR
+ CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY OR
+ SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT THAT
+ THE FUNCTIONS CONTAINED IN THE ORIGINAL CODE WILL MEET YOUR
+ REQUIREMENTS, OR THAT THE OPERATION OF THE ORIGINAL CODE WILL BE
+ UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE ORIGINAL CODE
+ WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN
+ BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A
+ WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. You
+ acknowledge that the Original Code is not intended for use in the
+ operation of nuclear facilities, aircraft navigation, communication
+ systems, or air traffic control machines in which case the failure
+ of the Original Code could lead to death, personal injury, or severe
+ physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement. If any of the Original Code becomes the subject of
+ a claim of infringement ("Affected Original Code"), Apple may, at
+ its sole discretion and option: (a) attempt to procure the rights
+ necessary for You to continue using the Affected Original Code; (b)
+ modify the Affected Original Code so that it is no longer
+ infringing; or (c) terminate Your rights to use the Affected
+ Original Code, effective immediately upon Apple's posting of a
+ notice to such effect on the Apple web site that is used for
+ implementation of this License.
+
+9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE
+ LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR
+ INABILITY TO USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER
+ UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE),
+ PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF
+ ESSENTIAL PURPOSE OF ANY REMEDY. In no event shall Apple's total
+ liability to You for all damages under this License exceed the
+ amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+ trademarks or trade names "Apple", "Apple Computer", "Mac OS X",
+ "Mac OS X Server" or any other trademarks or trade names belonging
+ to Apple (collectively "Apple Marks") and no Apple Marks may be
+ used to endorse or promote products derived from the Original Code
+ other than as permitted by and in strict compliance at all times
+ with Apple's third party trademark usage guidelines which are
+ posted at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Apple retains all rights, title and interest in and to
+ the Original Code and any Modifications made by or on behalf of
+ Apple ("Apple Modifications"), and such Apple Modifications will
+ not be automatically subject to this License. Apple may, at its
+ sole discretion, choose to license such Apple Modifications under
+ this License, or on different terms from those contained in this
+ License or may choose not to license them at all. Apple's
+ development, use, reproduction, modification, sublicensing and
+ distribution of Covered Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+ terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Sections 9.1 and/or 13.6(b); or (c)
+automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement
+against Apple.
+
+12.2 Effect of Termination. Upon termination, You agree to
+ immediately stop any further use, reproduction, modification and
+ distribution of the Covered Code, or Affected Original Code in the
+ case of termination under Section 9.1, and to destroy all copies of
+ the Covered Code or Affected Original Code (in the case of
+ termination under Section 9.1) that are in your possession or
+ control. All sublicenses to the Covered Code which have been
+ properly granted prior to termination shall survive any termination
+ of this License. Provisions which, by their nature, should remain
+ in effect beyond the termination of this License shall survive,
+ including but not limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and
+ 13. Neither party will be liable to the other for compensation,
+ indemnity or damages of any sort solely as a result of terminating
+ this License in accordance with its terms, and termination of this
+ License will be without prejudice to any other right or remedy of
+ either party.
+
+13. Miscellaneous.
+
+13.1 Export Law Assurances. You may not use or otherwise export or
+ re-export the Original Code except as authorized by United States
+ law and the laws of the jurisdiction in which the Original Code was
+ obtained. In particular, but without limitation, the Original Code
+ may not be exported or re-exported (a) into (or to a national or
+ resident of) any U.S. embargoed country or (b) to anyone on the
+ U.S. Treasury Department's list of Specially Designated Nationals
+ or the U.S. Department of Commerce's Table of Denial Orders. By
+ using the Original Code, You represent and warrant that You are not
+ located in, under control of, or a national or resident of any such
+ country or on any such list.
+
+13.2 Government End Users. The Covered Code is a "commercial item" as
+ defined in FAR 2.101. Government software and technical data
+ rights in the Covered Code include only those rights customarily
+ provided to the public as defined in this License. This customary
+ commercial license in technical data and software is provided in
+ accordance with FAR 12.211 (Technical Data) and 12.212 (Computer
+ Software) and, for Department of Defense purchases, DFAR
+ 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3
+ (Rights in Commercial Computer Software or Computer Software
+ Documentation). Accordingly, all U.S. Government End Users acquire
+ Covered Code with only those rights set forth herein.
+
+13.3 Relationship of Parties. This License will not be construed as
+ creating an agency, partnership, joint venture or any other form of
+ legal association between You and Apple, and You will not represent
+ to the contrary, whether expressly, by implication, appearance or
+ otherwise.
+
+13.4 Independent Development. Nothing in this License will impair
+ Apple's right to acquire, license, develop, have others develop for
+ it, market and/or distribute technology or products that perform
+ the same or similar functions as, or otherwise compete with,
+ Modifications, Larger Works, technology or products that You may
+ develop, produce, market or distribute.
+
+13.5 Waiver; Construction. Failure by Apple to enforce any provision
+ of this License will not be deemed a waiver of future enforcement
+ of that or any other provision. Any law or regulation which
+ provides that the language of a contract shall be construed against
+ the drafter will not apply to this License.
+
+13.6 Severability. (a) If for any reason a court of competent
+ jurisdiction finds any provision of this License, or portion
+ thereof, to be unenforceable, that provision of the License will be
+ enforced to the maximum extent permissible so as to effect the
+ economic benefits and intent of the parties, and the remainder of
+ this License will continue in full force and effect. (b)
+ Notwithstanding the foregoing, if applicable law prohibits or
+ restricts You from fully and/or specifically complying with
+ Sections 2 and/or 3 or prevents the enforceability of either of
+ those Sections, this License will immediately terminate and You
+ must immediately discontinue any use of the Covered Code and
+ destroy all copies of it that are in your possession or control.
+
+13.7 Dispute Resolution. Any litigation or other dispute resolution
+ between You and Apple relating to this License shall take place in
+ the Northern District of California, and You and Apple hereby
+ consent to the personal jurisdiction of, and venue in, the state
+ and federal courts within that District with respect to this
+ License. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly
+ excluded.
+
+13.8 Entire Agreement; Governing Law. This License constitutes the
+ entire agreement between the parties with respect to the subject
+ matter hereof. This License shall be governed by the laws of the
+ United States and the State of California, except that body of
+ California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+Reserved. This file contains Original Code and/or Modifications of
+Original Code as defined in and that are subject to the Apple Public
+Source License Version 1.0 (the 'License'). You may not use this file
+except in compliance with the License. Please obtain a copy of the
+License at http://www.apple.com/publicsource and read it before using
+this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+License for the specific language governing rights and limitations
+under the License."
diff --git a/network_cmds/arp.tproj/IMPORT_NOTES b/network_cmds/arp.tproj/IMPORT_NOTES
new file mode 100644
index 0000000..231c5ca
--- /dev/null
+++ b/network_cmds/arp.tproj/IMPORT_NOTES
@@ -0,0 +1,3 @@
+arp.c - FreeBSD file, included types.h, socket.h, ethernet.h, removed
+ token ring header, removed __unused__ attributes, hid token ring code
+ with #ifndef __APPLE__
diff --git a/network_cmds/arp.tproj/arp.8 b/network_cmds/arp.tproj/arp.8
new file mode 100644
index 0000000..b586c26
--- /dev/null
+++ b/network_cmds/arp.tproj/arp.8
@@ -0,0 +1,251 @@
+.\" Copyright (c) 2012 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1985, 1991, 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.
+.\" 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.
+.\"
+.\" @(#)arp.8 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.sbin/arp/arp.8,v 1.25.2.1 2008/04/25 16:38:14 sam Exp $
+.\"
+.Dd March 18, 2008
+.Dt ARP 8
+.Os
+.Sh NAME
+.Nm arp
+.Nd address resolution display and control
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Op Fl i Ar interface
+.Ar hostname
+.Nm
+.Op Fl n
+.Op Fl i Ar interface
+.Op Fl l
+.Fl a
+.Nm
+.Fl d Ar hostname
+.Op Cm pub
+.Op Cm ifscope interface
+.Nm
+.Fl d
+.Op Fl i Ar interface
+.Fl a
+.Nm
+.Fl s Ar hostname ether_addr
+.Op Cm temp
+.Op Cm reject
+.Op Cm blackhole
+.Op Cm pub Op Cm only
+.Op Cm ifscope interface
+.Nm
+.Fl S Ar hostname ether_addr
+.Op Cm temp
+.Op Cm reject
+.Op Cm blackhole
+.Op Cm pub Op Cm only
+.Op Cm ifscope interface
+.Nm
+.Fl f Ar filename
+.Sh DESCRIPTION
+The
+.Nm
+utility displays and modifies the Internet-to-Ethernet address translation
+tables used by the address resolution protocol
+.Pq Xr arp 4 .
+With no flags, the program displays the current
+.Tn ARP
+entry for
+.Ar hostname .
+The host may be specified by name or by number,
+using Internet dot notation.
+.Pp
+Available options:
+.Bl -tag -width indent
+.It Fl a
+The program displays or deletes all of the current
+.Tn ARP
+entries.
+.It Fl d
+A super-user may delete an entry for the host called
+.Ar hostname
+with the
+.Fl d
+flag.
+If the
+.Cm pub
+keyword is specified, only the
+.Dq published
+.Tn ARP
+entry
+for this host will be deleted.
+If the
+.Cm ifscope
+keyword is specified, the entry specific to the interface will be deleted.
+.Pp
+Alternatively, the
+.Fl d
+flag may be combined with the
+.Fl a
+flag to delete all entries.
+.It Fl i Ar interface
+Limit the operation scope to the
+.Tn ARP
+entries on
+.Ar interface .
+Applicable only to the following operations:
+display one, display all, delete all.
+.It Fl l
+Show link-layer reachability information.
+.It Fl n
+Show network addresses as numbers (normally
+.Nm
+attempts to display addresses symbolically).
+.It Fl s Ar hostname ether_addr
+Create an
+.Tn ARP
+entry for the host called
+.Ar hostname
+with the Ethernet address
+.Ar ether_addr .
+The Ethernet address is given as six hex bytes separated by colons.
+The entry will be permanent unless the word
+.Cm temp
+is given in the command.
+If the word
+.Cm pub
+is given, the entry will be
+.Dq published ;
+i.e., this system will
+act as an
+.Tn ARP
+server,
+responding to requests for
+.Ar hostname
+even though the host address is not its own.
+In this case the
+.Ar ether_addr
+can be given as
+.Cm auto
+in which case the interfaces on this host will be examined,
+and if one of them is found to occupy the same subnet, its
+Ethernet address will be used.
+If the
+.Cm only
+keyword is also specified, this will create a
+.Dq "published (proxy only)"
+entry.
+This type of entry is created automatically if
+.Nm
+detects that a routing table entry for
+.Ar hostname
+already exists.
+.Pp
+If the
+.Cm reject
+keyword is specified the entry will be marked so that traffic to
+the host will be discarded and the sender will be notified the
+host is unreachable.
+The
+.Cm blackhole
+keyword is similar in that traffic is discarded but the sender is
+not notified.
+These can be used to block external traffic to a host without
+using a firewall.
+.Pp
+If the
+.Cm ifscope
+keyword is specified, the entry will set with an additional property that
+strictly associate the entry to the interface. This allows
+for the presence of mutiple entries with the same destination
+on different interfaces.
+.It Fl S Ar hostname ether_addr
+Is just like
+.Fl s
+except any existing
+.Tn ARP
+entry for this host will be deleted first.
+.It Fl f Ar filename
+Cause the file
+.Ar filename
+to be read and multiple entries to be set in the
+.Tn ARP
+tables.
+Entries
+in the file should be of the form
+.Pp
+.Bd -ragged -offset indent -compact
+.Ar hostname ether_addr
+.Op Cm temp
+.Op Cm pub Op Cm only
+.Op Cm ifscope interface
+.Ed
+.Pp
+with argument meanings as given above.
+Leading whitespace and empty lines are ignored.
+A
+.Ql #
+character will mark the rest of the line as a comment.
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl l
+flag.
+.El
+.Sh SEE ALSO
+.Xr inet 3 ,
+.Xr arp 4 ,
+.Xr ifconfig 8 ,
+.Xr ndp 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 .
diff --git a/network_cmds/arp.tproj/arp.c b/network_cmds/arp.tproj/arp.c
new file mode 100644
index 0000000..eeca003
--- /dev/null
+++ b/network_cmds/arp.tproj/arp.c
@@ -0,0 +1,1163 @@
+/*
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sun Microsystems, Inc.
+ *
+ * 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.
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1984, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+#endif
+
+/*
+ * arp - display, set, and delete arp table entries
+ */
+
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#if 0
+#include <net/iso88025.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+typedef void (action_fn)(struct sockaddr_dl *sdl,
+ struct sockaddr_inarp *s_in, struct rt_msghdr *rtm);
+typedef void (action_ext_fn)(struct sockaddr_dl *sdl,
+ struct sockaddr_inarp *s_in, struct rt_msghdr_ext *rtm);
+
+static int search(in_addr_t addr, action_fn *action);
+static int search_ext(in_addr_t addr, action_ext_fn *action);
+static action_fn print_entry;
+static action_fn nuke_entry;
+static action_ext_fn print_entry_ext;
+
+static char *print_lladdr(struct sockaddr_dl *);
+static int delete(char *host, int do_proxy);
+static void usage(void);
+static int set(int argc, char **argv);
+static int get(char *host);
+static int file(char *name);
+static struct rt_msghdr *rtmsg(int cmd,
+ struct sockaddr_inarp *dst, struct sockaddr_dl *sdl);
+static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
+static struct sockaddr_inarp *getaddr(char *host);
+static int valid_type(int type);
+static char *sec2str(time_t);
+
+static int nflag; /* no reverse dns lookups */
+static int xflag; /* extended link-layer reachability information */
+static char *rifname;
+
+static int expire_time, flags, doing_proxy, proxy_only;
+
+static char *boundif = NULL;
+static unsigned int ifscope = 0;
+
+/* which function we're supposed to do */
+#define F_GET 1
+#define F_SET 2
+#define F_FILESET 3
+#define F_REPLACE 4
+#define F_DELETE 5
+
+#ifndef SA_SIZE
+#define SA_SIZE(sa) \
+ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
+ sizeof(uint32_t) : \
+ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
+#endif
+
+#define SETFUNC(f) { if (func) usage(); func = (f); }
+
+
+int
+main(int argc, char *argv[])
+{
+ int ch, func = 0;
+ int rtn = 0;
+ int aflag = 0; /* do it for all entries */
+ int lflag = 0;
+ uint32_t ifindex = 0;
+
+ while ((ch = getopt(argc, argv, "andflsSi:x")) != -1)
+ switch((char)ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ SETFUNC(F_DELETE);
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'S':
+ SETFUNC(F_REPLACE);
+ break;
+ case 's':
+ SETFUNC(F_SET);
+ break;
+ case 'f' :
+ SETFUNC(F_FILESET);
+ break;
+ case 'i':
+ rifname = optarg;
+ break;
+ case 'x':
+ xflag = 1;
+ lflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!func)
+ func = F_GET;
+ if (rifname) {
+ if (func != F_GET && !(func == F_DELETE && aflag))
+ errx(1, "-i not applicable to this operation");
+ if ((ifindex = if_nametoindex(rifname)) == 0) {
+ if (errno == ENXIO)
+ errx(1, "interface %s does not exist", rifname);
+ else
+ err(1, "if_nametoindex(%s)", rifname);
+ }
+ }
+ switch (func) {
+ case F_GET:
+ if (aflag) {
+ if (argc != 0)
+ usage();
+ if (lflag) {
+ printf("%-23s %-17s %-9.9s %-9.9s %8.8s %4s "
+ "%4s", "Neighbor",
+ "Linklayer Address", "Expire(O)",
+ "Expire(I)", "Netif", "Refs", "Prbs");
+ if (xflag)
+ printf(" %-7.7s %-7.7s %-7.7s",
+ "RSSI", "LQM", "NPM");
+ printf("\n");
+ search_ext(0, print_entry_ext);
+ } else {
+ search(0, print_entry);
+ }
+ } else {
+ if (argc != 1)
+ usage();
+ rtn = get(argv[0]);
+ }
+ break;
+ case F_SET:
+ case F_REPLACE:
+ if (argc < 2 || argc > 6)
+ usage();
+ if (func == F_REPLACE)
+ (void)delete(argv[0], 0);
+ rtn = set(argc, argv) ? 1 : 0;
+ break;
+ case F_DELETE:
+ if (aflag) {
+ if (argc != 0)
+ usage();
+ search(0, nuke_entry);
+ } else {
+ int do_proxy = 0;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strncmp(argv[i], "pub", sizeof("pub")) == 0) {
+ do_proxy = SIN_PROXY;
+ } else if (strncmp(argv[i], "ifscope", sizeof("ifscope")) == 0) {
+ if (i + 1 >= argc) {
+ printf("ifscope needs an interface parameter\n");
+ return (1);
+ }
+ boundif = argv[++i];
+ if ((ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "ifscope has bad interface name: %s", boundif);
+ } else {
+ usage();
+ }
+ }
+ if (i > argc)
+ usage();
+ rtn = delete(argv[0], do_proxy);
+ }
+ break;
+ case F_FILESET:
+ if (argc != 1)
+ usage();
+ rtn = file(argv[0]);
+ break;
+ }
+
+ return (rtn);
+}
+
+/*
+ * Process a file to set standard arp entries
+ */
+static int
+file(char *name)
+{
+ FILE *fp;
+ int i, retval;
+ char line[128], arg[7][50], *args[7], *p;
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "cannot open %s", name);
+ args[0] = &arg[0][0];
+ args[1] = &arg[1][0];
+ args[2] = &arg[2][0];
+ args[3] = &arg[3][0];
+ args[4] = &arg[4][0];
+ args[5] = &arg[5][0];
+ args[6] = &arg[6][0];
+ retval = 0;
+ while(fgets(line, sizeof(line), fp) != NULL) {
+ if ((p = strchr(line, '#')) != NULL)
+ *p = '\0';
+ for (p = line; isblank(*p); p++);
+ if (*p == '\n' || *p == '\0')
+ continue;
+ i = sscanf(p, "%49s %49s %49s %49s %49s %49s %49s", arg[0], arg[1],
+ arg[2], arg[3], arg[4], arg[5], arg[6]);
+ if (i < 2) {
+ warnx("bad line: %s", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+/*
+ * Given a hostname, fills up a (static) struct sockaddr_inarp with
+ * the address of the host and returns a pointer to the
+ * structure.
+ */
+static struct sockaddr_inarp *
+getaddr(char *host)
+{
+ struct hostent *hp;
+ static struct sockaddr_inarp reply;
+
+ bzero(&reply, sizeof(reply));
+ reply.sin_len = sizeof(reply);
+ reply.sin_family = AF_INET;
+ reply.sin_addr.s_addr = inet_addr(host);
+ if (reply.sin_addr.s_addr == INADDR_NONE) {
+ if (!(hp = gethostbyname(host))) {
+ warnx("%s: %s", host, hstrerror(h_errno));
+ return (NULL);
+ }
+ bcopy((char *)hp->h_addr, (char *)&reply.sin_addr,
+ sizeof reply.sin_addr);
+ }
+ return (&reply);
+}
+
+/*
+ * Returns true if the type is a valid one for ARP.
+ */
+static int
+valid_type(int type)
+{
+
+ switch (type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_ISO88023:
+ case IFT_ISO88024:
+#if 0
+ case IFT_ISO88025:
+#endif
+ case IFT_L2VLAN:
+#ifdef IFT_BRIDGE
+ case IFT_BRIDGE:
+#endif
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * Set an individual arp entry
+ */
+static int
+set(int argc, char **argv)
+{
+ struct sockaddr_inarp *addr;
+ struct sockaddr_inarp *dst; /* what are we looking for */
+ struct sockaddr_dl *sdl;
+ struct rt_msghdr *rtm;
+ struct ether_addr *ea;
+ char *host = argv[0], *eaddr = argv[1];
+ struct sockaddr_dl sdl_m;
+
+ argc -= 2;
+ argv += 2;
+
+ bzero(&sdl_m, sizeof(sdl_m));
+ sdl_m.sdl_len = sizeof(sdl_m);
+ sdl_m.sdl_family = AF_LINK;
+
+ dst = getaddr(host);
+ if (dst == NULL)
+ return (1);
+ doing_proxy = flags = proxy_only = expire_time = 0;
+ boundif = NULL;
+ ifscope = 0;
+ while (argc-- > 0) {
+ if (strncmp(argv[0], "temp", sizeof("temp")) == 0) {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ expire_time = tv.tv_sec + 20 * 60;
+ } else if (strncmp(argv[0], "pub", sizeof("pub")) == 0) {
+ flags |= RTF_ANNOUNCE;
+ doing_proxy = 1;
+ if (argc && strncmp(argv[1], "only", sizeof("only")) == 0) {
+ proxy_only = 1;
+ dst->sin_other = SIN_PROXY;
+ argc--; argv++;
+ }
+ } else if (strncmp(argv[0], "blackhole", sizeof("blackhole")) == 0) {
+ flags |= RTF_BLACKHOLE;
+ } else if (strncmp(argv[0], "reject", sizeof("reject")) == 0) {
+ flags |= RTF_REJECT;
+ } else if (strncmp(argv[0], "trail", sizeof("trail")) == 0) {
+ /* XXX deprecated and undocumented feature */
+ printf("%s: Sending trailers is no longer supported\n",
+ host);
+ } else if (strncmp(argv[0], "ifscope", sizeof("ifscope")) == 0) {
+ if (argc < 1) {
+ printf("ifscope needs an interface parameter\n");
+ return (1);
+ }
+ boundif = argv[1];
+ if ((ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "ifscope has bad interface name: %s", boundif);
+ argc--; argv++;
+ }
+ argv++;
+ }
+ ea = (struct ether_addr *)LLADDR(&sdl_m);
+ if (doing_proxy && !strcmp(eaddr, "auto")) {
+ if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
+ printf("no interface found for %s\n",
+ inet_ntoa(dst->sin_addr));
+ return (1);
+ }
+ sdl_m.sdl_alen = ETHER_ADDR_LEN;
+ } else {
+ struct ether_addr *ea1 = ether_aton(eaddr);
+
+ if (ea1 == NULL) {
+ warnx("invalid Ethernet address '%s'", eaddr);
+ return (1);
+ } else {
+ *ea = *ea1;
+ sdl_m.sdl_alen = ETHER_ADDR_LEN;
+ }
+ }
+ for (;;) { /* try at most twice */
+ rtm = rtmsg(RTM_GET, dst, &sdl_m);
+ if (rtm == NULL) {
+ warn("%s", host);
+ return (1);
+ }
+ addr = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
+ if (addr->sin_addr.s_addr != dst->sin_addr.s_addr)
+ break;
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY) &&
+ valid_type(sdl->sdl_type) )
+ break;
+ /*
+ * If we asked for a scope entry and did not get one or
+ * did not asked for a scope entry and got one, we can
+ * proceed.
+ */
+ if ((ifscope != 0) != (rtm->rtm_flags & RTF_IFSCOPE))
+ break;
+ if (doing_proxy == 0) {
+ printf("set: can only proxy for %s\n", host);
+ return (1);
+ }
+ if (dst->sin_other & SIN_PROXY) {
+ printf("set: proxy entry exists for non 802 device\n");
+ return (1);
+ }
+ dst->sin_other = SIN_PROXY;
+ proxy_only = 1;
+ }
+
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot intuit interface index and type for %s\n", host);
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL);
+}
+
+/*
+ * Display an individual arp entry
+ */
+static int
+get(char *host)
+{
+ struct sockaddr_inarp *addr;
+
+ addr = getaddr(host);
+ if (addr == NULL)
+ return (1);
+ if (0 == search(addr->sin_addr.s_addr, print_entry)) {
+ printf("%s (%s) -- no entry",
+ host, inet_ntoa(addr->sin_addr));
+ if (rifname)
+ printf(" on %s", rifname);
+ printf("\n");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Delete an arp entry
+ */
+static int
+delete(char *host, int do_proxy)
+{
+ struct sockaddr_inarp *addr, *dst;
+ struct rt_msghdr *rtm;
+ struct sockaddr_dl *sdl;
+
+ dst = getaddr(host);
+ if (dst == NULL)
+ return (1);
+ dst->sin_other = do_proxy;
+ for (;;) { /* try twice */
+ rtm = rtmsg(RTM_GET, dst, NULL);
+ if (rtm == NULL) {
+ warn("%s", host);
+ return (1);
+ }
+ addr = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
+ if (addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
+ sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY) &&
+ valid_type(sdl->sdl_type) )
+ break; /* found it */
+ if (dst->sin_other & SIN_PROXY) {
+ fprintf(stderr, "delete: cannot locate %s\n",host);
+ return (1);
+ }
+ dst->sin_other = SIN_PROXY;
+ }
+ if (rtmsg(RTM_DELETE, dst, NULL) != NULL) {
+ printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Search the arp table and do some action on matching entries
+ */
+static int
+search(in_addr_t addr, action_fn *action)
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *newbuf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_inarp *sin2;
+ struct sockaddr_dl *sdl;
+ char ifname[IF_NAMESIZE];
+ int st, found_entry = 0;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "route-sysctl-estimate");
+ if (needed == 0) /* empty table */
+ return 0;
+ buf = NULL;
+ for (;;) {
+ newbuf = realloc(buf, needed);
+ if (newbuf == NULL) {
+ if (buf != NULL)
+ free(buf);
+ errx(1, "could not reallocate memory");
+ }
+ buf = newbuf;
+ st = sysctl(mib, 6, buf, &needed, NULL, 0);
+ if (st == 0 || errno != ENOMEM)
+ break;
+ needed += needed / 8;
+ }
+ if (st == -1)
+ err(1, "actual retrieval of routing table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ sin2 = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
+ if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
+ strcmp(ifname, rifname))
+ continue;
+ if (addr) {
+ if (addr != sin2->sin_addr.s_addr)
+ continue;
+ found_entry = 1;
+ }
+ (*action)(sdl, sin2, rtm);
+ }
+ free(buf);
+ return (found_entry);
+}
+
+/*
+ * Stolen and adapted from ifconfig
+ */
+static char *
+print_lladdr(struct sockaddr_dl *sdl)
+{
+ static char buf[256];
+ char *cp;
+ int n, bufsize = sizeof (buf), p = 0;
+
+ bzero(buf, sizeof (buf));
+ cp = (char *)LLADDR(sdl);
+ if ((n = sdl->sdl_alen) > 0) {
+ while (--n >= 0)
+ p += snprintf(buf + p, bufsize - p, "%x%s",
+ *cp++ & 0xff, n > 0 ? ":" : "");
+ }
+ return (buf);
+}
+
+/*
+ * Display an arp entry
+ */
+static void
+print_entry(struct sockaddr_dl *sdl,
+ struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
+{
+ const char *host;
+ struct hostent *hp;
+ char ifname[IF_NAMESIZE];
+#if 0
+ struct iso88025_sockaddr_dl_data *trld;
+ int seg;
+#endif
+
+ if (nflag == 0)
+ hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
+ sizeof addr->sin_addr, AF_INET);
+ else
+ hp = 0;
+ if (hp)
+ host = hp->h_name;
+ else {
+ host = "?";
+ if (h_errno == TRY_AGAIN)
+ nflag = 1;
+ }
+ printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr));
+ if (sdl->sdl_alen) {
+#if 1
+ printf("%s", print_lladdr(sdl));
+#else
+ if ((sdl->sdl_type == IFT_ETHER ||
+ sdl->sdl_type == IFT_L2VLAN ||
+ sdl->sdl_type == IFT_BRIDGE) &&
+ sdl->sdl_alen == ETHER_ADDR_LEN)
+ printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
+ else {
+ int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+ printf("%s", link_ntoa(sdl) + n);
+ }
+#endif
+ } else
+ printf("(incomplete)");
+ if (if_indextoname(sdl->sdl_index, ifname) != NULL)
+ printf(" on %s", ifname);
+ if ((rtm->rtm_flags & RTF_IFSCOPE))
+ printf(" ifscope");
+ if (rtm->rtm_rmx.rmx_expire == 0)
+ printf(" permanent");
+ if (addr->sin_other & SIN_PROXY)
+ printf(" published (proxy only)");
+ if (rtm->rtm_addrs & RTA_NETMASK) {
+ addr = (struct sockaddr_inarp *)
+ (SA_SIZE(sdl) + (char *)sdl);
+ if (addr->sin_addr.s_addr == 0xffffffff)
+ printf(" published");
+ if (addr->sin_len != 8)
+ printf("(weird)");
+ }
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+ printf(" [ethernet]");
+ break;
+#if 0
+ case IFT_ISO88025:
+ printf(" [token-ring]");
+ trld = SDL_ISO88025(sdl);
+ if (trld->trld_rcf != 0) {
+ printf(" rt=%x", ntohs(trld->trld_rcf));
+ for (seg = 0;
+ seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2);
+ seg++)
+ printf(":%x", ntohs(*(trld->trld_route[seg])));
+ }
+ break;
+#endif
+ case IFT_FDDI:
+ printf(" [fddi]");
+ break;
+ case IFT_ATM:
+ printf(" [atm]");
+ break;
+ case IFT_L2VLAN:
+ printf(" [vlan]");
+ break;
+ case IFT_IEEE1394:
+ printf(" [firewire]");
+ break;
+#ifdef IFT_BRIDGE
+ case IFT_BRIDGE:
+ printf(" [bridge]");
+ break;
+#endif
+ default:
+ break;
+ }
+
+ printf("\n");
+
+}
+
+/*
+ * Nuke an arp entry
+ */
+static void
+nuke_entry(struct sockaddr_dl *sdl __unused,
+ struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
+{
+ char ip[20];
+
+ snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
+ /*
+ * When deleting all entries, specify the interface scope of each entry
+ */
+ if ((rtm->rtm_flags & RTF_IFSCOPE))
+ ifscope = rtm->rtm_index;
+ (void)delete(ip, 0);
+ ifscope = 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ "usage: arp [-n] [-i interface] hostname",
+ " arp [-n] [-i interface] [-l] -a",
+ " arp -d hostname [pub] [ifscope interface]",
+ " arp -d [-i interface] -a",
+ " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
+ " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
+ " arp -f filename");
+ exit(1);
+}
+
+static struct rt_msghdr *
+rtmsg(int cmd, struct sockaddr_inarp *dst, struct sockaddr_dl *sdl)
+{
+ static int seq;
+ int rlen;
+ int l;
+ struct sockaddr_in so_mask, *so_mask_ptr = &so_mask;
+ static int s = -1;
+ static pid_t pid;
+
+ static struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+ } m_rtmsg;
+
+ struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ char *cp = m_rtmsg.m_space;
+
+ if (s < 0) { /* first time: open socket, get pid */
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ err(1, "socket");
+ pid = getpid();
+ }
+ bzero(&so_mask, sizeof(so_mask));
+ so_mask.sin_len = 8;
+ so_mask.sin_addr.s_addr = 0xffffffff;
+
+ errno = 0;
+ /*
+ * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
+ * appropriately (except for the mask set just above).
+ */
+ if (cmd == RTM_DELETE)
+ goto doit;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ /*
+ * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and
+ * a unscoped route exist. That means we cannot delete a unscoped route if there is
+ * also a matching scope route
+ */
+ if (ifscope) {
+ rtm->rtm_index = ifscope;
+ rtm->rtm_flags |= RTF_IFSCOPE;
+ }
+
+ switch (cmd) {
+ default:
+ errx(1, "internal wrong cmd");
+ case RTM_ADD:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ dst->sin_other = 0;
+ if (doing_proxy) {
+ if (proxy_only)
+ dst->sin_other = SIN_PROXY;
+ else {
+ rtm->rtm_addrs |= RTA_NETMASK;
+ rtm->rtm_flags &= ~RTF_HOST;
+ }
+ }
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if ((s) != NULL && rtm->rtm_addrs & (w)) { \
+ bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);}
+
+ NEXTADDR(RTA_DST, dst);
+ NEXTADDR(RTA_GATEWAY, sdl);
+ NEXTADDR(RTA_NETMASK, so_mask_ptr);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+doit:
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if (errno != ESRCH || cmd != RTM_DELETE) {
+ warn("writing to routing socket");
+ return (NULL);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+ if (l < 0)
+ warn("read from routing socket");
+ return (rtm);
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+static int
+get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ in_addr_t ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+ int sock;
+ int retval = 0;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ err(1, "socket");
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ warnx("ioctl(SIOCGIFCONF)");
+ goto done;
+ }
+
+#define NEXTIFR(i) \
+ ((struct ifreq *)((char *)&(i)->ifr_addr \
+ + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) {
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ strlcpy(ifreq.ifr_name, ifr->ifr_name,
+ sizeof(ifreq.ifr_name));
+ ifreq.ifr_addr = ifr->ifr_addr;
+ /*
+ * Check that the interface is up,
+ * and not point-to-point or loopback.
+ */
+ if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
+ IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on
+ * the right subnet.
+ */
+ if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+ ina = ((struct sockaddr_in *)
+ &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) == (ina & mask))
+ break; /* ok, we got it! */
+ }
+
+ if (ifr >= ifend)
+ goto done;
+
+ /*
+ * Now scan through again looking for a link-level address
+ * for this interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr))
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 &&
+ ifr->ifr_addr.sa_family == AF_LINK)
+ break;
+ if (ifr >= ifend)
+ goto done;
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *) &ifr->ifr_addr;
+ memcpy(hwaddr, LLADDR(dla), dla->sdl_alen);
+ printf("using interface %s for proxy with address ",
+ ifp->ifr_name);
+ printf("%s\n", ether_ntoa(hwaddr));
+ retval = dla->sdl_alen;
+done:
+ close(sock);
+ return (retval);
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
+
+static int
+search_ext(in_addr_t addr, action_ext_fn *action)
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *newbuf, *next;
+ struct rt_msghdr_ext *ertm;
+ struct sockaddr_inarp *sin2;
+ struct sockaddr_dl *sdl;
+ char ifname[IF_NAMESIZE];
+ int st, found_entry = 0;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_DUMPX_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "route-sysctl-estimate");
+ if (needed == 0) /* empty table */
+ return 0;
+ buf = NULL;
+ for (;;) {
+ newbuf = realloc(buf, needed);
+ if (newbuf == NULL) {
+ if (buf != NULL)
+ free(buf);
+ errx(1, "could not reallocate memory");
+ }
+ buf = newbuf;
+ st = sysctl(mib, 6, buf, &needed, NULL, 0);
+ if (st == 0 || errno != ENOMEM)
+ break;
+ needed += needed / 8;
+ }
+ if (st == -1)
+ err(1, "actual retrieval of routing table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += ertm->rtm_msglen) {
+ ertm = (struct rt_msghdr_ext *)next;
+ sin2 = (struct sockaddr_inarp *)(ertm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
+ if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
+ strcmp(ifname, rifname))
+ continue;
+ if (addr) {
+ if (addr != sin2->sin_addr.s_addr)
+ continue;
+ found_entry = 1;
+ }
+ (*action)(sdl, sin2, ertm);
+ }
+ free(buf);
+ return (found_entry);
+}
+
+static void
+print_entry_ext(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr,
+ struct rt_msghdr_ext *ertm)
+{
+ const char *host;
+ struct hostent *hp;
+ char ifname[IF_NAMESIZE];
+ struct timeval time;
+
+ if (nflag == 0)
+ hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
+ sizeof (addr->sin_addr), AF_INET);
+ else
+ hp = 0;
+
+ if (hp)
+ host = hp->h_name;
+ else
+ host = inet_ntoa(addr->sin_addr);
+
+ printf("%-23s ", host);
+
+ if (sdl->sdl_alen)
+ printf("%-17s ", print_lladdr(sdl));
+ else
+ printf("%-17s ", "(incomplete)");
+
+ gettimeofday(&time, 0);
+
+ if (ertm->rtm_ri.ri_refcnt == 0 || ertm->rtm_ri.ri_snd_expire == 0)
+ printf("%-9.9s ", "(none)");
+ else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
+ printf("%-9.9s ",
+ sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
+ else
+ printf("%-9.9s ", "expired");
+
+ if (ertm->rtm_ri.ri_refcnt == 0 || ertm->rtm_ri.ri_rcv_expire == 0)
+ printf("%-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
+ printf("%-9.9s",
+ sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
+ else
+ printf("%-9.9s", "expired");
+
+ if (if_indextoname(sdl->sdl_index, ifname) == NULL)
+ snprintf(ifname, sizeof (ifname), "%s", "?");
+ printf(" %8.8s", ifname);
+
+ if (ertm->rtm_ri.ri_refcnt) {
+ printf(" %4d", ertm->rtm_ri.ri_refcnt);
+ if (ertm->rtm_ri.ri_probes)
+ printf(" %4d", ertm->rtm_ri.ri_probes);
+
+ if (xflag) {
+ if (!ertm->rtm_ri.ri_probes)
+ printf(" %-4.4s", "none");
+
+ if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", ertm->rtm_ri.ri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (ertm->rtm_ri.ri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_lqm);
+ break;
+ }
+
+ switch (ertm->rtm_ri.ri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_npm);
+ break;
+ }
+ }
+ }
+ printf("\n");
+}
diff --git a/network_cmds/arp.tproj/arp4.4 b/network_cmds/arp.tproj/arp4.4
new file mode 100644
index 0000000..a8bb6e7
--- /dev/null
+++ b/network_cmds/arp.tproj/arp4.4
@@ -0,0 +1,123 @@
+.\" Copyright (c) 1985, 1986, 1988, 1994
+.\" 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.
+.\"
+.\" @(#)arp4.4 6.5 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt ARP 4
+.Os BSD 4
+.Sh NAME
+.Nm arp
+.Nd Address Resolution Protocol
+.Sh SYNOPSIS
+.Em "pseudo-device ether"
+.Sh DESCRIPTION
+The Address Resolution Protocol (ARP) is a protocol used to dynamically
+map between Internet host addresses and 10Mb/s Ethernet addresses.
+It is used by all the 10Mb/s Ethernet interface drivers.
+It is not specific to Internet protocols or to 10Mb/s Ethernet,
+but this implementation currently supports only that combination.
+.Pp
+ARP caches Internet-Ethernet address mappings.
+When an interface requests a mapping for an address not in the cache,
+ARP queues the message which requires the mapping and broadcasts
+a message on the associated network requesting the address mapping.
+If a response is provided, the new mapping is cached and any pending
+message is transmitted.
+ARP will queue at most one packet while waiting for a response to a
+mapping request;
+only the most recently ``transmitted'' packet is kept.
+If the target host does not respond after several requests,
+the host is considered to be down for a short period (normally 20 seconds),
+allowing an error to be returned to transmission attempts during this
+interval.
+The error is
+.Li EHOSTDOWN
+for a non-responding destination host, and
+.Li EHOSTUNREACH
+for a non-responding router.
+.Pp
+The ARP cache is stored in the system routing table as
+dynamically-created host routes.
+The route to a directly-attached Ethernet network is installed as a
+.Dq cloning
+route (one with the
+.Li RTF_CLONING
+flag set),
+causing routes to individual hosts on that network to be created on
+demand.
+These routes time out periodically (normally 20 minutes after validated;
+entries are not validated when not in use).
+An entry for a host which is not responding is a
+.Dq reject
+route (one with the
+.Li RTF_REJECT
+flag set).
+.Pp
+ARP entries may be added, deleted or changed with the
+.Xr arp 8
+utility.
+Manually-added entries may be temporary or permanent,
+and may be
+.Dq published ,
+in which case the system will respond to ARP requests for that host
+as if it were the target of the request.
+.Pp
+In the past,
+ARP was used to negotiate the use of a trailer encapsulation.
+This is no longer supported.
+.Pp
+ARP watches passively for hosts impersonating the local host (i.e. a host
+which responds to an ARP mapping request for the local host's address).
+.Sh DIAGNOSTICS
+.Em "duplicate IP address %x!! sent from ethernet address: %x:%x:%x:%x:%x:%x."
+ARP has discovered another host on the local network which responds to
+mapping requests for its own Internet address with a different Ethernet
+address, generally indicating that two hosts are attempting to use the
+same Internet address.
+.Sh SEE ALSO
+.Xr inet 4 ,
+.Xr route 4 ,
+.Xr arp 8 ,
+.Xr ifconfig 8 ,
+.Xr route 8
+.sp
+.Rs
+.%A Plummer, D.
+.%B "An Ethernet Address Resolution Protocol"
+.%T RFC826
+.Re
+.Rs
+.%A Leffler, S.J.
+.%A Karels, M.J.
+.%B "Trailer Encapsulations
+.%T RFC893
+.Re
diff --git a/network_cmds/cfilutil/cfilstat.c b/network_cmds/cfilutil/cfilstat.c
new file mode 100644
index 0000000..a012e06
--- /dev/null
+++ b/network_cmds/cfilutil/cfilstat.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/errno.h>
+#include <sys/sysctl.h>
+#include <net/content_filter.h>
+#include <libproc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <unistd.h>
+#include <string.h>
+
+#define IPPROTOCOL_TCP 6
+#define IPPROTOCOL_UDP 17
+
+void
+print_filter_list()
+{
+ size_t total_len, curr_len;
+ void *buffer = NULL;
+ void *ptr;
+ uint32_t line = 0;
+
+ if (sysctlbyname("net.cfil.filter_list", NULL, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.filter_list)");
+
+ buffer = malloc(total_len);
+ if (buffer == NULL)
+ err(1, "malloc()");
+ if (sysctlbyname("net.cfil.filter_list", buffer, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.filter_list)");
+
+ ptr = buffer;
+ curr_len = 0;
+ do {
+ struct cfil_filter_stat *filter_stat;
+
+ filter_stat = (struct cfil_filter_stat *)ptr;
+
+ if (curr_len + filter_stat->cfs_len > total_len ||
+ filter_stat->cfs_len < sizeof(struct cfil_filter_stat))
+ break;
+
+ if (line % 16 == 0)
+ printf("%10s %10s %10s %10s\n",
+ "filter", "flags", "count", "necpunit");
+
+ printf("%10u 0x%08x %10u %10u\n",
+ filter_stat->cfs_filter_id,
+ filter_stat->cfs_flags,
+ filter_stat->cfs_sock_count,
+ filter_stat->cfs_necp_control_unit);
+
+ ptr += filter_stat->cfs_len;
+ curr_len += filter_stat->cfs_len;
+ } while (1);
+
+ free(buffer);
+}
+
+void
+sprint_offset(char *str, size_t len, const char *fmt, uint64_t offset)
+{
+ if (offset == CFM_MAX_OFFSET)
+ snprintf(str, len, "%s", "MAX");
+ else
+ snprintf(str, len, fmt, offset);
+}
+
+void
+print_socket_list()
+{
+ size_t total_len, curr_len;
+ void *buffer = NULL;
+ void *ptr;
+ int i;
+
+ if (sysctlbyname("net.cfil.sock_list", NULL, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.sock_list)");
+
+ buffer = malloc(total_len);
+ if (buffer == NULL)
+ err(1, "malloc()");
+ if (sysctlbyname("net.cfil.sock_list", buffer, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.sock_list)");
+
+ ptr = buffer;
+ curr_len = 0;
+ do {
+ struct cfil_sock_stat *sock_stat;
+ char opass[32];
+ char ipass[32];
+ char namebuffer[256];
+ char *procName = "<not found>";
+
+ sock_stat = (struct cfil_sock_stat *)ptr;
+
+ if (curr_len + sock_stat->cfs_len > total_len ||
+ sock_stat->cfs_len < sizeof(struct cfil_sock_stat))
+ break;
+
+ if (proc_name(sock_stat->cfs_e_pid, namebuffer, sizeof(namebuffer)) > 0) {
+ procName = namebuffer;
+ }
+
+ sprint_offset(opass, 32, "%8llu", sock_stat->cfs_snd.cbs_pass_offset);
+ sprint_offset(ipass, 32, "%8llu", sock_stat->cfs_rcv.cbs_pass_offset);
+
+ printf("%16s %5s %10s "
+ "%8s %8s %8s %8s %8s %8s %8s "
+ "%8s %8s %8s %8s %8s %8s %8s "
+ "%8s %8s %15s\n",
+ "sockid", "proto", "flags",
+ "ofirst", "olast", "oqlen", " ", "opass", " ", " ",
+ "ifirst", "ilast", "iqlen", " ", "ipass", " ", " ",
+ "pid", "epid", "eprocname");
+
+ printf("%016llu %5s 0x%08llx "
+ "%8llu %8llu %8llu %8s %8s %8s %8s "
+ "%8llu %8llu %8llu %8s %8s %8s %8s "
+ "%8u %8u %15s\n",
+
+ sock_stat->cfs_sock_id,
+ sock_stat->cfs_sock_protocol == IPPROTOCOL_TCP ? "TCP" : "UDP",
+ sock_stat->cfs_flags,
+
+ sock_stat->cfs_snd.cbs_pending_first,
+ sock_stat->cfs_snd.cbs_pending_last,
+ sock_stat->cfs_snd.cbs_inject_q_len,
+ " ",
+ opass,
+ " ",
+ " ",
+
+ sock_stat->cfs_rcv.cbs_pending_first,
+ sock_stat->cfs_rcv.cbs_pending_last,
+ sock_stat->cfs_rcv.cbs_inject_q_len,
+ " ",
+ ipass,
+ " ",
+ " ",
+ sock_stat->cfs_pid,
+ sock_stat->cfs_e_pid,
+ procName);
+
+
+ printf("%7s %10s %10s "
+ "%8s %8s %8s %8s %8s %8s %8s "
+ "%8s %8s %8s %8s %8s %8s %8s\n",
+ " ",
+ "filter", "flags",
+ "octlfrst", "octllast", "opndfrst", "opndlast", "opass", "opked", "opeek",
+ "ictlfrst", "ictllast", "ipndfrst", "ipndlast", "ipass", "ipked", "ipeek");
+ for (i = 0; i < CFIL_MAX_FILTER_COUNT; i++) {
+ struct cfil_entry_stat *estat;
+ char spass[32];
+ char speek[32];
+ char spked[32];
+ char rpass[32];
+ char rpeek[32];
+ char rpked[32];
+
+ estat = &sock_stat->ces_entries[i];
+
+ sprint_offset(spass, 32, "%8llu", estat->ces_snd.cbs_pass_offset);
+ sprint_offset(speek, 32, "%8llu", estat->ces_snd.cbs_peek_offset);
+ sprint_offset(spked, 32, "%8llu", estat->ces_snd.cbs_peeked);
+
+ sprint_offset(rpass, 32, "%8llu", estat->ces_rcv.cbs_pass_offset);
+ sprint_offset(rpeek, 32, "%8llu", estat->ces_rcv.cbs_peek_offset);
+ sprint_offset(rpked, 32, "%8llu", estat->ces_rcv.cbs_peeked);
+
+ printf("%7s %10u 0x%08x "
+ "%8llu %8llu %8llu %8llu %8s %8s %8s "
+ "%8llu %8llu %8llu %8llu %8s %8s %8s\n",
+
+ " ",
+ estat->ces_filter_id,
+ estat->ces_flags,
+
+ estat->ces_snd.cbs_ctl_first,
+ estat->ces_snd.cbs_ctl_last,
+ estat->ces_snd.cbs_pending_first,
+ estat->ces_snd.cbs_pending_last,
+ spass,
+ spked,
+ speek,
+
+ estat->ces_rcv.cbs_ctl_first,
+ estat->ces_rcv.cbs_ctl_last,
+ estat->ces_rcv.cbs_pending_first,
+ estat->ces_rcv.cbs_pending_last,
+ rpass,
+ rpked,
+ rpeek);
+ }
+
+
+ ptr += sock_stat->cfs_len;
+ curr_len += sock_stat->cfs_len;
+ } while (1);
+
+ free(buffer);
+}
+
+
+#define PR32(x) printf(#x " %u\n", stats-> x)
+#define PR64(x) printf(#x " %llu\n", stats-> x)
+void
+print_cfil_stats()
+{
+ size_t len, alloc_len;
+ void *buffer = NULL;
+ struct cfil_stats *stats;
+
+ if (sysctlbyname("net.cfil.stats", NULL, &len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.stats)");
+
+ if (len < sizeof(struct cfil_stats))
+ alloc_len = sizeof(struct cfil_stats);
+ else
+ alloc_len = len;
+
+ buffer = malloc(alloc_len);
+ if (buffer == NULL)
+ err(1, "malloc()");
+ if (sysctlbyname("net.cfil.stats", buffer, &len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.stats)");
+ stats = (struct cfil_stats *)buffer;
+
+ PR32(cfs_ctl_connect_ok);
+ PR32(cfs_ctl_connect_fail);
+ PR32(cfs_ctl_connect_ok);
+ PR32(cfs_ctl_connect_fail);
+ PR32(cfs_ctl_disconnect_ok);
+ PR32(cfs_ctl_disconnect_fail);
+ PR32(cfs_ctl_send_ok);
+ PR32(cfs_ctl_send_bad);
+ PR32(cfs_ctl_rcvd_ok);
+ PR32(cfs_ctl_rcvd_bad);
+ PR32(cfs_ctl_rcvd_flow_lift);
+ PR32(cfs_ctl_action_data_update);
+ PR32(cfs_ctl_action_drop);
+ PR32(cfs_ctl_action_bad_op);
+ PR32(cfs_ctl_action_bad_len);
+
+ PR32(cfs_sock_id_not_found);
+
+ PR32(cfs_cfi_alloc_ok);
+ PR32(cfs_cfi_alloc_fail);
+
+ PR32(cfs_sock_userspace_only);
+ PR32(cfs_sock_attach_in_vain);
+ PR32(cfs_sock_attach_already);
+ PR32(cfs_sock_attach_no_mem);
+ PR32(cfs_sock_attach_failed);
+ PR32(cfs_sock_attached);
+ PR32(cfs_sock_detached);
+
+ PR32(cfs_attach_event_ok);
+ PR32(cfs_attach_event_flow_control);
+ PR32(cfs_attach_event_fail);
+
+ PR32(cfs_closed_event_ok);
+ PR32(cfs_closed_event_flow_control);
+ PR32(cfs_closed_event_fail);
+
+ PR32(cfs_data_event_ok);
+ PR32(cfs_data_event_flow_control);
+ PR32(cfs_data_event_fail);
+
+ PR32(cfs_disconnect_in_event_ok);
+ PR32(cfs_disconnect_out_event_ok);
+ PR32(cfs_disconnect_event_flow_control);
+ PR32(cfs_disconnect_event_fail);
+
+ PR32(cfs_ctl_q_not_started);
+
+ PR32(cfs_close_wait);
+ PR32(cfs_close_wait_timeout);
+
+ PR32(cfs_flush_in_drop);
+ PR32(cfs_flush_out_drop);
+ PR32(cfs_flush_in_close);
+ PR32(cfs_flush_out_close);
+ PR32(cfs_flush_in_free);
+ PR32(cfs_flush_out_free);
+
+ PR32(cfs_inject_q_nomem);
+ PR32(cfs_inject_q_nobufs);
+ PR32(cfs_inject_q_detached);
+ PR32(cfs_inject_q_in_fail);
+ PR32(cfs_inject_q_out_fail);
+
+ PR32(cfs_inject_q_in_retry);
+ PR32(cfs_inject_q_out_retry);
+
+ PR32(cfs_data_in_control);
+ PR32(cfs_data_in_oob);
+ PR32(cfs_data_out_control);
+ PR32(cfs_data_out_oob);
+
+ PR64(cfs_ctl_q_in_enqueued);
+ PR64(cfs_ctl_q_out_enqueued);
+ PR64(cfs_ctl_q_in_peeked);
+ PR64(cfs_ctl_q_out_peeked);
+
+ PR64(cfs_pending_q_in_enqueued);
+ PR64(cfs_pending_q_out_enqueued);
+
+ PR64(cfs_inject_q_in_enqueued);
+ PR64(cfs_inject_q_out_enqueued);
+ PR64(cfs_inject_q_in_passed);
+ PR64(cfs_inject_q_out_passed);
+}
diff --git a/network_cmds/cfilutil/cfilutil.1 b/network_cmds/cfilutil/cfilutil.1
new file mode 100644
index 0000000..0d97adf
--- /dev/null
+++ b/network_cmds/cfilutil/cfilutil.1
@@ -0,0 +1,56 @@
+.Dd 2/10/14
+.Dt cfilutil 1
+.Os Darwin
+.Sh NAME
+.Nm cfilutil
+.Nd Tool to exercise the content filter subsystem.
+.Sh SYNOPSIS
+.Nm
+.Op Fl hilqsv
+.Fl u Ar unit
+.Op Fl a Ar offset
+.Op Fl d Ar offset value
+.Op Fl k Ar increment
+.Op Fl m Ar length
+.Op Fl p Ar offset
+.Op Fl r Ar random
+.Op Fl t Ar delay
+.Sh DESCRIPTION
+Use
+.Nm
+to exercise the content filter subsystem.
+.Pp
+The flags have the following meaning:
+.Bl -tag -width -indent
+.It Fl a Ar offset
+Auto start filtering with given offset.
+.It Fl a Ar offset value
+Default values for offset passin, peekin, passout, peekout, pass or peek.
+.It Fl h
+Display this help.
+.It Fl i
+Interactive mode.
+.It Fl k Ar increment
+Peek mode with increment.
+.It Fl l
+Pass loopback traffic.
+.It Fl m Ar length
+Maximum dump length.
+.It Fl p Ar offset
+Pass mode (all or after given offset if it is > 0).
+.It Fl q
+Decrease verbosity.
+.It Fl r Ar rate
+Random drop rate.
+.It Fl s
+display content filter statistics (all, sock, filt, cfil).
+.It Fl t Ar delay
+Pass delay in microseconds.
+.It Fl u Ar unit
+NECP filter control unit.
+.It Fl v
+Increase verbosity.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr neutil 1 \" rdar://16115914
diff --git a/network_cmds/cfilutil/cfilutil.c b/network_cmds/cfilutil/cfilutil.c
new file mode 100644
index 0000000..4aaa719
--- /dev/null
+++ b/network_cmds/cfilutil/cfilutil.c
@@ -0,0 +1,987 @@
+/*
+ * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/sys_domain.h>
+#include <sys/ioctl.h>
+#include <sys/kern_control.h>
+#include <sys/queue.h>
+#include <net/content_filter.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sysexits.h>
+
+extern void print_filter_list(void);
+extern void print_socket_list(void);
+extern void print_cfil_stats(void);
+
+#define MAX_BUFFER (65536 + 1024)
+
+#define MAXHEXDUMPCOL 16
+
+
+enum {
+ MODE_NONE = 0,
+ MODE_INTERACTIVE = 0x01,
+ MODE_PEEK = 0x02,
+ MODE_PASS = 0x04,
+ MODE_DELAY = 0x08
+};
+int mode = MODE_NONE;
+
+unsigned long delay_ms = 0;
+struct timeval delay_tv = { 0, 0 };
+long verbosity = 0;
+uint32_t necp_control_unit = 0;
+unsigned long auto_start = 0;
+uint64_t peek_inc = 0;
+uint64_t pass_offset = 0;
+struct timeval now, deadline;
+int sf = -1;
+int pass_loopback = 0;
+uint32_t random_drop = 0;
+uint32_t event_total = 0;
+uint32_t event_dropped = 0;
+
+uint64_t default_in_pass = 0;
+uint64_t default_in_peek = 0;
+uint64_t default_out_pass = 0;
+uint64_t default_out_peek = 0;
+
+unsigned long max_dump_len = 32;
+
+TAILQ_HEAD(sock_info_head, sock_info) sock_info_head = TAILQ_HEAD_INITIALIZER(sock_info_head);
+
+
+struct sock_info {
+ TAILQ_ENTRY(sock_info) si_link;
+ cfil_sock_id_t si_sock_id;
+ struct timeval si_deadline;
+ uint64_t si_in_pass;
+ uint64_t si_in_peek;
+ uint64_t si_out_pass;
+ uint64_t si_out_peek;
+};
+
+static void
+HexDump(void *data, size_t len)
+{
+ size_t i, j, k;
+ unsigned char *ptr = (unsigned char *)data;
+ unsigned char buf[32 + 3 * MAXHEXDUMPCOL + 2 + MAXHEXDUMPCOL + 1];
+
+ for (i = 0; i < len; i += MAXHEXDUMPCOL) {
+ k = snprintf((char *)buf, sizeof(buf), "\t0x%04lx: ", i);
+ for (j = i; j < i + MAXHEXDUMPCOL; j++) {
+ if (j < len) {
+ unsigned char msnbl = ptr[j] >> 4;
+ unsigned char lsnbl = ptr[j] & 0x0f;
+
+ buf[k++] = msnbl < 10 ? msnbl + '0' : msnbl + 'a' - 10;
+ buf[k++] = lsnbl < 10 ? lsnbl + '0' : lsnbl + 'a' - 10;
+ } else {
+ buf[k++] = ' ';
+ buf[k++] = ' ';
+ }
+ if ((j % 2) == 1)
+ buf[k++] = ' ';
+ if ((j % MAXHEXDUMPCOL) == MAXHEXDUMPCOL - 1)
+ buf[k++] = ' ';
+ }
+
+ buf[k++] = ' ';
+ buf[k++] = ' ';
+
+ for (j = i; j < i + MAXHEXDUMPCOL && j < len; j++) {
+ if (isprint(ptr[j]))
+ buf[k++] = ptr[j];
+ else
+ buf[k++] = '.';
+ }
+ buf[k] = 0;
+ printf("%s\n", buf);
+ }
+}
+
+void
+print_hdr(struct cfil_msg_hdr *hdr)
+{
+ const char *typestr = "unknown";
+ const char *opstr = "unknown";
+
+ if (hdr->cfm_type == CFM_TYPE_EVENT) {
+ typestr = "event";
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED:
+ opstr = "attached";
+ break;
+ case CFM_OP_SOCKET_CLOSED:
+ opstr = "closed";
+ break;
+ case CFM_OP_DATA_OUT:
+ opstr = "dataout";
+ break;
+ case CFM_OP_DATA_IN:
+ opstr = "datain";
+ break;
+ case CFM_OP_DISCONNECT_OUT:
+ opstr = "disconnectout";
+ break;
+ case CFM_OP_DISCONNECT_IN:
+ opstr = "disconnectin";
+ break;
+
+ default:
+ break;
+ }
+ } else if (hdr->cfm_type == CFM_TYPE_ACTION) {
+ typestr = "action";
+ switch (hdr->cfm_op) {
+ case CFM_OP_DATA_UPDATE:
+ opstr = "update";
+ break;
+ case CFM_OP_DROP:
+ opstr = "drop";
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ printf("%s %s len %u version %u type %u op %u sock_id 0x%llx\n",
+ typestr, opstr,
+ hdr->cfm_len, hdr->cfm_version, hdr->cfm_type,
+ hdr->cfm_op, hdr->cfm_sock_id);
+}
+
+void
+print_data_req(struct cfil_msg_data_event *data_req)
+{
+ size_t datalen;
+ void *databuf;
+
+ if (verbosity <= 0)
+ return;
+
+ print_hdr(&data_req->cfd_msghdr);
+
+ printf(" start %llu end %llu\n",
+ data_req->cfd_start_offset, data_req->cfd_end_offset);
+
+ datalen = (size_t)(data_req->cfd_end_offset - data_req->cfd_start_offset);
+
+ databuf = (void *)(data_req + 1);
+
+ if (verbosity > 1)
+ HexDump(databuf, MIN(datalen, max_dump_len));
+}
+
+void
+print_action_msg(struct cfil_msg_action *action)
+{
+ if (verbosity <= 0)
+ return;
+
+ print_hdr(&action->cfa_msghdr);
+
+ if (action->cfa_msghdr.cfm_op == CFM_OP_DATA_UPDATE)
+ printf(" out pass %llu peek %llu in pass %llu peek %llu\n",
+ action->cfa_out_pass_offset, action->cfa_out_peek_offset,
+ action->cfa_in_pass_offset, action->cfa_in_peek_offset);
+}
+
+struct sock_info *
+find_sock_info(cfil_sock_id_t sockid)
+{
+ struct sock_info *sock_info;
+
+ TAILQ_FOREACH(sock_info, &sock_info_head, si_link) {
+ if (sock_info->si_sock_id == sockid)
+ return (sock_info);
+ }
+ return (NULL);
+}
+
+struct sock_info *
+add_sock_info(cfil_sock_id_t sockid)
+{
+ struct sock_info *sock_info;
+
+ if (find_sock_info(sockid) != NULL)
+ return (NULL);
+
+ sock_info = calloc(1, sizeof(struct sock_info));
+ if (sock_info == NULL)
+ err(EX_OSERR, "calloc()");
+ sock_info->si_sock_id = sockid;
+ TAILQ_INSERT_TAIL(&sock_info_head, sock_info, si_link);
+
+ return (sock_info);
+}
+
+void
+remove_sock_info(cfil_sock_id_t sockid)
+{
+ struct sock_info *sock_info = find_sock_info(sockid);
+
+ if (sock_info != NULL) {
+ TAILQ_REMOVE(&sock_info_head, sock_info, si_link);
+ free(sock_info);
+ }
+}
+
+/* return 0 if timer is already set */
+int
+set_sock_info_deadline(struct sock_info *sock_info)
+{
+ if (timerisset(&sock_info->si_deadline))
+ return (0);
+
+ timeradd(&now, &sock_info->si_deadline, &sock_info->si_deadline);
+
+ if (!timerisset(&deadline)) {
+ timeradd(&now, &delay_tv, &deadline);
+ }
+
+ return (1);
+}
+
+void
+send_action_message(uint32_t op, struct sock_info *sock_info, int nodelay)
+{
+ struct cfil_msg_action action;
+
+ if (!nodelay && delay_ms) {
+ set_sock_info_deadline(sock_info);
+ return;
+ }
+ bzero(&action, sizeof(struct cfil_msg_action));
+ action.cfa_msghdr.cfm_len = sizeof(struct cfil_msg_action);
+ action.cfa_msghdr.cfm_version = CFM_VERSION_CURRENT;
+ action.cfa_msghdr.cfm_type = CFM_TYPE_ACTION;
+ action.cfa_msghdr.cfm_op = op;
+ action.cfa_msghdr.cfm_sock_id = sock_info->si_sock_id;
+ switch (op) {
+ case CFM_OP_DATA_UPDATE:
+ action.cfa_out_pass_offset = sock_info->si_out_pass;
+ action.cfa_out_peek_offset = sock_info->si_out_peek;
+ action.cfa_in_pass_offset = sock_info->si_in_pass;
+ action.cfa_in_peek_offset = sock_info->si_in_peek;
+ break;
+
+ default:
+ break;
+ }
+
+ if (verbosity > -1)
+ print_action_msg(&action);
+
+ if (send(sf, &action, sizeof(struct cfil_msg_action), 0) == -1)
+ warn("send()");
+
+ timerclear(&sock_info->si_deadline);
+}
+
+void
+process_delayed_actions()
+{
+ struct sock_info *sock_info;
+
+ TAILQ_FOREACH(sock_info, &sock_info_head, si_link) {
+ if (timerisset(&sock_info->si_deadline) &&
+ timercmp(&sock_info->si_deadline, &now, >=))
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 1);
+ }
+}
+
+int
+set_non_blocking(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ warn("fcntl(F_GETFL)");
+ return (-1);
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1) {
+ warn("fcntl(F_SETFL)");
+ return (-1);
+ }
+ return (0);
+}
+
+int
+offset_from_str(const char *str, uint64_t *ret_val)
+{
+ char *endptr;
+ uint64_t offset;
+ int success = 1;
+
+ if (strcasecmp(str, "max") == 0 || strcasecmp(str, "all") == 0)
+ offset = CFM_MAX_OFFSET;
+ else {
+ offset = strtoull(str, &endptr, 0);
+ if (*str == '\0' || *endptr != '\0')
+ success = 0;
+ }
+ if (success)
+ *ret_val = offset;
+ return (success);
+}
+
+#define IN6_IS_ADDR_V4MAPPED_LOOPBACK(a) \
+ ((*(const __uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const __uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const __uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)) && \
+ (*(const __uint32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(INADDR_LOOPBACK)))
+
+
+int
+is_loopback(struct cfil_msg_data_event *data_req)
+{
+ if (data_req->cfc_dst.sa.sa_family == AF_INET &&
+ ntohl(data_req->cfc_dst.sin.sin_addr.s_addr) == INADDR_LOOPBACK)
+ return (1);
+ if (data_req->cfc_dst.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&data_req->cfc_dst.sin6.sin6_addr))
+ return (1);
+ if (data_req->cfc_dst.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED_LOOPBACK(&data_req->cfc_dst.sin6.sin6_addr))
+ return (1);
+
+ if (data_req->cfc_src.sa.sa_family == AF_INET &&
+ ntohl(data_req->cfc_src.sin.sin_addr.s_addr) == INADDR_LOOPBACK)
+ return (1);
+ if (data_req->cfc_src.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&data_req->cfc_src.sin6.sin6_addr))
+ return (1);
+ if (data_req->cfc_src.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED_LOOPBACK(&data_req->cfc_src.sin6.sin6_addr))
+ return (1);
+
+ return (0);
+}
+
+int
+drop(struct sock_info *sock_info)
+{
+ event_total++;
+ if (random_drop > 0) {
+ uint32_t r = arc4random();
+ if (r <= random_drop) {
+ event_dropped++;
+ printf("dropping 0x%llx dropped %u total %u rate %f\n",
+ sock_info->si_sock_id,
+ event_dropped, event_total,
+ (double)event_dropped/(double)event_total * 100);
+ send_action_message(CFM_OP_DROP, sock_info, 0);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+int
+doit()
+{
+ struct sockaddr_ctl sac;
+ struct ctl_info ctl_info;
+ void *buffer = NULL;
+ struct cfil_msg_hdr *hdr;
+ int kq = -1;
+ struct kevent kv;
+ int fdin = fileno(stdin);
+ char *linep = NULL;
+ size_t linecap = 0;
+ char *cmdptr = NULL;
+ char *argptr = NULL;
+ size_t cmdlen = 0;
+ struct cfil_msg_action action;
+ cfil_sock_id_t last_sock_id = 0;
+ struct sock_info *sock_info = NULL;
+ struct timeval last_time, elapsed, delta;
+ struct timespec interval, *timeout = NULL;
+
+ kq = kqueue();
+ if (kq == -1)
+ err(1, "kqueue()");
+
+ sf = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (sf == -1)
+ err(1, "socket()");
+
+ bzero(&ctl_info, sizeof(struct ctl_info));
+ strlcpy(ctl_info.ctl_name, CONTENT_FILTER_CONTROL_NAME, sizeof(ctl_info.ctl_name));
+ if (ioctl(sf, CTLIOCGINFO, &ctl_info) == -1)
+ err(1, "ioctl(CTLIOCGINFO)");
+
+ if (fcntl(sf, F_SETNOSIGPIPE, 1) == -1)
+ err(1, "fcntl(F_SETNOSIGPIPE)");
+
+ bzero(&sac, sizeof(struct sockaddr_ctl));
+ sac.sc_len = sizeof(struct sockaddr_ctl);
+ sac.sc_family = AF_SYSTEM;
+ sac.ss_sysaddr = AF_SYS_CONTROL;
+ sac.sc_id = ctl_info.ctl_id;
+
+ if (connect(sf, (struct sockaddr *)&sac, sizeof(struct sockaddr_ctl)) == -1)
+ err(1, "connect()");
+
+ if (set_non_blocking(sf) == -1)
+ err(1, "set_non_blocking(sf)");
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, CFIL_OPT_NECP_CONTROL_UNIT,
+ &necp_control_unit, sizeof(uint32_t)) == -1)
+ err(1, "setsockopt(CFIL_OPT_NECP_CONTROL_UNIT, %u)", necp_control_unit);
+
+ bzero(&kv, sizeof(struct kevent));
+ kv.ident = sf;
+ kv.filter = EVFILT_READ;
+ kv.flags = EV_ADD;
+ if (kevent(kq, &kv, 1, NULL, 0, NULL) == -1)
+ err(1, "kevent(sf %d)", sf);
+
+ /*
+ * We can only read from an interactive terminal
+ */
+ if (isatty(fdin)) {
+ bzero(&kv, sizeof(struct kevent));
+ kv.ident = fdin;
+ kv.filter = EVFILT_READ;
+ kv.flags = EV_ADD;
+ if (kevent(kq, &kv, 1, NULL, 0, NULL) == -1)
+ err(1, "kevent(fdin %d)", fdin);
+ }
+
+ buffer = malloc(MAX_BUFFER);
+ if (buffer == NULL)
+ err(1, "malloc()");
+
+ gettimeofday(&now, NULL);
+
+ while (1) {
+ last_time = now;
+ if (delay_ms && timerisset(&deadline)) {
+ timersub(&deadline, &now, &delta);
+ TIMEVAL_TO_TIMESPEC(&delta, &interval);
+ timeout = &interval;
+ } else {
+ timeout = NULL;
+ }
+
+ if (kevent(kq, NULL, 0, &kv, 1, timeout) == -1) {
+ if (errno == EINTR)
+ continue;
+ err(1, "kevent()");
+ }
+ gettimeofday(&now, NULL);
+ timersub(&now, &last_time, &elapsed);
+ if (delay_ms && timerisset(&deadline)) {
+ if (timercmp(&now, &deadline, >=)) {
+ process_delayed_actions();
+ interval.tv_sec = 0;
+ interval.tv_nsec = 0;
+ }
+ }
+
+ if (kv.ident == sf && kv.filter == EVFILT_READ) {
+ while (1) {
+ ssize_t nread;
+
+ nread = recv(sf, buffer, MAX_BUFFER, 0);
+ if (nread == 0) {
+ warnx("recv(sf) returned 0, connection closed");
+ break;
+ }
+ if (nread == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK)
+ break;
+ err(1, "recv()");
+
+ }
+ if (nread < sizeof(struct cfil_msg_hdr))
+ errx(1, "too small");
+ hdr = (struct cfil_msg_hdr *)buffer;
+
+
+ if (hdr->cfm_type != CFM_TYPE_EVENT) {
+ warnx("not a content filter event type %u", hdr->cfm_type);
+ continue;
+ }
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED: {
+ struct cfil_msg_sock_attached *msg_attached = (struct cfil_msg_sock_attached *)hdr;
+
+ if (verbosity > -2)
+ print_hdr(hdr);
+ if (verbosity > -1)
+ printf(" fam %d type %d proto %d pid %u epid %u\n",
+ msg_attached->cfs_sock_family,
+ msg_attached->cfs_sock_type,
+ msg_attached->cfs_sock_protocol,
+ msg_attached->cfs_pid,
+ msg_attached->cfs_e_pid);
+ break;
+ }
+ case CFM_OP_SOCKET_CLOSED:
+ case CFM_OP_DISCONNECT_IN:
+ case CFM_OP_DISCONNECT_OUT:
+ if (verbosity > -2)
+ print_hdr(hdr);
+ break;
+ case CFM_OP_DATA_OUT:
+ case CFM_OP_DATA_IN:
+ if (verbosity > -3)
+ print_data_req((struct cfil_msg_data_event *)hdr);
+ break;
+ default:
+ warnx("unknown content filter event op %u", hdr->cfm_op);
+ continue;
+ }
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED:
+ sock_info = add_sock_info(hdr->cfm_sock_id);
+ if (sock_info == NULL) {
+ warnx("sock_id %llx already exists", hdr->cfm_sock_id);
+ continue;
+ }
+ break;
+ case CFM_OP_DATA_OUT:
+ case CFM_OP_DATA_IN:
+ case CFM_OP_DISCONNECT_IN:
+ case CFM_OP_DISCONNECT_OUT:
+ case CFM_OP_SOCKET_CLOSED:
+ sock_info = find_sock_info(hdr->cfm_sock_id);
+
+ if (sock_info == NULL) {
+ warnx("unexpected data message, sock_info is NULL");
+ continue;
+ }
+ break;
+ default:
+ warnx("unknown content filter event op %u", hdr->cfm_op);
+ continue;
+ }
+
+
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED: {
+ if ((mode & MODE_PASS) || (mode & MODE_PEEK) || auto_start) {
+ sock_info->si_out_pass = default_out_pass;
+ sock_info->si_out_peek = (mode & MODE_PEEK) ? peek_inc : (mode & MODE_PASS) ? CFM_MAX_OFFSET : default_out_peek;
+ sock_info->si_in_pass = default_in_pass;
+ sock_info->si_in_peek = (mode & MODE_PEEK) ? peek_inc : (mode & MODE_PASS) ? CFM_MAX_OFFSET : default_in_peek;
+
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 0);
+ }
+ break;
+ }
+ case CFM_OP_SOCKET_CLOSED: {
+ remove_sock_info(hdr->cfm_sock_id);
+ sock_info = NULL;
+ break;
+ }
+ case CFM_OP_DATA_OUT:
+ case CFM_OP_DATA_IN: {
+ struct cfil_msg_data_event *data_req = (struct cfil_msg_data_event *)hdr;
+
+ if (pass_loopback && is_loopback(data_req)) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+ } else {
+ if (drop(sock_info))
+ continue;
+
+ if ((mode & MODE_PASS)) {
+ if (data_req->cfd_msghdr.cfm_op == CFM_OP_DATA_OUT) {
+ if (pass_offset == 0 || pass_offset == CFM_MAX_OFFSET)
+ sock_info->si_out_pass = data_req->cfd_end_offset;
+ else if (data_req->cfd_end_offset > pass_offset) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+ }
+ sock_info->si_out_peek = (mode & MODE_PEEK) ?
+ data_req->cfd_end_offset + peek_inc : 0;
+ } else {
+ if (pass_offset == 0 || pass_offset == CFM_MAX_OFFSET)
+ sock_info->si_in_pass = data_req->cfd_end_offset;
+ else if (data_req->cfd_end_offset > pass_offset) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+ }
+ sock_info->si_in_peek = (mode & MODE_PEEK) ?
+ data_req->cfd_end_offset + peek_inc : 0;
+ }
+ } else {
+ break;
+ }
+ }
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 0);
+
+ break;
+ }
+ case CFM_OP_DISCONNECT_IN:
+ case CFM_OP_DISCONNECT_OUT: {
+ if (drop(sock_info))
+ continue;
+
+ if ((mode & MODE_PASS)) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 0);
+ }
+ break;
+ }
+ default:
+ warnx("unkown message op %u", hdr->cfm_op);
+ break;
+ }
+ if (sock_info)
+ last_sock_id = sock_info->si_sock_id;
+ }
+ }
+ if (kv.ident == fdin && kv.filter == EVFILT_READ) {
+ ssize_t nread;
+ uint64_t offset = 0;
+ int nitems;
+ int op = 0;
+
+ nread = getline(&linep, &linecap, stdin);
+ if (nread == -1)
+ errx(1, "getline()");
+
+ if (verbosity > 2)
+ printf("linecap %lu nread %lu\n", linecap, nread);
+ if (nread > 0)
+ linep[nread - 1] = '\0';
+
+ if (verbosity > 2)
+ HexDump(linep, linecap);
+
+ if (*linep == 0)
+ continue;
+
+ if (cmdptr == NULL || argptr == NULL || linecap > cmdlen) {
+ cmdlen = linecap;
+ cmdptr = realloc(cmdptr, cmdlen);
+ argptr = realloc(argptr, cmdlen);
+ }
+
+ /*
+ * Trick to support unisgned and hexadecimal arguments
+ * as I can't figure out sscanf() conversions
+ */
+ nitems = sscanf(linep, "%s %s", cmdptr, argptr);
+ if (nitems == 0) {
+ warnx("I didn't get that...");
+ continue;
+ } else if (nitems > 1) {
+ if (offset_from_str(argptr, &offset) == 0) {
+ warnx("I didn't get that either...");
+ continue;
+ }
+ }
+ if (verbosity > 2)
+ printf("nitems %d %s %s\n", nitems, cmdptr, argptr);
+
+ bzero(&action, sizeof(struct cfil_msg_action));
+ action.cfa_msghdr.cfm_len = sizeof(struct cfil_msg_action);
+ action.cfa_msghdr.cfm_version = CFM_VERSION_CURRENT;
+ action.cfa_msghdr.cfm_type = CFM_TYPE_ACTION;
+
+ if (strcasecmp(cmdptr, "passout") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = offset;
+ } else if (strcasecmp(cmdptr, "passin") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_in_pass_offset = offset;
+ } else if (strcasecmp(cmdptr, "pass") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = offset;
+ action.cfa_in_pass_offset = offset;
+ } else if (strcasecmp(cmdptr, "peekout") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_peek_offset = offset;
+ } else if (strcasecmp(cmdptr, "peekin") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_in_peek_offset = offset;
+ } else if (strcasecmp(cmdptr, "peek") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_peek_offset = offset;
+ action.cfa_in_peek_offset = offset;
+ } else if (strcasecmp(cmdptr, "start") == 0) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = 0;
+ action.cfa_out_peek_offset = CFM_MAX_OFFSET;
+ action.cfa_in_pass_offset = 0;
+ action.cfa_in_peek_offset = CFM_MAX_OFFSET;
+ } else if (strcasecmp(cmdptr, "peekall") == 0) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_peek_offset = CFM_MAX_OFFSET;
+ action.cfa_in_peek_offset = CFM_MAX_OFFSET;
+ } else if (strcasecmp(cmdptr, "passall") == 0) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = CFM_MAX_OFFSET;
+ action.cfa_out_peek_offset = CFM_MAX_OFFSET;
+ action.cfa_in_pass_offset = CFM_MAX_OFFSET;
+ action.cfa_in_peek_offset = CFM_MAX_OFFSET;
+ } else if (strcasecmp(cmdptr, "drop") == 0)
+ op = CFM_OP_DROP;
+ else if (strcasecmp(cmdptr, "sock") == 0) {
+ last_sock_id = offset;
+ printf("last_sock_id 0x%llx\n", last_sock_id);
+ } else
+ warnx("syntax error");
+
+ if (op == CFM_OP_DATA_UPDATE || op == CFM_OP_DROP) {
+ action.cfa_msghdr.cfm_op = op;
+ action.cfa_msghdr.cfm_sock_id = last_sock_id;
+ print_action_msg(&action);
+
+ if (send(sf, &action, sizeof(struct cfil_msg_action), 0) == -1)
+ warn("send()");
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const char *
+basename(const char * str)
+{
+ const char *last_slash = strrchr(str, '/');
+
+ if (last_slash == NULL)
+ return (str);
+ else
+ return (last_slash + 1);
+}
+
+struct option_desc {
+ const char *option;
+ const char *description;
+ int required;
+};
+
+struct option_desc option_desc_list[] = {
+ { "-a offset", "auto start with offset", 0 },
+ { "-d offset value", "default offset value for passin, peekin, passout, peekout, pass, peek", 0 },
+ { "-h", "dsiplay this help", 0 },
+ { "-i", "interactive mode", 0 },
+ { "-k increment", "peek mode with increment", 0 },
+ {"-l", "pass loopback", 0 },
+ { "-m length", "max dump length", 0 },
+ { "-p offset", "pass mode (all or after given offset if > 0)", 0 },
+ { "-q", "decrease verbose level", 0 },
+ { "-r random", "random drop rate", 0 },
+ { "-s ", "display content filter statistics (all, sock, filt, cfil)", 0 },
+ { "-t delay", "pass delay in microseconds", 0 },
+ { "-u unit", "NECP filter control unit", 1 },
+ { "-v", "increase verbose level", 0 },
+ { NULL, NULL, 0 } /* Mark end of list */
+};
+
+static void
+usage(const char *cmd)
+{
+ struct option_desc *option_desc;
+ char *usage_str = malloc(LINE_MAX);
+ size_t usage_len;
+
+ if (usage_str == NULL)
+ err(1, "%s: malloc(%d)", __func__, LINE_MAX);
+
+ usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd));
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ int len;
+
+ if (option_desc->required)
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option);
+ else
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option);
+ if (len < 0)
+ err(1, "%s: snprintf(", __func__);
+
+ usage_len += len;
+ if (usage_len > LINE_MAX)
+ break;
+ }
+ printf("%s\n", usage_str);
+ printf("options:\n");
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ printf(" %-20s # %s\n", option_desc->option, option_desc->description);
+ }
+
+}
+
+int
+main(int argc, char * const argv[])
+{
+ int ch;
+ double d;
+ int stats_sock_list = 0;
+ int stats_filt_list = 0;
+ int stats_cfil_stats = 0;
+
+ while ((ch = getopt(argc, argv, "a:d:hik:lm:p:qr:s:t:u:v")) != -1) {
+ switch (ch) {
+ case 'a':
+ auto_start = strtoul(optarg, NULL, 0);
+ break;
+ case 'd': {
+ if (optind >= argc)
+ errx(1, "'-d' needs 2 parameters");
+ if (strcasecmp(optarg, "passout") == 0) {
+ if (offset_from_str(argv[optind], &default_out_pass) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "passin") == 0) {
+ if (offset_from_str(argv[optind], &default_in_pass) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "pass") == 0) {
+ if (offset_from_str(argv[optind], &default_out_pass) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ default_in_pass = default_out_pass;
+ } else if (strcasecmp(optarg, "peekout") == 0) {
+ if (offset_from_str(argv[optind], &default_out_peek) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "peekin") == 0) {
+ if (offset_from_str(argv[optind], &default_in_peek) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "peek") == 0) {
+ if (offset_from_str(argv[optind], &default_out_peek) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ default_in_peek = default_out_peek;
+ } else
+ errx(1, "syntax error");
+ break;
+ }
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ case 'i':
+ mode |= MODE_INTERACTIVE;
+ break;
+ case 'k':
+ mode |= MODE_PEEK;
+ if (offset_from_str(optarg, &peek_inc) == 0)
+ errx(1, "bad peek offset: %s", optarg);
+ break;
+ case 'l':
+ pass_loopback = 1;
+ break;
+ case 'm':
+ max_dump_len = strtoul(optarg, NULL, 0);
+ break;
+ case 'p':
+ mode |= MODE_PASS;
+ if (offset_from_str(optarg, &pass_offset) == 0)
+ errx(1, "bad pass offset: %s", optarg);
+ break;
+ case 'q':
+ verbosity--;
+ break;
+ case 'r':
+ d = strtod(optarg, NULL);
+ if (d < 0 || d > 1)
+ errx(1, "bad drop rate: %s -- it must be between 0 and 1", optarg);
+ random_drop = (uint32_t)(d * UINT32_MAX);
+ break;
+ case 's':
+ if (strcasecmp(optarg, "all") == 0) {
+ stats_sock_list = 1;
+ stats_filt_list = 1;
+ stats_cfil_stats = 1;
+ } else if (strcasecmp(optarg, "sock") == 0) {
+ stats_sock_list = 1;
+ } else if (strcasecmp(optarg, "filt") == 0) {
+ stats_filt_list = 1;
+ } else if (strcasecmp(optarg, "cfil") == 0) {
+ stats_cfil_stats = 1;
+ } else {
+ warnx("# Error: unknown type of statistic: %s", optarg);
+ usage(argv[0]);
+ exit(0);
+ }
+ break;
+ case 't':
+ mode |= MODE_DELAY;
+ delay_ms = strtoul(optarg, NULL, 0);
+ delay_tv.tv_sec = delay_ms / 1000;
+ delay_tv.tv_usec = (delay_ms % 1000) * 1000;
+ break;
+ case 'u':
+ necp_control_unit = (uint32_t)strtoul(optarg, NULL, 0);
+ break;
+ case 'v':
+ verbosity++;
+ break;
+ default:
+ errx(1, "# syntax error, unknow option '%d'", ch);
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ if (stats_filt_list)
+ print_filter_list();
+ if (stats_sock_list)
+ print_socket_list();
+ if (stats_cfil_stats)
+ print_cfil_stats();
+ if (necp_control_unit == 0 && (stats_filt_list || stats_sock_list || stats_cfil_stats))
+ return (0);
+
+ if (necp_control_unit == 0) {
+ warnx("necp filter control unit is 0");
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+ doit();
+
+
+ return (0);
+}
+
diff --git a/network_cmds/dnctl/dnctl.8 b/network_cmds/dnctl/dnctl.8
new file mode 100644
index 0000000..4da4724
--- /dev/null
+++ b/network_cmds/dnctl/dnctl.8
@@ -0,0 +1,508 @@
+.Dd August 13, 2002
+.Dt DNCTL 8
+.Os Darwin
+.Sh NAME
+.Nm dnctl
+.Nd Traffic shaper control program
+.Sh SYNOPSIS
+.Nm
+.Op Fl anqs
+.Brq Cm list | show
+.Nm
+.Op Fl f | q
+.Cm flush
+.Nm
+.Op Fl q
+.Brq Cm delete
+.Op Ar number ...
+.Nm
+.Brq Cm pipe | queue
+.Ar number
+.Cm config
+.Ar config-options
+.Nm
+.Op Fl s Op Ar field
+.Brq Cm pipe | queue
+.Brq Cm delete | list | show
+.Op Ar number ...
+.Nm
+.Op Fl nq
+.Oo
+.Fl p Ar preproc
+.Oo
+.Ar preproc-flags
+.Oc
+.Oc
+.Ar pathname
+.Sh DESCRIPTION
+.Pp
+The
+.Nm
+utility is the user interface for controlling the
+.Xr dummynet 4
+traffic shaper.
+.Pp
+.Nm dummynet
+operates by first using a packet filter to classify packets and divide them into
+.Em flows ,
+using any match pattern that can be used in
+.Nm
+rules.
+Depending on local policies, a flow can contain packets for a single
+TCP connection, or from/to a given host, or entire subnet, or a
+protocol type, etc.
+.Pp
+Packets belonging to the same flow are then passed to either of two
+different objects, which implement the traffic regulation:
+.Bl -hang -offset XXXX
+.It Em pipe
+A pipe emulates a link with given bandwidth, propagation delay,
+queue size and packet loss rate.
+Packets are queued in front of the pipe as they come out from the classifier,
+and then transferred to the pipe according to the pipe's parameters.
+.Pp
+.It Em queue
+A queue
+is an abstraction used to implement the WF2Q+
+(Worst-case Fair Weighted Fair Queueing) policy, which is
+an efficient variant of the WFQ policy.
+.br
+The queue associates a
+.Em weight
+and a reference pipe to each flow, and then all backlogged (i.e.,
+with packets queued) flows linked to the same pipe share the pipe's
+bandwidth proportionally to their weights.
+Note that weights are not priorities; a flow with a lower weight
+is still guaranteed to get its fraction of the bandwidth even if a
+flow with a higher weight is permanently backlogged.
+.Pp
+.El
+In practice,
+.Em pipes
+can be used to set hard limits to the bandwidth that a flow can use, whereas
+.Em queues
+can be used to determine how different flow share the available bandwidth.
+.Pp
+The
+.Em pipe
+and
+.Em queue
+configuration commands are the following:
+.Bd -ragged -offset indent
+.Cm pipe Ar number Cm config Ar pipe-configuration
+.Pp
+.Cm queue Ar number Cm config Ar queue-configuration
+.Ed
+.Pp
+The following parameters can be configured for a pipe:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm bw Ar bandwidth | device
+Bandwidth, measured in
+.Sm off
+.Op Cm K | M
+.Brq Cm bit/s | Byte/s .
+.Sm on
+.Pp
+A value of 0 (default) means unlimited bandwidth.
+The unit must immediately follow the number, as in
+.Pp
+.Dl "dnctl pipe 1 config bw 300Kbit/s"
+.Pp
+If a device name is specified instead of a numeric value, as in
+.Pp
+.Dl "dnctl pipe 1 config bw tun0"
+.Pp
+then the transmit clock is supplied by the specified device.
+At the moment no
+device supports this
+functionality.
+.Pp
+.It Cm delay Ar ms-delay
+Propagation delay, measured in milliseconds.
+The value is rounded to the next multiple of the clock tick
+(typically 10ms, but it is a good practice to run kernels
+with
+.Dq "options HZ=1000"
+to reduce
+the granularity to 1ms or less).
+Default value is 0, meaning no delay.
+.El
+.Pp
+The following parameters can be configured for a queue:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm pipe Ar pipe_nr
+Connects a queue to the specified pipe.
+Multiple queues (with the same or different weights) can be connected to
+the same pipe, which specifies the aggregate rate for the set of queues.
+.Pp
+.It Cm weight Ar weight
+Specifies the weight to be used for flows matching this queue.
+The weight must be in the range 1..100, and defaults to 1.
+.El
+.Pp
+Finally, the following parameters can be configured for both
+pipes and queues:
+.Pp
+.Bl -tag -width XXXX -compact
+.It Cm buckets Ar hash-table-size
+Specifies the size of the hash table used for storing the
+various queues.
+Default value is 64 controlled by the
+.Xr sysctl 8
+variable
+.Em net.inet.ip.dummynet.hash_size ,
+allowed range is 16 to 65536.
+.Pp
+.It Cm mask Ar mask-specifier
+Packets sent to a given pipe or queue by an
+.Nm
+rule can be further classified into multiple flows, each of which is then
+sent to a different
+.Em dynamic
+pipe or queue.
+A flow identifier is constructed by masking the IP addresses,
+ports and protocol types as specified with the
+.Cm mask
+options in the configuration of the pipe or queue.
+For each different flow identifier, a new pipe or queue is created
+with the same parameters as the original object, and matching packets
+are sent to it.
+.Pp
+Thus, when
+.Em dynamic pipes
+are used, each flow will get the same bandwidth as defined by the pipe,
+whereas when
+.Em dynamic queues
+are used, each flow will share the parent's pipe bandwidth evenly
+with other flows generated by the same queue (note that other queues
+with different weights might be connected to the same pipe).
+.br
+Available mask specifiers are a combination of one or more of the following:
+.Pp
+.Cm dst-ip Ar mask ,
+.Cm dst-ip6 Ar mask ,
+.Cm src-ip Ar mask ,
+.Cm src-ip6 Ar mask ,
+.Cm dst-port Ar mask ,
+.Cm src-port Ar mask ,
+.Cm proto Ar mask
+or
+.Cm all ,
+.Pp
+where the latter means all bits in all fields are significant.
+.Pp
+.It Cm noerror
+When a packet is dropped by a dummynet queue or pipe, the error
+is normally reported to the caller routine in the kernel, in the
+same way as it happens when a device queue fills up. Setting this
+option reports the packet as successfully delivered, which can be
+needed for some experimental setups where you want to simulate
+loss or congestion at a remote router.
+.Pp
+.It Cm plr Ar packet-loss-rate
+Packet loss rate.
+Argument
+.Ar packet-loss-rate
+is a floating-point number between 0 and 1, with 0 meaning no
+loss, 1 meaning 100% loss.
+The loss rate is internally represented on 31 bits.
+.Pp
+.It Cm queue Brq Ar slots | size Ns Cm Kbytes
+Queue size, in
+.Ar slots
+or
+.Cm KBytes .
+Default value is 50 slots, which
+is the typical queue size for Ethernet devices.
+Note that for slow speed links you should keep the queue
+size short or your traffic might be affected by a significant
+queueing delay.
+E.g., 50 max-sized ethernet packets (1500 bytes) mean 600Kbit
+or 20s of queue on a 30Kbit/s pipe.
+Even worse effect can result if you get packets from an
+interface with a much larger MTU, e.g. the loopback interface
+with its 16KB packets.
+.Pp
+.It Cm red | gred Ar w_q Ns / Ns Ar min_th Ns / Ns Ar max_th Ns / Ns Ar max_p
+Make use of the RED (Random Early Detection) queue management algorithm.
+.Ar w_q
+and
+.Ar max_p
+are floating
+point numbers between 0 and 1 (0 not included), while
+.Ar min_th
+and
+.Ar max_th
+are integer numbers specifying thresholds for queue management
+(thresholds are computed in bytes if the queue has been defined
+in bytes, in slots otherwise).
+The
+.Xr dummynet 4
+also supports the gentle RED variant (gred).
+.Pp
+Three
+.Xr sysctl 8
+variables can be used to control the RED behaviour:
+.Bl -tag -width indent
+.It Em net.inet.ip.dummynet.red_lookup_depth
+specifies the accuracy in computing the average queue
+when the link is idle (defaults to 256, must be greater than zero)
+.It Em net.inet.ip.dummynet.red_avg_pkt_size
+specifies the expected average packet size (defaults to 512, must be
+greater than zero)
+.It Em net.inet.ip.dummynet.red_max_pkt_size
+specifies the expected maximum packet size, only used when queue
+thresholds are in bytes (defaults to 1500, must be greater than zero).
+.El
+.El
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+While listing, show counter values.
+The
+.Cm show
+command just implies this option.
+.It Fl f
+Don't ask for confirmation for commands that can cause problems
+if misused,
+.No i.e. Cm flush .
+If there is no tty associated with the process, this is implied.
+.It Fl h
+Displays a short help.
+.It Fl n
+Only check syntax of the command strings, without actually passing
+them to the kernel.
+.It Fl q
+While
+.Cm add Ns ing ,
+.Cm zero Ns ing ,
+.Cm resetlog Ns ging
+or
+.Cm flush Ns ing ,
+be quiet about actions
+(implies
+.Fl f ) .
+This is useful for adjusting rules by executing multiple
+.Nm
+commands in a script
+or by processing a file of many
+.Nm
+rules across a remote login session.
+If a
+.Cm flush
+is performed in normal (verbose) mode (with the default kernel
+configuration), it prints a message.
+Because all rules are flushed, the message might not be delivered
+to the login session, causing the remote login session to be closed
+and the remainder of the ruleset to not be processed.
+Access to the console would then be required to recover.
+.It Fl s Op Ar field
+While listing pipes, sort according to one of the four
+counters (total or current packets or bytes).
+.It Fl v
+Be verbose.
+.El
+.Pp
+To ease configuration, rules can be put into a file which is
+processed using
+.Nm
+as shown in the last synopsis line.
+An absolute
+.Ar pathname
+must be used.
+The file will be read line by line and applied as arguments to the
+.Nm
+utility.
+.Pp
+Optionally, a preprocessor can be specified using
+.Fl p Ar preproc
+where
+.Ar pathname
+is to be piped through.
+Useful preprocessors include
+.Xr cpp 1
+and
+.Xr m4 1 .
+If
+.Ar preproc
+doesn't start with a slash
+.Pq Ql /
+as its first character, the usual
+.Ev PATH
+name search is performed.
+Care should be taken with this in environments where not all
+file systems are mounted (yet) by the time
+.Nm
+is being run (e.g. when they are mounted over NFS).
+Once
+.Fl p
+has been specified, any additional arguments as passed on to the preprocessor
+for interpretation.
+This allows for flexible configuration files (like conditionalizing
+them on the local hostname) and the use of macros to centralize
+frequently required arguments like IP addresses.
+.El
+.Sh CHECKLIST
+Here are some important points to consider when designing your
+rules:
+.Bl -bullet
+.It
+Remember that you filter both packets going
+.Cm in
+and
+.Cm out .
+Most connections need packets going in both directions.
+.It
+Remember to test very carefully.
+It is a good idea to be near the console when doing this.
+.It
+Don't forget the loopback interface.
+.El
+.Sh SYSCTL VARIABLES
+A set of
+.Xr sysctl 8
+variables controls the behaviour of the
+.Nm dummynet
+module.
+These are shown below together with their default value
+(but always check with the
+.Xr sysctl 8
+command what value is actually in use) and meaning:
+.Bl -tag -width indent
+.It Em net.inet.ip.dummynet.expire : No 1
+Lazily delete dynamic pipes/queue once they have no pending traffic.
+You can disable this by setting the variable to 0, in which case
+the pipes/queues will only be deleted when the threshold is reached.
+.It Em net.inet.ip.dummynet.hash_size : No 64
+Default size of the hash table used for dynamic pipes/queues.
+This value is used when no
+.Cm buckets
+option is specified when configuring a pipe/queue.
+.It Em net.inet.ip.dummynet.max_chain_len : No 16
+Target value for the maximum number of pipes/queues in a hash bucket.
+The product
+.Cm max_chain_len*hash_size
+is used to determine the threshold over which empty pipes/queues
+will be expired even when
+.Cm net.inet.ip.dummynet.expire=0 .
+.It Em net.inet.ip.dummynet.red_lookup_depth : No 256
+.It Em net.inet.ip.dummynet.red_avg_pkt_size : No 512
+.It Em net.inet.ip.dummynet.red_max_pkt_size : No 1500
+Parameters used in the computations of the drop probability
+for the RED algorithm.
+.El
+.Sh EXAMPLES
+The following rules show some of the applications of
+for simulations and the like by using
+.Em dummynet
+rules in
+.Xr pf.conf 8
+configuration files.
+.Pp
+To drop random incoming IPv4 and IPv6 ICMP packets with a probability of 5%,
+create a pipe:
+.Dl "dnctl pipe 10 config plr 0.05"
+.Pp
+and add these rules in your pf.conf file:
+.Dl "dummynet in inet proto icmp all pipe 10"
+.Dl "dummynet in inet6 proto ipv6-icmp all pipe 10"
+.Pp
+Should we want to simulate a bidirectional link with bandwidth
+limitations, the correct way is to create a pipe for each direction:
+.Dl "dnctl pipe 1 config bw 14Kbit/s queue 10Kbytes"
+.Dl "dnctl pipe 2 config bw 1Kbit/s queue 10Kbytes"
+.Pp
+and add these rules in your pf.conf file:
+.Dl "dummynet in all pipe 1"
+.Dl "dummynet out all pipe 2"
+.Pp
+The above can be very useful, e.g. if you want to see how
+your fancy Web page will look for a residential user who
+is connected only through a slow link.
+You should not use only one pipe for both directions, unless
+you want to simulate a half-duplex medium (e.g. AppleTalk,
+Ethernet, IRDA).
+.Pp
+Note that with the above rules the pipes receive traffic for both the
+IPv4 and IPv6 protocols.
+.Pp
+Should we want to verify network performance with the RED queue
+management algorithm, create this pipe:
+.Dl "dnctl pipe 1 config bw 500Kbit/s queue 100 red 0.002/30/80/0.1"
+.Pp
+and then add these rules to you pf.conf file:
+.Dl "dummynet all pipe 1"
+.Pp
+Another typical application of the traffic shaper is to
+introduce some delay in the communication.
+This can significantly affect applications which do a lot of Remote
+Procedure Calls, and where the round-trip-time of the
+connection often becomes a limiting factor much more than
+bandwidth:
+.Dl "dnctl pipe 1 config delay 250ms bw 1Mbit/s"
+.Dl "dnctl pipe 2 config delay 250ms bw 1Mbit/s"
+.Pp
+and add these rules in your pf.conf file:
+.Dl "dummynet in all pipe 1"
+.Dl "dummynet out all pipe 2"
+.Pp
+Per-flow queueing can be useful for a variety of purposes.
+A very simple one is counting traffic:
+.Dl "dnctl pipe 1 config mask all"
+.Pp
+and add these statements in your pf.conf file:
+.Dl "dummynet in quick proto tcp all pipe 1"
+.Dl "dummynet out quick proto tcp all pipe 1"
+.Dl "dummynet in quick proto udp all pipe 1"
+.Dl "dummynet out quick proto udp all pipe 1"
+.Dl "dummynet in quick all pipe 1"
+.Dl "dummynet out quick all pipe 1"
+.Pp
+The above set of rules will create queues (and collect
+statistics) for all traffic.
+Because the pipes have no limitations, the only effect is
+collecting statistics.
+Note that we need six rules, not just the last two one, because
+when
+.Nm
+tries to match IP packets it will not consider ports, so we
+would not see connections on separate ports as different
+ones.
+.Sh SEE ALSO
+.Xr cpp 1 ,
+.Xr dummynet 4 ,
+.Xr m4 1 ,
+.Xr ip 4 ,
+.Xr pfctl 8 ,
+.Xr pf.conf 5 ,
+.Xr protocols 5 ,
+.Xr services 5 ,
+.Xr sysctl 8
+.Sh AUTHORS
+.An Ugen J. S. Antsilevich ,
+.An Poul-Henning Kamp ,
+.An Alex Nash ,
+.An Archie Cobbs ,
+.An Luigi Rizzo .
+.Pp
+.An -nosplit
+API based upon code written by
+.An Daniel Boulet
+for BSDI.
+.Pp
+Work on
+.Xr dummynet 4
+traffic shaper supported by Akamba Corp.
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 2.0 .
+.Xr dummynet 4
+was introduced in
+.Fx 2.2.8 .
+Stateful extensions were introduced in
+.Fx 4.0 .
diff --git a/network_cmds/dnctl/dnctl.c b/network_cmds/dnctl/dnctl.c
new file mode 100644
index 0000000..38cffe8
--- /dev/null
+++ b/network_cmds/dnctl/dnctl.c
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 2002-2003 Luigi Rizzo
+ * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Idea and grammar partially left from:
+ * Copyright (c) 1993 Daniel Boulet
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ */
+
+/*
+ * Ripped off ipfw2.c
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_dummynet.h>
+#include <arpa/inet.h>
+
+/*
+ * Limit delay to avoid computation overflow
+ */
+#define MAX_DELAY (INT_MAX / 1000)
+
+
+int
+do_quiet, /* Be quiet in add and flush */
+do_pipe, /* this cmd refers to a pipe */
+do_sort, /* field to sort results (0 = no) */
+test_only, /* only check syntax */
+verbose;
+
+#define IP_MASK_ALL 0xffffffff
+
+/*
+ * _s_x is a structure that stores a string <-> token pairs, used in
+ * various places in the parser. Entries are stored in arrays,
+ * with an entry with s=NULL as terminator.
+ * The search routines are match_token() and match_value().
+ * Often, an element with x=0 contains an error string.
+ *
+ */
+struct _s_x {
+ char const *s;
+ int x;
+};
+
+enum tokens {
+ TOK_NULL=0,
+
+ TOK_ACCEPT,
+ TOK_COUNT,
+ TOK_PIPE,
+ TOK_QUEUE,
+
+ TOK_PLR,
+ TOK_NOERROR,
+ TOK_BUCKETS,
+ TOK_DSTIP,
+ TOK_SRCIP,
+ TOK_DSTPORT,
+ TOK_SRCPORT,
+ TOK_ALL,
+ TOK_MASK,
+ TOK_BW,
+ TOK_DELAY,
+ TOK_RED,
+ TOK_GRED,
+ TOK_DROPTAIL,
+ TOK_PROTO,
+ TOK_WEIGHT,
+
+ TOK_DSTIP6,
+ TOK_SRCIP6,
+};
+
+struct _s_x dummynet_params[] = {
+ { "plr", TOK_PLR },
+ { "noerror", TOK_NOERROR },
+ { "buckets", TOK_BUCKETS },
+ { "dst-ip", TOK_DSTIP },
+ { "src-ip", TOK_SRCIP },
+ { "dst-port", TOK_DSTPORT },
+ { "src-port", TOK_SRCPORT },
+ { "proto", TOK_PROTO },
+ { "weight", TOK_WEIGHT },
+ { "all", TOK_ALL },
+ { "mask", TOK_MASK },
+ { "droptail", TOK_DROPTAIL },
+ { "red", TOK_RED },
+ { "gred", TOK_GRED },
+ { "bw", TOK_BW },
+ { "bandwidth", TOK_BW },
+ { "delay", TOK_DELAY },
+ { "pipe", TOK_PIPE },
+ { "queue", TOK_QUEUE },
+ { "dst-ipv6", TOK_DSTIP6},
+ { "dst-ip6", TOK_DSTIP6},
+ { "src-ipv6", TOK_SRCIP6},
+ { "src-ip6", TOK_SRCIP6},
+ { "dummynet-params", TOK_NULL },
+ { NULL, 0 } /* terminator */
+};
+
+static void show_usage(void);
+
+
+void n2mask(struct in6_addr *, int );
+unsigned long long align_uint64(const uint64_t *);
+
+/* n2mask sets n bits of the mask */
+void
+n2mask(struct in6_addr *mask, int n)
+{
+ static int minimask[9] =
+ { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ u_char *p;
+
+ memset(mask, 0, sizeof(struct in6_addr));
+ p = (u_char *) mask;
+ for (; n > 0; p++, n -= 8) {
+ if (n >= 8)
+ *p = 0xff;
+ else
+ *p = minimask[n];
+ }
+ return;
+}
+
+/*
+ * The following is used to generate a printable argument for
+ * 64-bit numbers, irrespective of platform alignment and bit size.
+ * Because all the printf in this program use %llu as a format,
+ * we just return an unsigned long long, which is larger than
+ * we need in certain cases, but saves the hassle of using
+ * PRIu64 as a format specifier.
+ * We don't care about inlining, this is not performance critical code.
+ */
+unsigned long long
+align_uint64(const uint64_t *pll)
+{
+ uint64_t ret;
+
+ bcopy (pll, &ret, sizeof(ret));
+ return ret;
+}
+
+/*
+ * conditionally runs the command.
+ */
+static int
+do_cmd(int optname, void *optval, socklen_t *optlen)
+{
+ static int s = -1; /* the socket */
+ int i;
+
+ if (test_only)
+ return 0;
+
+ if (s == -1)
+ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (s < 0)
+ err(EX_UNAVAILABLE, "socket");
+
+ if (optname == IP_DUMMYNET_GET)
+ i = getsockopt(s, IPPROTO_IP, optname, optval, optlen);
+ else
+ i = setsockopt(s, IPPROTO_IP, optname, optval, optlen ? *optlen : 0);
+ return i;
+}
+
+/**
+ * match_token takes a table and a string, returns the value associated
+ * with the string (-1 in case of failure).
+ */
+static int
+match_token(struct _s_x *table, char *string)
+{
+ struct _s_x *pt;
+ size_t i = strlen(string);
+
+ for (pt = table ; i && pt->s != NULL ; pt++)
+ if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
+ return pt->x;
+ return -1;
+};
+
+static int
+sort_q(const void *pa, const void *pb)
+{
+ int rev = (do_sort < 0);
+ int field = rev ? -do_sort : do_sort;
+ long long res = 0;
+ const struct dn_flow_queue *a = pa;
+ const struct dn_flow_queue *b = pb;
+
+ switch (field) {
+ case 1: /* pkts */
+ res = a->len - b->len;
+ break;
+ case 2: /* bytes */
+ res = a->len_bytes - b->len_bytes;
+ break;
+
+ case 3: /* tot pkts */
+ res = a->tot_pkts - b->tot_pkts;
+ break;
+
+ case 4: /* tot bytes */
+ res = a->tot_bytes - b->tot_bytes;
+ break;
+ }
+ if (res < 0)
+ res = -1;
+ if (res > 0)
+ res = 1;
+ return (int)(rev ? res : -res);
+}
+
+static void
+list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
+{
+ int l;
+ int index_printed = 0, indexes = 0;
+ char buff[255];
+ struct protoent *pe;
+
+ printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+ fs->flow_mask.proto,
+ fs->flow_mask.src_ip, fs->flow_mask.src_port,
+ fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+ if (fs->rq_elements == 0)
+ return;
+
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
+ if (do_sort != 0)
+ heapsort(q, fs->rq_elements, sizeof(struct dn_flow_queue), sort_q);
+
+ /* Print IPv4 flows */
+ for (l = 0; l < fs->rq_elements; l++) {
+ struct in_addr ina;
+
+ /* XXX: Should check for IPv4 flows */
+ if (IS_IP6_FLOW_ID(&(q[l].id)))
+ continue;
+
+ if (!index_printed) {
+ index_printed = 1;
+ if (indexes > 0) /* currently a no-op */
+ printf("\n");
+ indexes++;
+ printf(" "
+ "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+ fs->flow_mask.proto,
+ fs->flow_mask.src_ip, fs->flow_mask.src_port,
+ fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+
+ printf("%3d ", q[l].hash_slot);
+ pe = getprotobynumber(q[l].id.proto);
+ if (pe)
+ printf("%-4s ", pe->p_name);
+ else
+ printf("%4u ", q[l].id.proto);
+ ina.s_addr = htonl(q[l].id.src_ip);
+ printf("%15s/%-5d ",
+ inet_ntoa(ina), q[l].id.src_port);
+ ina.s_addr = htonl(q[l].id.dst_ip);
+ printf("%15s/%-5d ",
+ inet_ntoa(ina), q[l].id.dst_port);
+ printf("%4llu %8llu %2u %4u %3u\n",
+ align_uint64(&q[l].tot_pkts),
+ align_uint64(&q[l].tot_bytes),
+ q[l].len, q[l].len_bytes, q[l].drops);
+ if (verbose)
+ printf(" S %20llu F %20llu\n",
+ align_uint64(&q[l].S), align_uint64(&q[l].F));
+ }
+
+ /* Print IPv6 flows */
+ index_printed = 0;
+ for (l = 0; l < fs->rq_elements; l++) {
+ if (!IS_IP6_FLOW_ID(&(q[l].id)))
+ continue;
+
+ if (!index_printed) {
+ index_printed = 1;
+ if (indexes > 0)
+ printf("\n");
+ indexes++;
+ printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ",
+ fs->flow_mask.proto, fs->flow_mask.flow_id6);
+ inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
+ buff, sizeof(buff));
+ printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
+ inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
+ buff, sizeof(buff) );
+ printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
+
+ printf("BKT ___Prot___ _flow-id_ "
+ "______________Source IPv6/port_______________ "
+ "_______________Dest. IPv6/port_______________ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+ printf("%3d ", q[l].hash_slot);
+ pe = getprotobynumber(q[l].id.proto);
+ if (pe != NULL)
+ printf("%9s ", pe->p_name);
+ else
+ printf("%9u ", q[l].id.proto);
+ printf("%7d %39s/%-5d ", q[l].id.flow_id6,
+ inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
+ q[l].id.src_port);
+ printf(" %39s/%-5d ",
+ inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
+ q[l].id.dst_port);
+ printf(" %4llu %8llu %2u %4u %3u\n",
+ align_uint64(&q[l].tot_pkts),
+ align_uint64(&q[l].tot_bytes),
+ q[l].len, q[l].len_bytes, q[l].drops);
+ if (verbose)
+ printf(" S %20llu F %20llu\n",
+ align_uint64(&q[l].S),
+ align_uint64(&q[l].F));
+ }
+}
+
+static void
+print_flowset_parms(struct dn_flow_set *fs, char *prefix)
+{
+ int l;
+ char qs[30];
+ char plr[30];
+ char red[90]; /* Display RED parameters */
+
+ l = fs->qsize;
+ if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
+ if (l >= 8192)
+ snprintf(qs, sizeof(qs), "%d KB", l / 1024);
+ else
+ snprintf(qs, sizeof(qs), "%d B", l);
+ } else
+ snprintf(qs, sizeof(qs), "%3d sl.", l);
+ if (fs->plr)
+ snprintf(plr, sizeof(plr), "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
+ else
+ plr[0] = '\0';
+ if (fs->flags_fs & DN_IS_RED) /* RED parameters */
+ snprintf(red, sizeof(red),
+ "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
+ (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
+ 1.0 * fs->w_q / (double)(1 << SCALE_RED),
+ SCALE_VAL(fs->min_th),
+ SCALE_VAL(fs->max_th),
+ 1.0 * fs->max_p / (double)(1 << SCALE_RED));
+ else
+ snprintf(red, sizeof(red), "droptail");
+
+ printf("%s %s%s %d queues (%d buckets) %s\n",
+ prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
+}
+
+static void
+list_pipes(void *data, size_t nbytes, int ac, char *av[])
+{
+ unsigned int rulenum;
+ void *next = data;
+ struct dn_pipe *p = (struct dn_pipe *) data;
+ struct dn_flow_set *fs;
+ struct dn_flow_queue *q;
+ size_t l;
+
+ if (ac > 0)
+ rulenum = (unsigned int)strtoul(*av++, NULL, 10);
+ else
+ rulenum = 0;
+ for (; nbytes >= sizeof(struct dn_pipe); p = (struct dn_pipe *)next) {
+ double b = p->bandwidth;
+ char buf[30];
+ char prefix[80];
+
+ if (p->next.sle_next != (struct dn_pipe *)DN_IS_PIPE)
+ break; /* done with pipes, now queues */
+
+ /*
+ * compute length, as pipe have variable size
+ */
+ l = sizeof(struct dn_pipe) + p->fs.rq_elements * sizeof(struct dn_flow_queue);
+ next = (char *)p + l;
+ nbytes -= l;
+
+ if (rulenum != 0 && rulenum != p->pipe_nr)
+ continue;
+
+ /*
+ * Print rate (or clocking interface)
+ */
+ if (p->if_name[0] != '\0')
+ snprintf(buf, sizeof(buf), "%s", p->if_name);
+ else if (b == 0)
+ snprintf(buf, sizeof(buf), "unlimited");
+ else if (b >= 1000000)
+ snprintf(buf, sizeof(buf), "%7.3f Mbit/s", b/1000000);
+ else if (b >= 1000)
+ snprintf(buf, sizeof(buf), "%7.3f Kbit/s", b/1000);
+ else
+ snprintf(buf, sizeof(buf), "%7.3f bit/s ", b);
+
+ snprintf(prefix, sizeof(prefix), "%05d: %s %4d ms ",
+ p->pipe_nr, buf, p->delay);
+ print_flowset_parms(&(p->fs), prefix);
+ if (verbose)
+ printf(" V %20qd\n", p->V >> MY_M);
+
+ q = (struct dn_flow_queue *)(p+1);
+ list_queues(&(p->fs), q);
+ }
+ for (fs = next; nbytes >= sizeof *fs; fs = next) {
+ char prefix[80];
+
+ if (fs->next.sle_next != (struct dn_flow_set *)DN_IS_QUEUE)
+ break;
+ l = sizeof(struct dn_flow_set) + fs->rq_elements * sizeof(struct dn_flow_queue);
+ next = (char *)fs + l;
+ nbytes -= l;
+ q = (struct dn_flow_queue *)(fs+1);
+ snprintf(prefix, sizeof(prefix), "q%05d: weight %d pipe %d ",
+ fs->fs_nr, fs->weight, fs->parent_nr);
+ print_flowset_parms(fs, prefix);
+ list_queues(fs, q);
+ }
+}
+
+static void
+list(int ac, char *av[], int show_counters)
+{
+ void *data = NULL;
+ socklen_t nbytes;
+ int exitval = EX_OK;
+
+ int nalloc = 1024; /* start somewhere... */
+
+ if (test_only) {
+ fprintf(stderr, "Testing only, list disabled\n");
+ return;
+ }
+
+ ac--;
+ av++;
+
+ /* get rules or pipes from kernel, resizing array as necessary */
+ nbytes = nalloc;
+
+ while (nbytes >= nalloc) {
+ nalloc = nalloc * 2 + 200;
+ nbytes = nalloc;
+ if ((data = realloc(data, nbytes)) == NULL)
+ err(EX_OSERR, "realloc");
+
+ if (do_cmd(IP_DUMMYNET_GET, data, &nbytes) < 0) {
+ if (errno == ENOBUFS) {
+ nbytes = 0;
+ break;
+ }
+ err(EX_OSERR, "getsockopt(IP_DUMMYNET_GET)");
+
+ }
+ }
+
+ list_pipes(data, nbytes, ac, av);
+
+ free(data);
+
+ if (exitval != EX_OK)
+ exit(exitval);
+}
+
+static void
+show_usage(void)
+{
+ fprintf(stderr, "usage: dnctl [options]\n"
+ "do \"dnctl -h\" or see dnctl manpage for details\n"
+ );
+ exit(EX_USAGE);
+}
+
+static void
+help(void)
+{
+ fprintf(stderr,
+ "dnclt [-acdeftTnNpqS] <command> where <command> is one of:\n"
+ "{pipe|queue} N config PIPE-BODY\n"
+ "[pipe|queue] {zero|delete|show} [N{,N}]\n"
+ );
+ exit(0);
+}
+
+static void
+delete(int ac, char *av[])
+{
+ struct dn_pipe p;
+ int i;
+ int exitval = EX_OK;
+ socklen_t len;
+
+ memset(&p, 0, sizeof(struct dn_pipe));
+
+ av++; ac--;
+
+ while (ac && isdigit(**av)) {
+ i = atoi(*av); av++; ac--;
+
+ if (do_pipe == 1)
+ p.pipe_nr = i;
+ else
+ p.fs.fs_nr = i;
+ len = sizeof(struct dn_pipe);
+ i = do_cmd(IP_DUMMYNET_DEL, &p, &len);
+ if (i) {
+ exitval = 1;
+ warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
+ do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr);
+ }
+ }
+ if (exitval != EX_OK)
+ exit(exitval);
+}
+
+/*
+ * the following macro returns an error message if we run out of
+ * arguments.
+ */
+#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
+#define NEED2(msg, arg) {if (!ac) errx(EX_USAGE, msg, arg);}
+
+static void
+config_pipe(int ac, char **av)
+{
+ struct dn_pipe p;
+ int i;
+ char *end;
+ void *par = NULL;
+ socklen_t len;
+
+ memset(&p, 0, sizeof(struct dn_pipe));
+
+ av++; ac--;
+ /* Pipe number */
+ if (ac && isdigit(**av)) {
+ i = atoi(*av); av++; ac--;
+ if (do_pipe == 1)
+ p.pipe_nr = i;
+ else
+ p.fs.fs_nr = i;
+ }
+ while (ac > 0) {
+ double d;
+ int tok = match_token(dummynet_params, *av);
+ ac--; av++;
+
+ switch(tok) {
+ case TOK_NOERROR:
+ p.fs.flags_fs |= DN_NOERROR;
+ break;
+
+ case TOK_PLR:
+ NEED1("plr needs argument 0..1\n");
+ d = strtod(av[0], NULL);
+ if (d > 1)
+ d = 1;
+ else if (d < 0)
+ d = 0;
+ p.fs.plr = (int)(d*0x7fffffff);
+ ac--; av++;
+ break;
+
+ case TOK_QUEUE:
+ NEED1("queue needs queue size\n");
+ end = NULL;
+ p.fs.qsize = (int)strtoul(av[0], &end, 0);
+ if (*end == 'K' || *end == 'k') {
+ p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
+ p.fs.qsize *= 1024;
+ } else if (*end == 'B' || !strncmp(end, "by", 2)) {
+ p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
+ }
+ ac--; av++;
+ break;
+
+ case TOK_BUCKETS:
+ NEED1("buckets needs argument\n");
+ p.fs.rq_size = (int)strtoul(av[0], NULL, 0);
+ ac--; av++;
+ break;
+
+ case TOK_MASK:
+ NEED1("mask needs mask specifier\n");
+ /*
+ * per-flow queue, mask is dst_ip, dst_port,
+ * src_ip, src_port, proto measured in bits
+ */
+ par = NULL;
+
+ p.fs.flow_mask.dst_ip = 0;
+ p.fs.flow_mask.src_ip = 0;
+ p.fs.flow_mask.dst_port = 0;
+ p.fs.flow_mask.src_port = 0;
+ p.fs.flow_mask.proto = 0;
+ end = NULL;
+
+ while (ac >= 1) {
+ uint32_t *p32 = NULL;
+ uint16_t *p16 = NULL;
+ struct in6_addr *pa6 = NULL;
+ uint32_t a;
+
+ tok = match_token(dummynet_params, *av);
+ ac--; av++;
+ switch(tok) {
+ case TOK_ALL:
+ /*
+ * special case, all bits significant
+ */
+ p.fs.flow_mask.dst_ip = ~0;
+ p.fs.flow_mask.src_ip = ~0;
+ p.fs.flow_mask.dst_port = ~0;
+ p.fs.flow_mask.src_port = ~0;
+ p.fs.flow_mask.proto = ~0;
+ n2mask(&(p.fs.flow_mask.dst_ip6), 128);
+ n2mask(&(p.fs.flow_mask.src_ip6), 128);
+ p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+ goto end_mask;
+
+ case TOK_DSTIP:
+ p32 = &p.fs.flow_mask.dst_ip;
+ break;
+
+ case TOK_SRCIP:
+ p32 = &p.fs.flow_mask.src_ip;
+ break;
+
+ case TOK_DSTIP6:
+ pa6 = &(p.fs.flow_mask.dst_ip6);
+ break;
+
+ case TOK_SRCIP6:
+ pa6 = &(p.fs.flow_mask.src_ip6);
+ break;
+
+ case TOK_DSTPORT:
+ p16 = &p.fs.flow_mask.dst_port;
+ break;
+
+ case TOK_SRCPORT:
+ p16 = &p.fs.flow_mask.src_port;
+ break;
+
+ case TOK_PROTO:
+ break;
+
+ default:
+ ac++; av--; /* backtrack */
+ goto end_mask;
+ }
+ if (ac < 1)
+ errx(EX_USAGE, "mask: value missing");
+ if (*av[0] == '/') {
+ a = (int)strtoul(av[0]+1, &end, 0);
+ if (pa6 == NULL)
+ a = (a == 32) ? ~0 : (1 << a) - 1;
+ } else
+ a = (int)strtoul(av[0], &end, 0);
+ if (p32 != NULL)
+ *p32 = a;
+ else if (p16 != NULL) {
+ if (a > 65535)
+ errx(EX_DATAERR,
+ "mask: must be 16 bit");
+ *p16 = (uint16_t)a;
+ } else if (pa6 != NULL) {
+ if (a > 128)
+ errx(EX_DATAERR,
+ "in6addr invalid mask len");
+ else
+ n2mask(pa6, a);
+ } else {
+ if (a > 255)
+ errx(EX_DATAERR,
+ "mask: must be 8 bit");
+ p.fs.flow_mask.proto = (uint8_t)a;
+ }
+ if (a != 0)
+ p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+ ac--; av++;
+ } /* end while, config masks */
+end_mask:
+ break;
+
+ case TOK_RED:
+ case TOK_GRED:
+ NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
+ p.fs.flags_fs |= DN_IS_RED;
+ if (tok == TOK_GRED)
+ p.fs.flags_fs |= DN_IS_GENTLE_RED;
+ /*
+ * the format for parameters is w_q/min_th/max_th/max_p
+ */
+ if ((end = strsep(&av[0], "/"))) {
+ double w_q = strtod(end, NULL);
+ if (w_q > 1 || w_q <= 0)
+ errx(EX_DATAERR, "0 < w_q <= 1");
+ p.fs.w_q = (int) (w_q * (1 << SCALE_RED));
+ }
+ if ((end = strsep(&av[0], "/"))) {
+ p.fs.min_th = (int)strtoul(end, &end, 0);
+ if (*end == 'K' || *end == 'k')
+ p.fs.min_th *= 1024;
+ }
+ if ((end = strsep(&av[0], "/"))) {
+ p.fs.max_th = (int)strtoul(end, &end, 0);
+ if (*end == 'K' || *end == 'k')
+ p.fs.max_th *= 1024;
+ }
+ if ((end = strsep(&av[0], "/"))) {
+ double max_p = strtod(end, NULL);
+ if (max_p > 1 || max_p <= 0)
+ errx(EX_DATAERR, "0 < max_p <= 1");
+ p.fs.max_p = (int)(max_p * (1 << SCALE_RED));
+ }
+ ac--; av++;
+ break;
+
+ case TOK_DROPTAIL:
+ p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
+ break;
+
+ case TOK_BW:
+ NEED1("bw needs bandwidth or interface\n");
+ if (do_pipe != 1)
+ errx(EX_DATAERR, "bandwidth only valid for pipes");
+ /*
+ * set clocking interface or bandwidth value
+ */
+ if (av[0][0] >= 'a' && av[0][0] <= 'z') {
+ /* interface name */
+ strlcpy(p.if_name, av[0], sizeof(p.if_name));
+ p.bandwidth = 0;
+ } else {
+ p.if_name[0] = '\0';
+ p.bandwidth = (int)strtoul(av[0], &end, 0);
+ if (*end == 'K' || *end == 'k') {
+ end++;
+ p.bandwidth *= 1000;
+ } else if (*end == 'M') {
+ end++;
+ p.bandwidth *= 1000000;
+ }
+ if (*end == 'B' || !strncmp(end, "by", 2))
+ p.bandwidth *= 8;
+ if (p.bandwidth < 0)
+ errx(EX_DATAERR, "bandwidth too large");
+ }
+ ac--; av++;
+ break;
+
+ case TOK_DELAY:
+ if (do_pipe != 1)
+ errx(EX_DATAERR, "delay only valid for pipes");
+ NEED2("delay needs argument 0..%d\n", MAX_DELAY);
+ p.delay = (int)strtoul(av[0], NULL, 0);
+ ac--; av++;
+ break;
+
+ case TOK_WEIGHT:
+ if (do_pipe == 1)
+ errx(EX_DATAERR,"weight only valid for queues");
+ NEED1("weight needs argument 0..100\n");
+ p.fs.weight = (int)strtoul(av[0], &end, 0);
+ ac--; av++;
+ break;
+
+ case TOK_PIPE:
+ if (do_pipe == 1)
+ errx(EX_DATAERR,"pipe only valid for queues");
+ NEED1("pipe needs pipe_number\n");
+ p.fs.parent_nr = strtoul(av[0], &end, 0);
+ ac--; av++;
+ break;
+
+ default:
+ errx(EX_DATAERR, "unrecognised option ``%s''", *(--av));
+ }
+ }
+ if (do_pipe == 1) {
+ if (p.pipe_nr == 0)
+ errx(EX_DATAERR, "pipe_nr must be > 0");
+ if (p.delay > MAX_DELAY)
+ errx(EX_DATAERR, "delay must be < %d ms", MAX_DELAY);
+ } else { /* do_pipe == 2, queue */
+ if (p.fs.parent_nr == 0)
+ errx(EX_DATAERR, "pipe must be > 0");
+ if (p.fs.weight >100)
+ errx(EX_DATAERR, "weight must be <= 100");
+ }
+ if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) {
+ if (p.fs.qsize > 1024*1024)
+ errx(EX_DATAERR, "queue size must be < 1MB");
+ } else {
+ if (p.fs.qsize > 100)
+ errx(EX_DATAERR, "2 <= queue size <= 100");
+ }
+ if (p.fs.flags_fs & DN_IS_RED) {
+ size_t len;
+ int lookup_depth, avg_pkt_size;
+ double s, idle, weight, w_q;
+ struct clockinfo ck;
+ int t;
+
+ if (p.fs.min_th >= p.fs.max_th)
+ errx(EX_DATAERR, "min_th %d must be < than max_th %d",
+ p.fs.min_th, p.fs.max_th);
+ if (p.fs.max_th == 0)
+ errx(EX_DATAERR, "max_th must be > 0");
+
+ len = sizeof(int);
+ if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
+ &lookup_depth, &len, NULL, 0) == -1)
+
+ errx(1, "sysctlbyname(\"%s\")",
+ "net.inet.ip.dummynet.red_lookup_depth");
+ if (lookup_depth == 0)
+ errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
+ " must be greater than zero");
+
+ len = sizeof(int);
+ if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
+ &avg_pkt_size, &len, NULL, 0) == -1)
+
+ errx(1, "sysctlbyname(\"%s\")",
+ "net.inet.ip.dummynet.red_avg_pkt_size");
+ if (avg_pkt_size == 0)
+ errx(EX_DATAERR,
+ "net.inet.ip.dummynet.red_avg_pkt_size must"
+ " be greater than zero");
+
+ len = sizeof(struct clockinfo);
+ if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1)
+ errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
+
+ /*
+ * Ticks needed for sending a medium-sized packet.
+ * Unfortunately, when we are configuring a WF2Q+ queue, we
+ * do not have bandwidth information, because that is stored
+ * in the parent pipe, and also we have multiple queues
+ * competing for it. So we set s=0, which is not very
+ * correct. But on the other hand, why do we want RED with
+ * WF2Q+ ?
+ */
+ if (p.bandwidth==0) /* this is a WF2Q+ queue */
+ s = 0;
+ else
+ s = ck.hz * avg_pkt_size * 8 / p.bandwidth;
+
+ /*
+ * max idle time (in ticks) before avg queue size becomes 0.
+ * NOTA: (3/w_q) is approx the value x so that
+ * (1-w_q)^x < 10^-3.
+ */
+ w_q = ((double)p.fs.w_q) / (1 << SCALE_RED);
+ idle = s * 3. / w_q;
+ p.fs.lookup_step = (int)idle / lookup_depth;
+ if (!p.fs.lookup_step)
+ p.fs.lookup_step = 1;
+ weight = 1 - w_q;
+ for (t = p.fs.lookup_step; t > 0; --t)
+ weight *= weight;
+ p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
+ }
+ len = sizeof(struct dn_pipe);
+ i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, &len);
+ if (i)
+ err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
+}
+
+static void
+flush(int force)
+{
+ if (!force && !do_quiet) { /* need to ask user */
+ int c;
+
+ printf("Are you sure? [yn] ");
+ fflush(stdout);
+ do {
+ c = toupper(getc(stdin));
+ while (c != '\n' && getc(stdin) != '\n')
+ if (feof(stdin))
+ return; /* and do not flush */
+ } while (c != 'Y' && c != 'N');
+ printf("\n");
+ if (c == 'N') /* user said no */
+ return;
+ }
+
+ if (do_cmd(IP_DUMMYNET_FLUSH, NULL, 0) < 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_DUMMYNET_FLUSH)");
+
+ if (!do_quiet)
+ printf("Flushed all pipes.\n");
+}
+
+/*
+ * Free a the (locally allocated) copy of command line arguments.
+ */
+static void
+free_args(int ac, char **av)
+{
+ int i;
+
+ for (i=0; i < ac; i++)
+ free(av[i]);
+ free(av);
+}
+
+/*
+ * Called with the arguments (excluding program name).
+ * Returns 0 if successful, 1 if empty command, errx() in case of errors.
+ */
+static int
+parse_args(int oldac, char **oldav)
+{
+ int ch, ac, save_ac;
+ char **av, **save_av;
+ int do_acct = 0; /* Show packet/byte count */
+ int do_force = 0; /* Don't ask for confirmation */
+
+#define WHITESP " \t\f\v\n\r"
+ if (oldac == 0)
+ return 1;
+ else if (oldac == 1) {
+ /*
+ * If we are called with a single string, try to split it into
+ * arguments for subsequent parsing.
+ * But first, remove spaces after a ',', by copying the string
+ * in-place.
+ */
+ char *arg = oldav[0]; /* The string... */
+ size_t l = strlen(arg);
+ int copy = 0; /* 1 if we need to copy, 0 otherwise */
+ int i, j;
+ for (i = j = 0; i < l; i++) {
+ if (arg[i] == '#') /* comment marker */
+ break;
+ if (copy) {
+ arg[j++] = arg[i];
+ copy = !index("," WHITESP, arg[i]);
+ } else {
+ copy = !index(WHITESP, arg[i]);
+ if (copy)
+ arg[j++] = arg[i];
+ }
+ }
+ if (!copy && j > 0) /* last char was a 'blank', remove it */
+ j--;
+ l = j; /* the new argument length */
+ arg[j++] = '\0';
+ if (l == 0) /* empty string! */
+ return 1;
+
+ /*
+ * First, count number of arguments. Because of the previous
+ * processing, this is just the number of blanks plus 1.
+ */
+ for (i = 0, ac = 1; i < l; i++)
+ if (index(WHITESP, arg[i]) != NULL)
+ ac++;
+
+ av = calloc(ac, sizeof(char *));
+
+ /*
+ * Second, copy arguments from cmd[] to av[]. For each one,
+ * j is the initial character, i is the one past the end.
+ */
+ for (ac = 0, i = j = 0; i < l; i++)
+ if (index(WHITESP, arg[i]) != NULL || i == l-1) {
+ if (i == l-1)
+ i++;
+ av[ac] = calloc(i-j+1, 1);
+ bcopy(arg+j, av[ac], i-j);
+ ac++;
+ j = i + 1;
+ }
+ } else {
+ /*
+ * If an argument ends with ',' join with the next one.
+ * Just add its length to 'l' and continue. When we have a string
+ * without a ',' ending, we'll have the combined length in 'l'
+ */
+ int first, i;
+ size_t l;
+
+ av = calloc(oldac, sizeof(char *));
+ for (first = i = ac = 0, l = 0; i < oldac; i++) {
+ char *arg = oldav[i];
+ size_t k = strlen(arg);
+
+ l += k;
+ if (arg[k-1] != ',' || i == oldac-1) {
+ size_t buflen = l+1;
+ /* Time to copy. */
+ av[ac] = calloc(l+1, 1);
+ for (l=0; first <= i; first++) {
+ strlcat(av[ac]+l, oldav[first], buflen-l);
+ l += strlen(oldav[first]);
+ }
+ ac++;
+ l = 0;
+ first = i+1;
+ }
+ }
+ }
+
+ /* Set the force flag for non-interactive processes */
+ do_force = !isatty(STDIN_FILENO);
+
+ /* Save arguments for final freeing of memory. */
+ save_ac = ac;
+ save_av = av;
+
+ optind = optreset = 0;
+ while ((ch = getopt(ac, av, "afhnqsv")) != -1)
+ switch (ch) {
+ case 'a':
+ do_acct = 1;
+ break;
+
+ case 'f':
+ do_force = 1;
+ break;
+
+ case 'h': /* help */
+ free_args(save_ac, save_av);
+ help();
+ break; /* NOTREACHED */
+
+ case 'n':
+ test_only = 1;
+ break;
+
+ case 'q':
+ do_quiet = 1;
+ break;
+
+ case 's': /* sort */
+ do_sort = atoi(optarg);
+ break;
+
+ case 'v': /* verbose */
+ verbose = 1;
+ break;
+
+ default:
+ free_args(save_ac, save_av);
+ return 1;
+ }
+
+ ac -= optind;
+ av += optind;
+ NEED1("bad arguments, for usage summary ``dnctl''");
+
+ /*
+ * An undocumented behaviour of dnctl1 was to allow rule numbers first,
+ * e.g. "100 add allow ..." instead of "add 100 allow ...".
+ * In case, swap first and second argument to get the normal form.
+ */
+ if (ac > 1 && isdigit(*av[0])) {
+ char *p = av[0];
+
+ av[0] = av[1];
+ av[1] = p;
+ }
+
+ /*
+ * optional: pipe or queue
+ */
+ do_pipe = 0;
+ if (!strncmp(*av, "pipe", strlen(*av)))
+ do_pipe = 1;
+ else if (!strncmp(*av, "queue", strlen(*av)))
+ do_pipe = 2;
+ if (do_pipe) {
+ ac--;
+ av++;
+ }
+ NEED1("missing command");
+
+ /*
+ * For pipes and queues we normally say 'pipe NN config'
+ * but the code is easier to parse as 'pipe config NN'
+ * so we swap the two arguments.
+ */
+ if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) {
+ char *p = av[0];
+
+ av[0] = av[1];
+ av[1] = p;
+ }
+
+ if (do_pipe && !strncmp(*av, "config", strlen(*av)))
+ config_pipe(ac, av);
+ else if (!strncmp(*av, "delete", strlen(*av)))
+ delete(ac, av);
+ else if (!strncmp(*av, "flush", strlen(*av)))
+ flush(do_force);
+ else if (!strncmp(*av, "print", strlen(*av)) ||
+ !strncmp(*av, "list", strlen(*av)))
+ list(ac, av, do_acct);
+ else if (!strncmp(*av, "show", strlen(*av)))
+ list(ac, av, 1 /* show counters */);
+ else
+ errx(EX_USAGE, "bad command `%s'", *av);
+
+ /* Free memory allocated in the argument parsing. */
+ free_args(save_ac, save_av);
+ return 0;
+}
+
+static void
+dnctl_readfile(int ac, char *av[])
+{
+#define MAX_ARGS 32
+ char buf[BUFSIZ];
+ char *cmd = NULL, *filename = av[ac-1];
+ int c, lineno=0;
+ FILE *f = NULL;
+ pid_t preproc = 0;
+
+ while ((c = getopt(ac, av, "np:q")) != -1) {
+ switch(c) {
+ case 'n':
+ test_only = 1;
+ break;
+
+ case 'p':
+ cmd = optarg;
+ /*
+ * Skip previous args and delete last one, so we
+ * pass all but the last argument to the preprocessor
+ * via av[optind-1]
+ */
+ av += optind - 1;
+ ac -= optind - 1;
+ av[ac-1] = NULL;
+ fprintf(stderr, "command is %s\n", av[0]);
+ break;
+
+ case 'q':
+ do_quiet = 1;
+ break;
+
+ default:
+ errx(EX_USAGE, "bad arguments, for usage"
+ " summary ``dnctl''");
+ }
+
+ if (cmd != NULL)
+ break;
+ }
+
+ if (cmd == NULL && ac != optind + 1) {
+ fprintf(stderr, "ac %d, optind %d\n", ac, optind);
+ errx(EX_USAGE, "extraneous filename arguments");
+ }
+
+ if ((f = fopen(filename, "r")) == NULL)
+ err(EX_UNAVAILABLE, "fopen: %s", filename);
+
+ if (cmd != NULL) { /* pipe through preprocessor */
+ int pipedes[2];
+
+ if (pipe(pipedes) == -1)
+ err(EX_OSERR, "cannot create pipe");
+
+ preproc = fork();
+ if (preproc == -1)
+ err(EX_OSERR, "cannot fork");
+
+ if (preproc == 0) {
+ /*
+ * Child, will run the preprocessor with the
+ * file on stdin and the pipe on stdout.
+ */
+ if (dup2(fileno(f), 0) == -1
+ || dup2(pipedes[1], 1) == -1)
+ err(EX_OSERR, "dup2()");
+ fclose(f);
+ close(pipedes[1]);
+ close(pipedes[0]);
+ execvp(cmd, av);
+ err(EX_OSERR, "execvp(%s) failed", cmd);
+ } else { /* parent, will reopen f as the pipe */
+ fclose(f);
+ close(pipedes[1]);
+ if ((f = fdopen(pipedes[0], "r")) == NULL) {
+ int savederrno = errno;
+
+ (void)kill(preproc, SIGTERM);
+ errno = savederrno;
+ err(EX_OSERR, "fdopen()");
+ }
+ }
+ }
+
+ while (fgets(buf, BUFSIZ, f)) { /* read commands */
+ char linename[16];
+ char *args[1];
+
+ lineno++;
+ snprintf(linename, sizeof(linename), "Line %d", lineno);
+ setprogname(linename); /* XXX */
+ args[0] = buf;
+ parse_args(1, args);
+ }
+ fclose(f);
+ if (cmd != NULL) {
+ int status;
+
+ if (waitpid(preproc, &status, 0) == -1)
+ errx(EX_OSERR, "waitpid()");
+ if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
+ errx(EX_UNAVAILABLE,
+ "preprocessor exited with status %d",
+ WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ errx(EX_UNAVAILABLE,
+ "preprocessor exited with signal %d",
+ WTERMSIG(status));
+ }
+}
+
+int
+main(int ac, char *av[])
+{
+ /*
+ * If the last argument is an absolute pathname, interpret it
+ * as a file to be preprocessed.
+ */
+
+ if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
+ dnctl_readfile(ac, av);
+ else {
+ if (parse_args(ac-1, av+1))
+ show_usage();
+ }
+ return EX_OK;
+}
diff --git a/network_cmds/ecnprobe/base.h b/network_cmds/ecnprobe/base.h
new file mode 100644
index 0000000..562b4ef
--- /dev/null
+++ b/network_cmds/ecnprobe/base.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <assert.h>
diff --git a/network_cmds/ecnprobe/capture.c b/network_cmds/ecnprobe/capture.c
new file mode 100644
index 0000000..32a8e0b
--- /dev/null
+++ b/network_cmds/ecnprobe/capture.c
@@ -0,0 +1,204 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmt2local.h"
+#include "pcap.h"
+#include "inet.h"
+#include "capture.h"
+
+/* set snaplen to max etherenet packet size */
+#define DEFAULT_SNAPLEN 1500
+
+pcap_t *pc; /* pcap device */
+int datalinkOffset; /* offset of ip packet from datalink packet */
+int captureDebug = 1;
+unsigned int thisTimeZone;
+
+void CaptureInit(u_int32_t sourceIP, u_int16_t sourcePort,
+ u_int32_t targetIP, u_int16_t targetPort, char *dev)
+{
+
+ char *device = NULL;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ int snaplen = DEFAULT_SNAPLEN;
+ int promisc = 1;
+ int timeout = 10; /* timeout in 1 second (10 ms) */
+ char filtercmds[255];
+ bpf_u_int32 netmask = 0;
+ struct bpf_program filter;
+ char source[18];
+ char target[18];
+ int i;
+
+ /* Get local time zone for interpreting timestamps */
+ /* XXX - does this belong here? */
+ thisTimeZone = gmt2local(0);
+
+ if (dev != NULL) {
+ device = dev;
+ } else {
+ pcap_if_t *devlist;
+ /*
+ * Find the list of interfaces, and pick
+ * the first interface.
+ */
+ if (pcap_findalldevs(&devlist, errbuf) >= 0 &&
+ devlist != NULL) {
+ device = strdup(devlist->name);
+ pcap_freealldevs(devlist);
+ }
+
+ if (device == NULL) {
+ fprintf(stderr, "Can't find capture device: %s\n", errbuf);
+ exit(-1);
+ }
+ }
+
+ if (captureDebug) {
+ printf("Device name is %s\n", device);
+ }
+ pc = pcap_open_live(device, snaplen, promisc, timeout, errbuf);
+ if (pc == NULL) {
+ fprintf(stderr,"Can't open capture device %s: %s\n",device, errbuf);
+ exit(-1);
+ }
+
+ /* XXX why do we need to do this? */
+ i = pcap_snapshot(pc);
+ if (snaplen < i) {
+ fprintf(stderr, "Warning: snaplen raised to %d from %d",
+ snaplen, i);
+ }
+
+ if ((i = pcap_datalink(pc)) < 0) {
+ fprintf(stderr,"Unable to determine datalink type for %s: %s\n",
+ device, errbuf);
+ exit(-1);
+ }
+
+ switch(i) {
+
+ case DLT_EN10MB: datalinkOffset = 14; break;
+ case DLT_IEEE802: datalinkOffset = 22; break;
+ case DLT_NULL: datalinkOffset = 4; break;
+ case DLT_SLIP:
+ case DLT_PPP: datalinkOffset = 24; break;
+ case DLT_RAW: datalinkOffset = 0; break;
+ default:
+ fprintf(stderr,"Unknown datalink type %d\n",i);
+ exit(-1);
+ break;
+
+ }
+
+ if (InetAddress(sourceIP) < 0) {
+ fprintf(stderr, "Invalid source IP address (%d)\n", sourceIP);
+ exit(-1);
+ }
+
+ strlcpy(source, InetAddress(sourceIP), sizeof(source));
+ strlcpy(target, InetAddress(targetIP), sizeof(target));
+
+ /* Setup initial filter */
+ sprintf(filtercmds,
+ "(host %s && host %s && port %d) || icmp\n",
+ source, target, targetPort);
+
+ if (captureDebug) {
+ printf("datalinkOffset = %d\n", datalinkOffset);
+ printf("filter = %s\n", filtercmds);
+ }
+ if (pcap_compile(pc, &filter, filtercmds, 1, netmask) < 0) {
+ printf("Error: %s", pcap_geterr(pc));
+ exit(-1);
+ }
+
+ if (pcap_setfilter(pc, &filter) < 0) {
+ fprintf(stderr, "Can't set filter: %s",pcap_geterr(pc));
+ exit(-1);
+ }
+
+ if (captureDebug) {
+ printf("Listening on %s...\n", device);
+ }
+
+}
+
+char *CaptureGetPacket(struct pcap_pkthdr *pi)
+{
+
+ const u_char *p;
+
+ p = pcap_next(pc, (struct pcap_pkthdr *)pi);
+
+ if (p != NULL) {
+ p += datalinkOffset;
+ }
+
+ pi->ts.tv_sec = (pi->ts.tv_sec + thisTimeZone) % 86400;
+
+ return (char *)p;
+
+}
+
+
+void CaptureEnd()
+{
+ struct pcap_stat stat;
+
+ if (pcap_stats(pc, &stat) < 0) {
+ (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pc));
+ }
+ else {
+ (void)fprintf(stderr, "%d packets received by filter\n", stat.ps_recv);
+ (void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop);
+ }
+
+ pcap_close(pc);
+}
+
diff --git a/network_cmds/ecnprobe/capture.h b/network_cmds/ecnprobe/capture.h
new file mode 100644
index 0000000..9bb83be
--- /dev/null
+++ b/network_cmds/ecnprobe/capture.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#ifndef _CAPTURE_H_
+#define _CAPTURE_H_
+#include <pcap/pcap.h>
+
+struct PacketInfo {
+ struct timeval ts;
+ unsigned int caplen;
+ unsigned int len;
+};
+
+void CaptureInit(u_int32_t sourceIP, u_int16_t sourcePort,
+ u_int32_t targetIP, u_int16_t targetPort, char *dev);
+char *CaptureGetPacket(struct pcap_pkthdr *);
+void CaptureEnd();
+
+#endif /* _CAPTURE_H_ */
diff --git a/network_cmds/ecnprobe/ecn.c b/network_cmds/ecnprobe/ecn.c
new file mode 100644
index 0000000..b7dabdf
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn.c
@@ -0,0 +1,1119 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "history.h"
+#include "ecn.h"
+
+extern struct TcpSession session;
+extern struct History history[];
+
+#define ESTABLISH_SUCCESS 0
+#define ESTABLISH_FAILURE_EARLY_RST 1
+#define ESTABLISH_FAILURE_NO_REPLY 2
+int EstablishTcpConnection(u_int8_t syn_flags, u_int8_t ip_tos)
+{
+ struct IPPacket *synPacket = NULL, *ackPacket = NULL;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ int tcpoptlen = 4; /* For negotiating MSS */
+ u_int8_t *opt = NULL;
+ struct IPPacket *p = NULL;
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
+ opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
+ opt[0] = (u_int8_t)TCPOPT_MAXSEG;
+ opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
+ *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
+ timeoutTime = GetTime() + 1;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < 3) {
+ while(GetTime() < timeoutTime) {
+ /* Have we captured any packets? */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport,
+ session.dst, session.dport)) {
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totSeenSent++ ;
+ } else {
+ processBadPacket(p);
+ }
+ continue;
+ }
+
+ /* Received a packet from them to us */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport)) {
+ /* Is it a SYN/ACK? */
+ if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+
+ /*
+ * Save ttl for,admittedly poor,indications of reverse
+ * route change
+ */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd ++;
+ break;
+ } else {
+ if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
+ printf ("ERROR: EARLY_RST\n");
+ return(ESTABLISH_FAILURE_EARLY_RST);
+ }
+ }
+ }
+ }
+ }
+
+ if (!synAckReceived) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
+ timeoutTime = GetTime() + 1;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= 3) {
+ printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
+ NO_CONNECTION);
+ return(ESTABLISH_FAILURE_NO_REPLY);
+ }
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("Received SYN-ACK, try to send the third Ack\n");
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src),
+ session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
+ session.dport, session.irs);
+ }
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ ackPacket = AllocateIPPacket(0, 0, 0, "Third ACK");
+ /* send an ACK */
+ SendSessionPacket(ackPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ TCPFLAGS_ACK, 0, 0, 0);
+ FreeIPPacket(&synPacket);
+ FreeIPPacket(&ackPacket);
+ return(ESTABLISH_SUCCESS);
+}
+
+void ECNTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss)
+{
+ int rawSocket, rc, flag = 1;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ /* random initial sequence number */
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime ();
+ session.maxpkts = 1000;
+/* session.debug = SESSION_DEBUG_LOW; */
+ session.debug = 0;
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memmory to store data:\nRETURN CODE: %d",
+ ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Establish a TCP connections with ECN bits */
+ rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
+ switch (rc) {
+ case ESTABLISH_FAILURE_EARLY_RST:
+ {
+ /* Received a RST when ECN bits are used. Try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Received RST with or without ECN negotiation\n");
+ printf("The server might not be listening on this port\n");
+ Quit(EARLY_RST);
+ } else if (rc == ESTABLISH_SUCCESS) {
+ printf("Received RST with ECN.\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Received RST with ECN\n");
+ printf("Exceed max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ }
+ break;
+ }
+ case ESTABLISH_FAILURE_NO_REPLY:
+ {
+ /* No reply after retring, try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Received RST without ECN\n");
+ Quit(NO_CONNECTION);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Exceeded max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ } else {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ }
+ break;
+ }
+ }
+
+ /* Test for propogation of CE correctly */
+ DataPkt(session.filename, 3, 0);
+
+ checkECN();
+ return;
+}
+
+void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags)
+{
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i ;
+ int sendflag = 1 ;
+ u_int16_t lastSeqSent = session.snd_nxt;
+ double startTime = 0;
+ char *dataptr ;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ datalen = PrepareRequest (data, filename);
+
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr,(void *)data, datalen);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* send the data packet
+ * we try to "achieve" reliability by
+ * sending the packet upto 5 times, wating for
+ * 2 seconds between packets
+ * BAD busy-wait loop
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, iptos);
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++ ;
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src, session.sport,
+ session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
+ SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
+ lastSeqSent = ntohl(p->tcp->tcp_seq);
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.snd_nxt += datalen + 1;
+ session.totSeenSent ++ ;
+ continue ;
+ }
+
+ /*
+ * from them?
+ */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una)) {
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ session.snd_nxt = session.snd_una;
+ if (p->ip->ip_ttl != session.ttl) {
+ session.ttl = p->ip->ip_ttl;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totRcvd ++;
+ break ;
+ }
+ /*
+ * otherwise, this is a bad packet
+ * we must quit
+ */
+ //processBadPacket(p);
+ }
+ if ((GetTime() - startTime >= 1) && (sendflag == 0) && (i < 3)) {
+ sendflag = 1 ;
+ }
+ if (i >= 3) {
+ printf ("ERROR: sent request 3 times without response\n");
+ return;
+ }
+ }
+
+ FreeIPPacket(&datapkt);
+
+ /* process any response by sending Acks */
+ rcvData (ECNAckData);
+}
+
+void ECNAckData (struct IPPacket *p)
+{
+
+ uint32 seq = history[session.hsz - 1].seqno;
+ uint16 datalen = history[session.hsz - 1].dlen;
+ int fin = history[session.hsz - 1].fin;
+ int rst = history[session.hsz - 1].rst;
+ int i;
+ struct IPPacket *ackpkt = NULL;
+ static int ECT_00 = 0;
+ static int ECT_01 = 0;
+ static int ECT_10 = 0;
+ static int ECT_11 = 0;
+ static int ECN_ECHO = 0;
+ static int send_cwr = 0;
+ static int send_ece = 0;
+ uint8 tcp_flags = 0;
+
+
+ /* Legend:
+ * ECN_ECHO: counts packets with TCP header ECN bit set
+ * ECT_XX: counts packets with ECT codepoint XX (IP)
+ */
+
+ if (datalen > session.mss) {
+ printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
+ session.mss, datalen, MSS_ERR);
+ Quit(MSS_ERR);
+ }
+
+ if (datalen > 0) {
+ char *http_code = (char *)calloc(4, sizeof(char));
+ if (seq - session.irs == 1) {
+ /* Response to request packet --> check HTTP response code */
+ memcpy(http_code, ((char *)(p->tcp) + sizeof(struct TcpHeader) +
+ history[session.hsz - 1].optlen + 9), 3);
+ if (strncmp(http_code, HTTP_OK, 3) != 0) {
+ printf("HTTP ERROR - HTTP RESPONSE CODE: %s\nRETURN CODE: %d\n",
+ http_code, atoi(http_code));
+ Quit(atoi(http_code));
+ }
+ }
+
+ session.totDataPktsRcvd++;
+
+ if (session.verbose) {
+ printf ("r %f %d %d\n",
+ GetTime() - session.epochTime,
+ seq - session.irs,
+ seq - session.irs + datalen);
+ }
+
+ }
+
+ /* Check if packet has the ECN_ECHO flag set */
+ if (history[session.hsz - 1].ecn_echo) {
+ ECN_ECHO += 1;
+ }
+
+ if ((p->ip->ip_tos & 0x17) == 0) {
+ ECT_00 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 1) {
+ ECT_01 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 2) {
+ ECT_10 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 3) {
+ ECT_11 += 1;
+ }
+
+ if(session.maxseqseen < seq + datalen - 1) {
+ session.maxseqseen = seq + datalen - 1;
+ } else {
+ if (datalen > 0) {
+ if (reordered(p) != 1) {
+ session.num_unwanted_drops += 1;
+ }
+ }
+ }
+
+ /* from TCP/IP vol. 2, p 808 */
+ if (SEQ_LEQ(session.rcv_nxt, seq) &&
+ SEQ_LT(seq, (session.rcv_nxt + session.rcv_wnd)) &&
+ SEQ_LEQ(session.rcv_nxt, (seq + datalen)) &&
+ SEQ_LT((seq+datalen-1), (session.rcv_nxt + session.rcv_wnd))) {
+ int start, end;
+ start = seq - session.irs ;
+ end = start + datalen ;
+
+ for (i = start ; i < end ; i++) {
+ session.dataRcvd[i] = 1 ;
+ }
+
+ start = session.rcv_nxt - session.irs ;
+ end = session.mss * session.maxpkts ;
+
+ for (i = start ; i < end ; i++) {
+ if (session.dataRcvd[i] == 0) {
+ break ;
+ }
+ session.rcv_nxt++ ;
+ }
+ }
+
+ if (datalen > 0) {
+ if (session.verbose) {
+ printf ("a %f %d\n", GetTime() - session.epochTime,
+ session.rcv_nxt - session.irs);
+ }
+ ackpkt = AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
+ if ((p->ip->ip_tos & 0x17) == 3) {
+ tcp_flags = TCPFLAGS_ACK | TCPFLAGS_ECN_ECHO;
+ } else {
+ tcp_flags = TCPFLAGS_ACK;
+ }
+
+ if (send_cwr == 2 && send_ece < 2) {
+ /* Send ECE as if a CE was received, we have to get CWR back */
+ send_ece = 1;
+ tcp_flags |= TCPFLAGS_ECN_ECHO;
+ }
+
+ SendSessionPacket (ackpkt,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ tcp_flags, 0, 0, 0);
+ }
+
+ if (send_cwr == 0 && (p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
+ /* Send CWR atleast once if ECN ECHO is set */
+ int datalen;
+ struct IPPacket *datapkt;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int ipsz;
+
+ datalen = PrepareRequest(data, NULL);
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) +
+ datalen + 1;
+
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | TCPFLAGS_CWR, 0, 0, 2);
+
+ session.snd_nxt += (datalen + 1);
+ send_cwr = 1;
+ FreeIPPacket(&datapkt);
+ }
+
+ if (send_cwr == 1 && !(p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
+ /* ECE was reset in response to CWR, move to the next state of probing */
+ send_cwr = 2;
+ }
+
+ if (send_ece == 1 && (p->tcp->tcp_flags & TCPFLAGS_CWR)) {
+ /* Received CWR in response to ECE */
+ send_ece = 2;
+ }
+
+ if (SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una))
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ if (SEQ_LT(session.snd_nxt, session.snd_una))
+ session.snd_nxt = session.snd_una;
+
+ if (fin || rst) {
+ /* Increment sequence number for FIN rcvd */
+ session.rcv_nxt++;
+ if (ECT_01 == 0 && ECT_10 == 0) {
+ printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
+ }
+ if (ECT_11 > 3) {
+ /* If we received more than 3 CE, flag it as an error */
+ printf("Received too many ECT_CE (%d): FAIL\n", ECT_11);
+ }
+ printf ("Totdata = %d ECN_ECHO: %d ECT00: %d ECT01: %d ECT10: %d ECT11: %d drops: %d\n",
+ session.rcv_nxt - session.irs, ECN_ECHO, ECT_00,
+ ECT_01, ECT_10, ECT_11, session.num_unwanted_drops);
+ if (fin) {
+ SendSessionPacket (ackpkt,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ tcp_flags, 0, 0, 0);
+ }
+ checkECN();
+ Quit(SUCCESS);
+ }
+}
+
+void checkECN ()
+{
+ int i;
+ int sr = 0; /* sr=1: SYN/ACK rcvd */
+ int se = 0; /* se=0: no CWR/no ECHO; se=1: no CWR/ECHO; se=2: CWR/ECHO */
+ int ar = 0; /* ar=0: no ACK rcvd; ar=1: ACK rcvd */
+ int ae = 0; /* ae=0: ACK/no ECHO; ae=1: ACK/ECHO */
+ int we = 0; /* we=0: no ECHO; we=1 ECHO/CWR; we=2 ECHO/CWR/ECHO stop */
+ int ee = 0; /* ee=0 never sent ECE; ee=1 sent ECE; ee=2 ECE / CWR */
+
+ for (i = 0 ; i < session.hsz; i++) {
+ if ((history[i].type == RCVD) && (history[i].syn == 1) &&
+ (history[i].ack == 1)) {
+ sr = 1;
+ if (history[i].ecn_echo == 1) {
+ se = 1;
+ if (history[i].cwr == 1) {
+ se = 2;
+ }
+ }
+ }
+ }
+
+ for (i = 0 ; i < session.hsz; i++) {
+ if (history[i].type == RCVD && history[i].syn == 0 &&
+ history[i].ack == 1) {
+ ar = 1;
+ if (history[i].ecn_echo == 1) {
+ ae = 1;
+ }
+ }
+ }
+
+ for (i = 0; i < session.hsz; i++) {
+ if (history[i].type == SENT && history[i].dlen > 0 &&
+ history[i].cwr == 1) {
+ we = 1;
+ continue;
+ }
+ if (we == 1 && history[i].type == RCVD && history[i].ecn_echo == 0) {
+ we = 2;
+ break;
+ }
+ if (we == 2 && history[i].type == RCVD && history[i].ecn_echo == 1) {
+ we = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < session.hsz; i++) {
+ if (history[i].type == SENT && history[i].ecn_echo == 1) {
+ ee = 1;
+ continue;
+ }
+ if (ee == 1 && history[i].type == RCVD && history[i].dlen > 0 &&
+ history[i].cwr == 1) {
+ /* Received cwr in response to ECE */
+ ee = 2;
+ break;
+ }
+ }
+
+ printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr, se, ar, ae, we);
+ switch (sr) {
+ case 0:
+ printf("No SYN/ACK received from server\n");
+ break;
+ case 1:
+ printf("SYN/ACK received: PASS \n");
+ break;
+ default:
+ printf("Unknown value for sr: %d\n", sr);
+ break;
+ }
+ switch (se) {
+ case 0:
+ printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
+ break;
+ case 1:
+ printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
+ break;
+ case 2:
+ printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
+ break;
+ default:
+ printf("Unknown value for se: %d\n", se);
+ break;
+ }
+
+ switch (ar) {
+ case 0:
+ printf("No ACK received\n");
+ break;
+ case 1:
+ printf("ACK received: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ar: %d\n", ar);
+ break;
+ }
+
+ switch (ae) {
+ case 0:
+ printf("Received ACKS but never ECE\n");
+ break;
+ case 1:
+ printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ae: %d\n", ae);
+ break;
+ }
+
+ switch (we) {
+ case 0:
+ printf("Never received ECE\n");
+ break;
+ case 1:
+ printf("Received ECE and sent CWR\n");
+ break;
+ case 2:
+ printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
+ break;
+ default:
+ printf("Unknown value for we: %d\n", we);
+ break;
+ }
+
+ switch (ee) {
+ case 0:
+ printf("Never sent ECE\n");
+ break;
+ case 1:
+ printf("Sent ECE to simulate receiving CE \n");
+ break;
+ case 2:
+ printf("Sent ECE and received CWR in response: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ee: %d\n", ee);
+ break;
+ }
+ return;
+}
+
+void DataPktPathCheck(char *filename, u_int8_t iptos, u_int8_t tcp_flags)
+{
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i ;
+ int sendflag = 1 ;
+ u_int16_t lastSeqSent = session.snd_nxt;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+ unsigned int init_ttl;
+
+ datalen = PrepareRequest (data, filename);
+
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr,(void *)data, datalen);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+ /* send the data packet
+ * we try to "achieve" reliability by
+ * sending the packet upto 5 times, wating for
+ * 2 seconds between packets
+ * BAD busy-wait loop
+ */
+
+ i = 0 ;
+ init_ttl = 1;
+ while(1) {
+
+ if (sendflag == 1) {
+ session.curr_ttl = ++init_ttl;
+ if (init_ttl > 64) /* reached the max */
+ break;
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, 0x3);
+
+ startTime = GetTime();
+ sendflag = 0;
+ i++ ;
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src, session.sport,
+ session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
+ SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
+ lastSeqSent = ntohl(p->tcp->tcp_seq);
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.snd_nxt += datalen + 1;
+ session.totSeenSent ++ ;
+ continue ;
+ }
+
+ /*
+ * from them?
+ */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ ntohl(p->tcp->tcp_ack) == session.snd_nxt) {
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ session.snd_nxt = session.snd_una;
+ if (p->ip->ip_ttl != session.ttl) {
+ session.ttl = p->ip->ip_ttl;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totRcvd ++;
+ break ;
+ }
+ /*
+ * ICMP ttl exceeded
+ */
+ if (p->ip->ip_p == IPPROTOCOL_ICMP) {
+ uint16_t ip_hl;
+ struct IcmpHeader *icmp;
+ ip_hl = (p->ip->ip_vhl & 0x0f) << 2;
+ void *nexthdr;
+
+ icmp = (struct IcmpHeader *)((char *)p->ip + ip_hl);
+ nexthdr = (void *)icmp;
+ if (icmp->icmp_type == ICMP_TIMXCEED) {
+ struct IpHeader off_ip;
+ struct TcpHeader off_tcp;
+
+ bzero(&off_ip, sizeof(struct IpHeader));
+ nexthdr = nexthdr + sizeof(struct IcmpHeader);
+ memcpy((void *)&off_ip, nexthdr,
+ sizeof(struct IpHeader));
+ nexthdr += sizeof(struct IpHeader);
+
+ bzero(&off_tcp, sizeof(struct TcpHeader));
+ memcpy(&off_tcp, nexthdr, 4);
+ if (session.src == off_ip.ip_src &&
+ session.dst == off_ip.ip_dst) {
+ printf("Received ICMP TTL exceeded from %s:"
+ "ttl used %u ip_tos 0x%x sport %u dport %u\n",
+ InetAddress(p->ip->ip_src), init_ttl, off_ip.ip_tos,
+ ntohs(off_tcp.tcp_sport), ntohs(off_tcp.tcp_dport));
+ }
+ }
+ }
+ /*
+ * otherwise, this is a bad packet
+ * we must quit
+ */
+ //processBadPacket(p);
+ }
+ if ((GetTime() - startTime >= 1) && (sendflag == 0)) {
+ sendflag = 1;
+ session.snd_nxt = session.snd_una;
+ }
+ }
+
+ FreeIPPacket(&datapkt);
+}
+void ECNPathCheckTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss)
+{
+ int rawSocket, rc, flag;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime();
+ session.maxpkts = 1000;
+ session.debug = 0;
+
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ flag = 1;
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Establish a TCP connections with ECN bits */
+ rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
+ switch (rc) {
+ case ESTABLISH_FAILURE_EARLY_RST:
+ {
+ /* Received a RST when ECN bits are used. Try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Received RST with or without ECN negotiation\n");
+ printf("The server might not be listening on this port\n");
+ Quit(EARLY_RST);
+ } else if (rc == ESTABLISH_SUCCESS) {
+ printf("Received RST with ECN.\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Received RST with ECN\n");
+ printf("Exceed max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ }
+ break;
+ }
+ case ESTABLISH_FAILURE_NO_REPLY:
+ {
+ /* No reply after retring, try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Received RST without ECN\n");
+ Quit(NO_CONNECTION);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Exceeded max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ } else {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ }
+ break;
+ }
+ }
+
+ DataPktPathCheck(session.filename, 3, 0);
+ return;
+}
+
+
+void
+SynTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss, int syn_reply)
+{
+ int rawSocket, flag;
+ struct IPPacket *synPacket = NULL, *ackPacket = NULL;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ int tcpoptlen = 4; /* For negotiating MSS */
+ u_int8_t *opt = NULL;
+ struct IPPacket *p = NULL;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime();
+ session.maxpkts = 1000;
+
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ flag = 1;
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
+ opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
+ opt[0] = (u_int8_t)TCPOPT_MAXSEG;
+ opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
+ *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN , 0, tcpoptlen, 0);
+ timeoutTime = GetTime() + 1;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < 3) {
+ while(GetTime() < timeoutTime) {
+ /* Have we captured any packets? */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport,
+ session.dst, session.dport)) {
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totSeenSent++ ;
+ } else {
+ processBadPacket(p);
+ }
+ continue;
+ }
+
+ /* Received a packet from them to us */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport)) {
+ /* Is it a SYN/ACK? */
+ if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+
+ /*
+ * Save ttl for,admittedly poor,indications of reverse
+ * route change
+ */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd ++;
+ break;
+ } else {
+ if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
+ printf ("ERROR: EARLY_RST\n");
+ goto done;
+ }
+ }
+ }
+ }
+ }
+
+ if (!synAckReceived) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN , 0, tcpoptlen, 0);
+ timeoutTime = GetTime() + 1;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= 3) {
+ printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
+ NO_CONNECTION);
+ goto done;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("Received SYN-ACK\n");
+ if (syn_reply != 0) {
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("try to send the %s\n", syn_reply == TCPFLAGS_ACK ? "third Ack" : "RST");
+ printf("src = %s:%d (%u)\n", InetAddress(session.src),
+ session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
+ session.dport, session.irs);
+ }
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ ackPacket = AllocateIPPacket(0, 0, 0, "SYN reply");
+ /* send an ACK */
+ SendSessionPacket(ackPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ syn_reply, 0, 0, 0);
+ FreeIPPacket(&ackPacket);
+ }
+done:
+ FreeIPPacket(&synPacket);
+}
diff --git a/network_cmds/ecnprobe/ecn.h b/network_cmds/ecnprobe/ecn.h
new file mode 100644
index 0000000..5ac582c
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+void ECNTest (u_int32_t sourceIpAddress, u_int16_t sourcePort, u_int32_t targetIpAddress, u_int16_t targetPort, int mss) ;
+void ECNAckData (struct IPPacket *p);
+void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags);
+void checkECN ();
+void ECNPathCheckTest(u_int32_t sourceIpAddress, u_int16_t surcePort,
+ u_int32_t targetIpAddress, u_int16_t targetPort, int mss);
+void SynTest(u_int32_t sourceIpAddress, u_int16_t surcePort, u_int32_t targetIpAddress, u_int16_t targetPort, int mss, int syn_reply);
diff --git a/network_cmds/ecnprobe/ecn_probe.c b/network_cmds/ecnprobe/ecn_probe.c
new file mode 100644
index 0000000..362ff4f
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn_probe.c
@@ -0,0 +1,469 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <spawn.h>
+#include <ifaddrs.h>
+#include "inet.h"
+#include "capture.h"
+#include "support.h"
+#include "session.h"
+#include "ecn.h"
+#include "history.h"
+
+extern struct TcpSession session;
+
+void usage (char *name);
+int GetCannonicalInfo(char *string, size_t str_size, u_int32_t *address);
+int BindTcpPort(int sockfd) ;
+
+void usage(char *name)
+{
+ printf("%s [options]\n", name);
+ printf("\t-n <target hostname | ipaddress>\n");
+ printf("\t-p <target port>\n");
+ printf("\t-m <mss>\n");
+ printf("\t-M <mtu>\n");
+ printf("\t-w <sourcePort>\n");
+ printf("\t-s <source hostname or ip address>\n");
+ printf("\t-f <file-name to get>\n");
+ printf("\t-d <interface name>\n");
+ printf("\t-C for CE path check\n");
+ printf("\t-S [A|R|X] SYN followed by ACK or RST or nothing\n");
+ printf("\t-F [set|clear|skip] how to handle firewall rules\n");
+ return;
+}
+
+void SetupFirewall(u_int32_t targetIP, u_int16_t port, char *dev)
+{
+ char pfcmd[512];
+ char *pf_file_name = "/tmp/pf.conf";
+ int pf_fd = 0, rc;
+ ssize_t bytes;
+ char *args[4];
+
+ bzero(pfcmd, sizeof(pfcmd));
+
+ bzero(args, sizeof(args));
+ sprintf(pfcmd, "block in quick on %s inet proto tcp from %s port %u\n",
+ dev, InetAddress(targetIP), port);
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("PF rule: %s\n", pfcmd);
+
+ pf_fd = open(pf_file_name, O_RDWR|O_TRUNC|O_CREAT);
+ if (pf_fd < 0) {
+ perror("failed to open pf file");
+ exit(1);
+ }
+ bytes = write(pf_fd, pfcmd, strlen(pfcmd) + 1);
+ close(pf_fd);
+ args[0] = "pfctl";
+ args[1] = "-d";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -d: %d\n", rc);
+ Quit(FAIL);
+ }
+
+ args[1] = "-f";
+ args[2] = pf_file_name;
+ args[3] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -f /tmp/pf.conf: %d\n", rc);
+ Quit(FAIL);
+ }
+
+ args[1] = "-e";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -e: %d\n", rc);
+ Quit(FAIL);
+ }
+}
+
+void CleanupFirewall()
+{
+ char * args[3];
+ int rc;
+
+ args[0] = "pfctl";
+ args[1] = "-d";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -d: %d\n", rc);
+ Quit(FAIL);
+ }
+}
+
+void Cleanup()
+{
+ if (session.initSession > 0) {
+ shutdown(session.socket, 2);
+ }
+ if (session.initCapture > 0) {
+ CaptureEnd();
+ }
+ if (session.initFirewall > 0) {
+ CleanupFirewall();
+ }
+}
+
+void Quit(int how)
+{
+ SendReset();
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(how);
+}
+
+void SigHandle(int signo)
+{
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(-1);
+}
+
+int GetCannonicalInfo(char *string, size_t str_size, u_int32_t *address)
+{
+ struct hostent *hp;
+ /* Is string in dotted decimal format? */
+ if ((*address = inet_addr(string)) == INADDR_NONE) {
+ /* No, then lookup IP address */
+ if ((hp = gethostbyname(string)) == NULL) {
+ /* Can't find IP address */
+ printf("ERROR: Couldn't obtain address for %s\n"
+ "RETURN CODE: %d\n", string, FAIL);
+ return(-1);
+ } else {
+ strlcpy(string, hp->h_name, str_size);
+ memcpy((void *)address, (void *)hp->h_addr,
+ hp->h_length);
+ }
+ } else {
+ if ((hp = gethostbyaddr((char *)address, sizeof(*address),
+ AF_INET)) == NULL) {
+ /*
+ * Can't get cannonical hostname, so just use
+ * input string
+ */
+ if (session.debug) {
+ printf("WARNING: Couldn't obtain cannonical"
+ " name for %s\nRETURN CODE: %d",
+ string, NO_SRC_CANON_INFO);
+ }
+ /* strlcpy(name, string, MAXHOSTNAMELEN);*/
+ } else {
+ /* strlcpy(name, hp->h_name, MAXHOSTNAMELEN);*/
+ }
+ }
+ return(0);
+}
+
+int BindTcpPort(int sockfd)
+{
+ struct sockaddr_in sockName;
+ int port, result;
+ int randomOffset;
+
+#define START_PORT (50*1024)
+#define END_PORT (0xFFFF)
+
+ /*
+ * Choose random offset to reduce likelihood of
+ * collision with last run
+ */
+ randomOffset = (int)(1000.0*drand48());
+
+ /* Try to find a free port in the range START_PORT+1..END_PORT */
+ port = START_PORT+randomOffset;
+ do {
+ ++port;
+ sockName.sin_addr.s_addr = INADDR_ANY;
+ sockName.sin_family = AF_INET;
+ sockName.sin_port = 0; //htons(port);
+ result = bind(sockfd, (struct sockaddr *)&sockName,
+ sizeof(sockName));
+ } while ((result < 0) && (port < END_PORT));
+
+
+ if (result < 0) {
+ /* No free ports */
+ perror("bind");
+ port = 0;
+ } else {
+ socklen_t len = sizeof(sockName);
+ result = getsockname(sockfd, (struct sockaddr *)&sockName, &len);
+ if (result < 0) {
+ perror("getsockname");
+ port = 0;
+ } else {
+ port = ntohs(sockName.sin_port);
+ }
+ }
+ return port;
+
+}
+
+#define FIREWALL_DEFAULT 0
+#define FIREWALL_SET_ONLY 1
+#define FIREWALL_CLEAR_ONLY 2
+#define FIREWALL_SKIP 3
+
+int main(int argc, char **argv)
+{
+ u_int32_t targetIpAddress = 0;
+ u_int16_t targetPort = DEFAULT_TARGETPORT;
+ u_int16_t sourcePort = 0;
+ u_int32_t sourceIpAddress = 0;
+ int mss = DEFAULT_MSS;
+ int mtu = DEFAULT_MTU;
+ int fd, opt, usedev = 0, rc = 0, path_check = 0;
+ int syn_test = 0, syn_reply = 0;
+ struct sockaddr_in saddr;
+ char dev[11]; /* device name for pcap init */
+ struct ifaddrs *ifap, *tmp;
+ int firewall_mode = FIREWALL_DEFAULT;
+
+ bzero(&session, sizeof(session));
+ while ((opt = getopt(argc, argv, "n:p:w:m:M:s:d:f:-CS:vF:")) != -1) {
+ switch (opt) {
+ case 'n':
+ if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
+ printf("Target host name too long, max %u chars\n", MAXHOSTNAMELEN);
+ Quit(FAIL);
+ }
+ strlcpy(session.targetHostName, optarg,
+ sizeof(session.targetHostName));
+ strlcpy(session.targetName, session.targetHostName,
+ sizeof(session.targetName));
+ break;
+ case 'p':
+ targetPort = atoi(optarg);
+ break;
+ case 'm':
+ mss = atoi(optarg);
+ break;
+ case 'M':
+ mtu = atoi(optarg);
+ break;
+ case 'w':
+ sourcePort = atoi(optarg);
+ break;
+ case 's':
+ if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
+ printf("Source host name too long, max %u chars\n", MAXHOSTNAMELEN);
+ Quit(FAIL);
+ }
+ strlcpy(session.sourceHostName, optarg,
+ MAXHOSTNAMELEN);
+ break;
+ case 'd':
+ if (strlen(optarg) > (sizeof(dev) - 1)) {
+ printf("Interface nae is too large, max %lu chars\n", (sizeof(dev) - 1));
+ Quit(FAIL);
+ }
+ bzero(dev, sizeof(dev));
+ strlcpy(dev, optarg, sizeof(dev));
+ usedev = 1;
+ break;
+ case 'f':
+ if (strlen(optarg) > 0) {
+ session.filename = strndup(optarg, strlen(optarg) + 1);
+ } else {
+ printf("Invalid file name \n");
+ }
+ break;
+ case 'F':
+ if (strcasecmp(optarg, "default") == 0)
+ firewall_mode = FIREWALL_DEFAULT;
+ else if (strcasecmp(optarg, "set") == 0)
+ firewall_mode = FIREWALL_SET_ONLY;
+ else if (strcasecmp(optarg, "clear") == 0)
+ firewall_mode = FIREWALL_CLEAR_ONLY;
+ else if (strcasecmp(optarg, "skip") == 0)
+ firewall_mode = FIREWALL_SKIP;
+ else
+ printf("firewall mode\n");
+ break;
+ case 'C':
+ path_check = 1;
+ break;
+ case 'S':
+ syn_test = 1;
+ if (strcasecmp(optarg, "A") == 0)
+ syn_reply = TCPFLAGS_ACK;
+ else if (strcasecmp(optarg, "R") == 0)
+ syn_reply = TCPFLAGS_RST;
+ else if (strcasecmp(optarg, "X") == 0)
+ syn_reply = 0;
+ else
+ printf("Invalid SYN reply \n");
+ break;
+ case 'v':
+ session.debug++;
+ break;
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+ signal(SIGTERM, SigHandle);
+ signal(SIGINT, SigHandle);
+ signal(SIGHUP, SigHandle);
+
+ if (GetCannonicalInfo(session.targetHostName, sizeof(session.targetHostName),
+ &targetIpAddress) < 0)
+ {
+ printf("Failed to convert targetIP address\n");
+ Quit(NO_TARGET_CANON_INFO);
+ }
+ rc = getifaddrs(&ifap);
+ if (rc != 0 || ifap == NULL) {
+ printf("Failed to get source addresswith getifaddrs: %d\n", rc);
+ Quit(FAIL);
+ }
+ tmp = ifap;
+ sourceIpAddress = 0;
+ bzero(session.sourceHostName, MAXHOSTNAMELEN);
+ for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
+ struct sockaddr_in *sin;
+ if (tmp->ifa_addr == NULL)
+ continue;
+ if (tmp->ifa_addr->sa_family != PF_INET)
+ continue;
+ if (usedev == 1) {
+ /* we know which interface to use */
+ if (strcmp(dev, tmp->ifa_name) == 0) {
+ sin = (struct sockaddr_in *)tmp->ifa_addr;
+ sourceIpAddress = sin->sin_addr.s_addr;
+ strlcpy(session.sourceHostName,
+ inet_ntoa(sin->sin_addr),
+ sizeof(session.sourceHostName));
+ } else {
+ continue;
+ }
+ } else {
+ /* pick the first address */
+ bzero(dev, sizeof(dev));
+ sin = (struct sockaddr_in *)tmp->ifa_addr;
+ sourceIpAddress = sin->sin_addr.s_addr;
+ strlcpy(session.sourceHostName,
+ inet_ntoa(sin->sin_addr),
+ sizeof(session.sourceHostName));
+ strlcpy(dev, tmp->ifa_name, sizeof(dev));
+ }
+ }
+ freeifaddrs(ifap);
+ if (sourceIpAddress == 0) {
+ printf("Failed to get source Ip address\n");
+ Quit(FAIL);
+ }
+
+ if (sourcePort == 0) {
+ bzero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Can't open socket\n");
+ return (-1);
+ }
+ if ((sourcePort = BindTcpPort(fd)) == 0) {
+ printf("Can't bind to port\n");
+ return (-1);
+ }
+ }
+ printf("Source: %s:%d\n", session.sourceHostName, sourcePort);
+ printf("Destination: %s:%d\n", session.targetHostName, targetPort);
+
+ switch (firewall_mode) {
+ case FIREWALL_DEFAULT:
+ SetupFirewall(targetIpAddress, targetPort, dev);
+ session.initFirewall = 1;
+ break;
+ case FIREWALL_SET_ONLY:
+ SetupFirewall(targetIpAddress, targetPort, dev);
+ goto done;
+ case FIREWALL_CLEAR_ONLY:
+ session.initFirewall = 1;
+ goto done;
+ case FIREWALL_SKIP:
+ break;
+ }
+
+ CaptureInit(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, dev);
+ session.initCapture = 1;
+
+
+ printf("Starting ECN test\n");
+ if (syn_test) {
+ session.dont_send_reset = 1;
+ SynTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss, syn_reply);
+ } else if (path_check) {
+ ECNPathCheckTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss);
+ } else {
+ ECNTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss);
+ }
+done:
+ Quit(SUCCESS);
+ close(session.socket);
+ return (0);
+}
diff --git a/network_cmds/ecnprobe/ecnprobe.1 b/network_cmds/ecnprobe/ecnprobe.1
new file mode 100644
index 0000000..76c2173
--- /dev/null
+++ b/network_cmds/ecnprobe/ecnprobe.1
@@ -0,0 +1,20 @@
+.Dd 5/7/2015
+.Dt ecnprobe 1
+.Os Darwin
+.Sh NAME
+.Nm ecnprobe
+.Nd Tool to probe for TCP ECN related incompatibilities in the network
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar target hostname or ipaddress
+.Op Fl p Ar target port
+.Op Fl m Ar mss
+.Op Fl M Ar mtu
+.Op Fl w Ar source port
+.Op Fl s Ar source ip address
+.Op Fl f Ar file name to get
+.Op Fl d Ar interface name
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to test TCP ECN related incompatibilities in the network.
diff --git a/network_cmds/ecnprobe/gmt2local.c b/network_cmds/ecnprobe/gmt2local.c
new file mode 100644
index 0000000..a6114f3
--- /dev/null
+++ b/network_cmds/ecnprobe/gmt2local.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "gmt2local.h"
+
+/*
+ * Returns the difference between gmt and local time in seconds.
+ * Use gmtime() and localtime() to keep things simple.
+ */
+int32_t
+gmt2local(time_t t)
+{
+ register int dt, dir;
+ register struct tm *gmt, *loc;
+ struct tm sgmt;
+
+ if (t == 0)
+ t = time(NULL);
+ gmt = &sgmt;
+ *gmt = *gmtime(&t);
+ loc = localtime(&t);
+ dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+ (loc->tm_min - gmt->tm_min) * 60;
+
+ /*
+ * If the year or julian day is different, we span 00:00 GMT
+ * and must add or subtract a day. Check the year first to
+ * avoid problems when the julian day wraps.
+ */
+ dir = loc->tm_year - gmt->tm_year;
+ if (dir == 0)
+ dir = loc->tm_yday - gmt->tm_yday;
+ dt += dir * 24 * 60 * 60;
+
+ return (dt);
+}
diff --git a/network_cmds/ecnprobe/gmt2local.h b/network_cmds/ecnprobe/gmt2local.h
new file mode 100644
index 0000000..4933b09
--- /dev/null
+++ b/network_cmds/ecnprobe/gmt2local.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 1997
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: gmt2local.h,v 1.2 97/01/23 22:31:40 leres Exp $ (LBL)
+ */
+#ifndef gmt2local_h
+#define gmt2local_h
+
+int32_t gmt2local(time_t);
+#endif
diff --git a/network_cmds/ecnprobe/history.c b/network_cmds/ecnprobe/history.c
new file mode 100644
index 0000000..e19b0ba
--- /dev/null
+++ b/network_cmds/ecnprobe/history.c
@@ -0,0 +1,211 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "support.h"
+#include "history.h"
+
+extern struct TcpSession session;
+struct History history[MAXHSZ];
+
+void StorePacket (struct IPPacket *p) {
+
+ uint32 src, dst, seq, ack ;
+ uint16 sport, dport, win, urp, datalen, optlen;
+ uint16 ip_optlen;
+ uint8 flags;
+
+ ReadIPPacket(p,
+ &src, &dst,
+ &sport, &dport,
+ &seq,
+ &ack,
+ &flags,
+ &win,
+ &urp,
+ &datalen,
+ &ip_optlen,
+ &optlen);
+
+ if (src == session.src) {
+ history[session.hsz].type = SENT;
+ } else {
+ history[session.hsz].type = RCVD ;
+ }
+
+ history[session.hsz].timestamp = GetTime () - session.epochTime;
+ history[session.hsz].seqno = seq;
+ history[session.hsz].nextbyte = seq + datalen;
+ history[session.hsz].ackno = ack ;
+ history[session.hsz].fin = (flags & TCPFLAGS_FIN) ? 1 : 0;
+ history[session.hsz].syn = (flags & TCPFLAGS_SYN) ? 1 : 0;
+ history[session.hsz].rst = (flags & TCPFLAGS_RST) ? 1 : 0;
+ history[session.hsz].psh = (flags & TCPFLAGS_PSH) ? 1 : 0;
+ history[session.hsz].ack = (flags & TCPFLAGS_ACK) ? 1 : 0;
+ history[session.hsz].urg = (flags & TCPFLAGS_URG) ? 1 : 0;
+ history[session.hsz].ecn_echo = (flags & TCPFLAGS_ECN_ECHO) ? 1:0;
+ history[session.hsz].cwr = (flags & TCPFLAGS_CWR) ? 1 : 0;
+ history[session.hsz].ip_optlen = ip_optlen;
+ history[session.hsz].optlen = optlen ;
+
+ /* Grab IP Options from Ip Header - New */
+ if (ip_optlen > 0) {
+ if ((history[session.hsz].ip_opt = calloc(sizeof(uint8), ip_optlen)) == NULL) {
+ printf("StorePacket Error: Could not allocate history memory\nRETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit (ERR_MEM_ALLOC);
+ }
+ memcpy(history[session.hsz].ip_opt, (char *)p->ip + sizeof(struct IpHeader), ip_optlen);
+ }
+
+
+ /* Grab TCP options from TCP Header */
+ if (optlen > 0) {
+ if ((history[session.hsz].opt = calloc(sizeof(uint8), optlen)) == NULL) {
+ Quit (ERR_MEM_ALLOC);
+ }
+
+ memcpy(history[session.hsz].opt, (char *)p->tcp + sizeof(struct TcpHeader), optlen);
+ }
+
+ history[session.hsz].dlen = datalen;
+
+ if ((history[session.hsz].data = calloc(sizeof(uint8), datalen)) == NULL) {
+ Quit (ERR_MEM_ALLOC);
+ }
+
+ /* Copy data bytes */
+ memcpy(history[session.hsz].data,
+ (char *)p->tcp + sizeof(struct TcpHeader) + optlen,
+ datalen);
+
+ session.hsz++;
+
+ if (session.hsz >= MAXHSZ) {
+ Quit(TOO_MANY_PKTS);
+ }
+
+}
+
+int reordered(struct IPPacket *p) {
+
+ int i;
+ int count = 0;
+ double ts = -99999;
+
+ /*
+ * This might be either an unwanted packet drop, or just a reordering.
+ * Test:
+ * If we have not sent three acks for this packet
+ * AND the gap between this packet and previous one is "small" (i.e. not a timeout)
+ * then its a reordering, and not a retransmission.
+ */
+
+ /* count the number of (dup) ACKs sent */
+ for (i = 0; i < session.hsz; i++) {
+ if ((history[i].type == SENT) &&
+ (history[i].ack)) {
+ if (history[i].ackno == history[session.hsz - 1].seqno)
+ count += 1;
+ }
+ }
+
+ if (count > 0) {
+
+ session.num_dup_acks += count - 1;
+
+ switch (count) {
+ case 1: /* no dup acks */
+ session.num_pkts_0_dup_acks += 1;
+ break;
+
+ case 2: /* 1 dup acks */
+ session.num_pkts_1_dup_acks += 1;
+ break;
+
+ case 3: /* 2 dup acks */
+ session.num_pkts_2_dup_acks += 1;
+ break;
+
+ case 4: /* 3 dup acks */
+ session.num_pkts_3_dup_acks += 1;
+ break;
+
+ default:
+ session.num_pkts_4_or_more_dup_acks += 1;
+ break;
+ }
+ }
+
+ /* 3 dup acks? => Fast retransmission */
+ if (count > 3) {
+ printf("Fast retransmit...\n");
+ return 3;
+ }
+
+ /* Compute elapsed time between this packet and the previously RCVD packet */
+ for (i = (session.hsz - 2); i >= 0; i--) {
+ if ((history[i].type == RCVD) && (history[i].dlen > 0)) {
+ ts = history[i].timestamp;
+ break;
+ }
+ }
+
+ if ((history[session.hsz - 1].timestamp - ts) > RTT_TO_MULT * (session.rtt + PLOTDIFF)) {
+ printf ("RTO ===> %f %f\n", history[session.hsz - 1].timestamp, ts);
+ return 2;
+ }
+
+ printf ("#### Acks %d\n", count);
+ printf ("#### reordering detected\n");
+ session.num_reordered++;
+
+ return 1;
+
+}
diff --git a/network_cmds/ecnprobe/history.h b/network_cmds/ecnprobe/history.h
new file mode 100644
index 0000000..9e69d44
--- /dev/null
+++ b/network_cmds/ecnprobe/history.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#define SENT 1
+#define RCVD 2
+#define MAXHSZ 10000
+
+struct History { /* store history of each packet as it is seen */
+
+ int type ; /* sent or received */
+ double timestamp; /* when */
+ uint32 seqno;
+ uint32 nextbyte; /* seqno + dlen */
+ uint32 ackno;
+ int hlen;
+ int ecn_echo;
+ int cwr;
+ int urg;
+ int ack;
+ int psh;
+ int rst;
+ int syn;
+ int fin;
+ int ip_optlen; /* added to support IP options */
+ uint8 *ip_opt; /* added to support IP options */
+ int optlen;
+ uint8 *opt;
+ uint8 *data;
+ int dlen;
+
+ int pkt_num;
+
+};
+
+void StorePacket (struct IPPacket *p);
+int reordered (struct IPPacket *p);
diff --git a/network_cmds/ecnprobe/inet.c b/network_cmds/ecnprobe/inet.c
new file mode 100644
index 0000000..b145412
--- /dev/null
+++ b/network_cmds/ecnprobe/inet.c
@@ -0,0 +1,503 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "history.h"
+
+extern struct TcpSession session;
+extern struct History history[];
+
+/*
+ * Deal with struct in_addr type agreement once and for all
+ */
+char *InetAddress(uint32 addr)
+{
+
+ struct in_addr s;
+ s.s_addr = addr;
+
+ //printf("In InetAddress:\n");
+ //printf("addr = %s (%0x)\n", inet_ntoa(s), addr);
+
+ return (inet_ntoa(s));
+}
+
+/*
+ * Really slow implementation of ip checksum
+ * ripped off from rfc1071
+ */
+
+uint16 InetChecksum(uint16 *ip, uint16 *tcp, uint16 ip_len, uint16 tcp_len) {
+
+ uint32 sum = 0;
+
+ uint32 ip_count = ip_len;
+ uint32 tcp_count = tcp_len;
+ uint16 *ip_addr = ip;
+ uint16 *tcp_addr = tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In InetChecksum...\n");
+ printf("iplen: %d, tcplen: %d\n", ip_len, tcp_len);
+ }
+
+
+ while(ip_count > 1) {
+ //printf("ip[%d]: %x\n", ip_len - ip_count, htons(*ip_addr));
+ sum += *ip_addr++;
+ ip_count -= 2;
+ }
+
+ while(tcp_count > 1) {
+ //printf("tcp[%d]: %x\n", tcp_len - tcp_count, htons(*tcp_addr));
+ sum += *tcp_addr++;
+ tcp_count -= 2;
+ }
+
+ if(ip_count > 0) {
+ sum += *(uint8 *)ip_addr;
+ }
+
+ if(tcp_count > 0) {
+ sum += *(uint8 *)tcp_addr;
+ }
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out InetChecksum...\n");
+ }
+
+ return(~sum);
+
+}
+
+
+void WriteIPPacket(struct IPPacket *p,
+ uint32 src,
+ uint32 dst,
+ uint16 sport,
+ uint16 dport,
+ uint32 seq,
+ uint32 ack,
+ uint8 flags,
+ uint16 win,
+ uint16 urp,
+ uint16 datalen,
+ uint16 ip_optlen,
+ uint16 optlen,
+ uint8 iptos,
+ uint8 u4tf)
+{
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In WriteIPPacket...\n");
+ }
+
+ /* Zero out IpHeader to ensure proper checksum computation */
+ bzero((char *)(p->ip), sizeof(struct IpHeader));
+
+ ip->ip_src = src;
+ ip->ip_dst = dst;
+ ip->ip_p = IPPROTOCOL_TCP;
+ ip->ip_xsum =
+ htons((uint16)(sizeof(struct TcpHeader) + datalen + optlen)); /* pseudo hdr */
+
+ tcp->tcp_sport = htons(sport);
+ tcp->tcp_dport = htons(dport);
+ tcp->tcp_seq = htonl(seq);
+ tcp->tcp_ack = htonl(ack);
+ tcp->tcp_hl = (sizeof(struct TcpHeader) + optlen) << 2;
+ tcp->tcp_hl = tcp->tcp_hl | u4tf;
+ tcp->tcp_flags = flags;
+
+ tcp->tcp_win = htons(win);
+ tcp->tcp_urp = htons(urp);
+
+ tcp->tcp_xsum = 0;
+ tcp->tcp_xsum = InetChecksum((uint16 *)ip, (uint16 *)tcp,
+ (uint16)sizeof(struct IpHeader), /* IP Options should aren't included */
+ (uint16)(sizeof(struct TcpHeader) + datalen + optlen));
+
+ /* Fill in real ip header */
+ if (session.curr_ttl != 0) {
+ ip->ip_ttl = session.curr_ttl;
+ }else {
+ ip->ip_ttl = 60;
+ }
+
+ //printf("TTL: %d\n", ip->ip_ttl);
+
+ ip->ip_tos = iptos;
+
+ /* IP Version and Header len field */
+ ip->ip_vhl = 0x40 + 0x5 + (int)(ip_optlen/4);
+ ip->ip_p = IPPROTOCOL_TCP;
+
+ ip->ip_off = IP_DF;
+ ip->ip_len = (uint16)(sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen + datalen);
+
+ ip->ip_xsum = 0;
+ ip->ip_xsum = InetChecksum((uint16 *)ip, NULL,
+ (uint16)sizeof(struct IpHeader) + ip_optlen, /* IP Options should aren't included */
+ 0);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out WriteIPPacket...\n");
+ }
+
+}
+
+void ReadIPPacket(struct IPPacket *p,
+ uint32 *src,
+ uint32 *dst,
+ uint16 *sport,
+ uint16 *dport,
+ uint32 *seq,
+ uint32 *ack,
+ uint8 *flags,
+ uint16 *win,
+ uint16 *urp,
+ uint16 *datalen,
+ uint16 *ip_optlen,
+ uint16 *optlen)
+{
+
+ /* TODO: Add reading of IP options, if any */
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ uint16 ip_len;
+ uint16 ip_hl;
+ uint16 tcp_hl;
+
+ /* XXX do checksum check? */
+ if (ip->ip_p != IPPROTOCOL_TCP && ip->ip_p != IPPROTOCOL_ICMP) {
+ printf("Unexpected protocol packet: %u\n", ip->ip_p);
+ Quit(ERR_CHECKSUM);
+ }
+
+ *src = ip->ip_src;
+ *dst = ip->ip_dst;
+ *sport = ntohs(tcp->tcp_sport);
+ *dport = ntohs(tcp->tcp_dport);
+ *seq = ntohl(tcp->tcp_seq);
+ *ack = ntohl(tcp->tcp_ack);
+ *flags = tcp->tcp_flags;
+ *win = ntohs(tcp->tcp_win);
+ *urp = ntohs(tcp->tcp_urp);
+
+ tcp_hl = tcp->tcp_hl >> 2;
+ ip_len = ntohs(ip->ip_len);
+ ip_hl = (ip->ip_vhl & 0x0f) << 2;
+ *datalen = (ip_len - ip_hl) - tcp_hl;
+ *ip_optlen = ip_hl - (unsigned int)sizeof(struct IpHeader); /* added to support IP Options */
+ *optlen = tcp_hl - (unsigned int)sizeof(struct TcpHeader);
+
+}
+
+void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p)
+{
+
+ struct IpHeader *ip = &p->ip;
+ struct IcmpHeader *icmp = &p->icmp;
+ struct IpHeader *off_ip = &p->off_ip;
+
+ printf("IPHdr: ");
+ printf("%s > ", InetAddress(ip->ip_src));
+ printf("%s ", InetAddress(ip->ip_dst));
+ printf(" datalen: %u\n", ip->ip_len);
+ printf("ICMPHdr: ");
+ printf("Type: %u Code: %u MTU next hop: %u xsum: %x\n",
+ icmp->icmp_type,
+ icmp->icmp_code,
+ ntohs(icmp->icmp_mtu),
+ icmp->icmp_xsum);
+ printf("Off IPHdr: ");
+ printf("%s > ", InetAddress(off_ip->ip_src));
+ printf("%s ", InetAddress(off_ip->ip_dst));
+ printf(" datalen: %u ", off_ip->ip_len);
+ printf("tcp sport: %u ", ntohs(p->tcp_sport));
+ printf("tcp dport: %u ", ntohs(p->tcp_dport));
+ printf("tcp seqno: %u\n", (uint32)ntohl(p->tcp_seqno));
+
+}
+
+void PrintTcpPacket(struct IPPacket *p)
+{
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ char *opt;
+ int optlen;
+ char *ip_opt;
+ int ip_optlen;
+ int i;
+
+ printf("%s.%u > ", InetAddress(ip->ip_src), ntohs(tcp->tcp_sport));
+ printf("%s.%u ", InetAddress(ip->ip_dst), ntohs(tcp->tcp_dport));
+
+ if (tcp->tcp_flags & TCPFLAGS_SYN) {
+ printf("S");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_ACK) {
+ printf("A");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_FIN) {
+ printf("F");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_ECN_ECHO) {
+ printf("E");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_CWR) {
+ printf("W");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_RST) {
+ printf("R");
+ }
+ if (tcp->tcp_flags & TCPFLAGS_PSH) {
+ printf("P");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_URG) {
+ printf("U");
+ }
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport)) {
+ printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.iss, (uint32)ntohl(tcp->tcp_ack) - session.irs);
+ } else {
+ printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.irs, (uint32)ntohl(tcp->tcp_ack) - session.iss);
+ }
+
+ /* IP Options */
+ ip_optlen = ((ip->ip_vhl & 0x0f) << 2) - sizeof(struct IpHeader);
+ ip_opt = (char *)ip + sizeof(struct IpHeader);
+
+ i = 0;
+ while (i < ip_optlen) {
+
+ switch ((unsigned char)ip_opt[i]) {
+ case IPOPT_NOP:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_NOP");
+ i = i + 1;
+ break;
+
+ case IPOPT_EOL:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_EOL");
+ i = ip_optlen + 1;
+ break;
+
+ case IPOPT_RR:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_RR");
+ i = i + IPOLEN_RR;
+ break;
+
+ default:
+ printf("ip_opt%d: UNKNOWN ", i + 1);
+ i = i + (uint8)ip_opt[i+1] ;
+ }
+ }
+
+ printf(" win: %u, urg: %u, ttl: %d", ntohs(tcp->tcp_win), ntohs(tcp->tcp_urp), ip->ip_ttl);
+ printf(" datalen: %u, optlen: %u ",
+ ip->ip_len - ((ip->ip_vhl &0x0f) << 2) - (tcp->tcp_hl >> 2),
+ (tcp->tcp_hl >> 2) - (unsigned int)sizeof(struct TcpHeader));
+
+
+ /* TCP Options */
+ optlen = (tcp->tcp_hl >> 2) - (unsigned int)sizeof (struct TcpHeader) ;
+ opt = (char *)tcp + sizeof(struct TcpHeader);
+
+ i = 0 ;
+
+ while (i < optlen) {
+
+ switch ((unsigned char)opt[i]) {
+
+ case TCPOPT_EOL:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_EOL");
+ i = optlen + 1;
+ break ;
+
+ case TCPOPT_NOP:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_NOP");
+ i++ ;
+ break ;
+
+ case TCPOPT_MAXSEG:
+ printf (" opt%d: %s: %d ", i + 1, "TCPOPT_MAXSEG", ntohs(*(uint16 *)((char *)opt+2)));
+ i = i + TCPOLEN_MAXSEG ;
+ break ;
+
+ case TCPOPT_WINDOW:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_WINDOW");
+ i = i + TCPOLEN_WINDOW ;
+ break ;
+
+ case TCPOPT_SACK_PERMITTED:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_SACK_PERMITTED");
+ i = i + TCPOLEN_SACK_PERMITTED ;
+ break ;
+
+ case TCPOPT_TIMESTAMP:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_TIMESTAMP");
+ i = i + TCPOLEN_TIMESTAMP ;
+ break ;
+
+ default:
+ printf (" opt%d c:%d l:%d: UNKNOWN ", i + 1, (uint8)opt[i], (uint8)opt[i+1]);
+ if ((uint8)opt[i+1] > 0) {
+ i = i + (uint8)opt[i+1] ;
+ } else {
+ Quit(20);
+ }
+ break ;
+ }
+ }
+ printf ("\n");
+}
+
+
+struct IPPacket *FindHeaderBoundaries(char *p) {
+
+ struct IPPacket *packet;
+ uint16 ip_hl;
+
+ if ((packet = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) {
+ printf("FindHeaderBoundaries: Cannot allocate memory for read packet\nRETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ packet->ip = (struct IpHeader *)p;
+
+ if (packet->ip->ip_p != IPPROTOCOL_TCP &&
+ packet->ip->ip_p != IPPROTOCOL_ICMP) {
+ printf("Error: Unexpected protocol packet: %u \n", packet->ip->ip_p);
+ Quit(ERR_CHECKSUM);
+ }
+
+ ip_hl = (packet->ip->ip_vhl & 0x0f) << 2;
+
+ packet->tcp = (struct TcpHeader *)((char *)p + ip_hl);
+ return packet;
+
+}
+
+
+struct IPPacket *
+AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str)
+{
+ struct IPPacket *p;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In AllocateIPPacket: %s...\n", str);
+ }
+
+ if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket)))
+ == NULL) {
+ printf("%s ERROR: No space for packet\nRETURN CODE: %d",
+ str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((p->ip = (struct IpHeader *)calloc(1,
+ sizeof(struct IpHeader) + ip_optlen)) == NULL) {
+ printf("%s ERROR: No IpHeader space for packet\n"
+ "RETURN CODE: %d", str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((p->tcp = (struct TcpHeader *)calloc(1,
+ sizeof(struct TcpHeader) + tcp_optlen + datalen)) == NULL) {
+ printf("%s ERROR: No TcpHeader space for packet\n"
+ "RETURN CODE: %d", str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of AllocateIPPacket: %s...\n", str);
+ }
+ return(p);
+}
+
+void
+FreeIPPacket(struct IPPacket **pkt_p)
+{
+ struct IPPacket *pkt;
+ if (pkt_p == NULL)
+ return;
+ if ((pkt = *pkt_p) == NULL)
+ return;
+ if (pkt->ip != NULL) {
+ free(pkt->ip);
+ pkt->ip = NULL;
+ }
+ if (pkt->tcp != NULL) {
+ free(pkt->tcp);
+ pkt->tcp = NULL;
+ }
+ free(pkt);
+ *pkt_p = NULL;
+}
+
diff --git a/network_cmds/ecnprobe/inet.h b/network_cmds/ecnprobe/inet.h
new file mode 100644
index 0000000..8d1ccff
--- /dev/null
+++ b/network_cmds/ecnprobe/inet.h
@@ -0,0 +1,206 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+
+#ifndef _INET_H_
+#define _INET_H_
+
+/* XXX These are machine/compiler dependent */
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+#define IPPROTOCOL_ICMP 1
+#define IPPROTOCOL_IGMP 2
+#define IPPROTOCOL_TCP 6
+#define IPPROTOCOL_UDP 17
+#define IP_DF 0x4000
+
+/* ICMP type */
+#define ICMP_TIMXCEED 11
+
+/* TCP Flags */
+#define TCPFLAGS_FIN 0x01
+#define TCPFLAGS_SYN 0x02
+#define TCPFLAGS_RST 0x04
+#define TCPFLAGS_PSH 0x08
+#define TCPFLAGS_ACK 0x10
+#define TCPFLAGS_URG 0x20
+#define TCPFLAGS_ECN_ECHO 0x40
+#define TCPFLAGS_CWR 0x80
+
+/* IP Options Parameters -- for IP Options te*/
+#define IPOPT_EOL 0x0
+#define IPOLEN_EOL 0x1
+#define IPOPT_NOP 0x1
+#define IPOLEN_NOP 0x1
+#define IPOPT_RR 0x7
+#define IPOLEN_RR 0x27 /* Maximum length; up to 9 IP addresses */
+#define IPOPT_TS 0x44
+#define IPOLEN_TS 0x28
+#define IPOPT_FAKED 0xff
+#define IPOLEN_FAKED 0x4
+
+/* TCP Options Parameters */
+#define TCPOPT_EOL 0
+#define TCPOLEN_EOL 1
+#define TCPOPT_NOP 1
+#define TCPOLEN_NOP 1
+#define TCPOPT_MAXSEG 2
+#define TCPOLEN_MAXSEG 4
+#define TCPOPT_WINDOW 3
+#define TCPOLEN_WINDOW 3
+#define TCPOPT_SACK_PERMITTED 4
+#define TCPOLEN_SACK_PERMITTED 2
+#define TCPOPT_SACK 5
+#define TCPOPT_TIMESTAMP 8
+#define TCPOLEN_TIMESTAMP 10
+#define TCPOPT_FAKED 0x19
+#define TCPOLEN_FAKED 0x4
+
+struct IpHeader {
+ uint8 ip_vhl; /* version (4bits) & header length (4 bits) */
+ uint8 ip_tos; /* type of service */
+ uint16 ip_len; /* length of IP datagram */
+ uint16 ip_id; /* identification (for frags) */
+ uint16 ip_off; /* offset (within a fragment) and flags (3 bits) */
+ uint8 ip_ttl; /* time to live */
+ uint8 ip_p; /* protocol number */
+ uint16 ip_xsum; /* checksum */
+ uint32 ip_src; /* source address */
+ uint32 ip_dst; /* destination address */
+};
+
+/* Pseudo header for doing TCP checksum calculation */
+struct PseudoIpHeader {
+ uint32 filler[2];
+ uint8 zero;
+ uint8 ip_p;
+ uint16 ip_len;
+ uint32 ip_src;
+ uint32 ip_dst;
+};
+
+struct TcpHeader {
+ uint16 tcp_sport; /* source port */
+ uint16 tcp_dport; /* destination port */
+ uint32 tcp_seq; /* sequence number */
+ uint32 tcp_ack; /* acknoledgement number */
+ uint8 tcp_hl; /* header length (4 bits) */
+ uint8 tcp_flags; /* flags */
+ uint16 tcp_win; /* advertized window size */
+ uint16 tcp_xsum; /* checksum */
+ uint16 tcp_urp; /* urgent pointer */
+};
+
+
+
+struct IcmpHeader {
+ uint8 icmp_type; /* ICMP message type */
+ uint8 icmp_code; /* Message code */
+ uint16 icmp_xsum; /* checksum */
+ uint16 icmp_unused; /* unused field */
+ uint16 icmp_mtu; /* MTU of limiting interface */
+};
+
+struct IPPacket {
+ struct IpHeader *ip;
+ struct TcpHeader *tcp;
+};
+
+struct ICMPUnreachableErrorPacket {
+ struct IpHeader ip;
+ struct IcmpHeader icmp;
+ struct IpHeader off_ip;
+ /* 8-first bytes of TCP header */
+ uint16 tcp_sport;
+ uint16 tcp_dport;
+ uint32 tcp_seqno;
+};
+
+struct ICMPTimeExceededErrorPacket {
+ struct IpHeader ip;
+ struct IcmpHeader icmp;
+ struct IpHeader off_ip;
+ /* 8-first bytes of Tcpheader */
+ uint16 tcp_sport;
+ uint16 tcp_dport;
+ uint32 tcp_seqno;
+};
+
+char *InetAddress(uint32 addr);
+
+uint16 InetChecksum(uint16 *ip_addr, uint16 *tcp_addr, uint16 ip_len, uint16 tcp_len);
+
+void PrintTcpPacket(struct IPPacket *p);
+void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p);
+
+void WriteIPPacket(struct IPPacket *p,
+ uint32 src,
+ uint32 dst,
+ uint16 sport,
+ uint16 dport,
+ uint32 seq,
+ uint32 ack,
+ uint8 flags,
+ uint16 win,
+ uint16 urp,
+ uint16 datalen,
+ uint16 ip_optlen,
+ uint16 optlen,
+ uint8 iptos,
+ uint8 u4tf);
+
+void ReadIPPacket(struct IPPacket *p, uint32 *src, uint32 *dst,
+ uint16 *sport, uint16 *dport, uint32 *seq, uint32 *ack,
+ uint8 *flags, uint16 *win, uint16 *urp, uint16 *datalen,
+ uint16 *ip_optlen, uint16 *optlen);
+
+void StorePacket (struct IPPacket *p);
+
+struct IPPacket *FindHeaderBoundaries(char *p);
+
+struct IPPacket *AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str);
+
+void FreeIPPacket(struct IPPacket **pkt_p);
+
+#endif /* _INET_H_ */
diff --git a/network_cmds/ecnprobe/session.c b/network_cmds/ecnprobe/session.c
new file mode 100644
index 0000000..5ca97d8
--- /dev/null
+++ b/network_cmds/ecnprobe/session.c
@@ -0,0 +1,785 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "ecn.h"
+#include <errno.h>
+
+struct TcpSession session;
+
+int EstablishSession(uint32 sourceAddress,
+ uint16 sourcePort,
+ uint32 targetAddress,
+ uint16 targetPort,
+ int ip_optlen, // AM: add support for IP options
+ char *ip_opt, // AM: add support for IP options
+ int mss,
+ int optlen,
+ char *opt,
+ int maxwin,
+ int maxpkts,
+ uint8 iptos,
+ uint8 tcp_flags) // AM: Add a tcp_flags parameter
+{
+
+ int rawSocket;
+
+ struct IPPacket *p = NULL;
+ struct IPPacket *synPacket;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ double ts1 = 0, ts2;
+ int flag = 1;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In EstablishSession...\n");
+ }
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = maxwin * mss;
+ session.snd_nxt = arc4random(); /* random initial sequence number */
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss ;
+ session.maxseqseen = 0 ;
+ session.epochTime = GetTime();
+ session.maxpkts = maxpkts;
+ session.num_unwanted_drops = 0;
+ session.num_reordered = 0;
+ session.num_rtos = 0;
+ session.num_dup_acks = 0;
+ session.num_pkts_0_dup_acks = 0;
+ session.num_pkts_1_dup_acks = 0;
+ session.num_pkts_2_dup_acks = 0;
+ session.num_pkts_3_dup_acks = 0;
+ session.num_pkts_4_or_more_dup_acks = 0;
+ session.num_dupack_ret = 0;
+ session.num_reord_ret = 0;
+ session.num_reordered = 0;
+ session.num_dup_transmissions = 0;
+ session.ignore_result = 0;
+ session.curr_ttl = 0;
+
+ if ((session.mtu < 1) || (session.mtu > 1460)) {
+ session.mtu = 1500;
+ }
+
+ if (session.verbose) {
+ printf("session.MTU = %d\n", session.mtu);
+ }
+
+ if ((session.dataRcvd = (uint8 *)calloc(sizeof(uint8), mss * session.maxpkts)) == NULL) {
+ perror("ERROR: no memmory to store data:\n");
+ printf("RETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ /* Now open a raw socket for sending our "fake" TCP segments */
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ printf("RETURN CODE: %d\n", ERR_SOCKET_OPEN);
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, (char *)&flag,sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ printf("RETURN CODE: %d\n", ERR_SOCKOPT);
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Allocate SYN packet */
+ synPacket = AllocateIPPacket(ip_optlen, optlen, 0, "EstablishSession (SYN)");
+
+ /* Copy IP options at the end of IpHeader structure - New */
+ if (ip_optlen > 0) {
+ memcpy((char *)synPacket->ip + sizeof(struct IpHeader), ip_opt, ip_optlen);
+ }
+
+ /* Copy TCP options at the end of TcpHeader structure - New */
+ if (optlen > 0) {
+ memcpy((char *)synPacket->tcp + sizeof(struct TcpHeader), opt, optlen);
+ }
+
+ /* Send SYN Pkt */
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < MAXSYNRETRANSMITS) {
+
+ while(GetTime() < timeoutTime) {
+
+ /* Have we captured any packets? */
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport)) {
+
+ /* Is it a SYN? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit\n");
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ ts1 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.totSeenSent ++ ;
+
+ }
+
+ free(p);
+ continue;
+
+
+ }
+
+ if (INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & (TCPFLAGS_SYN | TCPFLAGS_ACK)) {
+
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ ts2 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.rtt = ts2 - ts1 ;
+
+ if (numRetransmits > 0) {
+ session.rtt_unreliable = 1;
+ printf("##### Unreliable\n"); /* ACK for which SYN? */
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd:\n");
+ PrintTcpPacket(p);
+ printf("Connection setup took %d ms\n",(int)((ts2 - ts1) * 1000.0));
+ }
+
+ StorePacket(p);
+
+ /* Save ttl for,admittedly poor,indications of reverse route change */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd++;
+
+ free(p);
+ break ;
+
+ }
+
+ }
+
+ free(p->ip);
+ free(p->tcp);
+ free(p);
+
+ }
+
+ }
+
+ if (!synAckReceived) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= MAXSYNRETRANSMITS) {
+ printf("ERROR: Could not establish contact after %d retries\nRETURN CODE: %d\n",
+ numRetransmits, NO_CONNECTION);
+ Quit(NO_CONNECTION);
+ }
+
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src), session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n", InetAddress(session.dst), session.dport, session.irs);
+ }
+
+ free(synPacket->ip);
+ free(synPacket->tcp);
+ free(synPacket);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of EstablishSession...\n");
+ }
+
+ session.start_time = GetTime();
+
+ return 1;
+
+}
+
+int PrepareRequest(char *data, char *filename)
+{
+
+ char h1[] = "GET ";
+ char h2[] = " HTTP/1.1";
+ char h3[] = "Host: ";
+ char h4[] = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11; DigExt; TBIT)";
+ char h5[] = "Accept: */*";
+
+ /* New */
+ char h7[] = "Pragma: no-cache";
+ char h8[] = "Cache-control: no-chache";
+ char deffile[] = DEFAULT_FILENAME;
+
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In PrepareRequest...\n");
+ }
+
+ if (filename == NULL) {
+ filename = deffile;
+ }
+
+
+ if (strlen(session.targetName) > 0) {
+
+ sprintf(data,
+
+ "%s/%s %s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4,
+ h7,
+ h8,
+ h5,
+ h3,
+ session.targetName);
+ }else {
+
+ sprintf(data,
+ "%s%s%s\r\n%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out PrepareRequest...\n");
+ }
+
+ return ((int)strlen(data));
+
+}
+
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p))
+{
+
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i;
+ int sendflag = 1;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendRequest...\n");
+ }
+
+ datalen = PrepareRequest(data, filename);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* Allocate space for IP data packet */
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "SendRequest (Data)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+
+ /* Send the data packet. Try to "achieve" reliability by sending the
+ * packet upto 5 times, wating for 2 seconds between packets (BAD
+ * busy-wait loop)
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+
+ SendSessionPacket(datapkt,
+ ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK,
+ 0, /* ip opt len */
+ 0, /* tcp opt len */
+ 0); /* tos */
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++;
+
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ free(p);
+
+ //session.snd_nxt += datalen + 1;
+ session.totSeenSent++;
+ continue;
+
+ }
+ /*
+ * packet from them?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+ session.totRcvd ++;
+ session.snd_nxt += datalen + 1;
+
+ /* if the packet also contains data, receive it and send an ack if needed */
+ (*ackData)(p);
+
+ free(p);
+ break;
+
+ }
+
+ free(p);
+
+ }
+
+ if ((GetTime() - startTime >= REXMITDELAY) &&
+ (sendflag == 0) && (i < MAXDATARETRANSMITS)) {
+ sendflag = 1 ;
+ }
+
+ if (i >= MAXDATARETRANSMITS) {
+ printf ("ERROR: sent request 5 times without response\nRETURN CODE: %d\n",
+ SEND_REQUEST_FAILED);
+ Quit(SEND_REQUEST_FAILED);
+ }
+
+ }
+
+ free(datapkt->ip);
+ free(datapkt->tcp);
+ free(datapkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendRequest...\n");
+ }
+}
+
+void SendSessionPacket(struct IPPacket *p,
+ uint16 ip_len, uint8 tcp_flags, uint16 ip_optlen, uint16 optlen,
+ uint8 iptos)
+{
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendSessionPacket...\n");
+ }
+ WriteIPPacket(p,
+ session.src, session.dst, session.sport, session.dport,
+ session.snd_nxt, session.rcv_nxt, tcp_flags,
+ session.rcv_wnd, 0,
+ (ip_len - sizeof(struct IpHeader) - ip_optlen - sizeof(struct TcpHeader) - optlen),
+ ip_optlen, optlen, iptos, 0);
+
+
+ /* Store packet here rather than in rcvData() because otherwise some
+ * ACKs may not be accounted for upon receiving reordered packets */
+
+ StorePacket(p);
+
+ SendPkt(p,
+ ip_len, /* Total IP datagram size */
+ ip_optlen, /* ip options len */
+ optlen); /* tcp options len */
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendSessionPacket...\n");
+ }
+
+}
+
+
+void SendICMPReply(struct IPPacket *p)
+{
+
+ struct ICMPUnreachableErrorPacket *icmp_pkt;
+ int icmpsz;
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendICMPReply...\n");
+ }
+
+ icmpsz = sizeof(struct ICMPUnreachableErrorPacket);
+ if ((icmp_pkt = (struct ICMPUnreachableErrorPacket *)calloc(icmpsz + 1, 1)) == NULL) {
+ perror("ERROR: no space for ICMP packet:");
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ /* Fill IP Header of ICMP packet */
+ bzero((char *)icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+ icmp_pkt->ip.ip_src = ip->ip_dst;
+ icmp_pkt->ip.ip_dst = ip->ip_src;
+ icmp_pkt->ip.ip_p = IPPROTOCOL_ICMP;
+ icmp_pkt->ip.ip_xsum =
+ htons((uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + sizeof(struct IpHeader) + 8)); /* pseudo hdr */
+ icmp_pkt->ip.ip_ttl = 60;
+ icmp_pkt->ip.ip_tos = 0x00;
+ icmp_pkt->ip.ip_vhl = 0x45;
+#ifdef __FreeBSD__
+ icmp_pkt->ip.ip_off = IP_DF;
+ icmp_pkt->ip.ip_len = (uint16)(sizeof(struct ICMPUnreachableErrorPacket));
+#else /* __FreeBSD__ */
+ icmp_pkt->ip.ip_off = htons(IP_DF);
+ icmp_pkt->ip.ip_len = htons((uint16)((sizeof (struct ICMPUnreachableErrorPacket) + 8 + 1)));
+#endif /* __FreeBSD__ */
+
+ /* Fill ICMP header */
+ icmp_pkt->icmp.icmp_type = 0x3;
+ icmp_pkt->icmp.icmp_code = 0x4;
+ icmp_pkt->icmp.icmp_xsum = 0;
+ icmp_pkt->icmp.icmp_unused = 0;
+ icmp_pkt->icmp.icmp_mtu = htons(session.mtu);
+
+ /* Fill in ip header of offending packet */
+ icmp_pkt->off_ip.ip_src = ip->ip_src;
+ icmp_pkt->off_ip.ip_dst = ip->ip_dst;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+ icmp_pkt->off_ip.ip_xsum = ip->ip_xsum;
+ icmp_pkt->off_ip.ip_ttl = ip->ip_ttl;
+ icmp_pkt->off_ip.ip_tos = ip->ip_tos;
+ icmp_pkt->off_ip.ip_vhl = ip->ip_vhl;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+#ifdef __FreeBSD__
+ icmp_pkt->off_ip.ip_off = ntohs(ip->ip_off);
+ icmp_pkt->off_ip.ip_len = ntohs(ip->ip_len);
+#else /* __FreeBSD__ */
+ icmp_pkt->off_ip.ip_off = ip->ip_off;
+ icmp_pkt->off_ip.ip_len = ip->ip_len;
+#endif /* __FreeBSD__ */
+
+ icmp_pkt->tcp_sport = tcp->tcp_sport;
+ icmp_pkt->tcp_dport = tcp->tcp_dport;
+ icmp_pkt->tcp_seqno = (uint32)tcp->tcp_seq;
+
+ icmp_pkt->icmp.icmp_xsum = InetChecksum((uint16 *)(&(icmp_pkt->icmp)), NULL,
+ (uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + 8), 0);
+
+ if (session.verbose) {
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ printf("TCP Packet: %lu\n", sizeof(struct IPPacket));
+ PrintTcpPacket(p);
+ printf("ICMP Packet: %lu\n", sizeof(struct ICMPUnreachableErrorPacket));
+ PrintICMPUnreachableErrorPacket(icmp_pkt);
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ }
+
+ SendICMPPkt(icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendICMPReply...\n");
+ }
+
+}
+
+void SendPkt(struct IPPacket *p, uint16 ip_len, int ip_optlen,
+ int tcp_optlen) {
+ int nbytes, datalen;
+ struct sockaddr_in sockAddr;
+ char *assembled_pkt;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendPkt...\n");
+ }
+ /* Assemble contiguos packet to be sent */
+ if ((assembled_pkt = (char *)calloc(1, ip_len)) == NULL) {
+ printf("SendPkt: Cannot allocate memory for assembled packet\n");
+ Quit(ERR_MEM_ALLOC);
+ }
+ /* Copy IP Header and options, if any */
+ memcpy((char *)assembled_pkt, (char *)(p->ip),
+ sizeof(struct IpHeader) + ip_optlen);
+
+ /* Copy TCP Header and options, if any */
+ memcpy((char *)(assembled_pkt + sizeof(struct IpHeader) + ip_optlen),
+ (char *)(p->tcp),
+ sizeof(struct TcpHeader) + tcp_optlen);
+
+ /* Copy data bytes, if any */
+ datalen = ip_len - ((sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen));
+
+ if (datalen > 0) {
+ memcpy((char *)assembled_pkt + sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen,
+ (char *)p->tcp + sizeof(struct TcpHeader) + tcp_optlen, datalen);
+ }
+
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ if ((nbytes = (int)sendto(session.socket,
+ (char *)assembled_pkt,
+ ip_len,
+ 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr))) < ip_len) {
+ printf("#### WARNING: only sent %d of %d bytes\n", nbytes, ip_len);
+ perror("here");
+
+ }
+
+ session.totSent++;
+
+ free(assembled_pkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out SendPkt...\n");
+ }
+
+}
+
+
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, uint16 len) {
+
+ ssize_t nbytes;
+ struct sockaddr_in sockAddr;
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ nbytes = sendto(session.socket, (char *)p, len, 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr));
+
+ if (nbytes < len) {
+ printf("#### WARNING: only sent %zd of %d (errno: %d) bytes\n",
+ nbytes, len, errno);
+ perror("here");
+ }
+
+ session.totSent++ ;
+
+}
+
+void rcvData (void (*ackData)(struct IPPacket *p))
+{
+
+ struct pcap_pkthdr pi;
+ struct IPPacket *p;
+ char *read_packet;
+ double startTime = GetTime () ;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In rcvData...\n");
+ }
+
+ while (1) {
+
+ if ((GetTime() - startTime) > (MAXDATARETRANSMITS * REXMITDELAY)) {
+ printf ("ERROR: no Data received for %f seconds\nRETURN CODE: %d\n",
+ (MAXDATARETRANSMITS*REXMITDELAY), NO_DATA_RCVD);
+ Quit(NO_DATA_RCVD) ;
+ }
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * Packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ ((p->tcp->tcp_flags & TCPFLAGS_ACK) || (p->tcp->tcp_flags & TCPFLAGS_FIN)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit:\n");
+ PrintTcpPacket(p);
+ }
+
+ session.totSeenSent++ ;
+
+ free(p);
+ continue;
+
+ }
+
+ /*
+ * Data that we were expecting?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd: \n");
+ PrintTcpPacket(p);
+ }
+
+ session.totRcvd++ ;
+ startTime = GetTime () ;
+ StorePacket(p);
+
+ /* if the packet also contains data, receive it, and send an ack if needed */
+ ECNAckData(p);
+
+ free(p);
+ continue ;
+
+ } else {
+
+ free(p);
+
+ }
+ }
+ }
+}
+
+
diff --git a/network_cmds/ecnprobe/session.h b/network_cmds/ecnprobe/session.h
new file mode 100644
index 0000000..bff3296
--- /dev/null
+++ b/network_cmds/ecnprobe/session.h
@@ -0,0 +1,183 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+
+#define MAXREQUESTLEN 1000
+
+#define SESSION_DEBUG_LOW 1
+#define SESSION_DEBUG_MEDIUM 2
+#define SESSION_DEBUG_HIGH 3
+
+struct TcpSession {
+
+ /* target name, as specified by the user */
+ char targetName[MAXHOSTNAMELEN];
+
+ /* DNS name of hosts */
+ char targetHostName[MAXHOSTNAMELEN];
+ char sourceHostName[MAXHOSTNAMELEN];
+
+ /* raw socket we use to send on */
+ int socket;
+
+ /* connection endpoint identifiers */
+ u_int32_t src;
+ u_int16_t sport;
+ u_int32_t dst;
+ u_int16_t dport;
+
+ /* sender info, from RFC 793 */
+ u_int32_t iss; // initial send sequence
+ u_int32_t snd_una; // sequence numbers of unacknowledged data
+ u_int32_t snd_nxt; // sequence number to be sent next
+ u_int16_t snd_wnd;
+ u_int16_t sndmss;
+
+ /* Receiver info */
+ u_int32_t irs;
+ u_int32_t rcv_wnd;
+ u_int32_t rcv_nxt;
+ u_int32_t maxseqseen;
+ u_int16_t mss;
+
+ /* timing */
+ double rtt;
+ u_int8_t ttl;
+ double start_time;
+
+ /* data buffer */
+ u_int8_t *dataRcvd ;
+
+ /* basic results */
+ int totSent;
+ int totRcvd;
+ int totSeenSent;
+ int totDataPktsRcvd;
+ int totOutofSeq;
+ int hsz;
+
+ /* basic control*/
+ int epochTime;
+ int debug;
+ int verbose;
+ int initSession;
+ int initCapture;
+ int initFirewall;
+ int firewall_rule_number;
+ char *filename;
+ int maxpkts;
+
+ /* New loss-rate parameters */
+ float loss_rate;
+ float prop_delay;
+
+ /* results are suspect for various reasons */
+ int rtt_unreliable;
+ int ignore_result;
+
+ /* Drops and reordering startistics */
+ int num_reordered;
+ int num_unwanted_drops;
+ int num_rtos;
+ int num_reord_ret;
+ int num_dup_transmissions;
+ int num_dup_acks;
+ int num_pkts_0_dup_acks;
+ int num_pkts_1_dup_acks;
+ int num_pkts_2_dup_acks;
+ int num_pkts_3_dup_acks;
+ int num_pkts_4_or_more_dup_acks;
+ int num_dupack_ret;
+
+ /* For PMTUD test */
+ int mtu;
+
+ /* For ByteCounting test */
+ int bytecounting_type;
+ int ack_bytes; /* How many bytes covered per ACK */
+ int ack_rate; /* ACK [every | every other | every third |...] packet */
+
+ /* For WindowScale Option test */
+ u_int8_t receiving_shift_count;
+ u_int8_t sending_shift_count;
+
+ /* For MidBoxTTL test */
+ int curr_ttl;
+
+ int dont_send_reset;
+};
+
+//void SendSessionPacket(struct IPPacket *packet,
+void SendSessionPacket(struct IPPacket *packet,
+ u_int16_t ip_len, /* Total size of IP datagram */
+ u_int8_t tcp_flags,
+ u_int16_t ip_optlen, /* IP options len - New */
+ u_int16_t optlen, /* TCP options len */
+ u_int8_t iptos);
+
+void SendICMPReply(struct IPPacket *p);
+
+void SendPkt(struct IPPacket *p, u_int16_t ip_len, int ip_optlen, int tcp_optlen);
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, u_int16_t ip_len);
+
+void StorePacket (struct IPPacket *p);
+
+int EstablishSession(u_int32_t sourceAddress, \
+ u_int16_t sourcePort, \
+ u_int32_t targetAddress,
+ u_int16_t targetPort, \
+ int ip_optlen,\
+ char *ip_opt,\
+ int mss,
+ int optlen,
+ char *opt, \
+ int maxwin,
+ int maxpkts,
+ u_int8_t iptos,
+ u_int8_t tcp_flags);
+
+void rcvData (void (*ackData)(struct IPPacket *p));
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p));
+
+int PrepareRequest(char *data, char *filename) ;
diff --git a/network_cmds/ecnprobe/support.c b/network_cmds/ecnprobe/support.c
new file mode 100644
index 0000000..2cdb405
--- /dev/null
+++ b/network_cmds/ecnprobe/support.c
@@ -0,0 +1,246 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+
+extern struct TcpSession session;
+
+void SendReset()
+{
+ struct IPPacket *p;
+ int i;
+
+ if (session.dont_send_reset)
+ return;
+
+ if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) {
+ perror("ERROR: Could not allocate RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ if ((p->ip = (struct IpHeader *)calloc(1, sizeof(struct IpHeader))) == NULL) {
+ perror("ERROR: Could not allocate IP Header for RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ if ((p->tcp = (struct TcpHeader *)calloc(1, sizeof(struct TcpHeader))) == NULL) {
+ perror("ERROR: Could not allocate TCP Header for RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ for (i = 0; i < MAXRESETRETRANSMITS; i++) {
+ SendSessionPacket(p,
+ //sizeof(struct IPPacket),
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ TCPFLAGS_RST,
+ 0,
+ 0,
+ 0);
+ }
+
+/* free(p->ip);
+ free(p->tcp);
+ free(p);
+*/
+
+}
+
+#if 0
+/* make a clean exit on interrupts */
+void SigHandle (int signo)
+{
+ Cleanup () ;
+ fflush(stdout);
+ fflush(stderr);
+ exit(-1);
+}
+
+
+void Cleanup()
+{
+
+ char ipfw_rule[100];
+ int r;
+
+ /* If a firewall rule has been installed then remove it */
+ if (session.initFirewall > 0) {
+
+#ifdef linux
+#define IP_FW_DEL (IP_FW_DELETE)
+#endif /* linux */
+
+ sprintf(ipfw_rule, "ipfw del 00%d", session.firewall_rule_number);
+ r = system(ipfw_rule);
+
+ }
+
+ if (session.initSession > 0) {
+
+ SendReset();
+ shutdown(session.socket,2);
+
+ }
+
+ if (session.initCapture > 0) {
+ CaptureEnd();
+ }
+
+}
+
+void Quit(int how)
+{
+
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(how);
+
+}
+#endif /* 0 */
+
+double GetTime()
+{
+ struct timeval tv;
+ struct timezone tz;
+ double postEpochSecs;
+
+ if (gettimeofday(&tv, &tz) < 0) {
+ perror("GetTime");
+ exit(-1);
+ }
+
+ postEpochSecs = (double)tv.tv_sec + ((double)tv.tv_usec/(double)1000000.0);
+ return postEpochSecs;
+}
+
+double GetTimeMicroSeconds()
+{
+ struct timeval tv;
+ struct timezone tz;
+ double postEpochMicroSecs;
+
+ if (gettimeofday(&tv, &tz) < 0) {
+ perror("GetTimeMicroSeconds");
+ exit(-1);
+ }
+
+ postEpochMicroSecs = (double)tv.tv_sec * 1000000 + (double)tv.tv_usec;
+ return postEpochMicroSecs;
+
+}
+
+void PrintTimeStamp(struct timeval *ts)
+{
+ (void)printf("%02d:%02d:%02d.%06u ",
+ (unsigned int)ts->tv_sec / 3600,
+ ((unsigned int)ts->tv_sec % 3600) / 60,
+ (unsigned int)ts->tv_sec % 60, (unsigned int)ts->tv_usec);
+}
+
+void processBadPacket (struct IPPacket *p)
+{
+
+ if (session.debug == SESSION_DEBUG_HIGH) {
+ printf("In ProcessBadPacket...\n");
+ }
+ /*
+ * reset? the other guy does not like us?
+ */
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) && (p->tcp->tcp_flags & TCPFLAGS_RST)) {
+ printf("ERROR: EARLY_RST.\nRETURN CODE: %d\n", EARLY_RST);
+ Quit(EARLY_RST);
+ }
+ /*
+ * some other packet between us that is none of the above
+ */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport) ||
+ INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ printf("ERROR: Unexpected packet\nRETURN CODE: %d\n", UNEXPECTED_PKT);
+ printf("Expecting:\n");
+ printf("\tsrc = %s:%d (seq=%u, ack=%u)\n",
+ InetAddress(session.src), session.sport,
+ session.snd_nxt-session.iss,
+ session.rcv_nxt-session.irs);
+ printf("\tdst = %s:%d (seq=%u, ack=%u)\n",
+ InetAddress(session.dst),session.dport,
+ session.rcv_nxt-session.irs, session.snd_una-session.iss);
+ printf("Received:\n\t");
+ PrintTcpPacket(p);
+ printf ("session.snd_nxt=%d, session.rcv_nxt=%d, session.snd_una=%d\n",
+ session.snd_nxt-session.iss, session.rcv_nxt-session.irs, session.snd_una-session.iss);
+ Quit(UNEXPECTED_PKT);
+ }
+ /*
+ * none of the above,
+ * so we must be seeing packets
+ * from some other flow!
+ */
+ else {
+ printf("ERRROR: Received packet from different flow\nRETURN CODE: %d\n", DIFF_FLOW);
+ PrintTcpPacket(p);
+ Quit(DIFF_FLOW) ;
+ }
+
+ if (session.debug == SESSION_DEBUG_HIGH) {
+ printf("Out ProcessBadPacket...\n");
+ }
+}
+
+void busy_wait (double wait)
+{
+ double now = GetTime();
+ double x = now ;
+ while ((x - now) < wait) {
+ x = GetTime();
+ }
+}
diff --git a/network_cmds/ecnprobe/support.h b/network_cmds/ecnprobe/support.h
new file mode 100644
index 0000000..94be2e5
--- /dev/null
+++ b/network_cmds/ecnprobe/support.h
@@ -0,0 +1,132 @@
+
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+
+#include <signal.h>
+
+#define MAXRESETRETRANSMITS (3)
+/*#define INSESSION(p, src, sport, dst, dport) \
+ (((p)->ip.ip_src == (src)) && ((p)->ip.ip_dst == (dst)) && \
+ ((p)->ip.ip_p == IPPROTOCOL_TCP) && \
+ ((p)->tcp.tcp_sport == htons(sport)) && \
+ ((p)->tcp.tcp_dport == htons(dport)))*/
+
+#define INSESSION(p, src, sport, dst, dport) \
+ (((p)->ip->ip_src == (src)) && ((p)->ip->ip_dst == (dst)) && \
+ ((p)->ip->ip_p == IPPROTOCOL_TCP) && \
+ ((p)->tcp->tcp_sport == htons(sport)) && \
+ ((p)->tcp->tcp_dport == htons(dport)))
+
+#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
+#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
+#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
+
+#define DEFAULT_TARGETPORT (80)
+#define DEFAULT_MSS 1360
+#define DEFAULT_MTU 1500
+#define RTT_TO_MULT 5
+#define PLOTDIFF 0.00009
+
+/* Response codes */
+#define FAIL -1
+#define SUCCESS 0
+#define NO_TARGET_CANON_INFO 1
+#define NO_LOCAL_HOSTNAME 2
+#define NO_SRC_CANON_INFO 3
+#define NO_SESSION_ESTABLISH 4
+#define MSS_TOO_SMALL 5
+#define BAD_ARGS 6
+#define FIREWALL_ERR 7
+#define ERR_SOCKET_OPEN 8
+#define ERR_SOCKOPT 9
+#define ERR_MEM_ALLOC 10
+#define NO_CONNECTION 11
+#define MSS_ERR 12
+#define BUFFER_OVERFLOW 13
+#define UNWANTED_PKT_DROP 14
+#define EARLY_RST 15
+#define UNEXPECTED_PKT 16
+#define DIFF_FLOW 17
+#define ERR_CHECKSUM 18
+#define NOT_ENOUGH_PKTS 19
+#define BAD_OPT_LEN 20
+#define TOO_MANY_PKTS 21
+#define NO_DATA_RCVD 22
+#define NO_TRGET_SPECIFIED 23
+#define BAD_OPTIONS 24
+#define TOO_MANY_TIMEOUTS 25
+#define TOO_MANY_RXMTS 26
+#define NO_SACK 27
+#define ERR_IN_SB_CALC 28
+#define TOO_MANY_HOLES 29
+#define TOO_MANY_DROPS 30
+#define UNWANTED_PKT_REORDER 31
+#define NO_PMTUD_ENABLED 32
+#define UNKNOWN_BEHAVIOR 33
+#define NO_SYNACK_RCVD 34
+#define SEND_REQUEST_FAILED 35
+#define PKT_SIZE_CHANGED 36
+#define ECN_SYN_DROP 37
+
+#define DEFAULT_FILENAME "/"
+
+#define RTT_TO_MULT 5
+#define SYNTIMEOUT (2.0)
+#define REXMITDELAY (2.0)
+#define MAXSYNRETRANSMITS (6)
+#define MAXDATARETRANSMITS (6)
+
+/* HTTP Response Codes */
+#define HTTP_OK "200"
+
+
+void SendReset();
+void SigHandle (int signo);
+void Cleanup();
+void Quit(int how);
+double GetTime();
+double GetTimeMicroSeconds();
+void PrintTimeStamp(struct timeval *ts);
+void processBadPacket (struct IPPacket *p);
+void busy_wait (double wait);
diff --git a/network_cmds/frame_delay/frame_delay.8 b/network_cmds/frame_delay/frame_delay.8
new file mode 100644
index 0000000..0f454d5
--- /dev/null
+++ b/network_cmds/frame_delay/frame_delay.8
@@ -0,0 +1,45 @@
+.Dd October 12, 2015
+.Dt FRAME_DELAY 8
+.Os Darwin
+.Sh NAME
+.Nm frame_delay
+.Nd Utility to measure TCP/UDP frame delay
+
+.Sh DESCRIPTION
+.Pp
+The
+.Nm
+utility is designed to measure the effect of latency on
+delivery of evenly spaced TCP/UDP frames. This can be latency induced
+due to buffering or protocol stack or network drivers.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl m
+Server/Client mode. Should be "server" or "client".
+.It Fl t
+TCP/UDP frame. Should be either "tcp" or "udp".
+.It Fl i
+(Client Only) Server ip address.
+.It Fl p
+Port number.
+.It Fl n
+Number of frames.
+.It Fl f
+Frame size.
+.It Fl d
+(Client only) Delay traffic class. Pick one from {BK_SYS, BK, BE, RD, QAM, AV, RV, VI, VO, CTL}.
+.El
+
+.Sh EXAMPLES
+.Pp
+Setup TCP server:
+.Dl "frame_delay -m server -t tcp -p 10010 -n 10 -f 1000"
+.Pp
+Setup corresponding TCP client:
+.Dl "frame_delay -m client -t tcp -i 127.0.0.1 -p 10010 -n 10 -f 1000 -d 2000 -k RD"
+
+.Sh AUTHORS
+.An Padma Bhooma ,
+.An Kang Sun ,
+.An Vincent Lubet . \ No newline at end of file
diff --git a/network_cmds/frame_delay/frame_delay.c b/network_cmds/frame_delay/frame_delay.c
new file mode 100644
index 0000000..37a58b7
--- /dev/null
+++ b/network_cmds/frame_delay/frame_delay.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2009-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Usage for frame_delay
+ *
+ * Server
+ * ./frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>
+ *
+ * Client
+ * ./frame_delay -m client -t <tcp/udp> -i <srv_ipv4_add> -p <srv_port> -n <num_frames> -f <frame_size> -d <delay_ms> -k <traffic_class>
+ */
+
+/*
+ * TODO list :
+ * 1. UDP fragmentation and reassembly
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+
+/* Server Static variable */
+static int so, srv_so;
+static int srv_port = 0;
+static struct sockaddr_in laddr, dst_addr;
+/* Client Static variable */
+static struct sockaddr_in srv_addr;
+static uint32_t tc = 0;
+/* Usage */
+void ErrorUsage(void);
+/* str2svc */
+uint32_t str2svc(const char *str);
+/* Show Stastics */
+void ShowStastics(int64_t *DiffsBuf, int num_frames);
+/* Returns difference between two timevals in microseconds */
+int64_t time_diff(struct timeval *b, struct timeval *a);
+/* tcp server */
+void tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
+/* udp server */
+void udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
+/* tcp server */
+void tcpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time);
+/* udp server */
+void udpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time);
+
+/* Main function */
+int
+main(int argc, char *argv[])
+{
+ int num_frames = 0, frame_size = 0, delay_ms = 0, rc = 0;
+ char *buf = NULL, ch, *type = NULL, *mode = NULL, *ip_addr = NULL;
+ int64_t *DiffsBuf;
+ struct timespec sleep_time;
+
+ while ((ch = getopt(argc, argv, "m:p:f:n:t:d:i:k:")) != -1) {
+ switch (ch) {
+ case 'm': {
+ mode = optarg;
+ break;
+ }
+ case 'p': {
+ srv_port = atoi(optarg);
+ break;
+ }
+ case 'f' : {
+ frame_size = atoi(optarg);
+ break;
+ }
+ case 'n' : {
+ num_frames = atoi(optarg);
+ break;
+ }
+ case 'i': {
+ ip_addr = optarg;
+ bzero(&srv_addr, sizeof(srv_addr));
+ rc = inet_aton(optarg, &srv_addr.sin_addr);
+ if (rc == 0) {
+ perror("inet_ntoa failed");
+ exit(1);
+ }
+ }
+ case 'd': {
+ delay_ms = atoi(optarg);
+ break;
+ }
+ case 't' : {
+ type = optarg;
+ break;
+ }
+ case 'k': {
+ tc = str2svc(optarg);
+ break;
+ }
+ default: {
+ printf("Invalid option: %c\n", ch);
+ ErrorUsage();
+ }
+ }
+ }
+ /* General check for both server and client */
+ if (srv_port <= 0 || frame_size <= 0 || num_frames <= 0 || !mode || !type) {
+ ErrorUsage();
+ }
+ if ( strcmp(type, "tcp") != 0 && strcmp(type, "udp") != 0 ) {
+ ErrorUsage();
+ }
+ /* Allocate memory for buf */
+ buf = calloc(1, frame_size);
+ if (buf == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if ( strcmp(mode, "server") == 0 ) {
+ /* Server */
+ printf("<LOG> : Start %s server on port %d with expected frame size of %d\n",
+ type, srv_port, frame_size);
+ DiffsBuf = (int64_t *)calloc(num_frames, sizeof(int64_t));
+ if (DiffsBuf == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if( strcmp(type, "tcp") == 0) {
+ /* tcpServer */
+ tcpServer(frame_size, num_frames, buf, DiffsBuf);
+ } else {
+ /* updServer */
+ udpServer(frame_size, num_frames, buf, DiffsBuf);
+ }
+ }
+ else if ( strcmp(mode, "client") == 0 ){
+ if ( !ip_addr || (tc > 0 && (tc < SO_TC_BK_SYS || tc > SO_TC_CTL)) ){
+ ErrorUsage();
+ }
+ /* Client */
+ printf("<LOG> : Start sending %d %s frames to %s:%d with a frame size of %d\n",
+ num_frames, type, ip_addr, srv_port, frame_size);
+ /* Resolving sleep time bug : delay_ms should just be calculated once */
+ bzero(&sleep_time, sizeof(sleep_time));
+ while (delay_ms >= 1000) {
+ sleep_time.tv_sec++;
+ delay_ms -= 1000;
+ }
+ sleep_time.tv_nsec = delay_ms * 1000 * 1000;
+ if( strcmp(type, "tcp") == 0) {
+ /* Call TCP client */
+ tcpClient(num_frames, frame_size, buf, sleep_time);
+ } else {
+ /* Call UDP client */
+ udpClient(num_frames, frame_size, buf, sleep_time);
+ }
+ } else {
+ ErrorUsage();
+ }
+}
+
+/* Error usage */
+void
+ErrorUsage(void) {
+ printf("Correct Usage");
+ printf("Server : frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>\n");
+ printf("Client : frame_delay -m client -t <tcp/udp> -i <srv_ipv4_add> -p <srv_port> -n <num_frames> -f <frame_size> -d <delay_ms> -k <traffic_class>\n");
+ exit(1);
+}
+
+/* str2svc */
+uint32_t
+str2svc(const char *str)
+{
+ uint32_t svc;
+ char *endptr;
+
+ if (str == NULL || *str == '\0')
+ svc = UINT32_MAX;
+ else if (strcasecmp(str, "BK_SYS") == 0)
+ return SO_TC_BK_SYS;
+ else if (strcasecmp(str, "BK") == 0)
+ return SO_TC_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return SO_TC_BE;
+ else if (strcasecmp(str, "RD") == 0)
+ return SO_TC_RD;
+ else if (strcasecmp(str, "OAM") == 0)
+ return SO_TC_OAM;
+ else if (strcasecmp(str, "AV") == 0)
+ return SO_TC_AV;
+ else if (strcasecmp(str, "RV") == 0)
+ return SO_TC_RV;
+ else if (strcasecmp(str, "VI") == 0)
+ return SO_TC_VI;
+ else if (strcasecmp(str, "VO") == 0)
+ return SO_TC_VO;
+ else if (strcasecmp(str, "CTL") == 0)
+ return SO_TC_CTL;
+ else {
+ svc = (uint32_t)strtoul(str, &endptr, 0);
+ if (*endptr != '\0')
+ svc = UINT32_MAX;
+ }
+ return (svc);
+}
+
+/* Show Stastics */
+void
+ShowStastics(int64_t *DiffsBuf, int num_frames) {
+ int i = 0;
+ int64_t sum = 0, mean = 0;
+
+ /* Mean */
+ while(i < num_frames)
+ sum += DiffsBuf[i++];
+ mean = sum / num_frames;
+ printf("<LOG> : Mean: %.2f usecs\n", sum / (double)num_frames);
+ /* Popular Standard Deviation */
+ i = 0;
+ sum = 0;
+ while(i < num_frames) {
+ sum += (DiffsBuf[i]-mean)*(DiffsBuf[i]-mean);
+ i++;
+ }
+ printf("<LOG> : Popular Standard Deviation: %.2f usecs\n",
+ sqrt(sum/(double)num_frames));
+}
+
+/* Returns difference between two timevals in microseconds */
+int64_t
+time_diff(struct timeval *b, struct timeval *a)
+{
+ int64_t usecs;
+ usecs = (a->tv_sec - b->tv_sec) * 1000 * 1000;
+ usecs += (int64_t)(a->tv_usec - b->tv_usec);
+ return(usecs);
+}
+
+/* Server */
+
+/* tcp server */
+void
+tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
+ int rc = 0, i = 0, ignore_count = 0;
+ uint32_t dst_len = 0;
+ struct timeval before, after;
+ ssize_t bytes;
+ int64_t usecs;
+ /* New change from Padama */
+ uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
+ uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
+
+ printf("<LOG> : TCP Server\n");
+ so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (so == -1) {
+ perror("failed to create socket");
+ exit(1);
+ }
+ bzero(&laddr, sizeof(laddr));
+ laddr.sin_family = AF_INET;
+ laddr.sin_port = htons(srv_port);
+ rc = bind(so, (const struct sockaddr *)&laddr, sizeof(laddr));
+ if (rc != 0) {
+ perror("failed to bind");
+ exit(1);
+ }
+ rc = listen(so, 10);
+ if (rc != 0) {
+ perror("failed to listen");
+ exit(1);
+ }
+ srv_so = accept(so, (struct sockaddr *)&dst_addr, &dst_len);
+ if (srv_so == -1) {
+ perror("failed to accept");
+ exit(1);
+ }
+ while (1) {
+ if ( i == num_frames ) {
+ printf("<LOG> : Completed\n");
+ break;
+ }
+ printf("<LOG> : Waiting for receiving\n");
+ bzero(&before, sizeof(before));
+ bzero(&after, sizeof(after));
+ rc = gettimeofday(&before, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ bytes = recv(srv_so, buf, frame_size, MSG_WAITALL);
+ if (bytes == -1) {
+ perror("recv failed");
+ exit(1);
+ }
+ else if (bytes > 0 && bytes != frame_size) {
+ printf("Client exited\n");
+ printf("Didn't recv the complete frame, bytes %ld\n",
+ bytes);
+ exit(1);
+ }
+ else if (bytes == 0) {
+ break;
+ }
+ rc = gettimeofday(&after, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
+ memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
+ if (prev_frame_ts > 0) {
+ int64_t d_variation = 0;
+ d_variation = (int64_t)((cur_recv - prev_recv) -
+ (frame_ts - prev_frame_ts));
+ /* printf("Frame %u ts %llu d_variation %lld usecs\n",
+ i, frame_ts, d_variation);*/
+ if (d_variation > 0) {
+ if (min_variation == 0)
+ min_variation = d_variation;
+ else
+ min_variation = ((min_variation <= d_variation) ?
+ min_variation : d_variation);
+ max_variation = ((max_variation >= d_variation) ?
+ max_variation : d_variation);
+ avg_variation += d_variation;
+ } else {
+ ignore_count++;
+ }
+ }
+ prev_recv = cur_recv;
+ prev_frame_ts = frame_ts;
+ ++i;
+ /* Compute the time differenc */
+ usecs = time_diff(&before, &after);
+ DiffsBuf[i] = usecs;
+ printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
+ }
+ if (i != ignore_count)
+ avg_variation = avg_variation / (i - ignore_count);
+ else
+ avg_variation = 0;
+
+ printf("<LOG> : Received frames: %u\n", i);
+ printf("<LOG> : Ignored frames: %u\n", ignore_count);
+ printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
+ printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
+ printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
+ ShowStastics(DiffsBuf, num_frames);
+}
+
+/* udp server */
+void
+udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
+ int rc = 0, i = 0, ignore_count = 0;
+ uint32_t dst_len = 0;
+ ssize_t bytes;
+ struct timeval before, after;
+ int64_t usecs;
+ /* New change from Padama */
+ uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
+ uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
+
+ printf("<LOG> : UDP Server\n");
+ so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (so == -1) {
+ perror("failed to create socket");
+ exit(1);
+ }
+ bzero(&laddr,sizeof(laddr));
+ laddr.sin_family = AF_INET;
+ laddr.sin_addr.s_addr=htonl(INADDR_ANY);
+ laddr.sin_port=htons(srv_port);
+ rc = bind(so, (struct sockaddr *)&laddr,sizeof(laddr));
+ if (rc != 0) {
+ perror("failed to bind");
+ exit(1);
+ }
+ while (1) {
+ if ( i == num_frames ) {
+ printf("<LOG> : Completed\n");
+ break;
+ }
+ printf("<LOG> : Waiting for receiving\n");
+ bzero(&before, sizeof(before));
+ bzero(&after, sizeof(after));
+ rc = gettimeofday(&before, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ bytes = recvfrom(so, buf, frame_size, 0, (struct sockaddr *)&dst_addr, &dst_len);
+ if (bytes == -1) {
+ perror("recv failed");
+ exit(1);
+ }
+ else if (bytes > 0 && bytes != frame_size) {
+ printf("Client exited\n");
+ printf("Didn't recv the complete frame, bytes %ld\n",
+ bytes);
+ exit(1);
+ }
+ else if (bytes == 0) {
+ break;
+ }
+ rc = gettimeofday(&after, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
+ memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
+ if (prev_frame_ts > 0) {
+ int64_t d_variation = 0;
+
+ d_variation = (int64_t)((cur_recv - prev_recv) -
+ (frame_ts - prev_frame_ts));
+ /* printf("Frame %u ts %llu d_variation %lld usecs\n",
+ i, frame_ts, d_variation);*/
+ if (d_variation > 0) {
+ if (min_variation == 0)
+ min_variation = d_variation;
+ else
+ min_variation = ((min_variation <= d_variation) ?
+ min_variation : d_variation);
+ max_variation = ((max_variation >= d_variation) ?
+ max_variation : d_variation);
+ avg_variation += d_variation;
+ } else {
+ ignore_count++;
+ }
+ }
+ prev_recv = cur_recv;
+ prev_frame_ts = frame_ts;
+ ++i;
+ /* Compute the time differenc */
+ usecs = time_diff(&before, &after);
+ DiffsBuf[i] = usecs;
+ printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
+ }
+ if (i != ignore_count)
+ avg_variation = avg_variation / (i - ignore_count);
+ else
+ avg_variation = 0;
+ printf("<LOG> : Received frames: %u\n", i);
+ printf("<LOG> : Ignored frames: %u\n", ignore_count);
+ printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
+ printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
+ printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
+ ShowStastics(DiffsBuf, num_frames);
+}
+
+/* Client */
+void
+tcpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time){
+ int rc = 0, i = 0;
+ ssize_t bytes;
+
+ printf("<LOG> : TCP Client\n");
+ so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (so <= 0) {
+ perror("creating socket failed");
+ exit(1);
+ }
+ srv_addr.sin_port = htons(srv_port);
+ srv_addr.sin_len = sizeof(srv_addr);
+ srv_addr.sin_family = AF_INET;
+ rc = connect(so, (const struct sockaddr *)&srv_addr,
+ sizeof(srv_addr));
+ if (rc != 0) {
+ perror("connect failed");
+ exit(1);
+ }
+ if (tc > 0) {
+ rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
+ sizeof(tc));
+ if (rc == -1) {
+ perror("failed to set traffic class");
+ exit(1);
+ }
+ }
+ for (i = 0; i < num_frames; ++i) {
+ struct timeval fts;
+ uint64_t frame_ts;
+ /* Add a timestamp to the frame */
+ rc = gettimeofday(&fts, NULL);
+ if (rc == -1) {
+ perror("faile to get time of day");
+ exit(1);
+ }
+ frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
+ memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
+ bytes = send(so, buf, frame_size, 0);
+ if (bytes == -1) {
+ perror("send failed \n");
+ exit(1);
+ }
+ if (bytes != frame_size) {
+ printf("failed to send all bytes, sent %ld\n", bytes);
+ exit (1);
+ }
+ rc = nanosleep(&sleep_time, NULL);
+ if (rc == -1) {
+ perror("sleep failed");
+ exit(1);
+ }
+ printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
+ }
+}
+
+void
+udpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time){
+ int rc = 0, i = 0;
+ ssize_t bytes;
+
+ printf("<LOG> : UDP Client\n");
+ so = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (so <= 0) {
+ perror("creating socket failed");
+ exit(1);
+ }
+ srv_addr.sin_port = htons(srv_port);
+ srv_addr.sin_len = sizeof(srv_addr);
+ srv_addr.sin_family = AF_INET;
+ if (tc > 0) {
+ rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
+ sizeof(tc));
+ if (rc == -1) {
+ perror("failed to set traffic class");
+ exit(1);
+ }
+ }
+ for (i = 0; i < num_frames; ++i) {
+ struct timeval fts;
+ uint64_t frame_ts;
+ /* Add a timestamp to the frame */
+ rc = gettimeofday(&fts, NULL);
+ if (rc == -1) {
+ perror("faile to get time of day");
+ exit(1);
+ }
+ frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
+ memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
+ bytes = sendto(so, buf, frame_size, 0, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
+ if (bytes == -1) {
+ perror("send failed \n");
+ exit(1);
+ }
+ if (bytes != frame_size) {
+ printf("failed to send all bytes, sent %ld\n", bytes);
+ exit (1);
+ }
+ rc = nanosleep(&sleep_time, NULL);
+ if (rc == -1) {
+ perror("sleep failed");
+ exit(1);
+ }
+ printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
+ }
+}
+
+
diff --git a/network_cmds/ifconfig.tproj/af_inet.c b/network_cmds/ifconfig.tproj/af_inet.c
new file mode 100644
index 0000000..621bd16
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/af_inet.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2009-2011, 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 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.
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h> /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq in_addreq;
+static struct ifreq in_ridreq;
+
+static void
+in_status(int s __unused, const struct ifaddrs *ifa)
+{
+ struct sockaddr_in *sin, null_sin;
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in *)ifa->ifa_addr;
+ if (sin == NULL)
+ return;
+
+ printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+
+ if (ifa->ifa_flags & IFF_POINTOPOINT) {
+ sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
+ if (sin == NULL)
+ sin = &null_sin;
+ printf("--> %s ", inet_ntoa(sin->sin_addr));
+ }
+
+ sin = (struct sockaddr_in *)ifa->ifa_netmask;
+ if (sin == NULL)
+ sin = &null_sin;
+ printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+
+ if (ifa->ifa_flags & IFF_BROADCAST) {
+ sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
+ if (sin != NULL && sin->sin_addr.s_addr != 0)
+ printf("broadcast %s", inet_ntoa(sin->sin_addr));
+ }
+ putchar('\n');
+}
+
+#define SIN(x) ((struct sockaddr_in *) &(x))
+static struct sockaddr_in *sintab[] = {
+ SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
+ SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
+};
+
+static void
+in_getaddr(const char *s, int which)
+{
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif /* MIN */
+ struct sockaddr_in *sin = sintab[which];
+ struct hostent *hp;
+ struct netent *np;
+
+ sin->sin_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin_family = AF_INET;
+
+ if (which == ADDR) {
+ char *p = NULL;
+
+ if((p = strrchr(s, '/')) != NULL) {
+ /* address is `name/masklen' */
+ int masklen;
+ int ret;
+ struct sockaddr_in *min = sintab[MASK];
+ *p = '\0';
+ ret = sscanf(p+1, "%u", &masklen);
+ if(ret != 1 || (masklen < 0 || masklen > 32)) {
+ *p = '/';
+ errx(1, "%s: bad value", s);
+ }
+ min->sin_len = sizeof(*min);
+ min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) &
+ 0xffffffff);
+ }
+ }
+
+ if (inet_aton(s, &sin->sin_addr))
+ return;
+ if ((hp = gethostbyname(s)) != 0)
+ bcopy(hp->h_addr, (char *)&sin->sin_addr,
+ MIN(hp->h_length, sizeof(sin->sin_addr)));
+ else if ((np = getnetbyname(s)) != 0)
+ sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
+ else
+ errx(1, "%s: bad value", s);
+#undef MIN
+}
+
+static void
+in_status_tunnel(int s)
+{
+ char src[NI_MAXHOST];
+ char dst[NI_MAXHOST];
+ struct ifreq ifr;
+ const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET)
+ return;
+ if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
+ src[0] = '\0';
+
+ if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET)
+ return;
+ if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
+ dst[0] = '\0';
+
+ printf("\ttunnel inet %s --> %s\n", src, dst);
+}
+
+static void
+in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+ struct ifaliasreq addreq;
+
+ memset(&addreq, 0, sizeof(addreq));
+ strlcpy(addreq.ifra_name, name, sizeof(addreq.ifra_name));
+ memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+ memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
+
+ if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
+ warn("SIOCSIFPHYADDR");
+}
+
+static void
+in_set_router(int s, int enable)
+{
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_intval = enable;
+
+ if (ioctl(s, SIOCSETROUTERMODE, &ifr) < 0)
+ warn("SIOCSETROUTERMODE");
+}
+
+static int
+routermode_from_string(char * str, int *mode_p)
+{
+ int success = 1;
+
+ if (strcasecmp(str, "enabled") == 0) {
+ *mode_p = 1;
+ } else if (strcasecmp(str, "disabled") == 0) {
+ *mode_p = 0;
+ } else {
+ success = 0;
+ }
+ return (success);
+}
+
+static const char *
+routermode_string(int mode)
+{
+ const char * str;
+
+ switch (mode) {
+ case 0:
+ str = "disabled";
+ break;
+ case 1:
+ str = "enabled";
+ break;
+ default:
+ str = "<unknown>";
+ break;
+ }
+ return str;
+}
+
+static int
+in_routermode(int s, int argc, char *const*argv)
+{
+ struct ifreq ifr;
+ int ret;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (argc == 0) {
+ ret = 0;
+#ifndef SIOCGETROUTERMODE
+#define SIOCGETROUTERMODE _IOWR('i', 209, struct ifreq) /* get IPv4 router mode state */
+#endif /* SIOCGETROUTERMODE */
+ if (ioctl(s, SIOCGETROUTERMODE, &ifr) < 0) {
+ if (argv != NULL) {
+ warn("SIOCGETROUTERMODE");
+ }
+ } else {
+ /* argv is NULL if we're called from status() */
+ printf("%s%s\n",
+ (argv == NULL) ? "\troutermode4: " : "",
+ routermode_string(ifr.ifr_intval));
+ }
+ ret = 0;
+ } else {
+ int mode;
+
+ if (routermode_from_string(argv[0], &mode) == 0) {
+ errx(EXIT_FAILURE,
+ "mode '%s' invalid, must be one of "
+ "disabled or enabled",
+ argv[0]);
+ }
+ ifr.ifr_intval = mode;
+ if (ioctl(s, SIOCSETROUTERMODE, &ifr) < 0) {
+ warn("SIOCSETROUTERMODE");
+ }
+ ret = 1;
+ }
+ return ret;
+}
+
+static struct afswtch af_inet = {
+ .af_name = "inet",
+ .af_af = AF_INET,
+ .af_status = in_status,
+ .af_getaddr = in_getaddr,
+ .af_status_tunnel = in_status_tunnel,
+ .af_settunnel = in_set_tunnel,
+ .af_setrouter = in_set_router,
+ .af_routermode = in_routermode,
+ .af_difaddr = SIOCDIFADDR,
+ .af_aifaddr = SIOCAIFADDR,
+ .af_ridreq = &in_ridreq,
+ .af_addreq = &in_addreq,
+};
+
+static __constructor void
+inet_ctor(void)
+{
+ af_register(&af_inet);
+}
diff --git a/network_cmds/ifconfig.tproj/af_inet6.c b/network_cmds/ifconfig.tproj/af_inet6.c
new file mode 100644
index 0000000..c32c5c0
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/af_inet6.c
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2009-2017, 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 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.
+ * 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.
+ */
+
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h> /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
+
+#include "ifconfig.h"
+
+#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
+ "\004IFDISABLED\005DONT_SET_IFROUTE\006PROXY_PREFIXES" \
+ "\007IGNORE_NA\010INSECURE\011REPLICATED\012DAD"
+
+static struct in6_ifreq in6_ridreq;
+static struct in6_aliasreq in6_addreq =
+ { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ 0,
+ { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
+static int ip6lifetime;
+
+static void in6_fillscopeid(struct sockaddr_in6 *sin6);
+static int prefix(void *, int);
+static char *sec2str(time_t);
+static int explicit_prefix = 0;
+
+static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
+
+static void
+setifprefixlen(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getprefix != NULL)
+ afp->af_getprefix(addr, MASK);
+ explicit_prefix = 1;
+}
+
+static void
+setnd6flags(const char *dummyaddr __unused, int d, int s,
+ const struct afswtch *afp)
+{
+ struct in6_ndireq nd;
+ int error;
+
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+ error = ioctl(s, SIOCGIFINFO_IN6, &nd);
+ if (error) {
+ warn("ioctl(SIOCGIFINFO_IN6)");
+ return;
+ }
+ if (d < 0)
+ nd.ndi.flags &= ~(-d);
+ else
+ nd.ndi.flags |= d;
+ error = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
+ if (error)
+ warn("ioctl(SIOCSIFINFO_FLAGS)");
+}
+
+static void
+setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
+ const struct afswtch *afp)
+{
+ if (afp->af_af != AF_INET6)
+ err(1, "address flags can be set only for inet6 addresses");
+
+ if (flag < 0)
+ in6_addreq.ifra_flags &= ~(-flag);
+ else
+ in6_addreq.ifra_flags |= flag;
+}
+
+static void
+setip6lifetime(const char *cmd, const char *val, int s,
+ const struct afswtch *afp)
+{
+ time_t newval, t;
+ char *ep;
+
+ t = time(NULL);
+ newval = (time_t)strtoul(val, &ep, 0);
+ if (val == ep)
+ errx(1, "invalid %s", cmd);
+ if (afp->af_af != AF_INET6)
+ errx(1, "%s not allowed for the AF", cmd);
+ if (strcmp(cmd, "vltime") == 0) {
+ in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_vltime = newval;
+ } else if (strcmp(cmd, "pltime") == 0) {
+ in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+ }
+}
+
+static void
+setip6pltime(const char *seconds, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ setip6lifetime("pltime", seconds, s, afp);
+}
+
+static void
+setip6vltime(const char *seconds, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ setip6lifetime("vltime", seconds, s, afp);
+}
+
+static void
+setip6eui64(const char *cmd, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct ifaddrs *ifap, *ifa;
+ const struct sockaddr_in6 *sin6 = NULL;
+ const struct in6_addr *lladdr = NULL;
+ struct in6_addr *in6;
+
+ if (afp->af_af != AF_INET6)
+ errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
+ in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+ if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
+ errx(EXIT_FAILURE, "interface index is already filled");
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ strcmp(ifa->ifa_name, name) == 0) {
+ sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ lladdr = &sin6->sin6_addr;
+ break;
+ }
+ }
+ }
+ if (!lladdr)
+ errx(EXIT_FAILURE, "could not determine link local address");
+
+ memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
+
+ freeifaddrs(ifap);
+}
+
+static void
+in6_fillscopeid(struct sockaddr_in6 *sin6)
+{
+#if defined(__KAME__) && defined(KAME_SCOPEID)
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ sin6->sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+ sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+}
+
+static void
+in6_status(int s __unused, const struct ifaddrs *ifa)
+{
+ struct sockaddr_in6 *sin, null_sin;
+ struct in6_ifreq ifr6;
+ int s6;
+ u_int32_t flags6;
+ struct in6_addrlifetime lifetime;
+ time_t t = time(NULL);
+ int error;
+ u_int32_t scopeid;
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (sin == NULL)
+ return;
+
+ strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warn("socket(AF_INET6,SOCK_DGRAM)");
+ return;
+ }
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warn("ioctl(SIOCGIFAFLAG_IN6)");
+ close(s6);
+ return;
+ }
+ flags6 = ifr6.ifr_ifru.ifru_flags6;
+ memset(&lifetime, 0, sizeof(lifetime));
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
+ warn("ioctl(SIOCGIFALIFETIME_IN6)");
+ close(s6);
+ return;
+ }
+ lifetime = ifr6.ifr_ifru.ifru_lifetime;
+ close(s6);
+
+ /* XXX: embedded link local addr check */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+ *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+ u_short index;
+
+ index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+ *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = ntohs(index);
+ }
+ scopeid = sin->sin6_scope_id;
+
+ error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
+ sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
+ if (error != 0)
+ inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ printf("\tinet6 %s ", addr_buf);
+
+ if (ifa->ifa_flags & IFF_POINTOPOINT) {
+ sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+ /*
+ * some of the interfaces do not have valid destination
+ * address.
+ */
+ if (sin != NULL && sin->sin6_family == AF_INET6) {
+ int error;
+
+ /* XXX: embedded link local addr check */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+ *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+ u_short index;
+
+ index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+ *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = ntohs(index);
+ }
+
+ error = getnameinfo((struct sockaddr *)sin,
+ sin->sin6_len, addr_buf,
+ sizeof(addr_buf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error != 0)
+ inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ printf("--> %s ", addr_buf);
+ }
+ }
+
+ sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
+ if (sin == NULL)
+ sin = &null_sin;
+ printf("prefixlen %d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
+
+ if ((flags6 & IN6_IFF_ANYCAST) != 0)
+ printf("anycast ");
+ if ((flags6 & IN6_IFF_TENTATIVE) != 0)
+ printf("tentative ");
+ if ((flags6 & IN6_IFF_OPTIMISTIC) != 0)
+ printf("optimistic ");
+ if ((flags6 & IN6_IFF_DUPLICATED) != 0)
+ printf("duplicated ");
+ if ((flags6 & IN6_IFF_DETACHED) != 0)
+ printf("detached ");
+ if ((flags6 & IN6_IFF_DEPRECATED) != 0)
+ printf("deprecated ");
+ if ((flags6 & IN6_IFF_AUTOCONF) != 0)
+ printf("autoconf ");
+ if ((flags6 & IN6_IFF_TEMPORARY) != 0)
+ printf("temporary ");
+ if ((flags6 & IN6_IFF_DYNAMIC) != 0)
+ printf("dynamic ");
+ if ((flags6 & IN6_IFF_SECURED) != 0)
+ printf("secured ");
+ if ((flags6 & IN6_IFF_CLAT46) != 0)
+ printf("clat46 ");
+
+ if (scopeid)
+ printf("scopeid 0x%x ", scopeid);
+
+ if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+ printf("pltime ");
+ if (lifetime.ia6t_preferred) {
+ printf("%s ", lifetime.ia6t_preferred < t
+ ? "0" : sec2str(lifetime.ia6t_preferred - t));
+ } else
+ printf("infty ");
+
+ printf("vltime ");
+ if (lifetime.ia6t_expire) {
+ printf("%s ", lifetime.ia6t_expire < t
+ ? "0" : sec2str(lifetime.ia6t_expire - t));
+ } else
+ printf("infty ");
+ }
+
+ putchar('\n');
+}
+
+#define SIN6(x) ((struct sockaddr_in6 *) &(x))
+static struct sockaddr_in6 *sin6tab[] = {
+ SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+ SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
+};
+
+static void
+in6_getprefix(const char *plen, int which)
+{
+ struct sockaddr_in6 *sin = sin6tab[which];
+ u_char *cp;
+ int len = atoi(plen);
+
+ if ((len < 0) || (len > 128))
+ errx(1, "%s: bad value", plen);
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+ if ((len == 0) || (len == 128)) {
+ memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
+ return;
+ }
+ memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
+ for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+ *cp++ = 0xff;
+ *cp = 0xff << (8 - len);
+}
+
+static void
+in6_getaddr(const char *s, int which)
+{
+ struct sockaddr_in6 *sin = sin6tab[which];
+ struct addrinfo hints, *res;
+ int error = -1;
+
+ newaddr &= 1;
+
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+
+ if (which == ADDR) {
+ char *p = NULL;
+ if((p = strrchr(s, '/')) != NULL) {
+ *p = '\0';
+ in6_getprefix(p + 1, MASK);
+ explicit_prefix = 1;
+ }
+ }
+
+ if (sin->sin6_family == AF_INET6) {
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6;
+ error = getaddrinfo(s, NULL, &hints, &res);
+ }
+ if (error != 0) {
+ if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+ errx(1, "%s: bad value", s);
+ } else
+ bcopy(res->ai_addr, sin, res->ai_addrlen);
+}
+
+static int
+prefix(void *val, int size)
+{
+ u_char *name = (u_char *)val;
+ int byte, bit, plen = 0;
+
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (name[byte] != 0xff)
+ break;
+ if (byte == size)
+ return (plen);
+ for (bit = 7; bit != 0; bit--, plen++)
+ if (!(name[byte] & (1 << bit)))
+ break;
+ for (; bit != 0; bit--)
+ if (name[byte] & (1 << bit))
+ return(0);
+ byte++;
+ for (; byte < size; byte++)
+ if (name[byte])
+ return(0);
+ return (plen);
+}
+
+static char *
+sec2str(time_t total)
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ if (0) {
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+ } else
+ snprintf(result, sizeof(result), "%lu", (unsigned long)total);
+
+ return(result);
+}
+
+static void
+in6_postproc(int s, const struct afswtch *afp)
+{
+ if (explicit_prefix == 0) {
+ /* Aggregatable address architecture defines all prefixes
+ are 64. So, it is convenient to set prefixlen to 64 if
+ it is not specified. */
+ setifprefixlen("64", 0, s, afp);
+ /* in6_getprefix("64", MASK) if MASK is available here... */
+ }
+}
+
+static void
+in6_status_tunnel(int s)
+{
+ char src[NI_MAXHOST];
+ char dst[NI_MAXHOST];
+ struct in6_ifreq in6_ifr;
+ const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
+
+ memset(&in6_ifr, 0, sizeof(in6_ifr));
+ strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET6)
+ return;
+ in6_fillscopeid(&in6_ifr.ifr_addr);
+ if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
+ NI_NUMERICHOST) != 0)
+ src[0] = '\0';
+
+ if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET6)
+ return;
+ in6_fillscopeid(&in6_ifr.ifr_addr);
+ if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
+ NI_NUMERICHOST) != 0)
+ dst[0] = '\0';
+
+ printf("\ttunnel inet6 %s --> %s\n", src, dst);
+}
+
+static void
+nd6_status(int s)
+{
+ struct in6_ndireq nd;
+ int s6;
+ int error;
+
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ if (errno != EPROTONOSUPPORT)
+ warn("socket(AF_INET6, SOCK_DGRAM)");
+ return;
+ }
+ error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
+ if (error) {
+ if (errno != EPFNOSUPPORT && errno != EINVAL)
+ warn("ioctl(SIOCGIFINFO_IN6)");
+ close(s6);
+ return;
+ }
+ close(s6);
+ if (nd.ndi.flags == 0)
+ return;
+ printb("\tnd6 options", (unsigned int)nd.ndi.flags, ND6BITS);
+ putchar('\n');
+}
+
+static void
+in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+ struct in6_aliasreq in6_addreq;
+
+ memset(&in6_addreq, 0, sizeof(in6_addreq));
+ strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name));
+ memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+ memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
+ dstres->ai_addr->sa_len);
+
+ if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
+ warn("SIOCSIFPHYADDR_IN6");
+}
+
+#ifndef IPV6_ROUTER_MODE_EXCLUSIVE
+#define IPV6_ROUTER_MODE_DISABLED 0
+#define IPV6_ROUTER_MODE_EXCLUSIVE 1
+#define IPV6_ROUTER_MODE_HYBRID 2
+#endif /* IPV6_ROUTER_MODE_EXCLUSIVE */
+
+static void
+in6_set_router(int s, int enable)
+{
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_intval = (enable == 0)
+ ? IPV6_ROUTER_MODE_DISABLED
+ : IPV6_ROUTER_MODE_EXCLUSIVE;
+
+ if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0)
+ warn("SIOCSETROUTERMODE_IN6");
+}
+
+static int
+routermode_from_string(char * str, int *mode_p)
+{
+ int success = 1;
+
+ if (strcasecmp(str, "exclusive") == 0 ||
+ strcasecmp(str, "enabled") == 0) {
+ *mode_p = IPV6_ROUTER_MODE_EXCLUSIVE;
+ } else if (strcasecmp(str, "hybrid") == 0) {
+ *mode_p = IPV6_ROUTER_MODE_HYBRID;
+ } else if (strcasecmp(str, "disabled") == 0) {
+ *mode_p = IPV6_ROUTER_MODE_DISABLED;
+ } else {
+ success = 0;
+ }
+ return (success);
+}
+
+static const char *
+routermode_string(int mode)
+{
+ const char * str;
+
+ switch (mode) {
+ case IPV6_ROUTER_MODE_EXCLUSIVE:
+ str = "enabled";
+ break;
+ case IPV6_ROUTER_MODE_HYBRID:
+ str = "hybrid";
+ break;
+ case IPV6_ROUTER_MODE_DISABLED:
+ str = "disabled";
+ break;
+ default:
+ str = "<unknown>";
+ break;
+ }
+ return str;
+}
+
+static int
+in6_routermode(int s, int argc, char *const*argv)
+{
+ struct in6_ifreq ifr;
+ int ret;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (argc == 0) {
+ ret = 0;
+#ifndef SIOCGETROUTERMODE_IN6
+#define SIOCGETROUTERMODE_IN6 _IOWR('i', 137, struct in6_ifreq)
+#endif /* SIOCGETROUTERMODE_IN6 */
+ if (ioctl(s, SIOCGETROUTERMODE_IN6, &ifr) < 0) {
+ if (argv != NULL) {
+ warn("SIOCGETROUTERMODE_IN6");
+ }
+ } else {
+ /* argv is NULL if we're called from status() */
+ printf("%s%s\n",
+ (argv == NULL) ? "\troutermode6: " : "",
+ routermode_string(ifr.ifr_intval));
+ }
+ ret = 0;
+ } else {
+ int mode;
+
+ if (routermode_from_string(argv[0], &mode) == 0) {
+ errx(EXIT_FAILURE,
+ "mode '%s' invalid, must be one of "
+ "disabled, exclusive, or hybrid",
+ argv[0]);
+ }
+ ifr.ifr_intval = mode;
+ if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0) {
+ warn("SIOCSETROUTERMODE_IN6");
+ }
+ ret = 1;
+ }
+ return ret;
+}
+
+static struct cmd inet6_cmds[] = {
+ DEF_CMD_ARG("prefixlen", setifprefixlen),
+ DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags),
+ DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
+ DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
+ /* RFC 4429, section 3.1, says:
+ * "Optimistic DAD SHOULD NOT be used for manually entered
+ * addresses."
+ * it's not a MUST...
+ */
+ DEF_CMD("optimistic", IN6_IFF_OPTIMISTIC, setip6flags),
+ DEF_CMD("-optimistic", -IN6_IFF_OPTIMISTIC, setip6flags),
+ DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
+ DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
+ DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
+ DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
+ DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
+ DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
+ DEF_CMD("replicated", ND6_IFF_REPLICATED, setnd6flags),
+ DEF_CMD("-replicated", -ND6_IFF_REPLICATED, setnd6flags),
+ DEF_CMD("proxy_prefixes", ND6_IFF_PROXY_PREFIXES, setnd6flags),
+ DEF_CMD("-proxy_prefixes", -ND6_IFF_PROXY_PREFIXES, setnd6flags),
+ DEF_CMD("insecure", ND6_IFF_INSECURE, setnd6flags),
+ DEF_CMD("-insecure", -ND6_IFF_INSECURE, setnd6flags),
+ DEF_CMD_ARG("pltime", setip6pltime),
+ DEF_CMD_ARG("vltime", setip6vltime),
+ DEF_CMD("eui64", 0, setip6eui64),
+ DEF_CMD("secured", IN6_IFF_SECURED, setip6flags),
+ DEF_CMD("-secured", -IN6_IFF_SECURED, setip6flags),
+ DEF_CMD("dad", ND6_IFF_DAD, setnd6flags),
+ DEF_CMD("-dad", -ND6_IFF_DAD, setnd6flags),
+};
+
+static struct afswtch af_inet6 = {
+ .af_name = "inet6",
+ .af_af = AF_INET6,
+ .af_status = in6_status,
+ .af_getaddr = in6_getaddr,
+ .af_getprefix = in6_getprefix,
+ .af_other_status = nd6_status,
+ .af_postproc = in6_postproc,
+ .af_status_tunnel = in6_status_tunnel,
+ .af_settunnel = in6_set_tunnel,
+ .af_setrouter = in6_set_router,
+ .af_routermode = in6_routermode,
+ .af_difaddr = SIOCDIFADDR_IN6,
+ .af_aifaddr = SIOCAIFADDR_IN6,
+ .af_ridreq = &in6_ridreq,
+ .af_addreq = &in6_addreq,
+};
+
+static void
+in6_Lopt_cb(const char *optarg __unused)
+{
+ ip6lifetime++; /* print IPv6 address lifetime */
+}
+static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
+
+static __constructor void
+inet6_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(inet6_cmds); i++)
+ cmd_register(&inet6_cmds[i]);
+ af_register(&af_inet6);
+ opt_register(&in6_Lopt);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/af_link.c b/network_cmds/ifconfig.tproj/af_link.c
new file mode 100644
index 0000000..ca9444c
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/af_link.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 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.
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include "ifconfig.h"
+
+static struct ifreq link_ridreq;
+
+static void
+link_status(int s __unused, const struct ifaddrs *ifa)
+{
+ /* XXX no const 'cuz LLADDR is defined wrong */
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+
+ if (sdl != NULL && sdl->sdl_alen > 0) {
+#ifdef notyet
+ if (sdl->sdl_type == IFT_ETHER &&
+ sdl->sdl_alen == ETHER_ADDR_LEN)
+ printf("\tether %s\n",
+ ether_ntoa((struct ether_addr *)LLADDR(sdl)));
+ else {
+ int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+ printf("\tlladdr %s\n", link_ntoa(sdl) + n);
+ }
+#else
+ char *cp = (char *)LLADDR(sdl);
+ int n = sdl->sdl_alen;
+
+ if (sdl->sdl_type == IFT_ETHER)
+ printf ("\tether ");
+ else
+ printf ("\tlladdr ");
+ while (--n >= 0)
+ printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
+ putchar('\n');
+#endif
+ }
+}
+
+static void
+link_getaddr(const char *addr, int which)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+ struct sockaddr *sa = &link_ridreq.ifr_addr;
+ size_t slen = strlen(addr);
+
+ if (which != ADDR)
+ errx(1, "can't set link-level netmask or broadcast");
+ if ((temp = malloc(slen + 2)) == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strlcpy(temp + 1, addr, slen + 1);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen > sizeof(sa->sa_data))
+ errx(1, "malformed link-level address");
+ sa->sa_family = AF_LINK;
+ sa->sa_len = sdl.sdl_alen;
+ bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
+}
+
+static struct afswtch af_link = {
+ .af_name = "link",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+static struct afswtch af_ether = {
+ .af_name = "ether",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+static struct afswtch af_lladdr = {
+ .af_name = "lladdr",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+
+static __constructor void
+link_ctor(void)
+{
+ af_register(&af_link);
+ af_register(&af_ether);
+ af_register(&af_lladdr);
+}
diff --git a/network_cmds/ifconfig.tproj/if6lowpan.c b/network_cmds/ifconfig.tproj/if6lowpan.c
new file mode 100644
index 0000000..f0f4b2e
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/if6lowpan.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_6lowpan_var.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+#include <sys/cdefs.h>
+
+
+static boolean_t is_sixlowpan_inited = FALSE;
+static struct sixlowpanreq params;
+
+static int
+get6lowpan(int s, struct ifreq *ifr, struct sixlowpanreq *req)
+{
+ bzero((char *)req, sizeof(*req));
+ ifr->ifr_data = (caddr_t)req;
+ return ioctl(s, SIOCGIF6LOWPAN, (caddr_t)ifr);
+}
+
+static void
+sixlowpan_status(int s)
+{
+ struct sixlowpanreq req;
+
+ if (get6lowpan(s, &ifr, &req) != -1)
+ printf("\t6lowpan: parent interface: %s\n",
+ req.parent[0] == '\0' ?
+ "<none>" : req.parent);
+}
+
+
+static void
+set6lowpandev(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct sixlowpanreq req;
+
+ strlcpy(params.parent, val, sizeof(params.parent));
+ is_sixlowpan_inited = TRUE;
+ fprintf(stderr, "val %s\n", val);
+
+ strlcpy(req.parent, val, sizeof(req.parent));
+ ifr.ifr_data = (caddr_t) &req;
+ if (ioctl(s, SIOCSIF6LOWPAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIF6LOWPAN");
+}
+
+static void
+unset6lowpandev(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct sixlowpanreq req;
+
+ bzero((char *)&req, sizeof(req));
+ ifr.ifr_data = (caddr_t)&req;
+
+ if (ioctl(s, SIOCGIF6LOWPAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGIF6LOWPAN");
+
+ bzero((char *)&req, sizeof(req));
+ if (ioctl(s, SIOCSIF6LOWPAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIF6LOWPAN");
+}
+
+static void
+sixlowpan_create(const char *val, int d, int s, const struct afswtch *afp)
+{
+ strlcpy(params.parent, val, sizeof(params.parent));
+ is_sixlowpan_inited = TRUE;
+}
+
+static void
+sixlowpan_clone_cb(int s, void *arg)
+{
+ if (is_sixlowpan_inited == TRUE && params.parent[0] == '\0')
+ errx(1, "6lowpandev must be specified");
+}
+
+static struct cmd sixlowpan_cmds[] = {
+ DEF_CLONE_CMD_ARG("6lowpandev", sixlowpan_create),
+ DEF_CMD_OPTARG("6lowpansetdev", set6lowpandev),
+ DEF_CMD_OPTARG("6lowpanunsetdev", unset6lowpandev),
+};
+static struct afswtch af_6lowpan = {
+ .af_name = "af_6lowpan",
+ .af_af = AF_UNSPEC,
+ .af_other_status = sixlowpan_status,
+};
+
+static __constructor void
+sixlowpan_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(sixlowpan_cmds); i++)
+ cmd_register(&sixlowpan_cmds[i]);
+ af_register(&af_6lowpan);
+ callback_register(sixlowpan_clone_cb, NULL);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifbond.c b/network_cmds/ifconfig.tproj/ifbond.c
new file mode 100644
index 0000000..b8bcdfe
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifbond.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * ifbond.c
+ * - add and remove interfaces from a bond interface
+ */
+
+/*
+ * Modification History:
+ *
+ * July 14, 2004 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_bond_var.h>
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+extern int bond_details;
+
+#define EA_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
+#define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
+
+static __inline__ const char *
+selected_state_string(u_char s)
+{
+ static const char * names[] = { "unselected", "selected", "standby" };
+
+ if (s <= IF_BOND_STATUS_SELECTED_STATE_STANDBY) {
+ return (names[s]);
+ }
+ return ("<unknown>");
+}
+
+static void
+bond_print_details(struct if_bond_status * ibs_p, int count)
+
+{
+ int i;
+ struct if_bond_status * scan_p = ibs_p;
+
+ for (i = 0; i < count; i++, scan_p++) {
+ struct if_bond_partner_state * ps;
+ ps = &scan_p->ibs_partner_state;
+ printf("\tbond interface: %s priority: 0x%04x "
+ "state: 0x%02x partner system: 0x%04x,"
+ EA_FORMAT " "
+ "key: 0x%04x port: 0x%04x priority: 0x%04x "
+ "state: 0x%02x\n",
+ scan_p->ibs_if_name, scan_p->ibs_port_priority,
+ scan_p->ibs_state, ps->ibps_system_priority,
+ EA_LIST(&ps->ibps_system), ps->ibps_key,
+ ps->ibps_port, ps->ibps_port_priority,
+ ps->ibps_state);
+ }
+ return;
+}
+
+void
+bond_status(int s)
+{
+ int i;
+ struct if_bond_req ibr;
+ struct if_bond_status * ibs_p;
+ struct if_bond_status_req * ibsr_p;
+ char mode_buf[16];
+ const char * mode_str;
+
+ bzero((char *)&ibr, sizeof(ibr));
+ ibr.ibr_op = IF_BOND_OP_GET_STATUS;
+ ibsr_p = &ibr.ibr_ibru.ibru_status;
+ ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION;
+ ifr.ifr_data = (caddr_t)&ibr;
+
+ /* how many of them are there? */
+ if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
+ return;
+ }
+ switch (ibsr_p->ibsr_mode) {
+ case IF_BOND_MODE_LACP:
+ mode_str = "lacp";
+ break;
+ case IF_BOND_MODE_STATIC:
+ mode_str = "static";
+ break;
+ default:
+ snprintf(mode_buf, sizeof(mode_buf), "%d", ibsr_p->ibsr_mode);
+ mode_str = mode_buf;
+ break;
+ }
+ if (ibsr_p->ibsr_total == 0) {
+ if (bond_details) {
+ printf("\tbond mode: %s\n"
+ "\tbond key: 0x%04x interfaces: <none>",
+ mode_str, ibsr_p->ibsr_key);
+ }
+ else {
+ printf("\tbond interfaces: <none>\n");
+ }
+ return;
+ }
+ ibsr_p->ibsr_buffer
+ = (char *)malloc(sizeof(struct if_bond_status)
+ * ibsr_p->ibsr_total);
+ ibsr_p->ibsr_count = ibsr_p->ibsr_total;
+
+ /* get the list */
+ if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
+ goto done;
+ }
+ if (ibsr_p->ibsr_total > 0) {
+ if (bond_details) {
+ printf("\tbond mode: %s\n"
+ "\tbond key: 0x%04x interfaces:",
+ mode_str, ibsr_p->ibsr_key);
+ }
+ else {
+ printf("\tbond interfaces:");
+ }
+ ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
+ for (i = 0; i < ibsr_p->ibsr_total; i++, ibs_p++) {
+ printf(" %s", ibs_p->ibs_if_name);
+ if (bond_details) {
+ u_char s = ibs_p->ibs_selected_state;
+ printf(" (%s)", selected_state_string(s));
+ }
+ }
+ printf("\n");
+ if (bond_details) {
+ bond_print_details((struct if_bond_status *)
+ ibsr_p->ibsr_buffer,
+ ibsr_p->ibsr_total);
+ }
+ }
+ else if (bond_details) {
+ printf("\tbond mode: %s\n"
+ "\tbond key: 0x%04x interfaces: <none>\n",
+ mode_str, ibsr_p->ibsr_key);
+ }
+ else {
+ printf("\tbond interfaces: <none>\n");
+ }
+
+ done:
+ free(ibsr_p->ibsr_buffer);
+ return;
+}
+
+static
+DECL_CMD_FUNC(setbonddev, val, d)
+{
+ struct if_bond_req ibr;
+
+ bzero((char *)&ibr, sizeof(ibr));
+ if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
+ sizeof(ibr.ibr_ibru.ibru_if_name),
+ "%s", val) >= IFNAMSIZ) {
+ errx(1, "interface name too long");
+ }
+ ibr.ibr_op = IF_BOND_OP_ADD_INTERFACE;
+ ifr.ifr_data = (caddr_t)&ibr;
+ if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIFBOND add interface");
+
+ return;
+}
+
+static
+DECL_CMD_FUNC(unsetbonddev, val, d)
+{
+ struct if_bond_req ibr;
+
+ bzero((char *)&ibr, sizeof(ibr));
+ if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
+ sizeof(ibr.ibr_ibru.ibru_if_name),
+ "%s", val) >= IFNAMSIZ) {
+ errx(1, "interface name too long");
+ }
+ ibr.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
+ ifr.ifr_data = (caddr_t)&ibr;
+ if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIFBOND remove interface");
+
+ return;
+}
+
+static
+DECL_CMD_FUNC(setbondmode, val, d)
+{
+ struct if_bond_req ibr;
+ int mode;
+
+ if (strcmp(val, "lacp") == 0) {
+ mode = IF_BOND_MODE_LACP;
+ }
+ else if (strcmp(val, "static") == 0) {
+ mode = IF_BOND_MODE_STATIC;
+ }
+ else {
+ mode = strtoul(val, NULL, 0);
+ if (errno != 0) {
+ errx(1, "invalid mode value "
+ "(must be either \"lacp\" or \"static\")");
+ }
+ }
+
+ bzero((char *)&ibr, sizeof(ibr));
+ if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
+ sizeof(ibr.ibr_ibru.ibru_if_name),
+ "%s", val) >= IFNAMSIZ) {
+ errx(1, "interface name too long");
+ }
+ ibr.ibr_op = IF_BOND_OP_SET_MODE;
+ ibr.ibr_ibru.ibru_int_val = mode;
+ ifr.ifr_data = (caddr_t)&ibr;
+ if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIFBOND set mode");
+
+ return;
+}
+
+static struct cmd bond_cmds[] = {
+ DEF_CLONE_CMD_ARG("bonddev", setbonddev),
+ DEF_CLONE_CMD_ARG("-bonddev", unsetbonddev),
+ DEF_CMD_ARG("bondmode", setbondmode),
+};
+static struct afswtch af_bond = {
+ .af_name = "af_bond",
+ .af_af = AF_UNSPEC,
+ .af_other_status = bond_status,
+};
+
+static __constructor void
+bond_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(bond_cmds); i++)
+ cmd_register(&bond_cmds[i]);
+ af_register(&af_bond);
+#undef N
+}
+
diff --git a/network_cmds/ifconfig.tproj/ifbridge.c b/network_cmds/ifconfig.tproj/ifbridge.c
new file mode 100644
index 0000000..951c56b
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifbridge.c
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2009-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*-
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_bridgevar.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include "ifconfig.h"
+
+#define PV2ID(pv, epri, eaddr) do { \
+ epri = pv >> 48; \
+ eaddr[0] = pv >> 40; \
+ eaddr[1] = pv >> 32; \
+ eaddr[2] = pv >> 24; \
+ eaddr[3] = pv >> 16; \
+ eaddr[4] = pv >> 8; \
+ eaddr[5] = pv >> 0; \
+} while (0)
+
+static const char *stpstates[] = {
+ "disabled",
+ "listening",
+ "learning",
+ "forwarding",
+ "blocking",
+ "discarding"
+};
+static const char *stpproto[] = {
+ "stp",
+ "-",
+ "rstp"
+};
+static const char *stproles[] = {
+ "disabled",
+ "root",
+ "designated",
+ "alternate",
+ "backup"
+};
+
+static int
+get_val(const char *cp, u_long *valp)
+{
+ char *endptr;
+ u_long val;
+
+ errno = 0;
+ val = strtoul(cp, &endptr, 0);
+ if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
+ return (-1);
+
+ *valp = val;
+ return (0);
+}
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+ struct ifdrv ifd;
+
+ memset(&ifd, 0, sizeof(ifd));
+
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = op;
+ ifd.ifd_len = argsize;
+ ifd.ifd_data = arg;
+
+ return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static void
+do_bridgeflag(int sock, const char *ifs, int flag, int set)
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
+
+ if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
+ err(1, "unable to get bridge flags");
+
+ if (set)
+ req.ifbr_ifsflags |= flag;
+ else
+ req.ifbr_ifsflags &= ~flag;
+
+ if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
+ err(1, "unable to set bridge flags");
+}
+
+static void
+bridge_interfaces(int s, const char *prefix)
+{
+ struct ifbifconf bifc;
+ struct ifbreq *req;
+ char *inbuf = NULL, *ninbuf;
+ char *p, *pad;
+ int i, len = 8192;
+
+ pad = strdup(prefix);
+ if (pad == NULL)
+ err(1, "strdup");
+ /* replace the prefix with whitespace */
+ for (p = pad; *p != '\0'; p++) {
+ if(isprint(*p))
+ *p = ' ';
+ }
+
+ for (;;) {
+ ninbuf = realloc(inbuf, len);
+ if (ninbuf == NULL)
+ err(1, "unable to allocate interface buffer");
+ bifc.ifbic_len = len;
+ bifc.ifbic_buf = inbuf = ninbuf;
+ if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
+ err(1, "unable to get interface list");
+ if ((bifc.ifbic_len + sizeof(*req)) < len)
+ break;
+ len *= 2;
+ }
+
+ for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
+ req = bifc.ifbic_req + i;
+ printf("%s%s ", prefix, req->ifbr_ifsname);
+ printb("flags", req->ifbr_ifsflags, IFBIFBITS);
+ printf("\n");
+
+ printf("%s", pad);
+ printf("ifmaxaddr %u", req->ifbr_addrmax);
+ printf(" port %u priority %u", req->ifbr_portno,
+ req->ifbr_priority);
+ printf(" path cost %u", req->ifbr_path_cost);
+
+ if (req->ifbr_ifsflags & IFBIF_STP) {
+ if (req->ifbr_proto <
+ sizeof(stpproto) / sizeof(stpproto[0]))
+ printf(" proto %s", stpproto[req->ifbr_proto]);
+ else
+ printf(" <unknown proto %d>",
+ req->ifbr_proto);
+
+ printf("\n%s", pad);
+ if (req->ifbr_role <
+ sizeof(stproles) / sizeof(stproles[0]))
+ printf("role %s", stproles[req->ifbr_role]);
+ else
+ printf("<unknown role %d>",
+ req->ifbr_role);
+ if (req->ifbr_state <
+ sizeof(stpstates) / sizeof(stpstates[0]))
+ printf(" state %s", stpstates[req->ifbr_state]);
+ else
+ printf(" <unknown state %d>",
+ req->ifbr_state);
+ }
+ printf("\n");
+
+ if (verbose) {
+ struct ifbrhostfilter ifbrfh;
+ struct in_addr in;
+ struct ether_addr ea;
+
+ bzero(&ifbrfh, sizeof(struct ifbrhostfilter));
+ strlcpy(ifbrfh.ifbrhf_ifsname, req->ifbr_ifsname, sizeof(ifbrfh.ifbrhf_ifsname));
+ if (do_cmd(s, BRDGGHOSTFILTER, &ifbrfh, sizeof(ifbrfh), 0) < 0)
+ err(1, "unable to get host filter settings for %s",
+ ifbrfh.ifbrhf_ifsname);
+
+ if (ifbrfh.ifbrhf_flags & IFBRHF_ENABLED) {
+ in.s_addr = ifbrfh.ifbrhf_ipsrc;
+ bcopy(ifbrfh.ifbrhf_hwsrca, ea.octet, ETHER_ADDR_LEN);
+ } else {
+ in.s_addr = INADDR_ANY;
+ bzero(ea.octet, ETHER_ADDR_LEN);
+ }
+ printf("%s", pad);
+ printf("hostfilter %d hw: %s ip: %s",
+ ifbrfh.ifbrhf_flags & IFBRHF_ENABLED ? 1 : 0,
+ ether_ntoa(&ea), inet_ntoa(in));
+
+ printf("\n");
+ }
+ }
+
+ free(inbuf);
+ free(pad);
+}
+
+static void
+bridge_addresses(int s, const char *prefix)
+{
+ struct ifbaconf ifbac;
+ struct ifbareq *ifba;
+ char *inbuf = NULL, *ninbuf;
+ int i, len = 8192;
+ struct ether_addr ea;
+
+ for (;;) {
+ ninbuf = realloc(inbuf, len);
+ if (ninbuf == NULL)
+ err(1, "unable to allocate address buffer");
+ ifbac.ifbac_len = len;
+ ifbac.ifbac_buf = inbuf = ninbuf;
+ if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
+ err(1, "unable to get address cache");
+ if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
+ break;
+ len *= 2;
+ }
+
+ for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
+ ifba = ifbac.ifbac_req + i;
+ memcpy(ea.octet, ifba->ifba_dst,
+ sizeof(ea.octet));
+ printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
+ ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
+ printb("flags", ifba->ifba_flags, IFBAFBITS);
+ printf("\n");
+ }
+
+ free(inbuf);
+}
+
+#define MAX_IPv6_STR_LEN INET6_ADDRSTRLEN
+static void
+bridge_mac_nat(int s, const char *prefix)
+{
+ char *buf;
+ unsigned int count;
+ struct ether_addr ea;
+ unsigned int i;
+ struct ifbrmnelist mnl;
+ char *scan;
+
+ bzero(&mnl, sizeof(mnl));
+ if (do_cmd(s, BRDGGMACNATLIST, &mnl, sizeof(mnl), 0) < 0) {
+ /* err(1, "unable to get mac nat list"); */
+ return;
+ }
+ if (mnl.ifbml_len == 0) {
+ return;
+ }
+ printf("\tMAC NAT list:\n");
+ if (mnl.ifbml_elsize == 0) {
+ err(1, "kernel reported zero length element size");
+ }
+ if (mnl.ifbml_elsize < sizeof(struct ifbrmne)) {
+ err(1, "struct element size too small, kernel mismatch");
+ }
+ buf = malloc(mnl.ifbml_len);
+ if (buf == NULL) {
+ err(1, "unable to allocate mac nat list buffer");
+ }
+ mnl.ifbml_buf = buf;
+ if (do_cmd(s, BRDGGMACNATLIST, &mnl, sizeof(mnl), 0) < 0) {
+ err(1, "unable to get mac nat list");
+ }
+ count = mnl.ifbml_len / mnl.ifbml_elsize;
+ for (i = 0, scan = buf; i < count; i++, scan += mnl.ifbml_elsize) {
+ struct ifbrmne *ifbmne = (struct ifbrmne *)scan;
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ memcpy(ea.octet, ifbmne->ifbmne_mac,
+ sizeof(ea.octet));
+ inet_ntop(ifbmne->ifbmne_af, &ifbmne->ifbmne_ip,
+ ntopbuf, sizeof(ntopbuf));
+ printf("%s%s %s %s %lu\n",
+ prefix, ifbmne->ifbmne_ifname, ntopbuf, ether_ntoa(&ea),
+ (unsigned long)ifbmne->ifbmne_expire);
+ }
+ free(buf);
+}
+
+static void
+bridge_status(int s)
+{
+ struct ifbropreq ifbp;
+ struct ifbrparam param;
+ u_int16_t pri;
+ u_int8_t ht, fd, ma, hc, pro;
+ u_int8_t lladdr[ETHER_ADDR_LEN];
+ u_int16_t bprio;
+ u_int32_t csize, ctime;
+ u_int32_t ipfflags;
+
+ if (do_cmd(s, BRDGGCACHE, &param, sizeof(param), 0) < 0)
+ return;
+ csize = param.ifbrp_csize;
+ if (do_cmd(s, BRDGGTO, &param, sizeof(param), 0) < 0)
+ return;
+ ctime = param.ifbrp_ctime;
+ if (do_cmd(s, BRDGGFILT, &param, sizeof(param), 0) < 0)
+ return;
+ ipfflags = param.ifbrp_filter;
+ if (do_cmd(s, BRDGPARAM, &ifbp, sizeof(ifbp), 0) < 0)
+ return;
+ pri = ifbp.ifbop_priority;
+ pro = ifbp.ifbop_protocol;
+ ht = ifbp.ifbop_hellotime;
+ fd = ifbp.ifbop_fwddelay;
+ hc = ifbp.ifbop_holdcount;
+ ma = ifbp.ifbop_maxage;
+
+ printf("\tConfiguration:\n");
+ PV2ID(ifbp.ifbop_bridgeid, bprio, lladdr);
+ printf("\t\tid %s priority %u hellotime %u fwddelay %u\n",
+ ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd);
+ printf("\t\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
+ ma, hc, stpproto[pro], csize, ctime);
+
+ PV2ID(ifbp.ifbop_designated_root, bprio, lladdr);
+ printf("\t\troot id %s priority %d ifcost %u port %u\n",
+ ether_ntoa((struct ether_addr *)lladdr), bprio,
+ ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
+
+ printf("\t\tipfilter %s flags 0x%x\n",
+ (ipfflags & IFBF_FILT_USEIPF) ? "enabled" : "disabled", ipfflags);
+
+ bridge_interfaces(s, "\tmember: ");
+
+ if (!all || verbose > 1) {
+ printf("\tAddress cache:\n");
+ bridge_addresses(s, "\t\t");
+ bridge_mac_nat(s, "\t\t");
+ }
+ return;
+
+}
+
+static void
+setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGADD %s", val);
+}
+
+static void
+setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGDEL %s", val);
+}
+
+static void
+setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
+}
+
+static void
+unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
+}
+
+static void
+setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_LEARNING, 1);
+}
+
+static void
+unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_LEARNING, 0);
+}
+
+#ifdef notdef
+static void
+setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STICKY, 1);
+}
+
+static void
+unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STICKY, 0);
+}
+
+static void
+setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGADDS %s", val);
+}
+
+static void
+unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGDELS %s", val);
+}
+#endif
+
+static void
+setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STP, 1);
+}
+
+static void
+unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STP, 0);
+}
+
+#ifdef notdef
+static void
+setbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1);
+}
+
+static void
+unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0);
+}
+
+static void
+setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1);
+}
+
+static void
+unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0);
+}
+
+static void
+setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1);
+}
+
+static void
+unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0);
+}
+
+static void
+setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1);
+}
+
+static void
+unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0);
+}
+#endif
+
+static void
+setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ req.ifbr_ifsflags = IFBF_FLUSHDYN;
+ if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ req.ifbr_ifsflags = IFBF_FLUSHALL;
+ if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_static(const char *val, const char *mac, int s,
+ const struct afswtch *afp)
+{
+ struct ifbareq req;
+ struct ether_addr *ea;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
+
+ ea = ether_aton(mac);
+ if (ea == NULL)
+ errx(1, "%s: invalid address: %s", val, mac);
+
+ memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+ req.ifba_flags = IFBAF_STATIC;
+ req.ifba_vlan = 1; /* XXX allow user to specify */
+
+ if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSADDR %s", val);
+}
+
+static void
+setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbareq req;
+ struct ether_addr *ea;
+
+ memset(&req, 0, sizeof(req));
+
+ ea = ether_aton(val);
+ if (ea == NULL)
+ errx(1, "invalid address: %s", val);
+
+ memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+
+ if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGDADDR %s", val);
+}
+
+static void
+setbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ bridge_addresses(s, "");
+}
+
+static void
+setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_csize = val & 0xffffffff;
+
+ if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSCACHE %s", arg);
+}
+
+static void
+setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_hellotime = val & 0xff;
+
+ if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSHT %s", arg);
+}
+
+static void
+setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_fwddelay = val & 0xff;
+
+ if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSFD %s", arg);
+}
+
+static void
+setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_maxage = val & 0xff;
+
+ if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSMA %s", arg);
+}
+
+static void
+setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_prio = val & 0xffff;
+
+ if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSPRI %s", arg);
+}
+
+#ifdef notdef
+static void
+setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+
+ if (strcasecmp(arg, "stp") == 0) {
+ param.ifbrp_proto = 0;
+ } else if (strcasecmp(arg, "rstp") == 0) {
+ param.ifbrp_proto = 2;
+ } else {
+ errx(1, "unknown stp protocol");
+ }
+
+ if (do_cmd(s, BRDGSPROTO, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSPROTO %s", arg);
+}
+
+static void
+setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_txhc = val & 0xff;
+
+ if (do_cmd(s, BRDGSTXHC, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSTXHC %s", arg);
+}
+#endif
+
+static void
+setbridge_ifpriority(const char *ifn, const char *pri, int s,
+ const struct afswtch *afp)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", pri);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_priority = val & 0xff;
+
+ if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFPRIO %s", pri);
+}
+
+static void
+setbridge_ifpathcost(const char *ifn, const char *cost, int s,
+ const struct afswtch *afp)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(cost, &val) < 0)
+ errx(1, "invalid value: %s", cost);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_path_cost = val;
+
+ if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFCOST %s", cost);
+}
+
+#ifdef notdef
+static void
+setbridge_ifmaxaddr(const char *ifn, const char *arg, int s,
+ const struct afswtch *afp)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_addrmax = val & 0xffffffff;
+
+ if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFAMAX %s", arg);
+}
+#endif
+
+static void
+setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_ctime = val & 0xffffffff;
+
+ if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSTO %s", arg);
+}
+
+#ifdef notdef
+static void
+setbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_PRIVATE, 1);
+}
+
+static void
+unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_PRIVATE, 0);
+}
+#endif
+
+
+static void
+setbridge_hostfilter(const char *ifn, const char *addr, int s,
+ const struct afswtch *afp)
+{
+ struct ifbrhostfilter req;
+ struct ether_addr *ea;
+ struct in_addr in;
+
+ memset(&req, 0, sizeof(req));
+ req.ifbrhf_flags = IFBRHF_ENABLED;
+
+ strlcpy(req.ifbrhf_ifsname, ifn, sizeof(req.ifbrhf_ifsname));
+
+ ea = ether_aton(addr);
+ if (ea != NULL) {
+ req.ifbrhf_flags |= IFBRHF_HWSRC;
+ bcopy(ea, req.ifbrhf_hwsrca, sizeof(req.ifbrhf_hwsrca));
+ } else if (inet_aton(addr, &in) != 0) {
+ req.ifbrhf_flags |= IFBRHF_IPSRC;
+ req.ifbrhf_ipsrc = in.s_addr;
+ } else
+ errx(1, "invalid address: %s", addr);
+
+ if (do_cmd(s, BRDGSHOSTFILTER, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSHOSTFILTER %s %s", ifn, addr);
+}
+
+static void
+unsetbridge_hostfilter(const char *ifn, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrhostfilter req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbrhf_ifsname, ifn, sizeof(req.ifbrhf_ifsname));
+
+ if (do_cmd(s, BRDGSHOSTFILTER, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSHOSTFILTER");
+}
+
+static void
+setbridge_macnat(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_MAC_NAT, 1);
+}
+
+static void
+unsetbridge_macnat(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_MAC_NAT, 0);
+}
+
+static struct cmd bridge_cmds[] = {
+ DEF_CMD_ARG("addm", setbridge_add),
+ DEF_CMD_ARG("deletem", setbridge_delete),
+ DEF_CMD_ARG("discover", setbridge_discover),
+ DEF_CMD_ARG("-discover", unsetbridge_discover),
+ DEF_CMD_ARG("learn", setbridge_learn),
+ DEF_CMD_ARG("-learn", unsetbridge_learn),
+#ifdef notdef
+ DEF_CMD_ARG("sticky", setbridge_sticky),
+ DEF_CMD_ARG("-sticky", unsetbridge_sticky),
+ DEF_CMD_ARG("span", setbridge_span),
+ DEF_CMD_ARG("-span", unsetbridge_span),
+#endif
+ DEF_CMD_ARG("stp", setbridge_stp),
+ DEF_CMD_ARG("-stp", unsetbridge_stp),
+#ifdef notdef
+ DEF_CMD_ARG("edge", setbridge_edge),
+ DEF_CMD_ARG("-edge", unsetbridge_edge),
+ DEF_CMD_ARG("autoedge", setbridge_autoedge),
+ DEF_CMD_ARG("-autoedge", unsetbridge_autoedge),
+ DEF_CMD_ARG("ptp", setbridge_ptp),
+ DEF_CMD_ARG("-ptp", unsetbridge_ptp),
+ DEF_CMD_ARG("autoptp", setbridge_autoptp),
+ DEF_CMD_ARG("-autoptp", unsetbridge_autoptp),
+#endif
+ DEF_CMD("flush", 0, setbridge_flush),
+ DEF_CMD("flushall", 0, setbridge_flushall),
+ DEF_CMD_ARG2("static", setbridge_static),
+ DEF_CMD_ARG("deladdr", setbridge_deladdr),
+ DEF_CMD("addr", 1, setbridge_addr),
+ DEF_CMD_ARG("maxaddr", setbridge_maxaddr),
+ DEF_CMD_ARG("hellotime", setbridge_hellotime),
+ DEF_CMD_ARG("fwddelay", setbridge_fwddelay),
+ DEF_CMD_ARG("maxage", setbridge_maxage),
+ DEF_CMD_ARG("priority", setbridge_priority),
+#ifdef notdef
+ DEF_CMD_ARG("proto", setbridge_protocol),
+ DEF_CMD_ARG("holdcnt", setbridge_holdcount),
+#endif
+ DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
+ DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
+#ifdef notdef
+ DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr),
+#endif
+ DEF_CMD_ARG("timeout", setbridge_timeout),
+#ifdef notdef
+ DEF_CMD_ARG("private", setbridge_private),
+ DEF_CMD_ARG("-private", unsetbridge_private),
+#endif
+ DEF_CMD_ARG2("hostfilter", setbridge_hostfilter),
+ DEF_CMD_ARG("-hostfilter", unsetbridge_hostfilter),
+ DEF_CMD_ARG("macnat", setbridge_macnat),
+ DEF_CMD_ARG("-macnat", unsetbridge_macnat),
+};
+static struct afswtch af_bridge = {
+ .af_name = "af_bridge",
+ .af_af = AF_UNSPEC,
+ .af_other_status = bridge_status,
+};
+
+static __constructor void
+bridge_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(bridge_cmds); i++)
+ cmd_register(&bridge_cmds[i]);
+ af_register(&af_bridge);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifclone.c b/network_cmds/ifconfig.tproj/ifclone.c
new file mode 100644
index 0000000..127d10b
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifclone.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1983, 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.
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void
+list_cloners(void)
+{
+ struct if_clonereq ifcr;
+ char *cp, *buf;
+ int idx;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+ memset(&ifcr, 0, sizeof(ifcr));
+
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+ err(1, "SIOCIFGCLONERS for count");
+
+ buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
+ if (buf == NULL)
+ err(1, "unable to allocate cloner name buffer");
+
+ ifcr.ifcr_count = ifcr.ifcr_total;
+ ifcr.ifcr_buffer = buf;
+
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+ err(1, "SIOCIFGCLONERS for names");
+
+ /*
+ * In case some disappeared in the mean time, clamp it down.
+ */
+ if (ifcr.ifcr_count > ifcr.ifcr_total)
+ ifcr.ifcr_count = ifcr.ifcr_total;
+
+ for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
+ if (idx > 0)
+ putchar(' ');
+ printf("%s", cp);
+ }
+
+ putchar('\n');
+ free(buf);
+}
+
+static clone_callback_func *clone_cb = NULL;
+
+void
+clone_setcallback(clone_callback_func *p)
+{
+ if (clone_cb != NULL && clone_cb != p)
+ errx(1, "conflicting device create parameters");
+ clone_cb = p;
+}
+
+/*
+ * Do the actual clone operation. Any parameters must have been
+ * setup by now. If a callback has been setup to do the work
+ * then defer to it; otherwise do a simple create operation with
+ * no parameters.
+ */
+static void
+ifclonecreate(int s, void *arg)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (clone_cb == NULL) {
+#ifdef SIOCIFCREATE2
+ /* NB: no parameters */
+ if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
+ err(1, "SIOCIFCREATE2");
+#else
+ if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
+ err(1, "SIOCIFCREATE");
+#endif
+ } else {
+ clone_cb(s, &ifr);
+ }
+
+ /*
+ * If we get a different name back than we put in, print it.
+ */
+ if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
+ strlcpy(name, ifr.ifr_name, sizeof(name));
+ printf("%s\n", name);
+ }
+}
+
+static
+DECL_CMD_FUNC(clone_create, arg, d)
+{
+ callback_register(ifclonecreate, NULL);
+}
+
+static
+DECL_CMD_FUNC(clone_destroy, arg, d)
+{
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+ err(1, "SIOCIFDESTROY");
+}
+
+static struct cmd clone_cmds[] = {
+ DEF_CLONE_CMD("create", 0, clone_create),
+ DEF_CMD("destroy", 0, clone_destroy),
+ DEF_CLONE_CMD("plumb", 0, clone_create),
+ DEF_CMD("unplumb", 0, clone_destroy),
+};
+
+static void
+clone_Copt_cb(const char *optarg __unused)
+{
+ list_cloners();
+ exit(0);
+}
+static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+
+static __constructor void
+clone_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(clone_cmds); i++)
+ cmd_register(&clone_cmds[i]);
+ opt_register(&clone_Copt);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifconfig.8 b/network_cmds/ifconfig.tproj/ifconfig.8
new file mode 100644
index 0000000..9b06f04
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifconfig.8
@@ -0,0 +1,1109 @@
+.\" Copyright (c) 2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1983, 1991, 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.
+.\" 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.
+.\"
+.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
+.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.142.2.6.2.1 2008/11/25 02:59:29 kensmith Exp $
+.\"
+.Dd June 20, 2008
+.Dt IFCONFIG 8
+.Os
+.Sh NAME
+.Nm ifconfig
+.Nd configure network interface parameters
+.Sh SYNOPSIS
+.Nm
+.Op Fl L
+.Op Fl m
+.Op Fl r
+.Ar interface
+.Op Cm create
+.Op Ar address_family
+.Oo
+.Ar address
+.Op Ar dest_address
+.Oc
+.Op Ar parameters
+.Nm
+.Ar interface
+.Cm destroy
+.Nm
+.Fl a
+.Op Fl L
+.Op Fl d
+.Op Fl m
+.Op Fl r
+.Op Fl u
+.Op Fl v
+.Op Ar address_family
+.Nm
+.Fl l
+.Op Fl d
+.Op Fl u
+.Op Ar address_family
+.Nm
+.Op Fl L
+.Op Fl d
+.Op Fl m
+.Op Fl r
+.Op Fl u
+.Op Fl v
+.Op Fl C
+.Nm
+.Ar interface
+.Cm vlan
+.Ar vlan-tag
+.Cm vlandev
+.Ar iface
+.Nm
+.Ar interface
+.Cm -vlandev
+.Ar iface
+.Nm
+.Ar interface
+.Cm bonddev
+.Ar iface
+.Nm
+.Ar interface
+.Cm -bonddev
+.Ar iface
+.Nm
+.Ar interface
+.Cm bondmode
+.Ar lacp | static
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to assign an address
+to a network interface and/or configure
+network interface parameters.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Ar address
+For the
+.Tn DARPA Ns -Internet
+family,
+the address is either a host name present in the host name data
+base,
+.Xr hosts 5 ,
+or a
+.Tn DARPA
+Internet address expressed in the Internet standard
+.Dq dot notation .
+.Pp
+It is also possible to use the CIDR notation (also known as the
+slash notation) to include the netmask.
+That is, one can specify an address like
+.Li 192.168.0.1/16 .
+.Pp
+For the
+.Dq inet6
+family, it is also possible to specify the prefix length using the slash
+notation, like
+.Li ::1/128 .
+See the
+.Cm prefixlen
+parameter below for more information.
+.\" For the Xerox Network Systems(tm) family,
+.\" addresses are
+.\" .Ar net:a.b.c.d.e.f ,
+.\" where
+.\" .Ar net
+.\" is the assigned network number (in decimal),
+.\" and each of the six bytes of the host number,
+.\" .Ar a
+.\" through
+.\" .Ar f ,
+.\" are specified in hexadecimal.
+.\" The host number may be omitted on IEEE 802 protocol
+.\" (Ethernet, FDDI, and Token Ring) interfaces,
+.\" which use the hardware physical address,
+.\" and on interfaces other than the first.
+.\" For the
+.\" .Tn ISO
+.\" family, addresses are specified as a long hexadecimal string,
+.\" as in the Xerox family.
+.\" However, two consecutive dots imply a zero
+.\" byte, and the dots are optional, if the user wishes to (carefully)
+.\" count out long strings of digits in network byte order.
+.Pp
+The link-level
+.Pq Dq link
+address
+is specified as a series of colon-separated hex digits.
+This can be used to
+e.g.\& set a new MAC address on an ethernet interface, though the
+mechanism used is not ethernet-specific.
+If the interface is already
+up when this option is used, it will be briefly brought down and
+then brought back up again in order to ensure that the receive
+filter in the underlying ethernet hardware is properly reprogrammed.
+.It Ar address_family
+Specify the
+address family
+which affects interpretation of the remaining parameters.
+Since an interface can receive transmissions in differing protocols
+with different naming schemes, specifying the address family is recommended.
+The address or protocol families currently
+supported are
+.Dq inet ,
+.Dq inet6 ,
+.\".Dq atalk ,
+.\".Dq ipx ,
+.\" .Dq iso ,
+and
+.Dq link .
+.\" and
+.\" .Dq ns .
+The default is
+.Dq inet .
+.Dq ether
+and
+.Dq lladdr
+are synonyms for
+.Dq link .
+.It Ar dest_address
+Specify the address of the correspondent on the other end
+of a point to point link.
+.It Ar interface
+This
+parameter is a string of the form
+.Dq name unit ,
+for example,
+.Dq Li en0 .
+\.El
+.Pp
+The following parameters may be set with
+.Nm :
+.Bl -tag -width indent
+.It Cm add
+Another name for the
+.Cm alias
+parameter.
+Introduced for compatibility
+with
+.Bsx .
+.It Cm alias
+Establish an additional network address for this interface.
+This is sometimes useful when changing network numbers, and
+one wishes to accept packets addressed to the old interface.
+If the address is on the same subnet as the first network address
+for this interface, a non-conflicting netmask must be given.
+Usually
+.Li 0xffffffff
+is most appropriate.
+.It Fl alias
+Remove the network address specified.
+This would be used if you incorrectly specified an alias, or it
+was no longer needed.
+If you have incorrectly set an NS address having the side effect
+of specifying the host portion, removing all NS addresses will
+allow you to respecify the host portion.
+.It Cm anycast
+(Inet6 only.)
+Specify that the address configured is an anycast address.
+Based on the current specification,
+only routers may configure anycast addresses.
+Anycast address will not be used as source address of any of outgoing
+IPv6 packets.
+.It Cm arp
+Enable the use of the Address Resolution Protocol
+.Pq Xr arp 4
+in mapping
+between network level addresses and link level addresses (default).
+This is currently implemented for mapping between
+.Tn DARPA
+Internet
+addresses and
+.Tn IEEE
+802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses).
+.It Fl arp
+Disable the use of the Address Resolution Protocol
+.Pq Xr arp 4 .
+.It Cm broadcast
+(Inet only.)
+Specify the address to use to represent broadcasts to the
+network.
+The default broadcast address is the address with a host part of all 1's.
+.It Cm debug
+Enable driver dependent debugging code; usually, this turns on
+extra console error logging.
+.It Fl debug
+Disable driver dependent debugging code.
+.It Cm delete
+Another name for the
+.Fl alias
+parameter.
+.It Cm down
+Mark an interface
+.Dq down .
+When an interface is marked
+.Dq down ,
+the system will not attempt to
+transmit messages through that interface.
+If possible, the interface will be reset to disable reception as well.
+.It Cm ether
+Another name for the
+.Cm lladdr
+parameter.
+.\" .It Cm ipdst
+.\" This is used to specify an Internet host who is willing to receive
+.\" ip packets encapsulating NS packets bound for a remote network.
+.\" An apparent point to point link is constructed, and
+.\" the address specified will be taken as the NS address and network
+.\" of the destination.
+.\" IP encapsulation of
+.\" .Tn CLNP
+.\" packets is done differently.
+.It Cm lladdr Ar addr
+Set the link-level address on an interface.
+This can be used to
+e.g. set a new MAC address on an ethernet interface, though the
+mechanism used is not ethernet-specific.
+The address
+.Ar addr
+is specified as a series of colon-separated hex digits.
+If the interface is already
+up when this option is used, it will be briefly brought down and
+then brought back up again in order to ensure that the receive
+filter in the underlying ethernet hardware is properly reprogrammed.
+.It Cm media Ar type
+If the driver supports the media selection system, set the media type
+of the interface to
+.Ar type .
+Some interfaces support the mutually exclusive use of one of several
+different physical media connectors.
+For example, a 10Mbit/s Ethernet
+interface might support the use of either
+.Tn AUI
+or twisted pair connectors.
+Setting the media type to
+.Cm 10base5/AUI
+would change the currently active connector to the AUI port.
+Setting it to
+.Cm 10baseT/UTP
+would activate twisted pair.
+Refer to the interfaces' driver
+specific documentation or man page for a complete list of the
+available types.
+.It Cm mediaopt Ar opts
+If the driver supports the media selection system, set the specified
+media options on the interface.
+The
+.Ar opts
+argument
+is a comma delimited list of options to apply to the interface.
+Refer to the interfaces' driver specific man page for a complete
+list of available options.
+.It Fl mediaopt Ar opts
+If the driver supports the media selection system, disable the
+specified media options on the interface.
+.It Cm rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+enable receive (or transmit) checksum offloading on the interface.
+Some drivers may not be able to enable these flags independently
+of each other, so setting one may also set the other.
+The driver will offload as much checksum work as it can reliably
+support, the exact level of offloading varies between drivers.
+.It Fl rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+disable receive (or transmit) checksum offloading on the interface.
+These settings may not always be independent of each other.
+.It Cm tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, enable TSO on the interface.
+Some drivers may not be able to support TSO for
+.Xr ip 4
+and
+.Xr ip6 4
+packets, so they may enable only one of them.
+.It Fl tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, disable TSO on the interface.
+It will always disable TSO for
+.Xr ip 4
+and
+.Xr ip6 4 .
+.It Cm lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, enable LRO on the interface.
+.It Fl lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, disable LRO on the interface.
+.It Cm av
+If supported by the driver, enable 802.1 AVB on the interface.
+.It Fl av
+If supported by the driver, disable 802.1 AVB on the interface.
+.It Cm vlanmtu , vlanhwtag
+If the driver offers user-configurable VLAN support, enable
+reception of extended frames or tag processing in hardware,
+respectively.
+Note that this must be issued on a physical interface associated with
+.Xr vlan 4 ,
+not on a
+.Xr vlan 4
+interface itself.
+.It Fl vlanmtu , vlanhwtag
+If the driver offers user-configurable VLAN support, disable
+reception of extended frames or tag processing in hardware,
+respectively.
+.It Cm create
+Create the specified network pseudo-device.
+If the interface is given without a unit number, try to create a new
+device with an arbitrary unit number.
+If creation of an arbitrary device is successful, the new device name is
+printed to standard output unless the interface is renamed or destroyed
+in the same
+.Nm
+invocation.
+.It Cm destroy
+Destroy the specified network pseudo-device.
+.It Cm plumb
+Another name for the
+.Cm create
+parameter.
+Included for
+.Tn Solaris
+compatibility.
+.It Cm unplumb
+Another name for the
+.Cm destroy
+parameter.
+Included for
+.Tn Solaris
+compatibility.
+.It Cm metric Ar n
+Set the routing metric of the interface to
+.Ar n ,
+default 0.
+The routing metric is used by the routing protocol
+.Pq Xr routed 8 .
+Higher metrics have the effect of making a route
+less favorable; metrics are counted as additional hops
+to the destination network or host.
+.It Cm mtu Ar n
+Set the maximum transmission unit of the interface to
+.Ar n ,
+default is interface specific.
+The MTU is used to limit the size of packets that are transmitted on an
+interface.
+Not all interfaces support setting the MTU, and some interfaces have
+range restrictions.
+.It Cm netmask Ar mask
+.\" (Inet and ISO.)
+(Inet only.)
+Specify how much of the address to reserve for subdividing
+networks into sub-networks.
+The mask includes the network part of the local address
+and the subnet part, which is taken from the host field of the address.
+The mask can be specified as a single hexadecimal number
+with a leading
+.Ql 0x ,
+with a dot-notation Internet address,
+or with a pseudo-network name listed in the network table
+.Xr networks 5 .
+The mask contains 1's for the bit positions in the 32-bit address
+which are to be used for the network and subnet parts,
+and 0's for the host part.
+The mask should contain at least the standard network portion,
+and the subnet field should be contiguous with the network
+portion.
+.Pp
+The netmask can also be specified in CIDR notation after the address.
+See the
+.Ar address
+option above for more information.
+.It Cm prefixlen Ar len
+(Inet6 only.)
+Specify that
+.Ar len
+bits are reserved for subdividing networks into sub-networks.
+The
+.Ar len
+must be integer, and for syntactical reason it must be between 0 to 128.
+It is almost always 64 under the current IPv6 assignment rule.
+If the parameter is omitted, 64 is used.
+.Pp
+The prefix can also be specified using the slash notation after the address.
+See the
+.Ar address
+option above for more information.
+.\" see
+.\" Xr eon 5 .
+.\" .It Cm nsellength Ar n
+.\" .Pf ( Tn ISO
+.\" only)
+.\" This specifies a trailing number of bytes for a received
+.\" .Tn NSAP
+.\" used for local identification, the remaining leading part of which is
+.\" taken to be the
+.\" .Tn NET
+.\" (Network Entity Title).
+.\" The default value is 1, which is conformant to US
+.\" .Tn GOSIP .
+.\" When an ISO address is set in an ifconfig command,
+.\" it is really the
+.\" .Tn NSAP
+.\" which is being specified.
+.\" For example, in
+.\" .Tn US GOSIP ,
+.\" 20 hex digits should be
+.\" specified in the
+.\" .Tn ISO NSAP
+.\" to be assigned to the interface.
+.\" There is some evidence that a number different from 1 may be useful
+.\" for
+.\" .Tn AFI
+.\" 37 type addresses.
+.It Cm remove
+Another name for the
+.Fl alias
+parameter.
+Introduced for compatibility
+with
+.Bsx .
+.Sm off
+.It Cm link Op Cm 0 No - Cm 2
+.Sm on
+Enable special processing of the link level of the interface.
+These three options are interface specific in actual effect, however,
+they are in general used to select special modes of operation.
+An example
+of this is to enable SLIP compression, or to select the connector type
+for some Ethernet cards.
+Refer to the man page for the specific driver
+for more information.
+.Sm off
+.It Fl link Op Cm 0 No - Cm 2
+.Sm on
+Disable special processing at the link level with the specified interface.
+.It Cm up
+Mark an interface
+.Dq up .
+This may be used to enable an interface after an
+.Dq Nm Cm down .
+It happens automatically when setting the first address on an interface.
+If the interface was reset when previously marked down,
+the hardware will be re-initialized.
+.El
+.Pp
+The following parameters are for ICMPv6 Neighbor Discovery Protocol.
+Note that the address family keyword
+.Dq Li inet6
+is needed for them:
+.Bl -tag -width indent
+.It Cm nud
+Perform network unreachability detection (NUD).
+.It Cm -nud
+Do not perform network unreachability detection (NUD).
+.It Cm ifdisabled
+Disable all IPv6 communication on the interface.
+.It Cm -ifdisabled
+Do not disable all IPv6 communication on the interface.
+.It Cm insecure
+Disable the processing of Secure Neighbor Discovery (SEND).
+.It Cm -insecure
+Do not disabled the processing of Secure Neighbor Discovery (SEND).
+.It Cm dad
+Perform duplicate address detection (DAD).
+.It Cm -dad
+Do not perform duplicate address detection (DAD).
+.It Cm replicated
+Modify duplicate address detection (DAD) protocol to expect that interface
+configuration is replicated at a network sleep proxy. Ignores certain NA
+messages and disables optimistic DAD.
+.It Cm -replicated
+Do not use modified duplicated address detection (DAD) protocol.
+.El
+.Pp
+The following parameters are specific to link aggregate interfaces:
+.Bl -tag -width indent
+.It Cm bonddev Ar iface
+If the interface is a bond pseudo device, associate physical interface
+.Ar iface
+with it. By default, the bond pseudo device is in LACP
+(Link Aggregation Control Protocol) mode (see \fBbondmode\fR below). In
+this mode, the device conforms to the IEEE 802.3ad Link Aggregation
+specification.
+.Pp
+If this is the first physical interface to be associated with the bond
+interface, the bond interface inherits the ethernet address from the
+physical interface. Physical interfaces that are added to the bond have
+their ethernet address re-programmed so that all members of the bond have
+the same ethernet address. If the physical interface is subsequently
+removed from the bond using
+.Fl bonddev ,
+a new ethernet address is chosen from the remaining interfaces, and all
+interfaces are re-programmed again with the new ethernet address. If no
+remaining interfaces exist, the bond interface's ethernet address is cleared.
+.Pp
+If the specified physical interface
+.Ar iface
+is not capable of having its ethernet address re-programmed, the
+.Cm bonddev
+command will fail.
+.Pp
+Once the physical interface
+.Ar iface
+is successfully associated with the bond interface, all received packets
+are diverted to the bond interface. The physical interface is no longer
+useable on its own, and remains that way until it is removed from the bond using
+.Fl bonddev .
+.Pp
+It is possible that the specified interface
+.Ar iface
+is not capable of aggregating, and may remain unused until the operating
+conditions change.
+.Pp
+The link status of the bond interface depends on the state of link aggregation.
+If no active partner is detected, the link status will remain inactive.
+.Pp
+To monitor the 802.3ad Link Aggregation state, use the
+.Fl b
+option.
+.Pp
+A physical interface that is associated with a vlan pseudo device cannot
+at the same time be associated with a bond pseudo device. A physical interface
+cannot be associated with more than one bond pseudo device at the same time.
+.Pp
+It is not possible to associate a bond with pseudo interfaces such as vlan.
+Only physical ethernet interfaces may be associated with a bond.
+.It Fl bonddev Ar iface
+If the interface is a bond pseudo device, disassociate the physical interface
+.Ar iface
+from it. Before the interface is removed from the bond, the bond device
+announces to the link partner that the interface is now individual and
+no longer aggregatable.
+If the physical
+.Ar iface
+is the last interface in the bond, the bond interface clears its link address.
+.It Cm bondmode Ar lacp | static
+If the interface is a bond pseudo device, this option will set the \fImode\fR
+on the bond interface. The two currently supported modes are
+.Ar lacp
+and
+.Ar static .
+The default mode is
+.Ar lacp .
+.Pp
+To enable static mode (and turn off LACP), specify
+.Ar static .
+In static mode, a member interface is made an active part of the
+link aggregate as long as the link status is active.
+.Pp
+To re-enable LACP mode, specify
+.Ar lacp .
+.El
+.Pp
+The following parameters are specific to IP tunnel interfaces,
+.Xr gif 4 :
+.Bl -tag -width indent
+.It Cm tunnel Ar src_addr dest_addr
+Configure the physical source and destination address for IP tunnel
+interfaces.
+The arguments
+.Ar src_addr
+and
+.Ar dest_addr
+are interpreted as the outer source/destination for the encapsulating
+IPv4/IPv6 header.
+.It Fl tunnel
+Unconfigure the physical source and destination address for IP tunnel
+interfaces previously configured with
+.Cm tunnel .
+.It Cm deletetunnel
+Another name for the
+.Fl tunnel
+parameter.
+.El
+.Pp
+The following parameters are specific to bridge interfaces:
+.Bl -tag -width indent
+.It Cm addm Ar interface
+Add the interface named by
+.Ar interface
+as a member of the bridge.
+The interface is put into promiscuous mode
+so that it can receive every packet sent on the network.
+.It Cm deletem Ar interface
+Remove the interface named by
+.Ar interface
+from the bridge.
+Promiscuous mode is disabled on the interface when
+it is removed from the bridge.
+.It Cm maxaddr Ar size
+Set the size of the bridge address cache to
+.Ar size .
+The default is 100 entries.
+.It Cm timeout Ar seconds
+Set the timeout of address cache entries to
+.Ar seconds
+seconds.
+If
+.Ar seconds
+is zero, then address cache entries will not be expired.
+The default is 240 seconds.
+.It Cm addr
+Display the addresses that have been learned by the bridge.
+.It Cm static Ar interface-name Ar address
+Add a static entry into the address cache pointing to
+.Ar interface-name .
+Static entries are never aged out of the cache or re-placed, even if the
+address is seen on a different interface.
+.It Cm deladdr Ar address
+Delete
+.Ar address
+from the address cache.
+.It Cm flush
+Delete all dynamically-learned addresses from the address cache.
+.It Cm flushall
+Delete all addresses, including static addresses, from the address cache.
+.It Cm discover Ar interface
+Mark an interface as a
+.Dq discovering
+interface.
+When the bridge has no address cache entry
+(either dynamic or static)
+for the destination address of a packet,
+the bridge will forward the packet to all
+member interfaces marked as
+.Dq discovering .
+This is the default for all interfaces added to a bridge.
+.It Cm -discover Ar interface
+Clear the
+.Dq discovering
+attribute on a member interface.
+For packets without the
+.Dq discovering
+attribute, the only packets forwarded on the interface are broadcast
+or multicast packets and packets for which the destination address
+is known to be on the interface's segment.
+.It Cm learn Ar interface
+Mark an interface as a
+.Dq learning
+interface.
+When a packet arrives on such an interface, the source
+address of the packet is entered into the address cache as being a
+destination address on the interface's segment.
+This is the default for all interfaces added to a bridge.
+.It Cm -learn Ar interface
+Clear the
+.Dq learning
+attribute on a member interface.
+.\".It Cm sticky Ar interface
+.\"Mark an interface as a
+.\".Dq sticky
+.\"interface.
+.\"Dynamically learned address entries are treated at static once entered into
+.\"the cache.
+.\"Sticky entries are never aged out of the cache or replaced, even if the
+.\"address is seen on a different interface.
+.\".It Cm -sticky Ar interface
+.\"Clear the
+.\".Dq sticky
+.\"attribute on a member interface.
+.\".It Cm private Ar interface
+.\"Mark an interface as a
+.\".Dq private
+.\"interface.
+.\"A private interface does not forward any traffic to any other port that is also
+.\"a private interface.
+.\".It Cm -private Ar interface
+.\"Clear the
+.\".Dq private
+.\"attribute on a member interface.
+.\".It Cm span Ar interface
+.\"Add the interface named by
+.\".Ar interface
+.\"as a span port on the bridge.
+.\"Span ports transmit a copy of every frame received by the bridge.
+.\"This is most useful for snooping a bridged network passively on
+.\"another host connected to one of the span ports of the bridge.
+.\".It Cm -span Ar interface
+.\"Delete the interface named by
+.\".Ar interface
+.\"from the list of span ports of the bridge.
+.It Cm stp Ar interface
+Enable Spanning Tree protocol on
+.Ar interface .
+The
+.Xr if_bridge 4
+driver has support for the IEEE 802.1D Spanning Tree protocol (STP).
+Spanning Tree is used to detect and remove loops in a network topology.
+.It Cm -stp Ar interface
+Disable Spanning Tree protocol on
+.Ar interface .
+This is the default for all interfaces added to a bridge.
+.\".It Cm edge Ar interface
+.\"Set
+.\".Ar interface
+.\"as an edge port.
+.\"An edge port connects directly to end stations cannot create bridging
+.\"loops in the network, this allows it to transition straight to forwarding.
+.\".It Cm -edge Ar interface
+.\"Disable edge status on
+.\".Ar interface .
+.\".It Cm autoedge Ar interface
+.\"Allow
+.\".Ar interface
+.\"to automatically detect edge status.
+.\"This is the default for all interfaces added to a bridge.
+.\".It Cm -autoedge Ar interface
+.\"Disable automatic edge status on
+.\".Ar interface .
+.\".It Cm ptp Ar interface
+.\"Set the
+.\".Ar interface
+.\"as a point to point link.
+.\"This is required for straight transitions to forwarding and
+.\"should be enabled on a direct link to another RSTP capable switch.
+.\".It Cm -ptp Ar interface
+.\"Disable point to point link status on
+.\".Ar interface .
+.\"This should be disabled for a half duplex link and for an interface
+.\"connected to a shared network segment,
+.\"like a hub or a wireless network.
+.\".It Cm autoptp Ar interface
+.\"Automatically detect the point to point status on
+.\".Ar interface
+.\"by checking the full duplex link status.
+.\"This is the default for interfaces added to the bridge.
+.\".It Cm -autoptp Ar interface
+.\"Disable automatic point to point link detection on
+.\".Ar interface .
+.It Cm maxage Ar seconds
+Set the time that a Spanning Tree protocol configuration is valid.
+The default is 20 seconds.
+The minimum is 6 seconds and the maximum is 40 seconds.
+.It Cm fwddelay Ar seconds
+Set the time that must pass before an interface begins forwarding
+packets when Spanning Tree is enabled.
+The default is 15 seconds.
+The minimum is 4 seconds and the maximum is 30 seconds.
+.It Cm hellotime Ar seconds
+Set the time between broadcasting of Spanning Tree protocol
+configuration messages.
+The hello time may only be changed when operating in legacy stp mode.
+The default is 2 seconds.
+The minimum is 1 second and the maximum is 2 seconds.
+.It Cm priority Ar value
+Set the bridge priority for Spanning Tree.
+The default is 32768.
+The minimum is 0 and the maximum is 61440.
+.\".It Cm proto Ar value
+.\"Set the Spanning Tree protocol.
+.\"The default is rstp.
+.\"The available options are stp and rstp.
+.\".It Cm holdcnt Ar value
+.\"Set the transmit hold count for Spanning Tree.
+.\"This is the number of packets transmitted before being rate limited.
+.\"The default is 6.
+.\"The minimum is 1 and the maximum is 10.
+.It Cm ifpriority Ar interface Ar value
+Set the Spanning Tree priority of
+.Ar interface
+to
+.Ar value .
+The default is 128.
+The minimum is 0 and the maximum is 240.
+.It Cm ifpathcost Ar interface Ar value
+Set the Spanning Tree path cost of
+.Ar interface
+to
+.Ar value .
+The default is calculated from the link speed.
+To change a previously selected path cost back to automatic, set the
+cost to 0.
+The minimum is 1 and the maximum is 200000000.
+.It Cm ifmaxaddr Ar interface Ar size
+Set the maximum number of hosts allowed from an interface, packets with unknown
+source addresses are dropped until an existing host cache entry expires or is
+removed.
+Set to 0 to disable.
+.It Cm hostfilter Ar interface Ar address
+Configure the bridge to accept incoming packet on the interface
+only if they match the given MAC address and IP address
+-- use the command twice to set both type of addresses.
+Other filtering restrictions apply.
+.It Cm -hostfilter Ar interface
+Allow traffic from any host on that interface.
+.El
+.Pp
+The following parameters are specific to vlan interfaces:
+.Bl -tag -width indent
+.It Cm vlan Ar vlan_tag
+Set the VLAN tag value to
+.Ar vlan_tag .
+This value is a 16-bit number which is used to create an 802.1Q
+VLAN header for packets sent from the
+.Xr vlan 4
+interface.
+Note that
+.Cm vlan
+and
+.Cm vlandev
+must both be set at the same time.
+.It Cm vlandev Ar iface
+Associate the physical interface
+.Ar iface
+with a
+.Xr vlan 4
+interface.
+Packets transmitted through the
+.Xr vlan 4
+interface will be
+diverted to the specified physical interface
+.Ar iface
+with 802.1Q VLAN encapsulation.
+Packets with 802.1Q encapsulation received
+by the parent interface with the correct VLAN tag will be diverted to
+the associated
+.Xr vlan 4
+pseudo-interface.
+The
+.Xr vlan 4
+interface is assigned a
+copy of the parent interface's flags and the parent's ethernet address.
+The
+.Cm vlandev
+and
+.Cm vlan
+must both be set at the same time.
+If the
+.Xr vlan 4
+interface already has
+a physical interface associated with it, this command will fail.
+To
+change the association to another physical interface, the existing
+association must be cleared first.
+.Pp
+Note: if the hardware tagging capability
+is set on the parent interface, the
+.Xr vlan 4
+pseudo
+interface's behavior changes:
+the
+.Xr vlan 4
+interface recognizes that the
+parent interface supports insertion and extraction of VLAN tags on its
+own (usually in firmware) and that it should pass packets to and from
+the parent unaltered.
+.It Fl vlandev Op Ar iface
+If the driver is a
+.Xr vlan 4
+pseudo device, disassociate the parent interface from it.
+This breaks the link between the
+.Xr vlan 4
+interface and its parent,
+clears its VLAN tag, flags and its link address and shuts the interface down.
+The
+.Ar iface
+argument is useless and hence deprecated.
+.El
+.Pp
+The
+.Nm
+utility displays the current configuration for a network interface
+when no optional parameters are supplied.
+If a protocol family is specified,
+.Nm
+will report only the details specific to that protocol family.
+.Pp
+If the
+.Fl m
+flag is passed before an interface name,
+.Nm
+will display the capability list and all
+of the supported media for the specified interface.
+.Pp
+If
+.Fl L
+flag is supplied, address lifetime is displayed for IPv6 addresses,
+as time offset string.
+.Pp
+Optionally, the
+.Fl a
+flag may be used instead of an interface name.
+This flag instructs
+.Nm
+to display information about all interfaces in the system.
+The
+.Fl d
+flag limits this to interfaces that are down, and
+.Fl u
+limits this to interfaces that are up.
+When no arguments are given,
+.Fl a
+is implied.
+.Pp
+The
+.Fl l
+flag may be used to list all available interfaces on the system, with
+no other additional information.
+Use of this flag is mutually exclusive
+with all other flags and commands, except for
+.Fl d
+(only list interfaces that are down)
+and
+.Fl u
+(only list interfaces that are up).
+.Pp
+The
+.Fl v
+flag may be used to get more verbose status for an interface.
+.Pp
+The
+.Fl C
+flag may be used to list all of the interface cloners available on
+the system, with no additional information.
+Use of this flag is mutually exclusive with all other flags and commands.
+.Pp
+The
+.Fl r
+flag may be used to show additional information related to the count of route references on the network interface.
+.Pp
+For bridge interfaces, the list of addresses learned by the bridge is not shown when displaying information about
+all interfaces except when the
+.Fl v
+flag is used.
+.Pp
+Only the super-user may modify the configuration of a network interface.
+.Sh NOTES
+The media selection system is relatively new and only some drivers support
+it (or have need for it).
+.Sh EXAMPLES
+Assign the IPv4 address
+.Li 192.0.2.10 ,
+with a network mask of
+.Li 255.255.255.0 ,
+to the interface
+.Li en0 :
+.Dl # ifconfig en0 inet 192.0.2.10 netmask 255.255.255.0
+.Pp
+Add the IPv4 address
+.Li 192.0.2.45 ,
+with the CIDR network prefix
+.Li /28 ,
+to the interface
+.Li en0 ,
+using
+.Cm add
+as a synonym for the canonical form of the option
+.Cm alias :
+.Dl # ifconfig en0 inet 192.0.2.45/28 add
+.Pp
+Remove the IPv4 address
+.Li 192.0.2.45
+from the interface
+.Li en0 :
+.Dl # ifconfig en0 inet 192.0.2.45 -alias
+.Pp
+Add the IPv6 address
+.Li 2001:DB8:DBDB::123/48
+to the interface
+.Li en0 :
+.Dl # ifconfig en0 inet6 2001:db8:bdbd::123 prefixlen 48 alias
+Note that lower case hexadecimal IPv6 addresses are acceptable.
+.Pp
+Remove the IPv6 address added in the above example,
+using the
+.Li /
+character as shorthand for the network prefix,
+and using
+.Cm delete
+as a synonym for the canonical form of the option
+.Fl alias :
+.Dl # ifconfig en0 inet6 2001:db8:bdbd::123/48 delete
+.Pp
+Configure the interface
+.Li en1 ,
+to use 100baseTX, full duplex Ethernet media options:
+.Dl # ifconfig en1 media 100baseTX mediaopt full-duplex
+.Pp
+Create the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 create
+.Pp
+Destroy the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 destroy
+.Sh DIAGNOSTICS
+Messages indicating the specified interface does not exist, the
+requested address is unknown, or the user is not privileged and
+tried to alter an interface's configuration.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr netintro 4 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.2 .
+.Sh BUGS
+Basic IPv6 node operation requires a link-local address on each
+interface configured for IPv6.
+Normally, such an address is automatically configured by the
+kernel on each interface added to the system; this behaviour may
+be disabled by setting the sysctl MIB variable
+.Va net.inet6.ip6.auto_linklocal
+to 0.
+.Pp
+If you delete such an address using
+.Nm ,
+the kernel may act very odd.
+Do this at your own risk.
diff --git a/network_cmds/ifconfig.tproj/ifconfig.c b/network_cmds/ifconfig.tproj/ifconfig.c
new file mode 100644
index 0000000..3449301
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifconfig.c
@@ -0,0 +1,2692 @@
+/*
+ * Copyright (c) 2009-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#ifndef __APPLE__
+#include <sys/module.h>
+#include <sys/linker.h>
+#endif
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_mib.h>
+#include <net/route.h>
+#include <net/pktsched/pktsched.h>
+#include <net/network_agent.h>
+
+/* IP */
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ifaddrs.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <syslog.h>
+
+#include "ifconfig.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+/*
+ * Since "struct ifreq" is composed of various union members, callers
+ * should pay special attention to interprete the value.
+ * (.e.g. little/big endian difference in the structure.)
+ */
+struct ifreq ifr;
+
+char name[IFNAMSIZ];
+int setaddr;
+int setmask;
+int doalias;
+int clearaddr;
+int newaddr = 1;
+int noload;
+int all;
+
+int bond_details = 0;
+int supmedia = 0;
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+int verbose = 1;
+int showrtref = 1;
+#else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+int verbose = 0;
+int showrtref = 0;
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+int printkeys = 0; /* Print keying material for interfaces. */
+
+static int ifconfig(int argc, char *const *argv, int iscreate,
+ const struct afswtch *afp);
+static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+ struct ifaddrs *ifa);
+static char *bytes_to_str(unsigned long long bytes);
+static char *bps_to_str(unsigned long long rate);
+static char *ns_to_str(unsigned long long nsec);
+static void tunnel_status(int s);
+static void clat46_addr(int s, char *name);
+static void nat64_status(int s, char *name);
+static void usage(void);
+static char *sched2str(unsigned int s);
+static char *tl2str(unsigned int s);
+static char *ift2str(unsigned int t, unsigned int f, unsigned int sf);
+static char *iffunct2str(u_int32_t functional_type);
+
+static struct afswtch *af_getbyname(const char *name);
+static struct afswtch *af_getbyfamily(int af);
+static void af_other_status(int);
+
+static struct option *opts = NULL;
+
+void
+opt_register(struct option *p)
+{
+ p->next = opts;
+ opts = p;
+}
+
+static void
+usage(void)
+{
+ char options[1024];
+ struct option *p;
+
+ /* XXX not right but close enough for now */
+ options[0] = '\0';
+ for (p = opts; p != NULL; p = p->next) {
+ strlcat(options, p->opt_usage, sizeof(options));
+ strlcat(options, " ", sizeof(options));
+ }
+
+ fprintf(stderr,
+ "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
+ " [parameters]\n"
+ " ifconfig interface create\n"
+ " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
+ " ifconfig -l [-d] [-u] [address_family]\n"
+ " ifconfig %s[-d] [-m] [-u] [-v]\n",
+ options, options, options);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, namesonly, downonly, uponly;
+ const struct afswtch *afp = NULL;
+ int ifindex;
+ struct ifaddrs *ifap, *ifa;
+ struct ifreq paifr;
+ const struct sockaddr_dl *sdl;
+ char options[1024], *cp;
+ const char *ifname;
+ struct option *p;
+ size_t iflen;
+
+ all = downonly = uponly = namesonly = noload = 0;
+
+ /* Parse leading line options */
+#ifndef __APPLE__
+ strlcpy(options, "adklmnuv", sizeof(options));
+#else
+ strlcpy(options, "abdlmruv", sizeof(options));
+#endif
+ for (p = opts; p != NULL; p = p->next)
+ strlcat(options, p->opt, sizeof(options));
+ while ((c = getopt(argc, argv, options)) != -1) {
+ switch (c) {
+ case 'a': /* scan all interfaces */
+ all++;
+ break;
+ case 'b': /* bond detailed output */
+ bond_details++;
+ break;
+ case 'd': /* restrict scan to "down" interfaces */
+ downonly++;
+ break;
+#ifndef __APPLE__
+ case 'k':
+ printkeys++;
+ break;
+#endif
+ case 'l': /* scan interface names only */
+ namesonly++;
+ break;
+ case 'm': /* show media choices in status */
+ supmedia = 1;
+ break;
+#ifndef __APPLE__
+ case 'n': /* suppress module loading */
+ noload++;
+ break;
+#endif
+ case 'r':
+ showrtref++;
+ break;
+ case 'u': /* restrict scan to "up" interfaces */
+ uponly++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ for (p = opts; p != NULL; p = p->next)
+ if (p->opt[0] == c) {
+ p->cb(optarg);
+ break;
+ }
+ if (p == NULL)
+ usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* -l cannot be used with -a or -q or -m or -b */
+ if (namesonly &&
+ (all || supmedia || bond_details))
+ usage();
+
+ /* nonsense.. */
+ if (uponly && downonly)
+ usage();
+
+ /* no arguments is equivalent to '-a' */
+ if (!namesonly && argc < 1)
+ all = 1;
+
+ /* -a and -l allow an address family arg to limit the output */
+ if (all || namesonly) {
+ if (argc > 1)
+ usage();
+
+ ifname = NULL;
+ if (argc == 1) {
+ afp = af_getbyname(*argv);
+ if (afp == NULL)
+ usage();
+ if (afp->af_name != NULL)
+ argc--, argv++;
+ /* leave with afp non-zero */
+ }
+ } else {
+ /* not listing, need an argument */
+ if (argc < 1)
+ usage();
+
+ ifname = *argv;
+ argc--, argv++;
+
+#ifdef notdef
+ /* check and maybe load support for this interface */
+ ifmaybeload(ifname);
+#endif
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0) {
+ /*
+ * NOTE: We must special-case the `create' command
+ * right here as we would otherwise fail when trying
+ * to find the interface.
+ */
+ if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
+ strcmp(argv[0], "plumb") == 0)) {
+ iflen = strlcpy(name, ifname, sizeof(name));
+ if (iflen >= sizeof(name))
+ errx(1, "%s: cloning name too long",
+ ifname);
+ ifconfig(argc, argv, 1, NULL);
+ exit(0);
+ }
+ errx(1, "interface %s does not exist", ifname);
+ }
+ }
+
+ /* Check for address family */
+ if (argc > 0) {
+ afp = af_getbyname(*argv);
+ if (afp != NULL)
+ argc--, argv++;
+ }
+
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ cp = NULL;
+ ifindex = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ memset(&paifr, 0, sizeof(paifr));
+ strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
+ if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
+ memcpy(&paifr.ifr_addr, ifa->ifa_addr,
+ ifa->ifa_addr->sa_len);
+ }
+
+ if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family == AF_LINK)
+ sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
+ else
+ sdl = NULL;
+ if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
+ continue;
+ iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
+ if (iflen >= sizeof(name)) {
+ warnx("%s: interface name too long, skipping",
+ ifa->ifa_name);
+ continue;
+ }
+ cp = ifa->ifa_name;
+
+ if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
+ continue;
+ if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ ifindex++;
+ /*
+ * Are we just listing the interfaces?
+ */
+ if (namesonly) {
+ if (ifindex > 1)
+ printf(" ");
+ fputs(name, stdout);
+ continue;
+ }
+
+ if (argc > 0)
+ ifconfig(argc, argv, 0, afp);
+ else
+ status(afp, sdl, ifa);
+ }
+ if (namesonly)
+ printf("\n");
+ freeifaddrs(ifap);
+
+ exit(0);
+}
+
+static struct afswtch *afs = NULL;
+
+void
+af_register(struct afswtch *p)
+{
+ p->af_next = afs;
+ afs = p;
+}
+
+static struct afswtch *
+af_getbyname(const char *name)
+{
+ struct afswtch *afp;
+
+ for (afp = afs; afp != NULL; afp = afp->af_next)
+ if (strcmp(afp->af_name, name) == 0)
+ return afp;
+ return NULL;
+}
+
+static struct afswtch *
+af_getbyfamily(int af)
+{
+ struct afswtch *afp;
+
+ for (afp = afs; afp != NULL; afp = afp->af_next)
+ if (afp->af_af == af)
+ return afp;
+ return NULL;
+}
+
+static void
+af_other_status(int s)
+{
+ struct afswtch *afp;
+ uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+ memset(afmask, 0, sizeof(afmask));
+ for (afp = afs; afp != NULL; afp = afp->af_next) {
+ if (afp->af_other_status == NULL)
+ continue;
+ if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+ continue;
+ afp->af_other_status(s);
+ setbit(afmask, afp->af_af);
+ }
+}
+
+static void
+af_all_tunnel_status(int s)
+{
+ struct afswtch *afp;
+ uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+ memset(afmask, 0, sizeof(afmask));
+ for (afp = afs; afp != NULL; afp = afp->af_next) {
+ if (afp->af_status_tunnel == NULL)
+ continue;
+ if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+ continue;
+ afp->af_status_tunnel(s);
+ setbit(afmask, afp->af_af);
+ }
+}
+
+static struct cmd *cmds = NULL;
+
+void
+cmd_register(struct cmd *p)
+{
+ p->c_next = cmds;
+ cmds = p;
+}
+
+static const struct cmd *
+cmd_lookup(const char *name)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ const struct cmd *p;
+
+ for (p = cmds; p != NULL; p = p->c_next)
+ if (strcmp(name, p->c_name) == 0)
+ return p;
+ return NULL;
+#undef N
+}
+
+struct callback {
+ callback_func *cb_func;
+ void *cb_arg;
+ struct callback *cb_next;
+};
+static struct callback *callbacks = NULL;
+
+void
+callback_register(callback_func *func, void *arg)
+{
+ struct callback *cb;
+
+ cb = malloc(sizeof(struct callback));
+ if (cb == NULL)
+ errx(1, "unable to allocate memory for callback");
+ cb->cb_func = func;
+ cb->cb_arg = arg;
+ cb->cb_next = callbacks;
+ callbacks = cb;
+}
+
+/* specially-handled commands */
+static void setifaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
+
+static void setifdstaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifdstaddr_cmd =
+ DEF_CMD("ifdstaddr", 0, setifdstaddr);
+
+static int
+ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp)
+{
+ const struct afswtch *nafp;
+ struct callback *cb;
+ int ret, s;
+
+ strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+top:
+ if (afp == NULL)
+ afp = af_getbyname("inet");
+ ifr.ifr_addr.sa_family =
+ afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
+ AF_INET : afp->af_af;
+
+ if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
+
+ while (argc > 0) {
+ const struct cmd *p;
+
+ p = cmd_lookup(*argv);
+ if (p == NULL) {
+ /*
+ * Not a recognized command, choose between setting
+ * the interface address and the dst address.
+ */
+ p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
+ }
+ if (p->c_u.c_func || p->c_u.c_func2) {
+ if (iscreate && !p->c_iscloneop) {
+ /*
+ * Push the clone create callback so the new
+ * device is created and can be used for any
+ * remaining arguments.
+ */
+ cb = callbacks;
+ if (cb == NULL)
+ errx(1, "internal error, no callback");
+ callbacks = cb->cb_next;
+ cb->cb_func(s, cb->cb_arg);
+ iscreate = 0;
+ /*
+ * Handle any address family spec that
+ * immediately follows and potentially
+ * recreate the socket.
+ */
+ nafp = af_getbyname(*argv);
+ if (nafp != NULL) {
+ argc--, argv++;
+ if (nafp != afp) {
+ close(s);
+ afp = nafp;
+ goto top;
+ }
+ }
+ }
+ if (p->c_parameter == NEXTARG) {
+ if (argv[1] == NULL)
+ errx(1, "'%s' requires argument",
+ p->c_name);
+ p->c_u.c_func(argv[1], 0, s, afp);
+ argc--, argv++;
+ } else if (p->c_parameter == OPTARG) {
+ p->c_u.c_func(argv[1], 0, s, afp);
+ if (argv[1] != NULL)
+ argc--, argv++;
+ } else if (p->c_parameter == NEXTARG2) {
+ if (argc < 3)
+ errx(1, "'%s' requires 2 arguments",
+ p->c_name);
+ p->c_u.c_func2(argv[1], argv[2], s, afp);
+ argc -= 2, argv += 2;
+ } else if (p->c_parameter == VAARGS) {
+ ret = p->c_u.c_funcv(argc - 1, argv + 1, s, afp);
+ if (ret < 0)
+ errx(1, "'%s' command error",
+ p->c_name);
+ argc -= ret, argv += ret;
+ } else {
+ p->c_u.c_func(*argv, p->c_parameter, s, afp);
+ }
+ }
+ argc--, argv++;
+ }
+
+ /*
+ * Do any post argument processing required by the address family.
+ */
+ if (afp->af_postproc != NULL)
+ afp->af_postproc(s, afp);
+ /*
+ * Do deferred callbacks registered while processing
+ * command-line arguments.
+ */
+ for (cb = callbacks; cb != NULL; cb = cb->cb_next)
+ cb->cb_func(s, cb->cb_arg);
+ /*
+ * Do deferred operations.
+ */
+ if (clearaddr) {
+ if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
+ warnx("interface %s cannot change %s addresses!",
+ name, afp->af_name);
+ clearaddr = 0;
+ }
+ }
+ if (clearaddr) {
+ strlcpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
+ ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
+ if (ret < 0) {
+ if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
+ /* means no previous address for interface */
+ } else
+ Perror("ioctl (SIOCDIFADDR)");
+ }
+ }
+ if (newaddr) {
+ if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
+ warnx("interface %s cannot change %s addresses!",
+ name, afp->af_name);
+ newaddr = 0;
+ }
+ }
+ if (newaddr && (setaddr || setmask)) {
+ strlcpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+ if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
+ Perror("ioctl (SIOCAIFADDR)");
+ }
+
+ close(s);
+ return(0);
+}
+
+/*ARGSUSED*/
+static void
+setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
+{
+ if (afp->af_getaddr == NULL)
+ return;
+ /*
+ * Delay the ioctl to set the interface addr until flags are all set.
+ * The address interpretation may depend on the flags,
+ * and the flags may change when the address is set.
+ */
+ setaddr++;
+ if (doalias == 0 && afp->af_af != AF_LINK)
+ clearaddr = 1;
+ afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
+}
+
+static void
+settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
+{
+ struct addrinfo *srcres, *dstres;
+ int ecode;
+
+ if (afp->af_settunnel == NULL) {
+ warn("address family %s does not support tunnel setup",
+ afp->af_name);
+ return;
+ }
+
+ if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
+ errx(1, "error in parsing address string: %s",
+ gai_strerror(ecode));
+
+ if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
+ errx(1, "error in parsing address string: %s",
+ gai_strerror(ecode));
+
+ if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
+ errx(1,
+ "source and destination address families do not match");
+
+ afp->af_settunnel(s, srcres, dstres);
+
+ freeaddrinfo(srcres);
+ freeaddrinfo(dstres);
+}
+
+/* ARGSUSED */
+static void
+deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
+{
+
+ if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
+ err(1, "SIOCDIFPHYADDR");
+}
+
+static void
+setifnetmask(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getaddr != NULL) {
+ setmask++;
+ afp->af_getaddr(addr, MASK);
+ }
+}
+
+static void
+setifbroadaddr(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getaddr != NULL)
+ afp->af_getaddr(addr, DSTADDR);
+}
+
+static void
+setifipdst(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ const struct afswtch *inet;
+
+ inet = af_getbyname("inet");
+ if (inet == NULL)
+ return;
+ inet->af_getaddr(addr, DSTADDR);
+ clearaddr = 0;
+ newaddr = 0;
+}
+
+static void
+notealias(const char *addr, int param, int s, const struct afswtch *afp)
+{
+#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
+ if (setaddr && doalias == 0 && param < 0)
+ if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
+ bcopy((caddr_t)rqtosa(af_addreq),
+ (caddr_t)rqtosa(af_ridreq),
+ rqtosa(af_addreq)->sa_len);
+ doalias = param;
+ if (param < 0) {
+ clearaddr = 1;
+ newaddr = 0;
+ } else
+ clearaddr = 0;
+#undef rqtosa
+}
+
+/*ARGSUSED*/
+static void
+setifdstaddr(const char *addr, int param __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getaddr != NULL)
+ afp->af_getaddr(addr, DSTADDR);
+}
+
+/*
+ * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
+ * of the ifreq structure, which may confuse other parts of ifconfig.
+ * Make a private copy so we can avoid that.
+ */
+static void
+setifflags(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ struct ifreq my_ifr;
+ int flags;
+
+ bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
+
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
+ Perror("ioctl (SIOCGIFFLAGS)");
+ exit(1);
+ }
+ strlcpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name));
+ flags = my_ifr.ifr_flags;
+
+ if (value < 0) {
+ value = -value;
+ flags &= ~value;
+ } else
+ flags |= value;
+ my_ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
+ Perror(vname);
+}
+
+void
+setifcap(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ int flags;
+
+ if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
+ Perror("ioctl (SIOCGIFCAP)");
+ exit(1);
+ }
+ flags = ifr.ifr_curcap;
+ if (value < 0) {
+ value = -value;
+ flags &= ~value;
+ } else
+ flags |= value;
+ flags &= ifr.ifr_reqcap;
+ ifr.ifr_reqcap = flags;
+ if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+static void
+setifmetric(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ ifr.ifr_metric = atoi(val);
+ if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
+ warn("ioctl (set metric)");
+}
+
+static void
+setifmtu(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = atoi(val);
+ if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
+ warn("ioctl (set mtu)");
+}
+
+#ifndef __APPLE__
+static void
+setifname(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ char *newname;
+
+ newname = strdup(val);
+ if (newname == NULL) {
+ warn("no memory to set ifname");
+ return;
+ }
+ ifr.ifr_data = newname;
+ if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
+ warn("ioctl (set name)");
+ free(newname);
+ return;
+ }
+ strlcpy(name, newname, sizeof(name));
+ free(newname);
+}
+#endif
+
+static void
+setrouter(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ if (afp->af_setrouter == NULL) {
+ warn("address family %s does not support router mode",
+ afp->af_name);
+ return;
+ }
+
+ afp->af_setrouter(s, value);
+}
+
+static int
+routermode(int argc, char *const *argv, int s, const struct afswtch *afp)
+{
+ return (*afp->af_routermode)(s, argc, argv);
+}
+
+
+static void
+setifdesc(const char *val, int dummy __unused, int s, const struct afswtch *afp)
+{
+ struct if_descreq ifdr;
+
+ bzero(&ifdr, sizeof (ifdr));
+ strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
+ ifdr.ifdr_len = strlen(val);
+ strlcpy((char *)ifdr.ifdr_desc, val, sizeof (ifdr.ifdr_desc));
+
+ if (ioctl(s, SIOCSIFDESC, (caddr_t)&ifdr) < 0) {
+ warn("ioctl (set desc)");
+ }
+}
+
+static void
+settbr(const char *val, int dummy __unused, int s, const struct afswtch *afp)
+{
+ struct if_linkparamsreq iflpr;
+ long double bps;
+ u_int64_t rate;
+ u_int32_t percent = 0;
+ char *cp;
+
+ errno = 0;
+ bzero(&iflpr, sizeof (iflpr));
+ strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
+
+ bps = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+ rate = (u_int64_t)bps;
+ if (cp != NULL) {
+ if (!strcmp(cp, "b") || !strcmp(cp, "bps")) {
+ ; /* nothing */
+ } else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbps")) {
+ rate *= 1000;
+ } else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbps")) {
+ rate *= 1000 * 1000;
+ } else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbps")) {
+ rate *= 1000 * 1000 * 1000;
+ } else if (!strcmp(cp, "%")) {
+ percent = rate;
+ if (percent == 0 || percent > 100) {
+ printf("Value out of range '%s'", val);
+ return;
+ }
+ } else if (*cp != '\0') {
+ printf("Unknown unit '%s'", cp);
+ return;
+ }
+ }
+ iflpr.iflpr_output_tbr_rate = rate;
+ iflpr.iflpr_output_tbr_percent = percent;
+ if (ioctl(s, SIOCSIFLINKPARAMS, &iflpr) < 0 &&
+ errno != ENOENT && errno != ENXIO && errno != ENODEV) {
+ warn("ioctl (set link params)");
+ } else if (errno == ENXIO) {
+ printf("TBR cannot be set on %s\n", name);
+ } else if (errno == 0 && rate == 0) {
+ printf("%s: TBR is now disabled\n", name);
+ } else if (errno == ENODEV) {
+ printf("%s: requires absolute TBR rate\n", name);
+ } else if (percent != 0) {
+ printf("%s: TBR rate set to %u%% of effective link rate\n",
+ name, percent);
+ } else {
+ printf("%s: TBR rate set to %s\n", name, bps_to_str(rate));
+ }
+}
+
+static int
+get_int64(uint64_t *i, char const *s)
+{
+ char *cp;
+ *i = strtol(s, &cp, 10);
+ if (cp == s || errno != 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+get_int32(uint32_t *i, char const *s)
+{
+ char *cp;
+ *i = strtol(s, &cp, 10);
+ if (cp == s || errno != 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+get_percent(double *d, const char *s)
+{
+ char *cp;
+ *d = strtod(s, &cp) / (double)100;
+ if (*d == HUGE_VALF || *d == HUGE_VALL) {
+ return (-1);
+ }
+ if (*d == 0.0 || (*cp != '\0' && strcmp(cp, "%") != 0)) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+get_percent_fixed_point(uint32_t *i, const char *s)
+{
+ double p;
+
+ if (get_percent(&p, s) != 0){
+ return (-1);
+ }
+
+ *i = p * IF_NETEM_PARAMS_PSCALE;
+ return (0);
+}
+
+static int
+netem_parse_args(struct if_netem_params *p, int argc, char *const *argv)
+{
+ int argc_saved = argc;
+ uint64_t bandwitdh = 0;
+ uint32_t latency = 0, jitter = 0;
+ uint32_t corruption = 0;
+ uint32_t duplication = 0;
+ uint32_t loss_p_gr_gl = 0, loss_p_gr_bl = 0, loss_p_bl_br = 0,
+ loss_p_bl_gr = 0, loss_p_br_bl = 0;
+ uint32_t reordering = 0;
+
+ bzero(p, sizeof (*p));
+
+ /* take out "input"/"output" */
+ argc--, argv++;
+
+ for ( ; argc > 0; ) {
+ if (strcmp(*argv, "bandwidth") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_int64(&bandwitdh, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "corruption") == 0) {
+ argc--, argv++;
+ if (argc <= 0 ||
+ get_percent_fixed_point(&corruption, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "delay") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_int32(&latency, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ if (argc > 0 && get_int32(&jitter, *argv) == 0) {
+ argc--, argv++;
+ }
+ } else if (strcmp(*argv, "duplication") == 0) {
+ argc--, argv++;
+ if (argc <= 0 ||
+ get_percent_fixed_point(&duplication, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ return (-1);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "loss") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_gl, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ /* we may have all 5 probs, use naive model if not */
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_bl, *argv) != 0) {
+ continue;
+ }
+ /* if more than p_gr_gl, then should have all probs */
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_br, *argv) != 0) {
+ err(1, "Invalid value '%s' for p_bl_br", *argv);
+ }
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_gr, *argv) != 0) {
+ err(1, "Invalid value '%s' for p_bl_gr", *argv);
+ }
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_br_bl, *argv) != 0) {
+ err(1, "Invalid value '%s' for p_br_bl", *argv);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "reordering") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&reordering, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ } else {
+ return (-1);
+ }
+ }
+
+ if (corruption > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "corruption percentage > 100%%");
+ }
+
+ if (duplication > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "duplication percentage > 100%%");
+ }
+
+ if (duplication > 0 && latency == 0) {
+ /* we need to insert dup'ed packet with latency */
+ err(1, "duplication needs latency param");
+ }
+
+ if (latency > 1000) {
+ err(1, "latency %dms too big (> 1 sec)", latency);
+ }
+
+ if (jitter * 3 > latency) {
+ err(1, "jitter %dms too big (latency %dms)", jitter, latency);
+ }
+
+ /* if gr_gl == 0 (no loss), other prob should all be zero */
+ if (loss_p_gr_gl == 0 &&
+ (loss_p_gr_bl != 0 || loss_p_bl_br != 0 || loss_p_bl_gr != 0 ||
+ loss_p_br_bl != 0)) {
+ err(1, "loss params not all zero when gr_gl is zero");
+ }
+
+ /* check state machine transition prob integrity */
+ if (loss_p_gr_gl > IF_NETEM_PARAMS_PSCALE ||
+ /* gr_gl = IF_NETEM_PARAMS_PSCALE for total loss */
+ loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_bl_br > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_br_bl > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_gr_gl + loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_bl_br + loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "loss params too big");
+ }
+
+ if (reordering > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "reordering percentage > 100%%");
+ }
+
+ p->ifnetem_bandwidth_bps = bandwitdh;
+ p->ifnetem_latency_ms = latency;
+ p->ifnetem_jitter_ms = jitter;
+ p->ifnetem_corruption_p = corruption;
+ p->ifnetem_duplication_p = duplication;
+ p->ifnetem_loss_p_gr_gl = loss_p_gr_gl;
+ p->ifnetem_loss_p_gr_bl = loss_p_gr_bl;
+ p->ifnetem_loss_p_bl_br = loss_p_bl_br;
+ p->ifnetem_loss_p_bl_gr = loss_p_bl_gr;
+ p->ifnetem_loss_p_br_bl = loss_p_br_bl;
+ p->ifnetem_reordering_p = reordering;
+
+ return (argc_saved - argc);
+}
+
+void
+print_netem_params(struct if_netem_params *p, const char *desc)
+{
+ struct if_netem_params zero_params;
+ double pscale = IF_NETEM_PARAMS_PSCALE / 100;
+ bzero(&zero_params, sizeof (zero_params));
+
+ if (memcmp(p, &zero_params, sizeof (zero_params)) == 0) {
+ printf("%s NetEm Disabled\n\n", desc);
+ } else {
+ printf(
+ "%s NetEm Parameters\n"
+ "\tbandwidth rate %llubps\n"
+ "\tdelay latency %dms\n"
+ "\t jitter %dms\n",
+ desc, p->ifnetem_bandwidth_bps,
+ p->ifnetem_latency_ms, p->ifnetem_jitter_ms);
+ if (p->ifnetem_loss_p_gr_bl == 0 &&
+ p->ifnetem_loss_p_bl_br == 0 &&
+ p->ifnetem_loss_p_bl_gr == 0 &&
+ p->ifnetem_loss_p_br_bl == 0) {
+ printf(
+ "\tloss %.3f%%\n",
+ (double) p->ifnetem_loss_p_gr_gl / pscale);
+ } else {
+ printf(
+ "\tloss GAP_RECV -> GAP_LOSS %.3f%%\n"
+ "\t GAP_RECV -> BURST_LOSS %.3f%%\n"
+ "\t BURST_LOSS -> BURST_RECV %.3f%%\n"
+ "\t BURST_LOSS -> GAP_RECV %.3f%%\n"
+ "\t BURST_RECV -> BURST_LOSS %.3f%%\n",
+ (double) p->ifnetem_loss_p_gr_gl / pscale,
+ (double) p->ifnetem_loss_p_gr_bl / pscale,
+ (double) p->ifnetem_loss_p_bl_br / pscale,
+ (double) p->ifnetem_loss_p_bl_gr / pscale,
+ (double) p->ifnetem_loss_p_br_bl / pscale);
+ }
+ printf(
+ "\tcorruption %.3f%%\n"
+ "\treordering %.3f%%\n\n",
+ (double) p->ifnetem_corruption_p / pscale,
+ (double) p->ifnetem_reordering_p / pscale);
+ }
+}
+
+static int
+setnetem(int argc, char *const *argv, int s, const struct afswtch *afp)
+{
+ struct if_linkparamsreq iflpr;
+ struct if_netem_params input_params, output_params;
+ int ret = 0, error = 0;
+
+ bzero(&iflpr, sizeof (iflpr));
+ bzero(&input_params, sizeof (input_params));
+ bzero(&output_params, sizeof (output_params));
+
+ if (argc > 1) {
+ if (strcmp(argv[0], "input") == 0) {
+ ret = netem_parse_args(&input_params, argc, argv);
+ } else if (strcmp(argv[0], "output") == 0) {
+ ret = netem_parse_args(&output_params, argc, argv);
+ } else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
+ goto bad_args;
+ } else {
+ fprintf(stderr, "uknown option %s\n", argv[0]);
+ goto bad_args;
+ }
+ if (ret < 0) {
+ goto bad_args;
+ }
+ }
+
+ errno = 0;
+ strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
+ error = ioctl(s, SIOCGIFLINKPARAMS, &iflpr);
+ if (error < 0) {
+ warn("ioctl (get link params)");
+ }
+
+ if (argc == 0) {
+ print_netem_params(&iflpr.iflpr_input_netem, "Input");
+ print_netem_params(&iflpr.iflpr_output_netem, "Output");
+ return (0);
+ } else if (argc == 1) {
+ if (strcmp(argv[0], "input") == 0) {
+ bzero(&iflpr.iflpr_input_netem,
+ sizeof (iflpr.iflpr_input_netem));
+ } else if (strcmp(argv[0], "output") == 0) {
+ bzero(&iflpr.iflpr_output_netem,
+ sizeof (iflpr.iflpr_output_netem));
+ } else {
+ fprintf(stderr, "uknown option %s\n", argv[0]);
+ goto bad_args;
+ }
+ printf("%s: netem is now disabled for %s\n", name, argv[0]);
+ ret = 1;
+ } else {
+ if (strcmp(argv[0], "input") == 0) {
+ iflpr.iflpr_input_netem = input_params;
+ } else if (strcmp(argv[0], "output") == 0) {
+ iflpr.iflpr_output_netem = output_params;
+ }
+ }
+
+ error = ioctl(s, SIOCSIFLINKPARAMS, &iflpr);
+ if (error < 0 && errno != ENOENT && errno != ENXIO && errno != ENODEV) {
+ warn("ioctl (set link params)");
+ } else if (errno == ENXIO) {
+ printf("netem cannot be set on %s\n", name);
+ } else {
+ printf("%s: netem configured\n", name);
+ }
+
+ return (ret);
+bad_args:
+ fprintf(stderr, "Usage:\n"
+ "\tTo enable/set netem params\n"
+ "\t\tnetem <input|output>\n"
+ "\t\t [ bandwidth BIT_PER_SEC ]\n"
+ "\t\t [ delay DELAY_MSEC [ JITTER_MSEC ] ]\n"
+ "\t\t [ loss PERCENTAGE ]\n"
+ "\t\t [ duplication PERCENTAGE ]\n"
+ "\t\t [ reordering PERCENTAGE ]\n\n"
+ "\tTo disable <input|output> netem\n"
+ "\t\tnetem <input|output>\n\n"
+ "\tTo show current settings\n"
+ "\t\tnetem\n\n");
+ return (-1);
+}
+
+static void
+setthrottle(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct if_throttlereq iftr;
+ char *cp;
+
+ errno = 0;
+ bzero(&iftr, sizeof (iftr));
+ strlcpy(iftr.ifthr_name, name, sizeof (iftr.ifthr_name));
+
+ iftr.ifthr_level = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+
+ if (ioctl(s, SIOCSIFTHROTTLE, &iftr) < 0 && errno != ENXIO) {
+ warn("ioctl (set throttling level)");
+ } else if (errno == ENXIO) {
+ printf("throttling level cannot be set on %s\n", name);
+ } else {
+ printf("%s: throttling level set to %d\n", name,
+ iftr.ifthr_level);
+ }
+}
+
+static void
+setdisableoutput(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct ifreq ifr;
+ char *cp;
+ errno = 0;
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+
+ ifr.ifr_ifru.ifru_disable_output = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+
+ if (ioctl(s, SIOCSIFDISABLEOUTPUT, &ifr) < 0 && errno != ENXIO) {
+ warn("ioctl set disable output");
+ } else if (errno == ENXIO) {
+ printf("output thread can not be disabled on %s\n", name);
+ } else {
+ printf("output %s on %s\n",
+ ((ifr.ifr_ifru.ifru_disable_output == 0) ? "enabled" : "disabled"),
+ name);
+ }
+}
+
+static void
+setlog(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ char *cp;
+
+ errno = 0;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ ifr.ifr_log.ifl_level = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+ ifr.ifr_log.ifl_flags = (IFRLOGF_DLIL|IFRLOGF_FAMILY|IFRLOGF_DRIVER|
+ IFRLOGF_FIRMWARE);
+
+ if (ioctl(s, SIOCSIFLOG, &ifr) < 0)
+ warn("ioctl (set logging parameters)");
+}
+
+void
+setcl2k(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_2kcl = value;
+
+ if (ioctl(s, SIOCSIF2KCL, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+void
+setexpensive(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_expensive = value;
+
+ if (ioctl(s, SIOCSIFEXPENSIVE, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+#ifdef SIOCSIFCONSTRAINED
+void
+setconstrained(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_constrained = value;
+
+ if (ioctl(s, SIOCSIFCONSTRAINED, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+#endif
+
+static void
+setifmpklog(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_mpk_log = value;
+
+ if (ioctl(s, SIOCSIFMPKLOG, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+void
+settimestamp(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (value == 0) {
+ if (ioctl(s, SIOCSIFTIMESTAMPDISABLE, (caddr_t)&ifr) < 0)
+ Perror(vname);
+ } else {
+ if (ioctl(s, SIOCSIFTIMESTAMPENABLE, (caddr_t)&ifr) < 0)
+ Perror(vname);
+ }
+}
+
+void
+setecnmode(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ char *cp;
+
+ if (strcmp(val, "default") == 0)
+ ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DEFAULT;
+ else if (strcmp(val, "enable") == 0)
+ ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_ENABLE;
+ else if (strcmp(val, "disable") == 0)
+ ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DISABLE;
+ else {
+ ifr.ifr_ifru.ifru_ecn_mode = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid ECN mode value '%s'", val);
+ return;
+ }
+ }
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCSECNMODE, (caddr_t)&ifr) < 0)
+ Perror("ioctl(SIOCSECNMODE)");
+}
+
+void
+setprobeconnectivity(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_probe_connectivity = value;
+
+ if (ioctl(s, SIOCSIFPROBECONNECTIVITY, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+#if defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED)
+
+void
+setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ u_long ioc;
+
+#if (DEBUG | DEVELOPMENT)
+ printf("%s(%s, %s)\n", __func__, cmd, arg);
+#endif /* (DEBUG | DEVELOPMENT) */
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (strcmp(cmd, "mode") == 0) {
+ ioc = SIOCSQOSMARKINGMODE;
+
+ if (strcmp(arg, "fastlane") == 0)
+ ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE;
+ else if (strcmp(arg, "rfc4594") == 0)
+ ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_RFC4594;
+ else if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "off") == 0)
+ ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
+ else
+ err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
+ } else if (strcmp(cmd, "enabled") == 0) {
+ ioc = SIOCSQOSMARKINGENABLED;
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ ifr.ifr_qosmarking_enabled = 1;
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ ifr.ifr_qosmarking_enabled = 0;
+ else
+ err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
+ } else {
+ err(EX_USAGE, "qosmarking takes mode or enabled");
+ }
+
+ if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
+ err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
+}
+
+void
+setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ warnx("### fastlane is obsolete, use qosmarking ###");
+
+ if (strcmp(cmd, "capable") == 0) {
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ setqosmarking("mode", "fastlane", s, afp);
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ setqosmarking("mode", "off", s, afp);
+ else
+ err(EX_USAGE, "bad value for fastlane %s", cmd);
+ } else if (strcmp(cmd, "enable") == 0) {
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ setqosmarking("enabled", "1", s, afp);
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ setqosmarking("enabled", "0", s, afp);
+ else
+ err(EX_USAGE, "bad value for fastlane %s", cmd);
+ } else {
+ err(EX_USAGE, "fastlane takes capable or enable");
+ }
+}
+
+#else /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
+
+void
+setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ int value;
+ u_long ioc;
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (strcmp(cmd, "capable") == 0)
+ ioc = SIOCSFASTLANECAPABLE;
+ else if (strcmp(cmd, "enable") == 0)
+ ioc = SIOCSFASTLEENABLED;
+ else
+ err(EX_USAGE, "fastlane takes capable or enabled");
+
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ value = 1;
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ value = 0;
+ else
+ err(EX_USAGE, "bad value for fastlane %s", cmd);
+
+ if (ioc == SIOCSFASTLANECAPABLE)
+ ifr.ifr_fastlane_capable = value;
+ else
+ ifr.ifr_fastlane_enabled = value;
+
+ if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
+ err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
+}
+
+
+void
+setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ if (strcmp(cmd, "mode") == 0) {
+ if (strcmp(arg, "fastlane") == 0)
+ setfastlane("capable", "on", s, afp);
+ else if (strcmp(arg, "none") == 0)
+ setfastlane("capable", "off", s, afp);
+ else
+ err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
+ } else if (strcmp(cmd, "enabled") == 0) {
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ setfastlane("enable", "on", s, afp);
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ setfastlane("enable", "off", s, afp);
+ else
+ err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
+ } else {
+ err(EX_USAGE, "qosmarking takes mode or enabled");
+ }
+}
+
+#endif /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
+
+void
+setlowpowermode(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_low_power_mode = !!value;
+
+ if (ioctl(s, SIOCSIFLOWPOWER, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+struct str2num {
+ const char *str;
+ uint32_t num;
+};
+
+static struct str2num subfamily_str2num[] = {
+ { .str = "any", .num = IFRTYPE_SUBFAMILY_ANY },
+ { .str = "USB", .num = IFRTYPE_SUBFAMILY_USB },
+ { .str = "Bluetooth", .num = IFRTYPE_SUBFAMILY_BLUETOOTH },
+ { .str = "Wi-Fi", .num = IFRTYPE_SUBFAMILY_WIFI },
+ { .str = "wifi", .num = IFRTYPE_SUBFAMILY_WIFI },
+ { .str = "Thunderbolt", .num = IFRTYPE_SUBFAMILY_THUNDERBOLT },
+ { .str = "reserverd", .num = IFRTYPE_SUBFAMILY_RESERVED },
+ { .str = "intcoproc", .num = IFRTYPE_SUBFAMILY_INTCOPROC },
+ { .str = "QuickRelay", .num = IFRTYPE_SUBFAMILY_QUICKRELAY },
+ { .str = "Default", .num = IFRTYPE_SUBFAMILY_DEFAULT },
+ { .str = NULL, .num = 0 },
+};
+
+static uint32_t
+get_num_from_str(struct str2num* str2nums, const char *str)
+{
+ struct str2num *str2num = str2nums;
+
+ while (str2num != NULL && str2num->str != NULL) {
+ if (strcasecmp(str2num->str, str) == 0) {
+ return str2num->num;
+ }
+ str2num++;
+ }
+ return 0;
+}
+
+static void
+setifsubfamily(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+
+ char *endptr;
+ uint32_t subfamily = strtoul(val, &endptr, 0);
+ if (*endptr != 0) {
+ subfamily = get_num_from_str(subfamily_str2num, val);
+ if (subfamily == 0) {
+ return;
+ }
+ }
+
+ ifr.ifr_type.ift_subfamily = subfamily;
+ if (ioctl(s, SIOCSIFSUBFAMILY, (caddr_t)&ifr) < 0)
+ warn("ioctl(SIOCSIFSUBFAMILY)");
+}
+
+void
+setifavailability(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_interface_state.valid_bitmask = IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID;
+ if (value == 0) {
+ ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE;
+ } else {
+ ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_AVAILABLE;
+ }
+ if (ioctl(s, SIOCSIFINTERFACESTATE, (caddr_t)&ifr) < 0)
+ warn("ioctl(SIOCSIFINTERFACESTATE)");
+}
+
+static void
+show_routermode(int s)
+{
+ struct afswtch *afp;
+
+ afp = af_getbyname("inet");
+ if (afp != NULL) {
+ (*afp->af_routermode)(s, 0, NULL);
+ }
+}
+
+static void
+show_routermode6(void)
+{
+ struct afswtch *afp;
+ static int s = -1;
+
+ afp = af_getbyname("inet6");
+ if (afp != NULL) {
+ if (s < 0) {
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return;
+ }
+ }
+ (*afp->af_routermode)(s, 0, NULL);
+ }
+}
+
+#define IFFBITS \
+"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
+"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
+"\20MULTICAST"
+
+#define IFEFBITS \
+"\020\1AUTOCONFIGURING\4PROBE_CONNECTIVITY\5FASTLN_CAP\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \
+"\12VLAN\13BOND\14ARPLL\15CLAT46\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \
+"\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \
+"\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\33CHANNEL_DRV\34CA" \
+"\35SENDLIST\36DIRECTLINK\37FASTLN_ON\40UPDOWNCHANGE"
+
+#define IFXFBITS \
+"\020\1WOL\2TIMESTAMP\3NOAUTONX\4LEGACY\5TXLOWINET\6RXLOWINET\7ALLOCKPI" \
+"\10LOWPOWER\11MPKLOG\12CONSTRAINED"
+
+#define IFCAPBITS \
+"\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \
+"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS\13CHANNEL_IO\14HW_TIMESTAMP\15SW_TIMESTAMP" \
+"\16PARTIAL_CSUM\17ZEROINVERT_CSUM"
+
+#define IFRLOGF_BITS \
+"\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE"
+
+/*
+ * Print the status of the interface. If an address family was
+ * specified, show only it; otherwise, show them all.
+ */
+static void
+status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+ struct ifaddrs *ifa)
+{
+ struct ifaddrs *ift;
+ int allfamilies, s;
+ struct ifstat ifs;
+ struct if_descreq ifdr;
+ struct if_linkparamsreq iflpr;
+ int mib[6];
+ struct ifmibdata_supplemental ifmsupp;
+ size_t miblen = sizeof(struct ifmibdata_supplemental);
+ u_int64_t eflags = 0;
+ u_int64_t xflags = 0;
+ int curcap = 0;
+
+ if (afp == NULL) {
+ allfamilies = 1;
+ afp = af_getbyname("inet");
+ } else
+ allfamilies = 0;
+
+ ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+ if (s < 0)
+ err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
+
+ printf("%s: ", name);
+ printb("flags", ifa->ifa_flags, IFFBITS);
+ if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
+ if (ifr.ifr_metric)
+ printf(" metric %d", ifr.ifr_metric);
+ if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
+ printf(" mtu %d", ifr.ifr_mtu);
+ if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1)
+ printf(" rtref %d", ifr.ifr_route_refcnt);
+ if (verbose) {
+ unsigned int ifindex = if_nametoindex(ifa->ifa_name);
+ if (ifindex != 0)
+ printf(" index %u", ifindex);
+ }
+#ifdef SIOCGIFCONSTRAINED
+ // Constrained is stored in if_xflags which isn't exposed directly
+ if (ioctl(s, SIOCGIFCONSTRAINED, (caddr_t)&ifr) == 0 &&
+ ifr.ifr_constrained != 0) {
+ printf(" constrained");
+ }
+#endif
+ putchar('\n');
+
+ if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 &&
+ (eflags = ifr.ifr_eflags) != 0) {
+ printb("\teflags", eflags, IFEFBITS);
+ putchar('\n');
+ }
+
+ if (verbose && ioctl(s, SIOCGIFXFLAGS, (caddr_t)&ifr) != -1 &&
+ (xflags = ifr.ifr_xflags) != 0) {
+ printb("\txflags", xflags, IFXFBITS);
+ putchar('\n');
+ }
+
+ if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
+ if (ifr.ifr_curcap != 0) {
+ curcap = ifr.ifr_curcap;
+ printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
+ putchar('\n');
+ }
+ if (supmedia && ifr.ifr_reqcap != 0) {
+ printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
+ putchar('\n');
+ }
+ }
+
+ tunnel_status(s);
+
+ for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
+ if (ift->ifa_addr == NULL)
+ continue;
+ if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
+ continue;
+ if (allfamilies) {
+ const struct afswtch *p;
+ p = af_getbyfamily(ift->ifa_addr->sa_family);
+ if (p != NULL && p->af_status != NULL)
+ p->af_status(s, ift);
+ } else if (afp->af_af == ift->ifa_addr->sa_family)
+ afp->af_status(s, ift);
+ }
+
+/* Print CLAT46 address */
+ clat46_addr(s, name);
+
+/* Print NAT64 prefix */
+ nat64_status(s, name);
+
+#if 0
+ if (allfamilies || afp->af_af == AF_LINK) {
+ const struct afswtch *lafp;
+
+ /*
+ * Hack; the link level address is received separately
+ * from the routing information so any address is not
+ * handled above. Cobble together an entry and invoke
+ * the status method specially.
+ */
+ lafp = af_getbyname("lladdr");
+ if (lafp != NULL) {
+ info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
+ lafp->af_status(s, &info);
+ }
+ }
+#endif
+ if (allfamilies)
+ af_other_status(s);
+ else if (afp->af_other_status != NULL)
+ afp->af_other_status(s);
+
+ strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+ if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
+ printf("%s", ifs.ascii);
+
+ /* The rest is for when verbose is set; if not set, we're done */
+ if (!verbose)
+ goto done;
+
+ if (ioctl(s, SIOCGIFTYPE, &ifr) != -1) {
+ char *c = ift2str(ifr.ifr_type.ift_type,
+ ifr.ifr_type.ift_family, ifr.ifr_type.ift_subfamily);
+ if (c != NULL)
+ printf("\ttype: %s\n", c);
+ }
+
+ if (verbose > 1) {
+ if (ioctl(s, SIOCGIFFUNCTIONALTYPE, &ifr) != -1) {
+ char *c = iffunct2str(ifr.ifr_functional_type);
+ if (c != NULL)
+ printf("\tfunctional type: %s\n", c);
+ }
+ }
+ {
+ struct if_agentidsreq ifar;
+ memset(&ifar, 0, sizeof(ifar));
+
+ strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
+
+ if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != -1) {
+ if (ifar.ifar_count != 0) {
+ ifar.ifar_uuids = calloc(ifar.ifar_count, sizeof(uuid_t));
+ if (ifar.ifar_uuids != NULL) {
+ if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != 1) {
+ for (int agent_i = 0; agent_i < ifar.ifar_count; agent_i++) {
+ struct netagent_req nar;
+ memset(&nar, 0, sizeof(nar));
+
+ uuid_copy(nar.netagent_uuid, ifar.ifar_uuids[agent_i]);
+
+ if (ioctl(s, SIOCGIFAGENTDATA, &nar) != 1) {
+ printf("\tagent domain:%s type:%s flags:0x%x desc:\"%s\"\n",
+ nar.netagent_domain, nar.netagent_type,
+ nar.netagent_flags, nar.netagent_desc);
+ }
+ }
+ }
+ free(ifar.ifar_uuids);
+ }
+ }
+ }
+ }
+
+ if (ioctl(s, SIOCGIFLINKQUALITYMETRIC, &ifr) != -1) {
+ int lqm = ifr.ifr_link_quality_metric;
+ if (verbose > 1) {
+ printf("\tlink quality: %d ", lqm);
+ if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("(off)");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("(unknown)");
+ else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
+ lqm <= IFNET_LQM_THRESH_BAD)
+ printf("(bad)");
+ else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
+ lqm <= IFNET_LQM_THRESH_POOR)
+ printf("(poor)");
+ else if (lqm > IFNET_LQM_THRESH_POOR &&
+ lqm <= IFNET_LQM_THRESH_GOOD)
+ printf("(good)");
+ else
+ printf("(?)");
+ printf("\n");
+ } else if (lqm > IFNET_LQM_THRESH_UNKNOWN) {
+ printf("\tlink quality: %d ", lqm);
+ if (lqm <= IFNET_LQM_THRESH_BAD)
+ printf("(bad)");
+ else if (lqm <= IFNET_LQM_THRESH_POOR)
+ printf("(poor)");
+ else if (lqm <= IFNET_LQM_THRESH_GOOD)
+ printf("(good)");
+ else
+ printf("(?)");
+ printf("\n");
+ }
+ }
+
+ {
+ if (ioctl(s, SIOCGIFINTERFACESTATE, &ifr) != -1) {
+ printf("\tstate");
+ if (ifr.ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_RRC_STATE_VALID) {
+ uint8_t rrc_state = ifr.ifr_interface_state.rrc_state;
+
+ printf(" rrc: %u ", rrc_state);
+ if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
+ printf("(connected)");
+ else if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_IDLE)
+ printf("(idle)");
+ else
+ printf("(?)");
+ }
+ if (ifr.ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
+ uint8_t ifavail = ifr.ifr_interface_state.interface_availability;
+
+ printf(" availability: %u ", ifavail);
+ if (ifavail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
+ printf("(true)");
+ else if (ifavail == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
+ printf("(false)");
+ else
+ printf("(?)");
+ } else {
+ printf(" availability: (not valid)");
+ }
+ if (verbose > 1 &&
+ ifr.ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_LQM_STATE_VALID) {
+ int8_t lqm = ifr.ifr_interface_state.lqm_state;
+
+ printf(" lqm: %d", lqm);
+
+ if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("(off)");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("(unknown)");
+ else if (lqm == IFNET_LQM_THRESH_BAD)
+ printf("(bad)");
+ else if (lqm == IFNET_LQM_THRESH_POOR)
+ printf("(poor)");
+ else if (lqm == IFNET_LQM_THRESH_GOOD)
+ printf("(good)");
+ else
+ printf("(?)");
+ }
+ }
+ printf("\n");
+ }
+
+ bzero(&iflpr, sizeof (iflpr));
+ strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
+ if (ioctl(s, SIOCGIFLINKPARAMS, &iflpr) != -1) {
+ u_int64_t ibw_max = iflpr.iflpr_input_bw.max_bw;
+ u_int64_t ibw_eff = iflpr.iflpr_input_bw.eff_bw;
+ u_int64_t obw_max = iflpr.iflpr_output_bw.max_bw;
+ u_int64_t obw_eff = iflpr.iflpr_output_bw.eff_bw;
+ u_int64_t obw_tbr = iflpr.iflpr_output_tbr_rate;
+ u_int32_t obw_pct = iflpr.iflpr_output_tbr_percent;
+ u_int64_t ilt_max = iflpr.iflpr_input_lt.max_lt;
+ u_int64_t ilt_eff = iflpr.iflpr_input_lt.eff_lt;
+ u_int64_t olt_max = iflpr.iflpr_output_lt.max_lt;
+ u_int64_t olt_eff = iflpr.iflpr_output_lt.eff_lt;
+
+
+ if (eflags & IFEF_TXSTART) {
+ u_int32_t flags = iflpr.iflpr_flags;
+ u_int32_t sched = iflpr.iflpr_output_sched;
+ struct if_throttlereq iftr;
+
+ printf("\tscheduler: %s%s ",
+ (flags & IFLPRF_ALTQ) ? "ALTQ_" : "",
+ sched2str(sched));
+ if (flags & IFLPRF_DRVMANAGED)
+ printf("(driver managed)");
+ printf("\n");
+
+ bzero(&iftr, sizeof (iftr));
+ strlcpy(iftr.ifthr_name, name,
+ sizeof (iftr.ifthr_name));
+ if (ioctl(s, SIOCGIFTHROTTLE, &iftr) != -1 &&
+ iftr.ifthr_level != IFNET_THROTTLE_OFF)
+ printf("\tthrottling: level %d (%s)\n",
+ iftr.ifthr_level, tl2str(iftr.ifthr_level));
+ }
+
+ if (obw_tbr != 0 && obw_eff > obw_tbr)
+ obw_eff = obw_tbr;
+
+ if (ibw_max != 0 || obw_max != 0) {
+ if (ibw_max == obw_max && ibw_eff == obw_eff &&
+ ibw_max == ibw_eff && obw_tbr == 0) {
+ printf("\tlink rate: %s\n",
+ bps_to_str(ibw_max));
+ } else {
+ printf("\tuplink rate: %s [eff] / ",
+ bps_to_str(obw_eff));
+ if (obw_tbr != 0) {
+ if (obw_pct == 0)
+ printf("%s [tbr] / ",
+ bps_to_str(obw_tbr));
+ else
+ printf("%s [tbr %u%%] / ",
+ bps_to_str(obw_tbr),
+ obw_pct);
+ }
+ printf("%s", bps_to_str(obw_max));
+ if (obw_tbr != 0)
+ printf(" [max]");
+ printf("\n");
+ if (ibw_eff == ibw_max) {
+ printf("\tdownlink rate: %s\n",
+ bps_to_str(ibw_max));
+ } else {
+ printf("\tdownlink rate: "
+ "%s [eff] / ", bps_to_str(ibw_eff));
+ printf("%s [max]\n",
+ bps_to_str(ibw_max));
+ }
+ }
+ } else if (obw_tbr != 0) {
+ printf("\tuplink rate: %s [tbr]\n",
+ bps_to_str(obw_tbr));
+ }
+
+ if (ilt_max != 0 || olt_max != 0) {
+ if (ilt_max == olt_max && ilt_eff == olt_eff &&
+ ilt_max == ilt_eff) {
+ printf("\tlink latency: %s\n",
+ ns_to_str(ilt_max));
+ } else {
+ if (olt_max != 0 && olt_eff == olt_max) {
+ printf("\tuplink latency: %s\n",
+ ns_to_str(olt_max));
+ } else if (olt_max != 0) {
+ printf("\tuplink latency: "
+ "%s [eff] / ", ns_to_str(olt_eff));
+ printf("%s [max]\n",
+ ns_to_str(olt_max));
+ }
+ if (ilt_max != 0 && ilt_eff == ilt_max) {
+ printf("\tdownlink latency: %s\n",
+ ns_to_str(ilt_max));
+ } else if (ilt_max != 0) {
+ printf("\tdownlink latency: "
+ "%s [eff] / ", ns_to_str(ilt_eff));
+ printf("%s [max]\n",
+ ns_to_str(ilt_max));
+ }
+ }
+ }
+ }
+
+ /* Common OID prefix */
+ mib[0] = CTL_NET;
+ mib[1] = PF_LINK;
+ mib[2] = NETLINK_GENERIC;
+ mib[3] = IFMIB_IFDATA;
+ mib[4] = if_nametoindex(name);
+ mib[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(mib, 6, &ifmsupp, &miblen, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ if (ifmsupp.ifmd_data_extended.ifi_alignerrs != 0) {
+ printf("\tunaligned pkts: %llu\n",
+ ifmsupp.ifmd_data_extended.ifi_alignerrs);
+ }
+ if (ifmsupp.ifmd_data_extended.ifi_dt_bytes != 0) {
+ printf("\tdata milestone interval: %s\n",
+ bytes_to_str(ifmsupp.ifmd_data_extended.ifi_dt_bytes));
+ }
+
+ bzero(&ifdr, sizeof (ifdr));
+ strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
+ if (ioctl(s, SIOCGIFDESC, &ifdr) != -1 && ifdr.ifdr_len) {
+ printf("\tdesc: %s\n", ifdr.ifdr_desc);
+ }
+
+ if (ioctl(s, SIOCGIFLOG, &ifr) != -1 && ifr.ifr_log.ifl_level) {
+ printf("\tlogging: level %d ", ifr.ifr_log.ifl_level);
+ printb("facilities", ifr.ifr_log.ifl_flags, IFRLOGF_BITS);
+ putchar('\n');
+ }
+
+ if (ioctl(s, SIOCGIFDELEGATE, &ifr) != -1 && ifr.ifr_delegated) {
+ char delegatedif[IFNAMSIZ+1];
+ if (if_indextoname(ifr.ifr_delegated, delegatedif) != NULL)
+ printf("\teffective interface: %s\n", delegatedif);
+ }
+
+ if (ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) {
+ if (ifr.ifr_start_delay_qlen > 0 &&
+ ifr.ifr_start_delay_timeout > 0) {
+ printf("\ttxstart qlen: %u packets "
+ "timeout: %u microseconds\n",
+ ifr.ifr_start_delay_qlen,
+ ifr.ifr_start_delay_timeout/1000);
+ }
+ }
+#if defined(IFCAP_HW_TIMESTAMP) && defined(IFCAP_SW_TIMESTAMP)
+ if ((curcap & (IFCAP_HW_TIMESTAMP | IFCAP_SW_TIMESTAMP)) &&
+ ioctl(s, SIOCGIFTIMESTAMPENABLED, &ifr) != -1) {
+ printf("\ttimestamp: %s\n",
+ (ifr.ifr_intval != 0) ? "enabled" : "disabled");
+ }
+#endif
+#if defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE)
+ if (ioctl(s, SIOCGQOSMARKINGENABLED, &ifr) != -1) {
+ printf("\tqosmarking enabled: %s mode: ",
+ ifr.ifr_qosmarking_enabled ? "yes" : "no");
+ if (ioctl(s, SIOCGQOSMARKINGMODE, &ifr) != -1) {
+ switch (ifr.ifr_qosmarking_mode) {
+ case IFRTYPE_QOSMARKING_FASTLANE:
+ printf("fastlane\n");
+ break;
+ case IFRTYPE_QOSMARKING_RFC4594:
+ printf("RFC4594\n");
+ break;
+ case IFRTYPE_QOSMARKING_MODE_NONE:
+ printf("none\n");
+ break;
+ default:
+ printf("unknown (%u)\n", ifr.ifr_qosmarking_mode);
+ break;
+ }
+ }
+ }
+#endif /* defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) */
+
+ if (ioctl(s, SIOCGIFLOWPOWER, &ifr) != -1) {
+ printf("\tlow power mode: %s\n",
+ (ifr.ifr_low_power_mode != 0) ? "enabled" : "disabled");
+ }
+ if (ioctl(s, SIOCGIFMPKLOG, &ifr) != -1) {
+ printf("\tmulti layer packet logging (mpklog): %s\n",
+ (ifr.ifr_mpk_log != 0) ? "enabled" : "disabled");
+ }
+ show_routermode(s);
+ show_routermode6();
+
+done:
+ close(s);
+ return;
+}
+
+#define KILOBYTES 1024
+#define MEGABYTES (KILOBYTES * KILOBYTES)
+#define GIGABYTES (KILOBYTES * KILOBYTES * KILOBYTES)
+
+static char *
+bytes_to_str(unsigned long long bytes)
+{
+ static char buf[32];
+ const char *u;
+ long double n = bytes, t;
+
+ if (bytes >= GIGABYTES) {
+ t = n / GIGABYTES;
+ u = "GB";
+ } else if (n >= MEGABYTES) {
+ t = n / MEGABYTES;
+ u = "MB";
+ } else if (n >= KILOBYTES) {
+ t = n / KILOBYTES;
+ u = "KB";
+ } else {
+ t = n;
+ u = "bytes";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %s", t, u);
+ return (buf);
+}
+
+#define GIGABIT_PER_SEC 1000000000 /* gigabit per second */
+#define MEGABIT_PER_SEC 1000000 /* megabit per second */
+#define KILOBIT_PER_SEC 1000 /* kilobit per second */
+
+static char *
+bps_to_str(unsigned long long rate)
+{
+ static char buf[32];
+ const char *u;
+ long double n = rate, t;
+
+ if (rate >= GIGABIT_PER_SEC) {
+ t = n / GIGABIT_PER_SEC;
+ u = "Gbps";
+ } else if (n >= MEGABIT_PER_SEC) {
+ t = n / MEGABIT_PER_SEC;
+ u = "Mbps";
+ } else if (n >= KILOBIT_PER_SEC) {
+ t = n / KILOBIT_PER_SEC;
+ u = "Kbps";
+ } else {
+ t = n;
+ u = "bps ";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+#define NSEC_PER_SEC 1000000000 /* nanosecond per second */
+#define USEC_PER_SEC 1000000 /* microsecond per second */
+#define MSEC_PER_SEC 1000 /* millisecond per second */
+
+static char *
+ns_to_str(unsigned long long nsec)
+{
+ static char buf[32];
+ const char *u;
+ long double n = nsec, t;
+
+ if (nsec >= NSEC_PER_SEC) {
+ t = n / NSEC_PER_SEC;
+ u = "sec ";
+ } else if (n >= USEC_PER_SEC) {
+ t = n / USEC_PER_SEC;
+ u = "msec";
+ } else if (n >= MSEC_PER_SEC) {
+ t = n / MSEC_PER_SEC;
+ u = "usec";
+ } else {
+ t = n;
+ u = "nsec";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+static void
+tunnel_status(int s)
+{
+ af_all_tunnel_status(s);
+}
+
+static void
+clat46_addr(int s, char * if_name)
+{
+ struct if_clat46req ifr;
+ char buf[MAXHOSTNAMELEN];
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifclat46_name, if_name, sizeof(ifr.ifclat46_name));
+
+ if (ioctl(s, SIOCGIFCLAT46ADDR, &ifr) < 0) {
+ if (errno != ENOENT)
+ syslog(LOG_WARNING, "ioctl (SIOCGIFCLAT46ADDR): %d", errno);
+ return;
+ }
+
+ if (inet_ntop(AF_INET6, &ifr.ifclat46_addr.v6_address, buf, sizeof(buf)) != NULL)
+ printf("\tinet6 %s prefixlen %d clat46\n",
+ buf, ifr.ifclat46_addr.v6_prefixlen);
+}
+
+static void
+nat64_status(int s, char * if_name)
+{
+ int i;
+ struct if_nat64req ifr;
+ char buf[MAXHOSTNAMELEN];
+
+ bzero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifnat64_name, if_name, sizeof(ifr.ifnat64_name));
+
+ if (ioctl(s, SIOCGIFNAT64PREFIX, &ifr) < 0) {
+ if (errno != ENOENT)
+ syslog(LOG_WARNING, "ioctl(SIOCGIFNAT64PREFIX): %d", errno);
+ return;
+ }
+
+ for (i = 0; i < NAT64_MAX_NUM_PREFIXES; i++) {
+ if (ifr.ifnat64_prefixes[i].prefix_len > 0) {
+ inet_ntop(AF_INET6, &ifr.ifnat64_prefixes[i].ipv6_prefix, buf, sizeof(buf));
+ printf("\tnat64 prefix %s prefixlen %d\n",
+ buf, ifr.ifnat64_prefixes[i].prefix_len << 3);
+ }
+ }
+}
+
+void
+Perror(const char *cmd)
+{
+ switch (errno) {
+
+ case ENXIO:
+ errx(1, "%s: no such interface", cmd);
+ break;
+
+ case EPERM:
+ errx(1, "%s: permission denied", cmd);
+ break;
+
+ default:
+ err(1, "%s", cmd);
+ }
+}
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+void
+printb(const char *s, unsigned v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}
+
+#ifndef __APPLE__
+void
+ifmaybeload(const char *name)
+{
+#define MOD_PREFIX_LEN 3 /* "if_" */
+ struct module_stat mstat;
+ int fileid, modid;
+ char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
+ const char *cp;
+
+ /* loading suppressed by the user */
+ if (noload)
+ return;
+
+ /* trim the interface number off the end */
+ strlcpy(ifname, name, sizeof(ifname));
+ for (dp = ifname; *dp != 0; dp++)
+ if (isdigit(*dp)) {
+ *dp = 0;
+ break;
+ }
+
+ /* turn interface and unit into module name */
+ strlcpy(ifkind, "if_", sizeof(ifkind));
+ strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
+ sizeof(ifkind) - MOD_PREFIX_LEN);
+
+ /* scan files in kernel */
+ mstat.version = sizeof(struct module_stat);
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ /* scan modules in file */
+ for (modid = kldfirstmod(fileid); modid > 0;
+ modid = modfnext(modid)) {
+ if (modstat(modid, &mstat) < 0)
+ continue;
+ /* strip bus name if present */
+ if ((cp = strchr(mstat.name, '/')) != NULL) {
+ cp++;
+ } else {
+ cp = mstat.name;
+ }
+ /* already loaded? */
+ if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
+ strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
+ return;
+ }
+ }
+
+ /* not present, we should try to load it */
+ kldload(ifkind);
+}
+#endif
+
+static struct cmd basic_cmds[] = {
+ DEF_CMD("up", IFF_UP, setifflags),
+ DEF_CMD("down", -IFF_UP, setifflags),
+ DEF_CMD("arp", -IFF_NOARP, setifflags),
+ DEF_CMD("-arp", IFF_NOARP, setifflags),
+ DEF_CMD("debug", IFF_DEBUG, setifflags),
+ DEF_CMD("-debug", -IFF_DEBUG, setifflags),
+#ifdef IFF_PPROMISC
+ DEF_CMD("promisc", IFF_PPROMISC, setifflags),
+ DEF_CMD("-promisc", -IFF_PPROMISC, setifflags),
+#endif /* IFF_PPROMISC */
+ DEF_CMD("add", IFF_UP, notealias),
+ DEF_CMD("alias", IFF_UP, notealias),
+ DEF_CMD("-alias", -IFF_UP, notealias),
+ DEF_CMD("delete", -IFF_UP, notealias),
+ DEF_CMD("remove", -IFF_UP, notealias),
+#ifdef notdef
+#define EN_SWABIPS 0x1000
+ DEF_CMD("swabips", EN_SWABIPS, setifflags),
+ DEF_CMD("-swabips", -EN_SWABIPS, setifflags),
+#endif
+ DEF_CMD_ARG("netmask", setifnetmask),
+ DEF_CMD_ARG("metric", setifmetric),
+ DEF_CMD_ARG("broadcast", setifbroadaddr),
+ DEF_CMD_ARG("ipdst", setifipdst),
+ DEF_CMD_ARG2("tunnel", settunnel),
+ DEF_CMD("-tunnel", 0, deletetunnel),
+ DEF_CMD("deletetunnel", 0, deletetunnel),
+ DEF_CMD("link0", IFF_LINK0, setifflags),
+ DEF_CMD("-link0", -IFF_LINK0, setifflags),
+ DEF_CMD("link1", IFF_LINK1, setifflags),
+ DEF_CMD("-link1", -IFF_LINK1, setifflags),
+ DEF_CMD("link2", IFF_LINK2, setifflags),
+ DEF_CMD("-link2", -IFF_LINK2, setifflags),
+#ifdef IFF_MONITOR
+ DEF_CMD("monitor", IFF_MONITOR:, setifflags),
+ DEF_CMD("-monitor", -IFF_MONITOR, setifflags),
+#endif /* IFF_MONITOR */
+ DEF_CMD("mpklog", 1, setifmpklog),
+ DEF_CMD("-mpklog", 0, setifmpklog),
+#ifdef IFF_STATICARP
+ DEF_CMD("staticarp", IFF_STATICARP, setifflags),
+ DEF_CMD("-staticarp", -IFF_STATICARP, setifflags),
+#endif /* IFF_STATICARP */
+#ifdef IFCAP_RXCSUM
+ DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
+ DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap),
+#endif /* IFCAP_RXCSUM */
+#ifdef IFCAP_TXCSUM
+ DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
+ DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap),
+#endif /* IFCAP_TXCSUM */
+#ifdef IFCAP_NETCONS
+ DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
+ DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap),
+#endif /* IFCAP_NETCONS */
+#ifdef IFCAP_POLLING
+ DEF_CMD("polling", IFCAP_POLLING, setifcap),
+ DEF_CMD("-polling", -IFCAP_POLLING, setifcap),
+#endif /* IFCAP_POLLING */
+#ifdef IFCAP_TSO
+ DEF_CMD("tso", IFCAP_TSO, setifcap),
+ DEF_CMD("-tso", -IFCAP_TSO, setifcap),
+#endif /* IFCAP_TSO */
+#ifdef IFCAP_LRO
+ DEF_CMD("lro", IFCAP_LRO, setifcap),
+ DEF_CMD("-lro", -IFCAP_LRO, setifcap),
+#endif /* IFCAP_LRO */
+#ifdef IFCAP_WOL
+ DEF_CMD("wol", IFCAP_WOL, setifcap),
+ DEF_CMD("-wol", -IFCAP_WOL, setifcap),
+#endif /* IFCAP_WOL */
+#ifdef IFCAP_WOL_UCAST
+ DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap),
+ DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap),
+#endif /* IFCAP_WOL_UCAST */
+#ifdef IFCAP_WOL_MCAST
+ DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap),
+ DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap),
+#endif /* IFCAP_WOL_MCAST */
+#ifdef IFCAP_WOL_MAGIC
+ DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap),
+ DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap),
+#endif /* IFCAP_WOL_MAGIC */
+ DEF_CMD("normal", -IFF_LINK0, setifflags),
+ DEF_CMD("compress", IFF_LINK0, setifflags),
+ DEF_CMD("noicmp", IFF_LINK1, setifflags),
+ DEF_CMD_ARG("mtu", setifmtu),
+#ifdef notdef
+ DEF_CMD_ARG("name", setifname),
+#endif /* notdef */
+#ifdef IFCAP_AV
+ DEF_CMD("av", IFCAP_AV, setifcap),
+ DEF_CMD("-av", -IFCAP_AV, setifcap),
+#endif /* IFCAP_AV */
+ DEF_CMD("router", 1, setrouter),
+ DEF_CMD("-router", 0, setrouter),
+ DEF_CMD_VA("routermode", routermode),
+ DEF_CMD_ARG("desc", setifdesc),
+ DEF_CMD_ARG("tbr", settbr),
+ DEF_CMD_VA("netem", setnetem),
+ DEF_CMD_ARG("throttle", setthrottle),
+ DEF_CMD_ARG("log", setlog),
+ DEF_CMD("cl2k", 1, setcl2k),
+ DEF_CMD("-cl2k", 0, setcl2k),
+ DEF_CMD("expensive", 1, setexpensive),
+ DEF_CMD("-expensive", 0, setexpensive),
+#ifdef SIOCSIFCONSTRAINED
+ DEF_CMD("constrained", 1, setconstrained),
+ DEF_CMD("-constrained", 0, setconstrained),
+#endif
+ DEF_CMD("timestamp", 1, settimestamp),
+ DEF_CMD("-timestamp", 0, settimestamp),
+ DEF_CMD_ARG("ecn", setecnmode),
+ DEF_CMD_ARG2("fastlane", setfastlane),
+ DEF_CMD_ARG2("qosmarking", setqosmarking),
+ DEF_CMD_ARG("disable_output", setdisableoutput),
+ DEF_CMD("probe_connectivity", 1, setprobeconnectivity),
+ DEF_CMD("-probe_connectivity", 0, setprobeconnectivity),
+ DEF_CMD("lowpowermode", 1, setlowpowermode),
+ DEF_CMD("-lowpowermode", 0, setlowpowermode),
+ DEF_CMD_ARG("subfamily", setifsubfamily),
+ DEF_CMD("available", 1, setifavailability),
+ DEF_CMD("-available", 0, setifavailability),
+ DEF_CMD("unavailable", 0, setifavailability),
+};
+
+static __constructor void
+ifconfig_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(basic_cmds); i++)
+ cmd_register(&basic_cmds[i]);
+#undef N
+}
+
+static char *
+sched2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case PKTSCHEDT_NONE:
+ c = "NONE";
+ break;
+ case PKTSCHEDT_FQ_CODEL:
+ c = "FQ_CODEL";
+ break;
+ default:
+ c = "UNKNOWN";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+tl2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case IFNET_THROTTLE_OFF:
+ c = "off";
+ break;
+ case IFNET_THROTTLE_OPPORTUNISTIC:
+ c = "opportunistic";
+ break;
+ default:
+ c = "unknown";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+ift2str(unsigned int t, unsigned int f, unsigned int sf)
+{
+ static char buf[256];
+ char *c = NULL;
+
+ switch (t) {
+ case IFT_ETHER:
+ switch (sf) {
+ case IFRTYPE_SUBFAMILY_USB:
+ c = "USB Ethernet";
+ break;
+ case IFRTYPE_SUBFAMILY_BLUETOOTH:
+ c = "Bluetooth PAN";
+ break;
+ case IFRTYPE_SUBFAMILY_WIFI:
+ c = "Wi-Fi";
+ break;
+ case IFRTYPE_SUBFAMILY_THUNDERBOLT:
+ c = "IP over Thunderbolt";
+ break;
+ case IFRTYPE_SUBFAMILY_ANY:
+ default:
+ c = "Ethernet";
+ break;
+ }
+ break;
+
+ case IFT_IEEE1394:
+ c = "IP over FireWire";
+ break;
+
+ case IFT_PKTAP:
+ c = "Packet capture";
+ break;
+
+ case IFT_CELLULAR:
+ c = "Cellular";
+ break;
+
+ case IFT_OTHER:
+ if (ifr.ifr_type.ift_family == APPLE_IF_FAM_IPSEC) {
+ if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_BLUETOOTH) {
+ c = "Companion Link Bluetooth";
+ } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_QUICKRELAY) {
+ c = "Companion Link QuickRelay";
+ } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_WIFI) {
+ c = "Companion Link Wi-Fi";
+ } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_DEFAULT) {
+ c = "Companion Link Default";
+ }
+ }
+ break;
+
+ case IFT_BRIDGE:
+ case IFT_PFLOG:
+ case IFT_PFSYNC:
+ case IFT_PPP:
+ case IFT_LOOP:
+ case IFT_GIF:
+ case IFT_STF:
+ case IFT_L2VLAN:
+ case IFT_IEEE8023ADLAG:
+ default:
+ break;
+ }
+
+ if (verbose > 1) {
+ if (c == NULL) {
+ (void) snprintf(buf, sizeof (buf),
+ "0x%x family: %u subfamily: %u",
+ ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
+ ifr.ifr_type.ift_subfamily);
+ } else {
+ (void) snprintf(buf, sizeof (buf),
+ "%s (0x%x) family: %u subfamily: %u", c,
+ ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
+ ifr.ifr_type.ift_subfamily);
+ }
+ c = buf;
+ }
+
+ return (c);
+}
+
+static char *
+iffunct2str(u_int32_t functional_type)
+{
+ char *str = NULL;
+
+ switch (functional_type) {
+ case IFRTYPE_FUNCTIONAL_UNKNOWN:
+ break;
+
+ case IFRTYPE_FUNCTIONAL_LOOPBACK:
+ str = "loopback";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_WIRED:
+ str = "wired";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_WIFI_INFRA:
+ str = "wifi";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_WIFI_AWDL:
+ str = "awdl";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_CELLULAR:
+ str = "cellular";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_INTCOPROC:
+ break;
+
+ case IFRTYPE_FUNCTIONAL_COMPANIONLINK:
+ str = "companionlink";
+ break;
+
+ default:
+ break;
+ }
+ return str;
+}
diff --git a/network_cmds/ifconfig.tproj/ifconfig.h b/network_cmds/ifconfig.tproj/ifconfig.h
new file mode 100644
index 0000000..5d4a7e0
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifconfig.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2009-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Peter Wemm.
+ * 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 for the FreeBSD Project
+ * by Peter Wemm.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * so there!
+ *
+ * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.21.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $
+ */
+
+#define __constructor __attribute__((constructor))
+
+struct afswtch;
+struct cmd;
+
+typedef void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
+typedef void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp);
+typedef int c_funcv(int argc, char *const *argv, int s, const struct afswtch *afp);
+
+struct cmd {
+ const char *c_name;
+ int c_parameter;
+#define NEXTARG 0xffffff /* has following arg */
+#define NEXTARG2 0xfffffe /* has 2 following args */
+#define OPTARG 0xfffffd /* has optional following arg */
+#define VAARGS 0xfffffc /* has variable following args */
+ union {
+ c_func *c_func;
+ c_func2 *c_func2;
+ c_funcv *c_funcv;
+ } c_u;
+ int c_iscloneop;
+ struct cmd *c_next;
+};
+void cmd_register(struct cmd *);
+
+typedef void callback_func(int s, void *);
+void callback_register(callback_func *, void *);
+
+/*
+ * Macros for declaring command functions and initializing entries.
+ */
+#define DECL_CMD_FUNC(name, cmd, arg) \
+ void name(const char *cmd, int arg, int s, const struct afswtch *afp)
+#define DECL_CMD_FUNC2(name, arg1, arg2) \
+ void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp)
+
+#define DEF_CMD(name, param, func) { name, param, { .c_func = func } }
+#define DEF_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func } }
+#define DEF_CMD_OPTARG(name, func) { name, OPTARG, { .c_func = func } }
+#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func } }
+#define DEF_CMD_VA(name, func) { name, VAARGS, { .c_funcv = func } }
+#define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1 }
+#define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1 }
+
+struct ifaddrs;
+struct addrinfo;
+
+enum {
+ RIDADDR,
+ ADDR,
+ MASK,
+ DSTADDR,
+};
+
+struct afswtch {
+ const char *af_name; /* as given on cmd line, e.g. "inet" */
+ short af_af; /* AF_* */
+ /*
+ * Status is handled one of two ways; if there is an
+ * address associated with the interface then the
+ * associated address family af_status method is invoked
+ * with the appropriate addressin info. Otherwise, if
+ * all possible info is to be displayed and af_other_status
+ * is defined then it is invoked after all address status
+ * is presented.
+ */
+ void (*af_status)(int, const struct ifaddrs *);
+ void (*af_other_status)(int);
+ /* parse address method */
+ void (*af_getaddr)(const char *, int);
+ /* parse prefix method (IPv6) */
+ void (*af_getprefix)(const char *, int);
+ void (*af_postproc)(int s, const struct afswtch *);
+ u_long af_difaddr; /* set dst if address ioctl */
+ u_long af_aifaddr; /* set if address ioctl */
+ void *af_ridreq; /* */
+ void *af_addreq; /* */
+ struct afswtch *af_next;
+
+ /* XXX doesn't fit model */
+ void (*af_status_tunnel)(int);
+ void (*af_settunnel)(int s, struct addrinfo *srcres,
+ struct addrinfo *dstres);
+
+ void (*af_setrouter)(int, int);
+ int (*af_routermode)(int, int, char *const *);
+};
+void af_register(struct afswtch *);
+
+struct option {
+ const char *opt;
+ const char *opt_usage;
+ void (*cb)(const char *arg);
+ struct option *next;
+};
+void opt_register(struct option *);
+
+extern struct ifreq ifr;
+extern char name[IFNAMSIZ]; /* name of interface */
+extern int allmedia;
+extern int supmedia;
+extern int printkeys;
+extern int newaddr;
+extern int verbose;
+extern int all;
+
+void setifcap(const char *, int value, int s, const struct afswtch *);
+
+void Perror(const char *cmd);
+void printb(const char *s, unsigned value, const char *bits);
+
+void ifmaybeload(const char *name);
+
+typedef void clone_callback_func(int, struct ifreq *);
+void clone_setcallback(clone_callback_func *);
+
+/*
+ * XXX expose this so modules that neeed to know of any pending
+ * operations on ifmedia can avoid cmd line ordering confusion.
+ */
+struct ifmediareq *ifmedia_getstate(int s);
diff --git a/network_cmds/ifconfig.tproj/iffake.c b/network_cmds/ifconfig.tproj/iffake.c
new file mode 100644
index 0000000..c8065a2
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/iffake.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * iffake.c
+ * - manage fake interfaces that pretend to be e.g. ethernet
+ */
+
+/*
+ * Modification History:
+ *
+ * January 17, 2017 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_fake_var.h>
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static void
+fake_status(int s)
+{
+ struct ifdrv ifd;
+ struct if_fake_request iffr;
+
+ bzero((char *)&ifd, sizeof(ifd));
+ bzero((char *)&iffr, sizeof(iffr));
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = IF_FAKE_G_CMD_GET_PEER;
+ ifd.ifd_len = sizeof(iffr);
+ ifd.ifd_data = &iffr;
+ if (ioctl(s, SIOCGDRVSPEC, &ifd) < 0) {
+ return;
+ }
+ if (iffr.iffr_peer_name[0] == '\0') {
+ printf("\tpeer: <none>\n");
+ } else {
+ printf("\tpeer: %s\n", iffr.iffr_peer_name);
+ }
+ return;
+}
+
+static void
+set_peer(int s, const char * operation, const char * val)
+{
+ struct ifdrv ifd;
+ struct if_fake_request iffr;
+
+ bzero((char *)&ifd, sizeof(ifd));
+ bzero((char *)&iffr, sizeof(iffr));
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = IF_FAKE_S_CMD_SET_PEER;
+ ifd.ifd_len = sizeof(iffr);
+ ifd.ifd_data = &iffr;
+ if (val != NULL) {
+ strlcpy(iffr.iffr_peer_name, val, sizeof(iffr.iffr_peer_name));
+ }
+ if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
+ err(1, "SIOCDRVSPEC %s peer", operation);
+ }
+ return;
+}
+
+static
+DECL_CMD_FUNC(setpeer, val, d)
+{
+ set_peer(s, "set", val);
+ return;
+}
+
+static
+DECL_CMD_FUNC(unsetpeer, val, d)
+{
+ set_peer(s, "unset", NULL);
+ return;
+}
+
+static struct cmd fake_cmds[] = {
+ DEF_CLONE_CMD_ARG("peer", setpeer),
+ DEF_CMD_OPTARG("-peer", unsetpeer),
+};
+static struct afswtch af_fake = {
+ .af_name = "af_fake",
+ .af_af = AF_UNSPEC,
+ .af_other_status = fake_status,
+};
+
+static __constructor void
+fake_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(fake_cmds); i++)
+ cmd_register(&fake_cmds[i]);
+ af_register(&af_fake);
+#undef N
+}
+
diff --git a/network_cmds/ifconfig.tproj/ifmedia.c b/network_cmds/ifconfig.tproj/ifmedia.c
new file mode 100644
index 0000000..713c136
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifmedia.c
@@ -0,0 +1,872 @@
+/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */
+/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.25.6.1 2008/11/25 02:59:29 kensmith Exp $ */
+
+/*
+ * Copyright (c) 1997 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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) 1983, 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void domediaopt(const char *, int, int);
+static int get_media_subtype(int, const char *);
+#ifdef notdef
+static int get_media_mode(int, const char *);
+#endif
+static int get_media_options(int, const char *);
+static int lookup_media_word(struct ifmedia_description *, const char *);
+static void print_media_word(int, int);
+static void print_media_word_ifconfig(int);
+
+static struct ifmedia_description *get_toptype_desc(int);
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
+static struct ifmedia_description *get_subtype_desc(int,
+ struct ifmedia_type_to_subtype *ttos);
+
+static void
+media_status(int s)
+{
+ struct ifmediareq ifmr;
+ int *media_list, i;
+
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) {
+ /*
+ * Interface doesn't support SIOC{G,S}IFMEDIA.
+ */
+ return;
+ }
+
+ if (ifmr.ifm_count == 0) {
+ warnx("%s: no media types?", name);
+ return;
+ }
+
+ media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+ if (media_list == NULL)
+ err(1, "malloc");
+ ifmr.ifm_ulist = media_list;
+
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+
+ printf("\tmedia: ");
+ print_media_word(ifmr.ifm_current, 1);
+ if (ifmr.ifm_active != ifmr.ifm_current) {
+ putchar(' ');
+ putchar('(');
+ print_media_word(ifmr.ifm_active, 0);
+ putchar(')');
+ }
+
+ putchar('\n');
+
+ if (ifmr.ifm_status & IFM_AVALID) {
+ printf("\tstatus: ");
+#ifdef notdef
+ switch (IFM_TYPE(ifmr.ifm_active)) {
+ case IFM_ETHER:
+ case IFM_ATM:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("active");
+ else
+ printf("no carrier");
+ break;
+
+ case IFM_FDDI:
+ case IFM_TOKEN:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("inserted");
+ else
+ printf("no ring");
+ break;
+
+ case IFM_IEEE80211:
+ /* XXX: Different value for adhoc? */
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("associated");
+ else
+ printf("no carrier");
+ break;
+ }
+#else
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("active");
+ else
+ printf("inactive");
+#endif
+ putchar('\n');
+ }
+
+ if (ifmr.ifm_count > 0 && supmedia) {
+ printf("\tsupported media:\n");
+ for (i = 0; i < ifmr.ifm_count; i++) {
+ printf("\t\t");
+ print_media_word_ifconfig(media_list[i]);
+ putchar('\n');
+ }
+ }
+
+ free(media_list);
+}
+
+struct ifmediareq *
+ifmedia_getstate(int s)
+{
+ static struct ifmediareq *ifmr = NULL;
+ int *mwords;
+
+ if (ifmr == NULL) {
+ ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+ if (ifmr == NULL)
+ err(1, "malloc");
+
+ (void) memset(ifmr, 0, sizeof(struct ifmediareq));
+ (void) strlcpy(ifmr->ifm_name, name,
+ sizeof(ifmr->ifm_name));
+
+ ifmr->ifm_count = 0;
+ ifmr->ifm_ulist = NULL;
+
+ /*
+ * We must go through the motions of reading all
+ * supported media because we need to know both
+ * the current media type and the top-level type.
+ */
+
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) {
+ err(1, "SIOCGIFXMEDIA");
+ }
+
+ if (ifmr->ifm_count == 0)
+ errx(1, "%s: no media types?", name);
+
+ mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
+ if (mwords == NULL)
+ err(1, "malloc");
+
+ ifmr->ifm_ulist = mwords;
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+ }
+
+ return ifmr;
+}
+
+static void
+setifmediacallback(int s, void *arg)
+{
+ struct ifmediareq *ifmr = (struct ifmediareq *)arg;
+ static int did_it = 0;
+
+ if (!did_it) {
+ ifr.ifr_media = ifmr->ifm_current;
+ if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+ err(1, "SIOCSIFMEDIA (media)");
+ free(ifmr->ifm_ulist);
+ free(ifmr);
+ did_it = 1;
+ }
+}
+
+static void
+setmedia(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int subtype;
+
+ ifmr = ifmedia_getstate(s);
+
+ /*
+ * We are primarily concerned with the top-level type.
+ * However, "current" may be only IFM_NONE, so we just look
+ * for the top-level type in the first "supported type"
+ * entry.
+ *
+ * (I'm assuming that all supported media types for a given
+ * interface will be the same top-level type..)
+ */
+ subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
+ IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
+
+ if ((ifr.ifr_media & IFM_TMASK) == 0) {
+ ifr.ifr_media &= ~IFM_GMASK;
+ }
+
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ domediaopt(val, 0, s);
+}
+
+static void
+unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ domediaopt(val, 1, s);
+}
+
+static void
+domediaopt(const char *val, int clear, int s)
+{
+ struct ifmediareq *ifmr;
+ int options;
+
+ ifmr = ifmedia_getstate(s);
+
+ options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = ifmr->ifm_current;
+ if (clear)
+ ifr.ifr_media &= ~options;
+ else {
+ if (options & IFM_HDX) {
+ ifr.ifr_media &= ~IFM_FDX;
+ options &= ~IFM_HDX;
+ }
+ ifr.ifr_media |= options;
+ }
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediainst(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int inst;
+
+ ifmr = ifmedia_getstate(s);
+
+ inst = atoi(val);
+ if (inst < 0 || inst > IFM_INST_MAX)
+ errx(1, "invalid media instance: %s", val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
+
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+
+#ifdef notdef
+static void
+setmediamode(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int mode;
+
+ ifmr = ifmedia_getstate(s);
+
+ mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
+
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+#endif
+
+/**********************************************************************
+ * A good chunk of this is duplicated from sys/net/ifmedia.c
+ **********************************************************************/
+
+static struct ifmedia_description ifm_type_descriptions[] =
+ IFM_TYPE_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+ IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
+ IFM_SUBTYPE_ETHERNET_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+ IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
+ IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
+ IFM_SUBTYPE_TOKENRING_ALIASES;
+
+static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
+ IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
+ IFM_SUBTYPE_FDDI_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_aliases[] =
+ IFM_SUBTYPE_FDDI_ALIASES;
+
+static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
+ IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
+#ifdef notdef
+static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+IFM_SUBTYPE_IEEE80211_ALIASES;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+ IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_descriptions[] =
+ IFM_SUBTYPE_ATM_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_atm_aliases[] =
+ IFM_SUBTYPE_ATM_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+ IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
+#endif
+
+static struct ifmedia_description ifm_subtype_shared_descriptions[] =
+ IFM_SUBTYPE_SHARED_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_shared_aliases[] =
+ IFM_SUBTYPE_SHARED_ALIASES;
+
+static struct ifmedia_description ifm_shared_option_descriptions[] =
+ IFM_SHARED_OPTION_DESCRIPTIONS;
+
+struct ifmedia_type_to_subtype {
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } subtypes[5];
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } options[3];
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } modes[3];
+};
+
+/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
+static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_ethernet_descriptions[0], 0 },
+ { &ifm_subtype_ethernet_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_ethernet_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_tokenring_descriptions[0], 0 },
+ { &ifm_subtype_tokenring_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_tokenring_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_fddi_descriptions[0], 0 },
+ { &ifm_subtype_fddi_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_fddi_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+#ifdef __APPLE__
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_ieee80211_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_option_descriptions[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+#else /* __APPLE__ */
+#ifdef notdef
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_ieee80211_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
+ { NULL, 0 },
+ },
+ },
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_atm_descriptions[0], 0 },
+ { &ifm_subtype_atm_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_atm_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+#endif
+#endif /* __APPLE__ */
+};
+
+static int
+get_media_subtype(int type, const char *val)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int rval, i;
+
+ /* Find the top-level interface type. */
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (type == desc->ifmt_word)
+ break;
+ if (desc->ifmt_string == NULL)
+ errx(1, "unknown media type 0x%x", type);
+
+ for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+ rval = lookup_media_word(ttos->subtypes[i].desc, val);
+ if (rval != -1)
+ return (rval);
+ }
+ errx(1, "unknown media subtype: %s", val);
+ /*NOTREACHED*/
+}
+
+#ifdef notdef
+static int
+get_media_mode(int type, const char *val)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int rval, i;
+
+ /* Find the top-level interface type. */
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (type == desc->ifmt_word)
+ break;
+ if (desc->ifmt_string == NULL)
+ errx(1, "unknown media mode 0x%x", type);
+
+ for (i = 0; ttos->modes[i].desc != NULL; i++) {
+ rval = lookup_media_word(ttos->modes[i].desc, val);
+ if (rval != -1)
+ return (rval);
+ }
+ return -1;
+}
+#endif
+
+static int
+get_media_options(int type, const char *val)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ char *optlist, *optptr;
+ int option = 0, i, rval = 0;
+
+ /* We muck with the string, so copy it. */
+ optlist = strdup(val);
+ if (optlist == NULL)
+ err(1, "strdup");
+
+ /* Find the top-level interface type. */
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (type == desc->ifmt_word)
+ break;
+ if (desc->ifmt_string == NULL)
+ errx(1, "unknown media type 0x%x", type);
+
+ /*
+ * Look up the options in the user-provided comma-separated
+ * list.
+ */
+ optptr = optlist;
+ for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
+ for (i = 0; ttos->options[i].desc != NULL; i++) {
+ option = lookup_media_word(ttos->options[i].desc, optptr);
+ if (option != -1)
+ break;
+ }
+ if (option == 0)
+ errx(1, "unknown option: %s", optptr);
+ rval |= option;
+ }
+
+ free(optlist);
+ return (rval);
+}
+
+static int
+lookup_media_word(struct ifmedia_description *desc, const char *val)
+{
+
+ for (; desc->ifmt_string != NULL; desc++)
+ if (strcasecmp(desc->ifmt_string, val) == 0)
+ return (desc->ifmt_word);
+
+ return (-1);
+}
+
+static struct ifmedia_description *get_toptype_desc(int ifmw)
+{
+ struct ifmedia_description *desc;
+
+ for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
+ if (IFM_TYPE(ifmw) == desc->ifmt_word)
+ break;
+
+ return desc;
+}
+
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (IFM_TYPE(ifmw) == desc->ifmt_word)
+ break;
+
+ return ttos;
+}
+
+static struct ifmedia_description *get_subtype_desc(int ifmw,
+ struct ifmedia_type_to_subtype *ttos)
+{
+ int i;
+ struct ifmedia_description *desc;
+
+ for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+ if (ttos->subtypes[i].alias)
+ continue;
+ for (desc = ttos->subtypes[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
+ return desc;
+ }
+ }
+
+ return NULL;
+}
+
+#ifdef notdef
+static struct ifmedia_description *get_mode_desc(int ifmw,
+ struct ifmedia_type_to_subtype *ttos)
+{
+ int i;
+ struct ifmedia_description *desc;
+
+ for (i = 0; ttos->modes[i].desc != NULL; i++) {
+ if (ttos->modes[i].alias)
+ continue;
+ for (desc = ttos->modes[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (IFM_MODE(ifmw) == desc->ifmt_word)
+ return desc;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+static void
+print_media_word(int ifmw, int print_toptype)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int seen_option = 0, i;
+
+ /* Find the top-level interface type. */
+ desc = get_toptype_desc(ifmw);
+ ttos = get_toptype_ttos(ifmw);
+ if (desc->ifmt_string == NULL) {
+ printf("<unknown type>");
+ return;
+#ifdef notdef
+ } else if (print_toptype) {
+ printf("%s", desc->ifmt_string);
+#endif
+ }
+
+ /*
+ * Don't print the top-level type; it's not like we can
+ * change it, or anything.
+ */
+
+ /* Find subtype. */
+ desc = get_subtype_desc(ifmw, ttos);
+ if (desc == NULL) {
+ printf("<unknown subtype>");
+ return;
+ }
+
+#ifdef notdef
+ if (print_toptype)
+ putchar(' ');
+#endif
+
+ printf("%s", desc->ifmt_string);
+
+#ifdef notdef
+ if (print_toptype) {
+ desc = get_mode_desc(ifmw, ttos);
+ if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
+ printf(" mode %s", desc->ifmt_string);
+ }
+#endif
+ /* Find options. */
+ for (i = 0; ttos->options[i].desc != NULL; i++) {
+ if (ttos->options[i].alias)
+ continue;
+ for (desc = ttos->options[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (ifmw & desc->ifmt_word) {
+ if (seen_option == 0)
+ printf(" <");
+ printf("%s%s", seen_option++ ? "," : "",
+ desc->ifmt_string);
+ }
+ }
+ }
+ printf("%s", seen_option ? ">" : "");
+
+#ifdef notdef
+ if (print_toptype && IFM_INST(ifmw) != 0)
+ printf(" instance %d", IFM_INST(ifmw));
+#endif
+}
+
+static void
+print_media_word_ifconfig(int ifmw)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int i;
+
+ /* Find the top-level interface type. */
+ desc = get_toptype_desc(ifmw);
+ ttos = get_toptype_ttos(ifmw);
+ if (desc->ifmt_string == NULL) {
+ printf("<unknown type>");
+ return;
+ }
+
+ /*
+ * Don't print the top-level type; it's not like we can
+ * change it, or anything.
+ */
+
+ /* Find subtype. */
+ desc = get_subtype_desc(ifmw, ttos);
+ if (desc == NULL) {
+ printf("<unknown subtype>");
+ return;
+ }
+
+ printf("media %s", desc->ifmt_string);
+
+#ifdef notdef
+ desc = get_mode_desc(ifmw, ttos);
+ if (desc != NULL)
+ printf(" mode %s", desc->ifmt_string);
+#endif
+
+ /* Find options. */
+ for (i = 0; ttos->options[i].desc != NULL; i++) {
+ if (ttos->options[i].alias)
+ continue;
+ for (desc = ttos->options[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (ifmw & desc->ifmt_word) {
+ printf(" mediaopt %s", desc->ifmt_string);
+ }
+ }
+ }
+
+ if (IFM_INST(ifmw) != 0)
+ printf(" instance %d", IFM_INST(ifmw));
+}
+
+/**********************************************************************
+ * ...until here.
+ **********************************************************************/
+
+static struct cmd media_cmds[] = {
+ DEF_CMD_ARG("media", setmedia),
+#ifdef notdef
+ DEF_CMD_ARG("mode", setmediamode),
+#endif
+ DEF_CMD_ARG("mediaopt", setmediaopt),
+ DEF_CMD_ARG("-mediaopt",unsetmediaopt),
+ DEF_CMD_ARG("inst", setmediainst),
+ DEF_CMD_ARG("instance", setmediainst),
+};
+static struct afswtch af_media = {
+ .af_name = "af_media",
+ .af_af = AF_UNSPEC,
+ .af_other_status = media_status,
+};
+
+static __constructor void
+ifmedia_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(media_cmds); i++)
+ cmd_register(&media_cmds[i]);
+ af_register(&af_media);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifvlan.c b/network_cmds/ifconfig.tproj/ifvlan.c
new file mode 100644
index 0000000..9ec0a0a
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifvlan.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+#include <sys/cdefs.h>
+
+#define NOTAG ((u_short) -1)
+
+static struct vlanreq params = {
+ .vlr_tag = NOTAG,
+};
+
+static int
+getvlan(int s, struct ifreq *ifr, struct vlanreq *vreq)
+{
+ bzero((char *)vreq, sizeof(*vreq));
+ ifr->ifr_data = (caddr_t)vreq;
+
+ return ioctl(s, SIOCGETVLAN, (caddr_t)ifr);
+}
+
+static void
+vlan_status(int s)
+{
+ struct vlanreq vreq;
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ printf("\tvlan: %d parent interface: %s\n",
+ vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
+ "<none>" : vreq.vlr_parent);
+}
+
+static void
+vlan_create(int s, struct ifreq *ifr)
+{
+ if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
+ /*
+ * One or both parameters were specified, make sure both.
+ */
+ if (params.vlr_tag == NOTAG)
+ errx(1, "must specify a tag for vlan create");
+ if (params.vlr_parent[0] == '\0')
+ errx(1, "must specify a parent device for vlan create");
+ ifr->ifr_data = (caddr_t) &params;
+ }
+#ifdef SIOCIFCREATE2
+ if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+ err(1, "SIOCIFCREATE2");
+#else
+ if (ioctl(s, SIOCIFCREATE, ifr) < 0)
+ err(1, "SIOCIFCREATE");
+#endif
+}
+
+static void
+vlan_cb(int s, void *arg)
+{
+ if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0'))
+ errx(1, "both vlan and vlandev must be specified");
+}
+
+static void
+vlan_set(int s, struct ifreq *ifr)
+{
+ if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') {
+ ifr->ifr_data = (caddr_t) &params;
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1)
+ err(1, "SIOCSETVLAN");
+ }
+}
+
+static
+DECL_CMD_FUNC(setvlantag, val, d)
+{
+ struct vlanreq vreq;
+ u_long ul;
+ char *endp;
+
+ ul = strtoul(val, &endp, 0);
+ if (*endp != '\0')
+ errx(1, "invalid value for vlan");
+ params.vlr_tag = ul;
+ /* check if the value can be represented in vlr_tag */
+ if (params.vlr_tag != ul)
+ errx(1, "value for vlan out of range");
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ vlan_set(s, &ifr);
+ else
+ clone_setcallback(vlan_create);
+}
+
+static
+DECL_CMD_FUNC(setvlandev, val, d)
+{
+ struct vlanreq vreq;
+
+ strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent));
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ vlan_set(s, &ifr);
+ else
+ clone_setcallback(vlan_create);
+}
+
+static
+DECL_CMD_FUNC(unsetvlandev, val, d)
+{
+ struct vlanreq vreq;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
+ vreq.vlr_tag = 0;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+}
+
+static struct cmd vlan_cmds[] = {
+ DEF_CLONE_CMD_ARG("vlan", setvlantag),
+ DEF_CLONE_CMD_ARG("vlandev", setvlandev),
+ /* XXX For compatibility. Should become DEF_CMD() some day. */
+ DEF_CMD_OPTARG("-vlandev", unsetvlandev),
+#ifdef IFCAP_VLAN_MTU
+ DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap),
+ DEF_CMD("-vlanmtu", -IFCAP_VLAN_MTU, setifcap),
+#endif /* IFCAP_VLAN_MTU */
+#ifdef IFCAP_VLAN_HWTAGGING
+ DEF_CMD("vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap),
+ DEF_CMD("-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap),
+#endif /* IFCAP_VLAN_HWTAGGING */
+};
+static struct afswtch af_vlan = {
+ .af_name = "af_vlan",
+ .af_af = AF_UNSPEC,
+ .af_other_status = vlan_status,
+};
+
+static __constructor void
+vlan_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(vlan_cmds); i++)
+ cmd_register(&vlan_cmds[i]);
+ af_register(&af_vlan);
+ callback_register(vlan_cb, NULL);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/nexus.c b/network_cmds/ifconfig.tproj/nexus.c
new file mode 100644
index 0000000..3df9842
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/nexus.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * nexus.c
+ * - report information about attached nexus
+ */
+
+/*
+ * Modification History:
+ *
+ * April 10, 2017 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_fake_var.h>
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static void
+nexus_status(int s)
+{
+ struct if_nexusreq ifnr;
+ uuid_string_t flowswitch;
+ uuid_string_t netif;
+
+ if (!verbose) {
+ return;
+ }
+ bzero((char *)&ifnr, sizeof(ifnr));
+ strlcpy(ifnr.ifnr_name, ifr.ifr_name, sizeof(ifnr.ifnr_name));
+ if (ioctl(s, SIOCGIFNEXUS, &ifnr) < 0) {
+ return;
+ }
+ if (uuid_is_null(ifnr.ifnr_netif)) {
+ /* technically, this shouldn't happen */
+ return;
+ }
+ uuid_unparse_upper(ifnr.ifnr_netif, netif);
+ printf("\tnetif: %s\n", netif);
+ if (uuid_is_null(ifnr.ifnr_flowswitch) == 0) {
+ uuid_unparse_upper(ifnr.ifnr_flowswitch, flowswitch);
+ printf("\tflowswitch: %s\n", flowswitch);
+ }
+ return;
+}
+
+static struct afswtch af_fake = {
+ .af_name = "af_fake",
+ .af_af = AF_UNSPEC,
+ .af_other_status = nexus_status,
+};
+
+static __constructor void
+fake_ctor(void)
+{
+ af_register(&af_fake);
+}
+
diff --git a/network_cmds/ip6addrctl.tproj/ip6addrctl.8 b/network_cmds/ip6addrctl.tproj/ip6addrctl.8
new file mode 100644
index 0000000..59154d4
--- /dev/null
+++ b/network_cmds/ip6addrctl.tproj/ip6addrctl.8
@@ -0,0 +1,126 @@
+.\" $KAME: ip6addrctl.8,v 1.3 2003/03/22 05:56:41 jinmei Exp $
+.\"
+.\" Copyright (C) 2001 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 25, 2001
+.Dt IP6ADDRCTL 8
+.Os
+.\"
+.Sh NAME
+.Nm ip6addrctl
+.Nd configure address selection policy for IPv6 and IPv4
+.\"
+.Sh SYNOPSIS
+.Nm
+.Op Cm show
+.Nm
+.Cm add
+.Ar prefix precedence label
+.Nm
+.Cm delete
+.Ar prefix
+.Nm
+.Cm flush
+.Nm
+.Cm install
+.Ar configfile
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+utility manages the policy table of source and destination address
+selection for outgoing IPv4 and IPv6 packets.
+When
+.Nm
+is invoked without an argument or with a single argument
+.Cm show ,
+it prints the content of the policy table currently installed in the
+kernel.
+.Pp
+To modify the table, the following operations are available:
+.Bl -tag -width indent
+.It Cm add Ar prefix precedence label
+Add a policy entry.
+The
+.Ar prefix
+argument
+is an IPv6 prefix, which is a key for the entry.
+An IPv4 prefix should be specified with an IPv6 prefix using an
+IPv4-mapped IPv6 address.
+The
+.Ar precedence
+and
+.Ar label
+arguments
+are decimal numbers, which specify the precedence and label values
+for the entry, respectively.
+This operation should be performed without an existing entry for the
+prefix.
+.It Cm delete Ar prefix
+Delete a policy entry specified by
+.Ar prefix ,
+which should be an IPv6 prefix.
+A corresponding entry for the prefix should have already been
+installed.
+.It Cm flush
+Delete all existing policy entries in the kernel.
+.It Cm install Ar configfile
+Install policy entries from a configuration file named
+.Ar configfile .
+The configuration file should contain a set of policy entries.
+Each entry is specified in a single line which contains an IPv6 prefix,
+a decimal precedence value, and a decimal label value, separated with
+white space or tab characters.
+In the configuration file, lines beginning with the pound-sign
+.Pq Ql #
+are
+comments and are ignored.
+.El
+.\"
+.Sh EXIT STATUS
+.Ex -std
+.\"
+.Sh SEE ALSO
+.Rs
+.%A "Richard Draves"
+.%T "Default Address Selection for IPv6"
+.%N RFC 3484
+.Re
+.\"
+.Sh HISTORY
+The
+.Nm
+utility first appeared in the KAME IPv6 protocol stack kit.
+The original command name was
+.Nm addrselect ,
+but it was then renamed to the current one so that the name would
+describe its function well.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/network_cmds/ip6addrctl.tproj/ip6addrctl.c b/network_cmds/ip6addrctl.tproj/ip6addrctl.c
new file mode 100644
index 0000000..400412a
--- /dev/null
+++ b/network_cmds/ip6addrctl.tproj/ip6addrctl.c
@@ -0,0 +1,467 @@
+/* $KAME: ip6addrctl.c,v 1.3 2003/12/16 08:14:28 suz Exp $ */
+
+/*
+ * Copyright (C) 2001 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <err.h>
+
+static char *configfile;
+
+struct policyqueue {
+ TAILQ_ENTRY(policyqueue) pc_entry;
+ struct in6_addrpolicy pc_policy;
+};
+TAILQ_HEAD(policyhead, policyqueue);
+struct policyhead policyhead;
+
+static void usage __P((void));
+static void get_policy __P((void));
+static void dump_policy __P((void));
+static int mask2plen __P((struct sockaddr_in6 *));
+static int parse_prefix __P((const char *, struct in6_addrpolicy *));
+static void make_policy_fromfile __P((char *));
+static void plen2mask __P((struct sockaddr_in6 *, int));
+static void set_policy __P((void));
+static void add_policy __P((char *, char *, char *));
+static void delete_policy __P((char *));
+static void flush_policy __P(());
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ TAILQ_INIT(&policyhead);
+
+ if (argc == 1 || strcasecmp(argv[1], "show") == 0) {
+ get_policy();
+ dump_policy();
+ } else if (strcasecmp(argv[1], "add") == 0) {
+ if (argc < 5)
+ usage();
+ add_policy(argv[2], argv[3], argv[4]);
+ } else if (strcasecmp(argv[1], "delete") == 0) {
+ if (argc < 3)
+ usage();
+ delete_policy(argv[2]);
+ } else if (strcasecmp(argv[1], "flush") == 0) {
+ get_policy();
+ flush_policy();
+ } else if (strcasecmp(argv[1], "install") == 0) {
+ if (argc < 3)
+ usage();
+ configfile = argv[2];
+ make_policy_fromfile(configfile);
+ set_policy();
+ } else
+ usage();
+
+ exit(0);
+}
+
+static void
+get_policy()
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+ size_t l;
+ char *buf;
+ struct in6_addrpolicy *pol, *ep;
+
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
+ err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+ /* NOTREACHED */
+ }
+ if (l == 0) {
+ printf("no source-address-selection policy is installed\n");
+ return;
+ }
+ if ((buf = malloc(l)) == NULL) {
+ errx(1, "malloc failed");
+ /* NOTREACHED */
+ }
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
+ err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+ /* NOTREACHED */
+ }
+
+ ep = (struct in6_addrpolicy *)(buf + l);
+ for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
+ struct policyqueue *new;
+
+ if ((new = malloc(sizeof(*new))) == NULL)
+ errx(1, "malloc failed\n");
+ new->pc_policy = *pol;
+ TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
+ }
+
+ free(buf);
+}
+
+static void
+dump_policy()
+{
+ size_t addrlen;
+ char addrbuf[NI_MAXHOST];
+ struct in6_addrpolicy *pol;
+ struct policyqueue *ent;
+ int plen, first = 1;
+
+ for (ent = TAILQ_FIRST(&policyhead); ent;
+ ent = TAILQ_NEXT(ent, pc_entry)) {
+ pol = &ent->pc_policy;
+ if (first) {
+ printf("%-30s %5s %5s %8s\n",
+ "Prefix", "Prec", "Label", "Use");
+ first = 0;
+ }
+
+ if ((getnameinfo((struct sockaddr *)&pol->addr,
+ sizeof(pol->addr), addrbuf, sizeof(addrbuf),
+ NULL, 0, NI_NUMERICHOST))) {
+ warnx("getnameinfo for prefix address failed");
+ continue;
+ }
+ if ((plen = mask2plen(&pol->addrmask)) < 0) {
+ warnx("invalid address mask");
+ continue;
+ }
+ addrlen = strlen(addrbuf);
+ if (addrlen + sizeof("/128") < sizeof(addrbuf)) {
+ snprintf(&addrbuf[addrlen],
+ sizeof(addrbuf) - addrlen - 1,
+ "/%d", plen);
+ printf("%-30s", addrbuf);
+ } else /* XXX */
+ printf("%s/%d", addrbuf, plen);
+ printf(" %5d %5d %8llu\n", pol->preced, pol->label,
+ (unsigned long long)pol->use);
+ }
+}
+
+#define SKIP_WHITE(p, emptyok) \
+ do { \
+ while((*(p) == ' ' || *(p) == '\t')) \
+ (p)++; \
+ if ((*(p) == '\0' || (*(p) == '\n')) && !(emptyok)) \
+ goto bad; \
+ } while (0);
+#define SKIP_WORD(p) \
+ do { \
+ while(*(p) != ' ' && *(p) != '\t') \
+ (p)++; \
+ if (*(p) == '\0' || *(p) == '\n') \
+ goto bad; \
+ } while (0);
+
+static void
+make_policy_fromfile(conf)
+ char *conf;
+{
+ char line[_POSIX2_LINE_MAX], *cp;
+ char *addrstr;
+ FILE *fp;
+ int count = 0;
+ struct in6_addrpolicy pol0;
+ struct policyqueue *new;
+
+ if ((fp = fopen(conf, "r")) == NULL)
+ err(1, "fopen: %s", conf);
+
+ while(fgets(line, sizeof(line), fp)) {
+ count++;
+ cp = line;
+
+ memset(&pol0, 0, sizeof(pol0));
+
+ /* get prefix */
+ SKIP_WHITE(cp, 1);
+ if (*cp == '\n') /* empty line */
+ continue;
+ if (*cp == '#')
+ continue;
+ addrstr = cp;
+ if (parse_prefix((const char *)addrstr, &pol0))
+ goto bad;
+
+ /* get precedence value */
+ SKIP_WORD(cp);
+ SKIP_WHITE(cp, 0);
+ pol0.preced = atoi(cp);
+
+ /* get label */
+ SKIP_WORD(cp);
+ SKIP_WHITE(cp, 0);
+ pol0.label = atoi(cp);
+
+ /* parse succeeded. make a control buffer entry. */
+ if ((new = malloc(sizeof(*new))) == NULL)
+ errx(1, "malloc failed\n");
+ memset(new, 0, sizeof(*new));
+ new->pc_policy = pol0;
+ TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
+ }
+
+ fclose(fp);
+ return;
+
+ bad:
+ errx(1, "parse failed at line %d", count);
+ /* NOTREACHED */
+}
+
+static int
+parse_prefix(prefix0, pol)
+ const char *prefix0;
+ struct in6_addrpolicy *pol;
+{
+ int e = 0, plen;
+ char *prefix, *plenstr;
+ struct addrinfo hints, *res;
+
+ if ((prefix = strdup(prefix0)) == NULL)
+ errx(1, "strdup failed");
+
+ if ((plenstr = strchr(prefix, '/')) == NULL) {
+ e = -1;
+ goto end;
+ }
+ *plenstr = '\0';
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = AF_INET6;
+
+ if ((e = getaddrinfo(prefix, NULL, &hints, &res)) != 0) {
+ warnx("getaddrinfo failed for %s: %s", prefix,
+ gai_strerror(e));
+ goto end;
+ }
+ memcpy(&pol->addr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ plen = atoi(plenstr + 1);
+ if (plen < 0 || plen > 128) {
+ warnx("invalid prefix length: %d", plen);
+ e = -1;
+ goto end;
+ }
+ plen2mask(&pol->addrmask, plen);
+
+ end:
+ free(prefix);
+ return(e);
+}
+
+static void
+plen2mask(mask, plen)
+ struct sockaddr_in6 *mask;
+ int plen;
+{
+ u_char *cp = (unsigned char *)&mask->sin6_addr;
+
+ memset(mask, 0, sizeof(*mask));
+ mask->sin6_family = AF_INET6; /* just in case */
+ mask->sin6_len = sizeof(*mask);
+
+ for(; plen >= 8; plen -= 8)
+ *cp++ = 0xff;
+ if (plen > 0)
+ *cp = (0xff << (8 - plen));
+}
+
+static void
+set_policy()
+{
+ struct policyqueue *ent;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+
+ for (ent = TAILQ_FIRST(&policyhead); ent;
+ ent = TAILQ_NEXT(ent, pc_entry)) {
+ if (ioctl(s, SIOCAADDRCTL_POLICY, &ent->pc_policy))
+ warn("ioctl(SIOCAADDRCTL_POLICY)");
+ }
+
+ close(s);
+}
+
+static int
+mask2plen(mask)
+ struct sockaddr_in6 *mask;
+{
+ int masklen, final = 0;
+ u_char *p, *lim;
+
+ masklen = 0;
+ lim = (u_char *)(mask + 1);
+ for (p = (u_char *)(&mask->sin6_addr); p < lim; p++) {
+ if (final && *p) {
+ goto bad;
+ }
+
+ switch (*p & 0xff) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ final++;
+ break;
+ case 0xfc:
+ masklen += 6;
+ final++;
+ break;
+ case 0xf8:
+ masklen += 5;
+ final++;
+ break;
+ case 0xf0:
+ masklen += 4;
+ final++;
+ break;
+ case 0xe0:
+ masklen += 3;
+ final++;
+ break;
+ case 0xc0:
+ masklen += 2;
+ final++;
+ break;
+ case 0x80:
+ masklen += 1;
+ final++;
+ break;
+ case 0x00:
+ final++;
+ break;
+ default:
+ goto bad;
+ break;
+ }
+ }
+ return(masklen);
+
+ bad:
+ return(-1);
+}
+
+static void
+add_policy(prefix, prec, label)
+ char *prefix, *prec, *label;
+{
+ struct in6_addrpolicy p;
+ int s;
+
+ memset(&p, 0, sizeof(p));
+
+ if (parse_prefix((const char *)prefix, &p))
+ errx(1, "bad prefix: %s", prefix);
+ p.preced = atoi(prec);
+ p.label = atoi(label);
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+ if (ioctl(s, SIOCAADDRCTL_POLICY, &p))
+ err(1, "ioctl(SIOCAADDRCTL_POLICY)");
+
+ close(s);
+}
+
+static void
+delete_policy(prefix)
+ char *prefix;
+{
+ struct in6_addrpolicy p;
+ int s;
+
+ memset(&p, 0, sizeof(p));
+
+ if (parse_prefix((const char *)prefix, &p))
+ errx(1, "bad prefix: %s", prefix);
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+ if (ioctl(s, SIOCDADDRCTL_POLICY, &p))
+ err(1, "ioctl(SIOCDADDRCTL_POLICY)");
+
+ close(s);
+}
+
+static void
+flush_policy()
+{
+ struct policyqueue *ent;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+
+ for (ent = TAILQ_FIRST(&policyhead); ent;
+ ent = TAILQ_NEXT(ent, pc_entry)) {
+ if (ioctl(s, SIOCDADDRCTL_POLICY, &ent->pc_policy))
+ warn("ioctl(SIOCDADDRCTL_POLICY)");
+ }
+
+ close(s);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: ip6addrctl [show]\n");
+ fprintf(stderr, " ip6addrctl add "
+ "<prefix> <precedence> <label>\n");
+ fprintf(stderr, " ip6addrctl delete <prefix>\n");
+ fprintf(stderr, " ip6addrctl flush\n");
+ fprintf(stderr, " ip6addrctl install <configfile>\n");
+
+ exit(1);
+}
diff --git a/network_cmds/ip6addrctl.tproj/ip6addrctl.conf b/network_cmds/ip6addrctl.tproj/ip6addrctl.conf
new file mode 100644
index 0000000..a2b3759
--- /dev/null
+++ b/network_cmds/ip6addrctl.tproj/ip6addrctl.conf
@@ -0,0 +1,12 @@
+# default policy table based on RFC 3484.
+# usage: ip6addrctl install path_to_this_file
+#
+# $FreeBSD$
+#
+#Format:
+#Prefix Precedence Label
+::1/128 50 0
+::/0 40 1
+2002::/16 30 2
+::/96 20 3
+::ffff:0:0/96 10 4
diff --git a/network_cmds/kdumpd.tproj/com.apple.kdumpd.plist b/network_cmds/kdumpd.tproj/com.apple.kdumpd.plist
new file mode 100644
index 0000000..3b09ade
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/com.apple.kdumpd.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>InitGroups</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.kdumpd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/kdumpd</string>
+ <string>/var/tmp/PanicDumps</string>
+ </array>
+ <key>Sockets</key>
+ <dict>
+ <key>Listener</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>1069</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+ <key>UserName</key>
+ <string>nobody</string>
+ <key>Umask</key>
+ <integer>7</integer>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+</dict>
+</plist>
diff --git a/network_cmds/kdumpd.tproj/kdump.h b/network_cmds/kdumpd.tproj/kdump.h
new file mode 100644
index 0000000..9536946
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdump.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * @(#)kdump.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _KDUMP_H_
+#define _KDUMP_H_
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+/* Mac OS X kernel core dump server, based on the BSD trivial file
+ * transfer protocol server (FreeBSD distribution), with several
+ * modifications. This server is *not* compatible with tftp, as the
+ * protocol has changed considerably.
+ */
+
+#define SEGSIZE 512 /* data segment size */
+#define MAXIMUM_KDP_PKTSIZE (16384)
+/*
+ * Packet types.
+ */
+#define RRQ 1 /* read request */
+#define WRQ 2 /* write request */
+#define DATA 3 /* data packet */
+#define ACK 4 /* acknowledgement */
+#define ERROR 5 /* error code */
+#define KDP_SEEK 6 /* Seek to specified offset */
+#define KDP_EOF 7 /* end of file */
+
+struct kdumphdr {
+ short th_opcode; /* packet type */
+ union {
+ unsigned int tu_block; /* block # */
+ unsigned int tu_code; /* error code */
+ char tu_stuff[1]; /* request packet stuff */
+ } th_u;
+ char th_data[0]; /* data or error string */
+}__attribute__((packed));
+
+#define th_block th_u.tu_block
+#define th_code th_u.tu_code
+#define th_stuff th_u.tu_stuff
+#define th_msg th_data
+
+/*
+ * Error codes.
+ */
+#define EUNDEF 0 /* not defined */
+#define ENOTFOUND 1 /* file not found */
+#define EACCESS 2 /* access violation */
+#define ENOSPACE 3 /* disk full or allocation exceeded */
+#define EBADOP 4 /* illegal KDUMP operation */
+#define EBADID 5 /* unknown transfer ID */
+#define EEXISTS 6 /* file already exists */
+#define ENOUSER 7 /* no such user */
+
+#define DEBUG 0
+#define WRITE_DEBUG 0
+#define KDUMPD_DEBUG_LEVEL LOG_ALERT
+#define KDP_LARGE_CRASHDUMP_PKT_SIZE (1440 - sizeof(struct udpiphdr))
+
+#endif
diff --git a/network_cmds/kdumpd.tproj/kdumpd.8 b/network_cmds/kdumpd.tproj/kdumpd.8
new file mode 100755
index 0000000..8ce4a8e
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpd.8
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1983, 1991, 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.
+.\"
+.\" @(#)tftpd.8 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/libexec/tftpd/tftpd.8,v 1.15 2001/07/15 07:53:42 dd Exp $
+.\"
+.Dd June 10, 2020
+.Dt KDUMPD 8
+.Os
+.Sh NAME
+.Nm kdumpd
+.Nd Mac OS X remote kernel core dump server
+.Sh SYNOPSIS
+.Nm /usr/libexec/kdumpd
+.Op Ar directory
+.Sh DESCRIPTION
+.Nm Kdumpd
+is a server which receives
+kernel states in the form of
+a core dump from a remote
+Mac OS X machine.
+The
+.Tn kdumpd
+server operates
+on UDP port 1069, although this
+may be configurable in the future.
+The server should be started by
+.Xr launchctl 1 .
+.Pp
+The server should have the user ID
+with the lowest possible privilege,
+usually the user "nobody".
+.Pp
+By default the server stores kernel cores
+in the directory
+.Pa /var/tmp/PanicDumps .
+The directory needs to already exist for kdumpd
+to save core dumps.
+.Pp
+The server returns an EEXIST error
+to the remote kernel if it receives a
+request for an existing file - i.e.
+only new files can be created. The server
+also disallows path specifications in the
+incoming file name.
+.Sh HISTORY
+The
+.Nm
+command is based on Berkeley
+.Xr tftpd 8 ,
+by way of FreeBSD, with several modifications.
+.Sh SEE ALSO
+.Xr launchd 8 ,
+.Xr launchctl 1 ,
+.Xr launchd.plist 5
diff --git a/network_cmds/kdumpd.tproj/kdumpd.c b/network_cmds/kdumpd.tproj/kdumpd.c
new file mode 100644
index 0000000..61762fe
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpd.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 1983, 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/* Mac OS X kernel core dump server, based on the BSD trivial file
+ * transfer protocol server (FreeBSD distribution), with several
+ * modifications. This server is *not* compatible with tftp, as the
+ * protocol has changed considerably.
+ */
+
+/*
+ * Based on the trivial file transfer protocol server.
+ *
+ * The original version included many modifications by Jim Guyton
+ * <guyton@rand-unix>.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <netinet/in.h>
+#include "kdump.h"
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <libkern/OSByteOrder.h>
+
+#include "kdumpsubs.h"
+
+#define DEFAULT_KDUMPD_PORTNO (1069)
+#define TIMEOUT 2
+
+int peer;
+int rexmtval = TIMEOUT;
+int maxtimeout = 25 * TIMEOUT;
+
+#define PKTSIZE SEGSIZE+6
+
+char buf[MAXIMUM_KDP_PKTSIZE];
+char ackbuf[MAXIMUM_KDP_PKTSIZE];
+struct sockaddr_in from;
+socklen_t fromlen;
+
+void kdump __P((struct kdumphdr *, int));
+
+/*
+ * Null-terminated directory prefix list for absolute pathname requests and
+ * search list for relative pathname requests.
+ *
+ * MAXDIRS should be at least as large as the number of arguments that
+ * inetd allows (currently 20).
+ */
+#define MAXDIRS 20
+static struct dirlist {
+ char *name;
+ int len;
+} dirs[MAXDIRS+1];
+static int suppress_naks;
+static int logging = 1;
+static int ipchroot;
+static int server_mode = 1;
+
+static char *errtomsg __P((int));
+static void nak __P((int));
+static char * __P(verifyhost(struct sockaddr_in *));
+uint32_t kdp_crashdump_pkt_size = (SEGSIZE + (sizeof(struct kdumphdr)));
+uint32_t kdp_crashdump_seg_size = SEGSIZE;
+
+#define KDP_FEATURE_MASK_STRING "features"
+enum {KDP_FEATURE_LARGE_CRASHDUMPS = 1, KDP_FEATURE_LARGE_PKT_SIZE = 2};
+
+uint32_t kdp_crashdump_feature_mask;
+uint32_t kdp_feature_large_crashdumps, kdp_feature_large_packets;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct kdumphdr *tp;
+ register int n;
+ int ch, on;
+ struct sockaddr_in sin;
+ char *chroot_dir = NULL;
+ struct passwd *nobody;
+ char *chuser = "nobody";
+
+ openlog("kdumpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+ while ((ch = getopt(argc, argv, "cClns:u:w")) != -1) {
+ switch (ch) {
+ case 'c':
+ ipchroot = 1;
+ break;
+ case 'C':
+ ipchroot = 2;
+ break;
+ case 'l':
+ logging = 1;
+ break;
+ case 'n':
+ suppress_naks = 1;
+ break;
+ case 's':
+ chroot_dir = optarg;
+ break;
+ case 'u':
+ chuser = optarg;
+ break;
+ case 'w':
+ server_mode = 0;
+ break;
+ default:
+ syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
+ }
+ }
+
+ if (optind < argc) {
+ struct dirlist *dirp;
+
+ /* Get list of directory prefixes. Skip relative pathnames. */
+ for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
+ optind++) {
+ if (argv[optind][0] == '/') {
+ dirp->name = argv[optind];
+ dirp->len = strlen(dirp->name);
+ dirp++;
+ }
+ }
+ }
+ else if (chroot_dir) {
+ dirs->name = "/";
+ dirs->len = 1;
+ }
+ if (ipchroot && chroot_dir == NULL) {
+ syslog(LOG_ERR, "-c requires -s");
+ exit(1);
+ }
+
+ /* If we are not in server mode, skip the whole 'inetd' logic below. */
+ if (server_mode) {
+ on = 1;
+ if (ioctl(0, FIONBIO, &on) < 0) {
+ syslog(LOG_ERR, "ioctl(FIONBIO): %m");
+ exit(1);
+ }
+ fromlen = sizeof (from);
+ n = recvfrom(0, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ if (n < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ /*
+ * Now that we have read the message out of the UDP
+ * socket, we fork and exit. Thus, inetd will go back
+ * to listening to the kdump port, and the next request
+ * to come in will start up a new instance of kdumpd.
+ *
+ * We do this so that inetd can run kdumpd in "wait" mode.
+ * The problem with kdumpd running in "nowait" mode is that
+ * inetd may get one or more successful "selects" on the
+ * kdump port before we do our receive, so more than one
+ * instance of kdumpd may be started up. Worse, if kdumpd
+ * breaks before doing the above "recvfrom", inetd would
+ * spawn endless instances, clogging the system.
+ */
+ {
+ int pid;
+ int i;
+ socklen_t j;
+
+ for (i = 1; i < 20; i++) {
+ pid = fork();
+ if (pid < 0) {
+ sleep(i);
+ /*
+ * flush out to most recently sent request.
+ *
+ * This may drop some requests, but those
+ * will be resent by the clients when
+ * they timeout. The positive effect of
+ * this flush is to (try to) prevent more
+ * than one kdumpd being started up to service
+ * a single request from a single client.
+ */
+ j = sizeof from;
+ i = recvfrom(0, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &j);
+ if (i > 0) {
+ n = i;
+ fromlen = j;
+ }
+ } else {
+ break;
+ }
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ } else if (pid != 0) {
+ exit(0);
+ }
+ }
+ }
+
+ /*
+ * Since we exit here, we should do that only after the above
+ * recvfrom to keep inetd from constantly forking should there
+ * be a problem. See the above comment about system clogging.
+ */
+ if (chroot_dir) {
+ if (ipchroot) {
+ char tempchroot[MAXPATHLEN];
+ char *tempaddr;
+ struct stat sb;
+ int statret;
+
+ tempaddr = inet_ntoa(from.sin_addr);
+ snprintf(tempchroot, sizeof(tempchroot), "%s/%s", chroot_dir, tempaddr);
+ statret = stat(tempchroot, &sb);
+ if (((sb.st_mode & S_IFMT ) == S_IFDIR) &&
+ (statret == 0 || (statret == -1 && ipchroot == 1)))
+ chroot_dir = tempchroot;
+ }
+ /* Must get this before chroot because /etc might go away */
+ if ((nobody = getpwnam(chuser)) == NULL) {
+ syslog(LOG_ERR, "%s: no such user", chuser);
+ exit(1);
+ }
+ if (chroot(chroot_dir)) {
+ syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
+ exit(1);
+ }
+ chdir( "/" );
+ setuid(nobody->pw_uid);
+ } else if (0 != chdir(dirs->name)) {
+ syslog(LOG_ERR, "chdir%s: %m", dirs->name);
+ }
+
+ from.sin_family = AF_INET;
+ alarm(0);
+ close(0);
+ close(1);
+ peer = socket(AF_INET, SOCK_DGRAM, 0);
+ if (peer < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ if (!server_mode) {
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_port = htons((uint16_t) DEFAULT_KDUMPD_PORTNO);
+ }
+
+ if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ exit(1);
+ }
+
+ if (!server_mode) {
+ /*
+ * Wait for an incoming message from a remote peer, note that we need to
+ * populate n since kdump() expect the first message to be in buf
+ * already.
+ */
+ socklen_t slen = sizeof(from);
+ n = recvfrom(peer, buf, sizeof(buf), 0,
+ (struct sockaddr *) &from, &slen);
+ if (n <= 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ }
+
+ if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
+ syslog(LOG_ERR, "connect: %m");
+ exit(1);
+ }
+ tp = (struct kdumphdr *)buf;
+ tp->th_opcode = ntohs(tp->th_opcode);
+ if (tp->th_opcode == WRQ)
+ kdump(tp, n);
+ exit(1);
+}
+
+struct formats;
+int validate_access __P((char **, int));
+
+void recvfile __P((struct formats *));
+
+struct formats {
+ char *f_mode;
+ int (*f_validate) __P((char **, int));
+
+ void (*f_recv) __P((struct formats *));
+ int f_convert;
+} formats[] = {
+ { "netascii", validate_access, recvfile, 1 },
+ { "octet", validate_access, recvfile, 0 },
+ { 0 }
+};
+
+/*
+ * Handle initial connection protocol.
+ */
+void
+kdump(tp, size)
+ struct kdumphdr *tp;
+ int size;
+{
+ register char *cp;
+ int first = 1, ecode;
+ register struct formats *pf;
+ char *filename, *mode = NULL;
+
+ filename = cp = tp->th_stuff;
+again:
+ while (cp < buf + size) {
+ if (*cp == '\0')
+ break;
+ cp++;
+ }
+ if (*cp != '\0') {
+ nak(EBADOP);
+ exit(1);
+ }
+ if (first) {
+ mode = ++cp;
+ first = 0;
+ goto again;
+ }
+ for (cp = mode; *cp; cp++)
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+
+ cp++;
+ if (strncmp(KDP_FEATURE_MASK_STRING, cp, sizeof(KDP_FEATURE_MASK_STRING)) == 0) {
+ kdp_crashdump_feature_mask = ntohl(*(uint32_t *) (cp + sizeof(KDP_FEATURE_MASK_STRING)));
+ kdp_feature_large_crashdumps = kdp_crashdump_feature_mask & KDP_FEATURE_LARGE_CRASHDUMPS;
+ kdp_feature_large_packets = kdp_crashdump_feature_mask & KDP_FEATURE_LARGE_PKT_SIZE;
+
+ if (kdp_feature_large_packets) {
+ kdp_crashdump_pkt_size = KDP_LARGE_CRASHDUMP_PKT_SIZE;
+ kdp_crashdump_seg_size = kdp_crashdump_pkt_size - sizeof(struct kdumphdr);
+ }
+ syslog(KDUMPD_DEBUG_LEVEL, "Received feature mask %s:0x%x", cp, kdp_crashdump_feature_mask);
+ } else
+ syslog(KDUMPD_DEBUG_LEVEL, "Unable to locate feature mask, mode: %s", mode);
+
+ for (pf = formats; pf->f_mode; pf++)
+ if (strcmp(pf->f_mode, mode) == 0)
+ break;
+ if (pf->f_mode == 0) {
+ nak(EBADOP);
+ exit(1);
+ }
+ ecode = (*pf->f_validate)(&filename, tp->th_opcode);
+ if (logging) {
+ syslog(KDUMPD_DEBUG_LEVEL, "%s: %s request for %s: %s", verifyhost(&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ filename, errtomsg(ecode));
+ }
+ if (ecode) {
+ /*
+ * Avoid storms of naks to a RRQ broadcast for a relative
+ * bootfile pathname from a diskless Sun.
+ */
+ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
+ exit(0);
+ nak(ecode);
+ exit(1);
+ }
+ if (tp->th_opcode == WRQ)
+ (*pf->f_recv)(pf);
+
+ exit(0);
+}
+
+
+FILE *file;
+
+/*
+ * Validate file access. We only allow storage of files that do not already
+ * exist, and that do not include directory specifiers in their pathnames.
+ * This is because kernel coredump filenames should always be of the form
+ * "core-version-IP as dotted quad-random string" as in :
+ * core-custom-17.202.40.204-a75b4eec
+ * The file is written to the directory supplied as the first argument
+ * in inetd.conf
+ */
+
+int
+validate_access(char **filep, int mode)
+{
+ struct stat stbuf;
+ int fd;
+ char *filename = *filep;
+ static char pathname[MAXPATHLEN];
+
+ if (strstr(filename, "/") || strstr(filename, ".."))
+ return (EACCESS);
+
+ snprintf(pathname, sizeof(pathname), "./%s", filename);
+
+ if (0 == stat(pathname, &stbuf))
+ return (EEXIST);
+
+ if (errno != ENOENT)
+ return (errno);
+
+
+ fd = open(filename, O_RDWR|O_CREAT|O_TRUNC , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+
+ if (fd < 0)
+ return (errno + 100);
+
+ file = fdopen(fd, (mode == RRQ)? "r":"w");
+ if (file == NULL) {
+ return errno+100;
+ }
+
+ return (0);
+}
+
+int timeout;
+jmp_buf timeoutbuf;
+
+void
+timer()
+{
+
+ timeout += rexmtval;
+ if (timeout >= maxtimeout)
+ {
+ longjmp(timeoutbuf, 2);
+ }
+ longjmp(timeoutbuf, 1);
+}
+
+void
+justquit()
+{
+ exit(0);
+}
+
+/*
+ * Receive a file.
+ */
+void
+recvfile(pf)
+ struct formats *pf;
+{
+ struct kdumphdr *dp, *w_init();
+ register struct kdumphdr *ap; /* ack buffer */
+ register int n, size;
+ volatile unsigned int block;
+ volatile unsigned int jmpval = 0;
+
+ signal(SIGALRM, timer);
+ dp = w_init();
+ ap = (struct kdumphdr *)ackbuf;
+ block = 0;
+ do {
+send_seek_ack: timeout = 0;
+ if (block == 0)
+ ap->th_opcode = htons((u_short)ACK | ((kdp_feature_large_crashdumps | kdp_feature_large_packets) << 8));
+ else
+ ap->th_opcode = htons((u_short)ACK);
+ ap->th_block = htonl((unsigned int)block);
+ block++;
+ jmpval = setjmp(timeoutbuf);
+ if (2 == jmpval)
+ {
+ syslog (LOG_ERR, "Timing out and flushing file to disk");
+ goto flushfile;
+ }
+send_ack:
+ if (send(peer, ackbuf, 6 , 0) != 6) {
+ syslog(LOG_ERR, "write: %m");
+ goto abort;
+ }
+ write_behind(file, pf->f_convert);
+ for ( ; ; ) {
+ alarm(rexmtval);
+ n = recv(peer, dp, kdp_crashdump_pkt_size, 0);
+ alarm(0);
+ if (n < 0) { /* really? */
+ syslog(LOG_ERR, "read: %m");
+ goto abort;
+ }
+ dp->th_opcode = ntohs((u_short)dp->th_opcode);
+ dp->th_block = ntohl((unsigned int)dp->th_block);
+#if DEBUG
+ syslog(KDUMPD_DEBUG_LEVEL, "Received packet type %u, block %u\n", (unsigned)dp->th_opcode, (unsigned)dp->th_block);
+#endif
+
+ if (dp->th_opcode == ERROR)
+ goto abort;
+
+ if (dp->th_opcode == KDP_EOF)
+ {
+ syslog (LOG_ERR, "Received last panic dump packet");
+ goto final_ack;
+ }
+ if (dp->th_opcode == KDP_SEEK)
+ {
+ if (dp->th_block == block)
+ {
+ off_t crashdump_offset = 0;
+ unsigned int tempoff = 0;
+
+ if (kdp_feature_large_crashdumps) {
+ crashdump_offset = OSSwapBigToHostInt64((*(uint64_t *)dp->th_data));
+ }
+ else {
+ bcopy (dp->th_data, &tempoff, sizeof(unsigned int));
+ crashdump_offset = ntohl(tempoff);
+ }
+
+#if DEBUG
+ syslog(KDUMPD_DEBUG_LEVEL, "Seeking to offset 0x%llx\n", crashdump_offset);
+#endif
+ errno = 0;
+ lseek(fileno (file), crashdump_offset, SEEK_SET);
+ if (errno)
+ syslog (LOG_ERR, "lseek: %m");
+
+ goto send_seek_ack;
+ }
+ (void) synchnet(peer);
+ if (dp->th_block == (block-1))
+ {
+ syslog (LOG_DAEMON|LOG_ERR, "Retransmitting seek ack - current block %u, received block %u", block, dp->th_block);
+ goto send_ack; /* rexmit */
+ }
+ }
+
+ if (dp->th_opcode == DATA) {
+ if (dp->th_block == block) {
+ break; /* normal */
+ }
+ /* Re-synchronize with the other side */
+ (void) synchnet(peer);
+ if (dp->th_block == (block-1))
+ {
+ syslog (LOG_DAEMON|LOG_ERR, "Retransmitting ack - current block %u, received block %u", block, dp->th_block);
+ goto send_ack; /* rexmit */
+ }
+ else
+ syslog (LOG_DAEMON|LOG_ERR, "Not retransmitting ack - current block %u, received block %u", block, dp->th_block);
+ }
+ }
+#if DEBUG
+ syslog(KDUMPD_DEBUG_LEVEL, "Writing block sized %u, current offset 0x%llx\n", n - 6, ftello(file));
+#endif
+ size = writeit(file, &dp, n - 6, pf->f_convert);
+ if (size != (n-6)) { /* ahem */
+ if (size < 0) nak(errno + 100);
+ else nak(ENOSPACE);
+ goto abort;
+ }
+ } while (dp->th_opcode != KDP_EOF);
+
+final_ack:
+ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
+ ap->th_block = htonl((unsigned int) (block));
+ (void) send(peer, ackbuf, 6, 0);
+flushfile:
+ write_behind(file, pf->f_convert);
+ (void) fclose(file); /* close data file */
+ syslog (LOG_ERR, "file closed, sending final ACK\n");
+
+ signal(SIGALRM, justquit); /* just quit on timeout */
+ alarm(rexmtval);
+ n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
+ alarm(0);
+ if (n >= 6 && /* if read some data */
+ dp->th_opcode == DATA && /* and got a data block */
+ block == dp->th_block) { /* then my last ack was lost */
+ (void) send(peer, ackbuf, 6, 0); /* resend final ack */
+ }
+abort:
+ return;
+}
+
+/* update if needed, when adding new errmsgs */
+#define MAXERRMSGLEN 40
+
+struct errmsg {
+ int e_code;
+ char *e_msg;
+} errmsgs[] = {
+ { EUNDEF, "Undefined error code" },
+ { ENOTFOUND, "File not found" },
+ { EACCESS, "Access violation" },
+ { ENOSPACE, "Disk full or allocation exceeded" },
+ { EBADOP, "Illegal KDUMP operation" },
+ { EBADID, "Unknown transfer ID" },
+ { EEXISTS, "File already exists" },
+ { ENOUSER, "No such user" },
+ { -1, 0 }
+};
+
+static char *
+errtomsg(error)
+ int error;
+{
+ static char buf[20];
+ register struct errmsg *pe;
+ if (error == 0)
+ return "success";
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ return pe->e_msg;
+ snprintf(buf, sizeof(buf), "error %d", error);
+ return buf;
+}
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard KDUMP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void
+nak(error)
+ int error;
+{
+ register struct kdumphdr *tp;
+ int length;
+ register struct errmsg *pe;
+
+ tp = (struct kdumphdr *)buf;
+ tp->th_opcode = htons((u_short)ERROR);
+ tp->th_code = htons((unsigned int)error);
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ break;
+ if (pe->e_code < 0) {
+ pe->e_msg = strerror(error - 100);
+ tp->th_code = EUNDEF; /* set 'undef' errorcode */
+ }
+ if (strlen(pe->e_msg) > MAXERRMSGLEN) {
+ syslog(LOG_ERR, "nak: error msg too long");
+ return;
+ }
+
+ strlcpy(tp->th_msg, pe->e_msg, MAXERRMSGLEN);
+ length = strlen(pe->e_msg);
+ tp->th_msg[length] = '\0';
+ length += 5;
+ if (send(peer, buf, length, 0) != length)
+ syslog(LOG_ERR, "nak: %m");
+
+ return;
+}
+
+static char *
+verifyhost(fromp)
+ struct sockaddr_in *fromp;
+{
+ struct hostent *hp;
+
+ hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(fromp->sin_addr),
+ fromp->sin_family);
+ if(hp)
+ return hp->h_name;
+ else
+ return inet_ntoa(fromp->sin_addr);
+}
diff --git a/network_cmds/kdumpd.tproj/kdumpsubs.c b/network_cmds/kdumpd.tproj/kdumpsubs.c
new file mode 100644
index 0000000..283ca62
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpsubs.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 1983, 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.
+ * 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.
+ */
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+ server. Written originally with multiple buffers in mind, but current
+ implementation has two buffer logic wired in.
+
+ Todo: add some sort of final error check so when the write-buffer
+ is finally flushed, the caller can detect if the disk filled up
+ (or had an i/o error) and return a nak to the other side.
+
+ Jim Guyton 10/85
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+#include <netinet/in.h>
+#include "kdump.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include "kdumpsubs.h"
+
+#define PKTSIZE SEGSIZE+6 /* should be moved to kdump.h */
+
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[MAXIMUM_KDP_PKTSIZE]; /* room for data packet */
+} bfs[2];
+
+ /* Values for bf.counter */
+#define BF_ALLOC -3 /* alloc'd but not yet filled */
+#define BF_FREE -2 /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone; /* index of next buffer to use */
+static int current; /* index of buffer in use */
+
+ /* control flags for crlf conversions */
+int newline = 0; /* fillbuf: in middle of newline expansion */
+int prevchar = -1; /* putbuf: previous char (cr check) */
+
+static struct kdumphdr *rw_init __P ((int));
+
+struct kdumphdr *w_init() { return rw_init(0); } /* write-behind */
+struct kdumphdr *r_init() { return rw_init(1); } /* read-ahead */
+
+extern uint32_t kdp_crashdump_pkt_size;
+extern uint32_t kdp_crashdump_seg_size;
+
+/* init for either read-ahead or write-behind */
+/* zero for write-behind, one for read-head */
+static struct kdumphdr *
+rw_init(int x)
+{
+ newline = 0; /* init crlf flag */
+ prevchar = -1;
+ bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
+ current = 0;
+ bfs[1].counter = BF_FREE;
+ nextone = x; /* ahead or behind? */
+ return (struct kdumphdr *)bfs[0].buf;
+}
+
+
+/* Have emptied current buffer by sending to net and getting ack.
+ Free it and return next buffer filled with data.
+ */
+/* if true, convert to ascii */
+/* file opened for read */
+
+/* int */
+/* readit(FILE *file, struct kdumphdr **dpp, int convert) */
+/* { */
+/* struct bf *b; */
+
+/* bfs[current].counter = BF_FREE; /\* free old one *\/ */
+/* current = !current; /\* "incr" current *\/ */
+
+/* b = &bfs[current]; /\* look at new buffer *\/ */
+/* if (b->counter == BF_FREE) /\* if it's empty *\/ */
+/* read_ahead(file, convert); /\* fill it *\/ */
+/* /\* assert(b->counter != BF_FREE);*\//\* check *\/ */
+/* *dpp = (struct kdumphdr *)b->buf; /\* set caller's ptr *\/ */
+/* return b->counter; */
+/* } */
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are lf -> cr,lf and cr -> cr, nul
+ */
+/* FILE *file; file opened for read */
+/* int convert; if true, convert to ascii */
+void
+read_ahead(FILE *file, int convert)
+{
+ register int i;
+ register char *p;
+ register int c;
+ struct bf *b;
+ struct kdumphdr *dp;
+
+ b = &bfs[nextone]; /* look at "next" buffer */
+ if (b->counter != BF_FREE) /* nop if not free */
+ return;
+ nextone = !nextone; /* "incr" next buffer ptr */
+
+ dp = (struct kdumphdr *)b->buf;
+
+ if (convert == 0) {
+ b->counter = read(fileno(file), dp->th_data, kdp_crashdump_seg_size);
+ return;
+ }
+
+ p = dp->th_data;
+ for (i = 0 ; i < kdp_crashdump_seg_size; i++) {
+ if (newline) {
+ if (prevchar == '\n')
+ c = '\n'; /* lf to cr,lf */
+ else c = '\0'; /* cr to cr,nul */
+ newline = 0;
+ }
+ else {
+ c = getc(file);
+ if (c == EOF) break;
+ if (c == '\n' || c == '\r') {
+ prevchar = c;
+ c = '\r';
+ newline = 1;
+ }
+ }
+ *p++ = c;
+ }
+ b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+ from the queue. Calls write_behind only if next buffer not
+ available.
+ */
+int
+writeit(FILE *file, struct kdumphdr **dpp, int ct, int convert)
+{
+ bfs[current].counter = ct; /* set size of data to write */
+ current = !current; /* switch to other buffer */
+ if (bfs[current].counter != BF_FREE) /* if not free */
+ (void)write_behind(file, convert); /* flush it */
+ bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
+ *dpp = (struct kdumphdr *)bfs[current].buf;
+ return ct; /* this is a lie of course */
+}
+
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else. In this case we leave it alone.
+ */
+int
+write_behind(FILE *file, int convert)
+{
+ char *buf;
+ int count;
+ register int ct;
+ register char *p;
+ register int c; /* current character */
+ struct bf *b;
+ struct kdumphdr *dp;
+
+ b = &bfs[nextone];
+ if (b->counter < -1) /* anything to flush? */
+ return 0; /* just nop if nothing to do */
+
+ count = b->counter; /* remember byte count */
+ b->counter = BF_FREE; /* reset flag */
+ dp = (struct kdumphdr *)b->buf;
+ nextone = !nextone; /* incr for next time */
+ buf = dp->th_data;
+
+ if (count <= 0) return -1; /* nak logic? */
+
+ if (convert == 0)
+ return write(fileno(file), buf, count);
+
+ p = buf;
+ ct = count;
+ while (ct--) { /* loop over the buffer */
+ c = *p++; /* pick up a character */
+ if (prevchar == '\r') { /* if prev char was cr */
+ if (c == '\n') /* if have cr,lf then just */
+ fseek(file, -1, 1); /* smash lf on top of the cr */
+ else
+ if (c == '\0') /* if have cr,nul then */
+ goto skipit; /* just skip over the putc */
+ /* else just fall through and allow it */
+ }
+ putc(c, file);
+skipit:
+ prevchar = c;
+ }
+ return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch. Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+/*int f;socket to flush */
+int
+synchnet(int f)
+{
+ int i, j = 0;
+ char rbuf[kdp_crashdump_pkt_size];
+ struct sockaddr_in from;
+ socklen_t fromlen;
+
+ while (1) {
+ (void) ioctl(f, FIONREAD, &i);
+ if (i) {
+ j++;
+ fromlen = sizeof from;
+ (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } else {
+ return(j);
+ }
+ }
+}
diff --git a/network_cmds/kdumpd.tproj/kdumpsubs.h b/network_cmds/kdumpd.tproj/kdumpsubs.h
new file mode 100644
index 0000000..b7ec1c6
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpsubs.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 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.
+ *
+ * @(#)kdumpsubs.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Prototypes for read-ahead/write-behind subroutines for kdump user and
+ * server.
+ */
+struct kdumphdr *r_init __P((void));
+void read_ahead __P((FILE *, int));
+int readit __P((FILE *, struct kdumphdr **, int));
+
+int synchnet __P((int));
+
+struct kdumphdr *w_init __P((void));
+int write_behind __P((FILE *, int));
+int writeit __P((FILE *, struct kdumphdr **, int, int));
+
diff --git a/network_cmds/mnc.tproj/LICENCE b/network_cmds/mnc.tproj/LICENCE
new file mode 100644
index 0000000..4fec3e3
--- /dev/null
+++ b/network_cmds/mnc.tproj/LICENCE
@@ -0,0 +1,37 @@
+/*
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+ *
+ */
+
diff --git a/network_cmds/mnc.tproj/README b/network_cmds/mnc.tproj/README
new file mode 100644
index 0000000..77cbaa8
--- /dev/null
+++ b/network_cmds/mnc.tproj/README
@@ -0,0 +1,63 @@
+1 MNC - Multicast NetCat
+ ------------------------
+
+1. Introduction
+
+mnc is a simple, one-direction-at-a-time, "netcat"-like application using
+multicast. The aim is to provide a tool for easy debugging and testing when
+setting up a multicast network or host. MNC supports IPv4 and IPv6
+any-source-multicast and single-source-multicast, but depending on your
+platform some of those features may not be available:
+
+ L = Listen (Implies IGMP/MLD mupport)
+ S = Send
+
+ +----------+----------+----------+----------+----------+
+ | Platform | IPv4 ASM | IPv4 SSM | IPv6 ASM | IPv6 SSM |
+ +----------+----------+----------+----------+----------+
+ | *nix | L + S | L + S | L + S | L + S |
+ +----------+----------+----------+----------+----------+
+ | Win2k | L + S | S | None | None |
+ +----------+----------+----------+----------+----------+
+ | WinXP | L + S | L + S | S | S |
+ +----------+----------+----------+----------+----------+
+ | Win2k3 | L + S | L + S | S | S |
+ +----------+----------+----------+----------+----------+
+
+man doc/mnc.1 for information and help on how to run multicast.
+
+2. Supported platforms
+
+As of September 2004, mnc has been compiled and tested with Linux 2.6.8
+kernels, the BSD KAME stack and Windows XP Profesional. Currently automatic
+interface selection does not work on a KAME-based host and you will need to
+specify the interface when in listening mode.
+
+3. Installing mnc from source on UNIX:
+
+ ./configure ; make ; make install
+
+4. Compiling from source on Windows:
+
+nmc is compilable with free utilities available from Microsoft. You need to
+download and install the free (as in beer) MS Visual C++ command-line tools
+from:
+
+ http://msdn.microsoft.com/visualc/vctoolkit2003/
+
+and the SDK relevant to your platform from:
+
+ http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+
+You can run a Visual C++ command-line session, and use:
+
+ cl /DWINDOWS=1 /TC /c *.c
+ link /fixed /out:mnc.exe *.obj ws2_32.lib
+
+to compile a working mnc.exe. The Windows version of MNC does not yet fully
+support IPv6 due to underlying limitation in the Operating System.
+
+5. Reporting problems
+
+Any problems, bugs or suggested features should be mailed to colm
+at apache.org.
diff --git a/network_cmds/mnc.tproj/mnc.1 b/network_cmds/mnc.tproj/mnc.1
new file mode 100644
index 0000000..ed1073b
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc.1
@@ -0,0 +1,101 @@
+.\"
+.\" mnc.1 -- mnc manual
+.\"
+.\" Colm MacCárthaigh, <colm@apache.org>
+.\"
+.\" Copyright (c) 2007 Coolm MacCarthaigh.
+.\" Copyright (c) 2004-2006 HEAnet Ltd.
+.\"
+.\" This software is an open source.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" Redistributions of source code must retain the above copyright notice,
+.\" this list of conditions and the following disclaimer.
+.\"
+.\" 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.
+.\"
+.\" Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+.\"
+.TH mnc 1 "17 September 2004" "mnc"
+.SH NAME
+mnc \- Multicast NetCat
+.SH SYNOPSIS
+.BR mnc
+[ -l ] [ -i interface ] [ -p port ] group-id [ source-address ]
+.SH DESCRIPTION
+.B mnc
+is designed for simple multicast debugging and testing. It supports
+IPv4 and IPv6 any-source multicast and source-specific multicast.
+In standard mode it will multicast the standard-input verbatim.
+In listening mode it recieves the content and displays it on the
+standard output.
+.PP
+When given the optional source-address, mnc will attempt to use
+source-specific multicast. You may also specify this address
+in standard mode and mnc will use this source-address for
+outgoing packets.
+.PP
+.SH OPTIONS
+.IP \-l
+Listen for multicast packets. Default is to send.
+.IP \-i\ "interface"
+When listening for multicast packets, use the specified interface.
+.IP \-p\ "port"
+Specify a UDP port to use for sending or receiving packets. Default is to use port 1234.
+.SH "SEE ALSO"
+.BR nc (1)
+.PP
+.SH EXAMPLES
+To send IPv4 packets to an ASM group-id:
+.PP
+.RS
+mnc 233.1.2.3
+.RE
+.PP
+To receive IPv4 ASM packets from the same group-id, using eth0 as
+the listening interface:
+.PP
+.RS
+mnc -l -i eth0 233.1.2.3
+.RE
+.PP
+To receive IPv4 packets from an SSM group-id, using eth1 as the
+listening interface and 193.1.219.90 as the permitted source:
+.PP
+.RS
+mnc -l -i eth1 232.0.0.1 193.1.219.90
+.RE
+.PP
+To receive IPv6 packets from an SSM group-id, using eth1 as the
+listening interface and 2001:770:18:2::90 as the permitted source:
+.PP
+.RS
+mnc -l -i eth1 ff31::12 2001:770:18:2::90
+.RE
+.PP
+.SH CREDITS
+mnc is by Colm MacCárthaigh <colm@apache.org> and is available from:
+.PP
+http://people.apache.org/~colm/mnc/
+.PP
+Additional multicast development and support provided by John Lyons
+<john.lyons@heanet.ie> and Eoin Kenny <eoin.kenny@heanet.ie>
diff --git a/network_cmds/mnc.tproj/mnc.h b/network_cmds/mnc.tproj/mnc.h
new file mode 100644
index 0000000..db6e68e
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc.h
@@ -0,0 +1,92 @@
+/*
+ * $Id: mnc.h,v 1.4 2004/09/22 14:07:10 colmmacc Exp $
+ *
+ * mnc.h -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#ifndef _MNC_H_
+#define _MNC_H_
+
+#ifndef WINDOWS
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#else
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#endif
+
+/* The UDP port MNC will use by default */
+#define MNC_DEFAULT_PORT "1234"
+
+struct mnc_configuration
+{
+ /* Are we sending or recieving ? */
+ enum {SENDER, LISTENER} mode;
+
+ /* What UDP port are we using ? */
+ char * port;
+
+ /* The group-id */
+ struct addrinfo * group;
+
+ /* The source */
+ struct addrinfo * source;
+
+ /* An interface index for listening */
+ char * iface;
+};
+
+
+/* Functions in mnc_opts.c */
+void usage(void);
+struct mnc_configuration * parse_arguments(int argc, char **argv);
+
+/* Functions in mnc_multicast.c */
+int multicast_setup_listen(int, struct addrinfo *, struct addrinfo *, char *);
+int multicast_setup_send(int, struct addrinfo *, struct addrinfo *);
+
+/* Functions in mnc_error.c */
+void mnc_warning(char * string, ...);
+void mnc_error(char * string, ...);
+
+#endif /* _MNC_H_ */
diff --git a/network_cmds/mnc.tproj/mnc_error.c b/network_cmds/mnc.tproj/mnc_error.c
new file mode 100644
index 0000000..4478e7e
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_error.c
@@ -0,0 +1,95 @@
+/*
+ * $Id: mnc_error.c,v 1.2 2004/09/22 16:02:26 colmmacc Exp $
+ *
+ * mnc_multicast.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "mnc.h"
+
+void mnc_warning(char * string, ...)
+{
+ va_list ap;
+
+ /* Do the vararg stuff */
+ va_start(ap, string);
+
+ /* Output our name */
+ if (fprintf(stderr, "mnc: ") < 0)
+ {
+ exit(2);
+ }
+
+ /* Output our error */
+ if (vfprintf(stderr, string, ap) < 0)
+ {
+ exit(2);
+ }
+
+ /* End the vararg stuff */
+ va_end(ap);
+}
+
+void mnc_error(char * string, ...)
+{
+ va_list ap;
+
+ /* Do the vararg stuff */
+ va_start(ap, string);
+
+ /* Output our name */
+ if (fprintf(stderr, "mnc: ") < 0)
+ {
+ exit(2);
+ }
+
+ /* Output our error */
+ if (vfprintf(stderr, string, ap) < 0)
+ {
+ exit(2);
+ }
+
+ /* End the vararg stuff */
+ va_end(ap);
+
+ /* Die! */
+ exit(1);
+}
diff --git a/network_cmds/mnc.tproj/mnc_main.c b/network_cmds/mnc.tproj/mnc_main.c
new file mode 100644
index 0000000..1e5c5af
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_main.c
@@ -0,0 +1,131 @@
+/*
+ * $Id: mnc_main.c,v 1.12 2004/09/22 19:14:23 colmmacc Exp $
+ *
+ * mnc_main.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#ifndef WINDOWS
+
+/* Non-windows includes */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#else
+
+/* Windows-specific includes */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#endif /* WINDOWS */
+
+#include "mnc.h"
+
+int main(int argc, char **argv)
+{
+ /* Utility variables */
+ int sock,
+ len;
+ char buffer[1024];
+
+ /* Our main configuration */
+ struct mnc_configuration * config;
+
+#ifdef WINDOWS
+ WSADATA wsaData;
+
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
+ {
+ mnc_error("This operating system is not supported\n");
+ }
+#endif
+
+ /* Parse the command line */
+ config = parse_arguments(argc, argv);
+
+ /* Create a socket */
+ if ((sock = socket(config->group->ai_family, config->group->ai_socktype,
+ config->group->ai_protocol)) < 0)
+ {
+ mnc_error("Could not create socket\n");
+ }
+
+ /* Are we supposed to listen? */
+ if (config->mode == LISTENER)
+ {
+ /* Set up the socket for listening */
+ if (multicast_setup_listen(sock, config->group, config->source,
+ config->iface) < 0)
+ {
+ mnc_error("Can not listen for multicast packets.\n");
+ }
+
+ /* Recieve the packets */
+ while ((len = recvfrom(sock, buffer, sizeof(buffer),
+ 0, NULL, NULL)) >= 0)
+ {
+ write(STDOUT_FILENO, buffer, len);
+ }
+ }
+ else /* Assume MODE == SENDER */
+ {
+ /* Set up the socket for sending */
+ if (multicast_setup_send(sock, config->group, config->source)
+ < 0)
+ {
+ mnc_error("Can not send multicast packets\n");
+ }
+
+ /* Send the packets */
+ while((len = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0)
+ {
+ sendto(sock, buffer, len, 0, config->group->ai_addr,
+ config->group->ai_addrlen);
+ }
+ }
+
+ /* Close the socket */
+ close(sock);
+
+ return 0;
+}
diff --git a/network_cmds/mnc.tproj/mnc_multicast.c b/network_cmds/mnc.tproj/mnc_multicast.c
new file mode 100644
index 0000000..35f3415
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_multicast.c
@@ -0,0 +1,404 @@
+/*
+ * $Id: mnc_multicast.c,v 1.8 2004/09/22 19:14:23 colmmacc Exp $
+ *
+ * mnc_multicast.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#ifndef WINDOWS
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+
+#else
+
+#include <sys/types.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <stdlib.h>
+
+#endif
+
+#include "mnc.h"
+
+#ifndef MCAST_JOIN_GROUP
+
+#ifdef IP_ADD_SOURCE_MEMBERSHIP
+int mnc_join_ipv4_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ struct ip_mreq_source multicast_request;
+
+ if (iface != NULL)
+ {
+ /* See if interface is a literal IPv4 address */
+ if ((multicast_request.imr_interface.s_addr =
+ inet_addr(iface)) == INADDR_NONE)
+ {
+ mnc_warning("Invalid interface address\n");
+ return -1;
+ }
+ }
+ else
+ {
+ /* set the interface to the default */
+ multicast_request.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ multicast_request.imr_multiaddr.s_addr =
+ ((struct sockaddr_in *)group->ai_addr)->sin_addr.s_addr;
+
+ multicast_request.imr_sourceaddr.s_addr =
+ ((struct sockaddr_in *)source->ai_addr)->sin_addr.s_addr;
+
+ /* Set the socket option */
+ if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
+ (char *) &multicast_request,
+ sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+#else
+
+int mnc_join_ipv4_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ mnc_warning("Sorry, No support for IPv4 source-specific multicast in this build\n");
+
+ return -1;
+}
+#endif
+
+int mnc_join_ipv6_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ mnc_warning("Sorry, No support for IPv6 source-specific multicast in this build\n");
+
+ return -1;
+}
+#else /* if MCAST_JOIN_GROUP .. */
+
+#define mnc_join_ipv6_asm(a, b, c) mnc_join_ip_asm((a), (b), (c))
+#define mnc_join_ipv4_asm(a, b, c) mnc_join_ip_asm((a), (b), (c))
+
+int mnc_join_ip_asm(int socket, struct addrinfo * group, char * iface)
+{
+ struct group_req multicast_request;
+ int ip_proto;
+
+ if (group->ai_family == AF_INET6)
+ {
+ ip_proto = IPPROTO_IPV6;
+ }
+ else
+ {
+ ip_proto = IPPROTO_IP;
+ }
+
+ if (iface != NULL)
+ {
+ if ((multicast_request.gr_interface = if_nametoindex(iface))
+ == 0)
+ {
+ mnc_warning("Ignoring unknown interface: %s\n", iface);
+ }
+ }
+ else
+ {
+ multicast_request.gr_interface = 0;
+ }
+
+ memcpy(&multicast_request.gr_group, group->ai_addr, group->ai_addrlen);
+
+ /* Set the socket option */
+ if (setsockopt(socket, ip_proto, MCAST_JOIN_GROUP, (char *)
+ &multicast_request, sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* MCAST_JOIN_GROUP */
+
+#ifndef MCAST_JOIN_SOURCE_GROUP
+int mnc_join_ipv4_asm(int socket, struct addrinfo * group, char * iface)
+{
+ struct ip_mreq multicast_request;
+
+ if (iface != NULL)
+ {
+ /* See if interface is a literal IPv4 address */
+ if ((multicast_request.imr_interface.s_addr =
+ inet_addr(iface)) == INADDR_NONE)
+ {
+ mnc_warning("Invalid interface address\n");
+ return -1;
+ }
+ }
+ else
+ {
+ /* Set the interface to the default */
+ multicast_request.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ multicast_request.imr_multiaddr.s_addr =
+ ((struct sockaddr_in *)group->ai_addr)->sin_addr.s_addr;
+
+ /* Set the socket option */
+ if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *) &multicast_request,
+ sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int mnc_join_ipv6_asm(int socket, struct addrinfo * group, char * iface)
+{
+ mnc_warning("Sorry, No support for IPv6 any-source multicast in this build\n");
+
+ return -1;
+}
+#else /* if MCAST_JOIN_SOURCE_GROUP ... */
+
+#define mnc_join_ipv4_ssm(a, b, c, d) mnc_join_ip_ssm((a), (b), (c), (d))
+#define mnc_join_ipv6_ssm(a, b, c, d) mnc_join_ip_ssm((a), (b), (c), (d))
+
+int mnc_join_ip_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source,
+ char * iface)
+{
+ struct group_source_req multicast_request;
+ int ip_proto;
+
+ if (group->ai_family == AF_INET6)
+ {
+ ip_proto = IPPROTO_IPV6;
+ }
+ else
+ {
+ ip_proto = IPPROTO_IP;
+ }
+
+ if (iface != NULL)
+ {
+ if ((multicast_request.gsr_interface = if_nametoindex(iface))
+ == 0)
+ {
+ mnc_warning("Ignoring unknown interface: %s\n", iface);
+ }
+ }
+ else
+ {
+ multicast_request.gsr_interface = 0;
+ }
+
+ memcpy(&multicast_request.gsr_group, group->ai_addr, group->ai_addrlen);
+ memcpy(&multicast_request.gsr_source, source->ai_addr,
+ source->ai_addrlen);
+
+ /* Set the socket option */
+ if (setsockopt(socket, ip_proto, MCAST_JOIN_SOURCE_GROUP,
+ (char *) &multicast_request,
+ sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* MCAST_JOIN_SOURCE_GROUP */
+
+int multicast_setup_listen(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ size_t rcvbuf;
+
+#ifndef WINDOWS
+ /* bind to the group address before anything */
+ if (bind(socket, group->ai_addr, group->ai_addrlen) != 0)
+ {
+ mnc_warning("Could not bind to group-id\n");
+ return -1;
+ }
+#else
+ if (group->ai_family == AF_INET)
+ {
+ struct sockaddr_in sin;
+
+ sin.sin_family = group->ai_family;
+ sin.sin_port = group->ai_port;
+ sin.sin_addr = INADDR_ANY;
+
+ if (bind(socket, (struct sockaddr *) sin,
+ sizeof(sin)) != 0)
+ {
+ mnc_warning("Could not bind to ::\n");
+ return -1;
+ }
+ }
+ else if (group->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 sin6;
+
+ sin6.sin6_family = group->ai_family;
+ sin6.sin6_port = group->ai_port;
+ sin6.sin6_addr = in6addr_any;
+
+ if (bind(socket, (struct sockaddr *) sin6,
+ sizeof(sin6)) != 0)
+ {
+ mnc_warning("Could not bind to ::\n");
+ return -1;
+ }
+ }
+#endif
+
+ /* Set a receive buffer size of 64k */
+ rcvbuf = 1 << 15;
+ if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
+ sizeof(rcvbuf)) < 0) {
+ mnc_warning("Could not set receive buffer to 64k\n");
+ }
+
+ if (source != NULL)
+ {
+ if (group->ai_family == AF_INET6)
+ {
+ /* Use whatever IPv6 API is appropriate */
+ return
+ mnc_join_ipv6_ssm(socket, group, source, iface);
+ }
+ else if (group->ai_family == AF_INET)
+ {
+ /* Use the fully portable IPv4 API */
+ return
+ mnc_join_ipv4_ssm(socket, group, source, iface);
+ }
+ else
+ {
+ mnc_warning("Only IPv4 and IPv6 are supported\n");
+ return -1;
+ }
+ }
+ else
+ {
+ if (group->ai_family == AF_INET6)
+ {
+ /* Use the fully portable IPv4 API */
+ return
+ mnc_join_ipv6_asm(socket, group, iface);
+ }
+ else if (group->ai_family == AF_INET)
+ {
+ /* Use the fully portable IPv4 API */
+ return
+ mnc_join_ipv4_asm(socket, group, iface);
+ }
+ else
+ {
+ mnc_warning("Only IPv4 and IPv6 are supported\n");
+ return -1;
+ }
+ }
+
+ /* We should never get here */
+ return -1;
+}
+
+
+int multicast_setup_send(int socket, struct addrinfo * group,
+ struct addrinfo * source)
+{
+ int ttl = 255;
+
+ if (source != NULL)
+ {
+ /* bind to the address before anything */
+ if (bind(socket, source->ai_addr, source->ai_addrlen) != 0)
+ {
+ mnc_warning("Could not bind to source-address\n");
+ return -1;
+ }
+ }
+
+ if (group->ai_family == AF_INET)
+ {
+ if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)
+ &ttl, sizeof(ttl)) != 0)
+ {
+ mnc_warning("Could not increase the TTL\n");
+ return -1;
+ }
+ }
+ else if (group->ai_family == AF_INET6)
+ {
+ if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ (char *) &ttl, sizeof(ttl)) != 0)
+ {
+ mnc_warning("Could not increase the hop-count\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/network_cmds/mnc.tproj/mnc_opts.c b/network_cmds/mnc.tproj/mnc_opts.c
new file mode 100644
index 0000000..606746f
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_opts.c
@@ -0,0 +1,182 @@
+/*
+ * $Id: mnc_opts.c,v 1.3 2004/09/22 16:02:26 colmmacc Exp $
+ *
+ * mnc_opts.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of the HEAnet Ltd. 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 COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef WINDOWS
+
+/* UNIX-y includes */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#else
+
+/* WINDOWS-y includes */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "mnc.h"
+
+/* Display a usage statement */
+void usage(void)
+{
+ fprintf(stderr,
+ "Usage: mnc [-l] [-i interface] [-p port] group-id "
+ "[source-address]\n\n"
+ "-l : listen mode\n"
+ "-i : specify interface to listen\n"
+ "-p : specify port to listen/send on\n\n");
+ exit(1);
+}
+
+struct mnc_configuration * parse_arguments(int argc, char **argv)
+{
+ /* Utility variables */
+ int optind,
+ errorcode;
+ struct addrinfo hints;
+
+ /* Our persisting configuration */
+ static struct mnc_configuration config;
+
+ /* Set some defaults */
+ config.mode = SENDER;
+ config.port = MNC_DEFAULT_PORT;
+ config.iface = NULL;
+ config.source = NULL;
+
+ /* Loop through the arguments */
+ for (optind = 1; optind < (argc - 1); optind++)
+ {
+ if ( (argv[optind][0] == '-') || (argv[optind][0] == '/') )
+ {
+ switch(argv[optind][1])
+ {
+ /* Set listening mode */
+ case 'l': config.mode = LISTENER;
+ break;
+
+ /* Set port */
+ case 'p': config.port = argv[++optind];
+ break;
+
+ /* Set an interface */
+ case 'i': config.iface = argv[++optind];
+ break;
+
+ /* Unrecognised option */
+ default: usage();
+ break;
+ }
+ }
+ else
+ {
+ /* assume we've ran out of options */
+ break;
+ }
+ }
+
+ /* There's a chance we were passed one option */
+ if (optind >= argc || argv[optind][0] == '-')
+ {
+ usage();
+ }
+
+ /* Now make sure we have either exactly 1 or 2 more arguments */
+ if ( (argc - optind) != 1 && (argc - optind) != 2 )
+ {
+ /* We have not been given the right ammount of
+ arguments */
+ usage();
+ }
+
+ /* You can't have an interface without also listening */
+ if (config.mode == SENDER && config.iface != NULL)
+ {
+ mnc_error("You may only specify the interface when in"
+ " listening mode\n");
+ }
+
+ /* Set some hints for getaddrinfo */
+ memset(&hints, 0, sizeof(hints));
+
+ /* We want a UDP socket */
+ hints.ai_socktype = SOCK_DGRAM;
+
+ /* Don't do any name-lookups */
+ hints.ai_flags = AI_NUMERICHOST;
+
+ /* Get the group-id information */
+ if ( (errorcode =
+ getaddrinfo(argv[optind], config.port, &hints, &config.group)) != 0)
+ {
+ mnc_error("Error getting group-id address information: %s\n",
+ gai_strerror(errorcode));
+ }
+
+ /* Move on to next argument */
+ optind++;
+
+ /* Get the source information */
+ if ( (argc - optind) == 1)
+ {
+
+ if ( (errorcode =
+ getaddrinfo(argv[optind], config.port, &hints, &config.source))
+ != 0)
+ {
+ mnc_error("Error getting source-address information: %s\n",
+ gai_strerror(errorcode));
+ }
+
+ /* Confirm that the source and group are in the same Address Family */
+ if ( config.source->ai_family != config.group->ai_family )
+ {
+ mnc_error("Group ID and Source address are not of "
+ "the same type\n");
+ }
+ }
+
+ return &config;
+}
diff --git a/network_cmds/mptcp_client/conn_lib.c b/network_cmds/mptcp_client/conn_lib.c
new file mode 100644
index 0000000..1c83915
--- /dev/null
+++ b/network_cmds/mptcp_client/conn_lib.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+//
+// Created by Anumita Biswas on 10/30/12.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+
+#include "conn_lib.h"
+
+int
+copyassocids(int s, sae_associd_t **aidpp, uint32_t *cnt)
+{
+ struct so_aidreq aidr;
+ sae_associd_t *buf;
+ int err;
+
+ if (aidpp == NULL || cnt == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *aidpp = NULL;
+ *cnt = 0;
+
+ bzero(&aidr, sizeof (aidr));
+
+ err = ioctl(s, SIOCGASSOCIDS, &aidr);
+ if (err != 0)
+ return (-1);
+
+ /* none, just return */
+ if (aidr.sar_cnt == 0)
+ return (0);
+
+ buf = calloc(aidr.sar_cnt, sizeof (sae_associd_t));
+ if (buf == NULL)
+ return (-1);
+
+ aidr.sar_aidp = buf;
+ err = ioctl(s, SIOCGASSOCIDS, &aidr);
+ if (err != 0) {
+ free(buf);
+ return (-1);
+ }
+
+ *aidpp = buf;
+ *cnt = aidr.sar_cnt;
+
+ return (0);
+}
+
+void
+freeassocids(sae_associd_t *aidp)
+{
+ free(aidp);
+}
+
+int
+copyconnids(int s, sae_associd_t aid, sae_connid_t **cidp, uint32_t *cnt)
+{
+ struct so_cidreq cidr;
+ sae_connid_t *buf;
+ int err;
+
+ if (cidp == NULL || cnt == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *cidp = NULL;
+ *cnt = 0;
+
+ bzero(&cidr, sizeof (cidr));
+
+ cidr.scr_aid = aid;
+ err = ioctl(s, SIOCGCONNIDS, &cidr);
+ if (err != 0)
+ return (-1);
+
+ /* none, just return */
+ if (cidr.scr_cnt == 0)
+ return (0);
+
+ buf = calloc(cidr.scr_cnt, sizeof (sae_connid_t));
+ if (buf == NULL)
+ return (-1);
+
+ cidr.scr_cidp = buf;
+ err = ioctl(s, SIOCGCONNIDS, &cidr);
+ if (err != 0) {
+ free(buf);
+ return (-1);
+ }
+
+ *cidp = buf;
+ *cnt = cidr.scr_cnt;
+
+ return (0);
+}
+
+void
+freeconnids(sae_connid_t *cidp)
+{
+ free(cidp);
+}
+
+int
+copyconninfo(int s, sae_connid_t cid, conninfo_t **cfop)
+{
+ struct sockaddr *src = NULL, *dst = NULL, *aux = NULL;
+ struct so_cinforeq scir;
+ conninfo_t *buf = NULL;
+
+ if (cfop == NULL) {
+ errno = EINVAL;
+ goto error;
+ }
+ *cfop = NULL;
+
+ bzero(&scir, sizeof (scir));
+
+ scir.scir_cid = cid;
+ if (ioctl(s, SIOCGCONNINFO, &scir) != 0)
+ goto error;
+
+ if (scir.scir_src_len != 0) {
+ src = calloc(1, scir.scir_src_len);
+ if (src == NULL)
+ goto error;
+ scir.scir_src = src;
+ }
+ if (scir.scir_dst_len != 0) {
+ dst = calloc(1, scir.scir_dst_len);
+ if (dst == NULL)
+ goto error;
+ scir.scir_dst = dst;
+ }
+ if (scir.scir_aux_len != 0) {
+ aux = calloc(1, scir.scir_aux_len);
+ if (aux == NULL)
+ goto error;
+ scir.scir_aux_data = aux;
+ }
+
+ if (ioctl(s, SIOCGCONNINFO, &scir) != 0)
+ goto error;
+
+ buf = calloc(1, sizeof (*buf));
+ if (buf == NULL)
+ goto error;
+
+ // When we query for the length using the first ioctl call above, the kernel
+ // tells us the length of the aux structure so we know how much to allocate
+ // memory. There may not be any aux data, which will be indicated by the aux
+ // data length using the second ioctl call.
+ if (scir.scir_aux_len == 0 && aux != NULL) {
+ free(aux);
+ aux = NULL;
+ scir.scir_aux_data = NULL;
+ }
+
+ buf->ci_flags = scir.scir_flags;
+ buf->ci_ifindex = scir.scir_ifindex;
+ buf->ci_src = src;
+ buf->ci_dst = dst;
+ buf->ci_error = scir.scir_error;
+ buf->ci_aux_type = scir.scir_aux_type;
+ buf->ci_aux_data = aux;
+ *cfop = (conninfo_t*)buf;
+
+ return (0);
+
+error:
+ if (src != NULL)
+ free(src);
+ if (dst != NULL)
+ free(dst);
+ if (aux != NULL)
+ free(aux);
+ if (buf != NULL)
+ free(buf);
+
+ return (-1);
+}
+
+void
+freeconninfo(conninfo_t *cfo)
+{
+ if (cfo->ci_src != NULL)
+ free(cfo->ci_src);
+
+ if (cfo->ci_dst != NULL)
+ free(cfo->ci_dst);
+
+ if (cfo->ci_aux_data != NULL)
+ free(cfo->ci_aux_data);
+
+ free(cfo);
+}
diff --git a/network_cmds/mptcp_client/conn_lib.h b/network_cmds/mptcp_client/conn_lib.h
new file mode 100644
index 0000000..b69b73c
--- /dev/null
+++ b/network_cmds/mptcp_client/conn_lib.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+//
+// Created by Anumita Biswas on 10/30/12.
+//
+
+#ifndef mptcp_client_conn_lib_h
+#define mptcp_client_conn_lib_h
+
+typedef struct conninfo {
+ __uint32_t ci_flags; /* see flags in sys/socket.h (CIF_CONNECTING, etc...) */
+ __uint32_t ci_ifindex; /* outbound interface */
+ struct sockaddr *ci_src; /* source address */
+ struct sockaddr *ci_dst; /* destination address */
+ int ci_error; /* saved error */
+ __uint32_t ci_aux_type; /* auxiliary data type */
+ void *ci_aux_data; /* auxiliary data */
+} conninfo_t;
+
+extern int copyassocids(int, sae_associd_t **, uint32_t *);
+extern void freeassocids(sae_associd_t *);
+extern int copyconnids(int, sae_associd_t, sae_connid_t **, uint32_t *);
+extern void freeconnids(sae_connid_t *);
+extern int copyconninfo(int, sae_connid_t, conninfo_t **);
+extern void freeconninfo(conninfo_t *);
+
+#endif
diff --git a/network_cmds/mptcp_client/mptcp_client.1 b/network_cmds/mptcp_client/mptcp_client.1
new file mode 100644
index 0000000..2ca3cad
--- /dev/null
+++ b/network_cmds/mptcp_client/mptcp_client.1
@@ -0,0 +1,21 @@
+.Dd 6/12/14
+.Dt mptcp_client 1
+.Os Darwin
+.Sh NAME
+.Nm mptcp_client
+.Nd Tool to exercise MPTCP.
+.Sh SYNOPSIS
+.Nm
+.Ar hostname
+.Ar port
+.Ar reqlen
+.Ar rsplen
+.Ar times
+.Ar alt_addr
+.Ar 0
+.Ar longlived
+.Sh DESCRIPTION
+.Nm
+is as an MPTCP client test tool that use the
+.Xr socket 2
+API.
diff --git a/network_cmds/mptcp_client/mptcp_client.c b/network_cmds/mptcp_client/mptcp_client.c
new file mode 100644
index 0000000..770aabc
--- /dev/null
+++ b/network_cmds/mptcp_client/mptcp_client.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1997
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+//
+// Created by Anumita Biswas on 7/17/12.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <err.h>
+#include <sysexits.h>
+#include <getopt.h>
+
+#include "conn_lib.h"
+
+struct so_cordreq socorder;
+static void showmpinfo(int s);
+
+#define MSG_HDR "Message Header"
+#define RESPONSE "I got your message"
+
+static int verbose = 0;
+
+static int32_t thiszone = 0; /* time difference with gmt */
+
+char *setup_buffer1(int bufsz)
+{
+ int i = 0, j = 1;
+ char *buf;
+
+ buf = malloc(bufsz);
+ if (!buf)
+ return NULL;
+
+ bzero(buf, bufsz);
+ strlcpy(buf, MSG_HDR, bufsz);
+
+ for (i = sizeof(MSG_HDR); i < bufsz; i++) {
+ buf[i] = j;
+ j++;
+ if (j >= 255)
+ j = 1;
+ }
+ return buf;
+}
+
+char *setup_buffer2(int bufsz)
+{
+ int i = 0;
+ char j = 'A';
+ char *buf;
+
+ buf = malloc(bufsz);
+ if (!buf)
+ return NULL;
+
+ bzero(buf, bufsz);
+ strlcpy(buf, MSG_HDR, bufsz);
+
+ for (i = sizeof(MSG_HDR); i < bufsz; i++) {
+ buf[i] = j;
+ j++;
+ if (j >= 'z')
+ j = 'A';
+ }
+ return buf;
+}
+
+char *setup_buffer3(int bufsz)
+{
+ char *buf;
+
+ buf = malloc(bufsz);
+ if (!buf)
+ return NULL;
+
+ bzero(buf, bufsz);
+ return buf;
+}
+
+/*
+ * Returns the difference between gmt and local time in seconds.
+ * Use gmtime() and localtime() to keep things simple.
+ * from tcpdump/gmt2local.c
+ */
+static int32_t
+gmt2local(time_t t)
+{
+ int dt, dir;
+ struct tm *gmt, *loc;
+ struct tm sgmt;
+
+ if (t == 0)
+ t = time(NULL);
+ gmt = &sgmt;
+ *gmt = *gmtime(&t);
+ loc = localtime(&t);
+ dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+ (loc->tm_min - gmt->tm_min) * 60;
+
+ /*
+ * If the year or julian day is different, we span 00:00 GMT
+ * and must add or subtract a day. Check the year first to
+ * avoid problems when the julian day wraps.
+ */
+ dir = loc->tm_year - gmt->tm_year;
+ if (dir == 0)
+ dir = loc->tm_yday - gmt->tm_yday;
+ dt += dir * 24 * 60 * 60;
+
+ return (dt);
+}
+
+/*
+ * Print the timestamp
+ * from tcpdump/util.c
+ */
+static void
+ts_print(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ /* Default */
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
+static const char *
+basename(const char * str)
+{
+ const char *last_slash = strrchr(str, '/');
+
+ if (last_slash == NULL)
+ return (str);
+ else
+ return (last_slash + 1);
+}
+
+struct option_desc {
+ const char *option;
+ const char *description;
+ int required;
+};
+
+struct option_desc option_desc_list[] = {
+ { "--host addr", "address of server to connect to", 1 },
+ { "--port n", "port of server to connect to", 1 },
+ { "--reqlen n", "length of request (256 by default)", 0 },
+ { "--rsplen n", "length of response (256 by default)", 0 },
+ { "--ntimes n", "number of time to send request (1 by default)", 0 },
+ { "--alt_addr addr", "alternate server to connect to", 0 },
+ { "--verbose", "increase verbosity", 0 },
+ { "--help", "display this help", 0 },
+
+ { NULL, NULL, 0 } /* Mark end of list */
+};
+
+static void
+usage(const char *cmd)
+{
+ struct option_desc *option_desc;
+ char *usage_str = malloc(LINE_MAX);
+ size_t usage_len;
+
+ if (usage_str == NULL)
+ err(1, "%s: malloc(%d)", __func__, LINE_MAX);
+
+ usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd));
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ int len;
+
+ if (option_desc->required)
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option);
+ else
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option);
+ if (len < 0)
+ err(1, "%s: snprintf(", __func__);
+
+ usage_len += len;
+ if (usage_len > LINE_MAX)
+ break;
+ }
+ printf("%s\n", usage_str);
+ printf("options:\n");
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ printf(" %-24s # %s\n", option_desc->option, option_desc->description);
+ }
+ printf("\n");
+ printf("# legacy usage: ");
+}
+
+static struct option longopts[] = {
+ { "host", required_argument, NULL, 'c' },
+ { "port", required_argument, NULL, 'p' },
+ { "reqlen", required_argument, NULL, 'r' },
+ { "rsplen", required_argument, NULL, 'R' },
+ { "ntimes", required_argument, NULL, 'n' },
+ { "alt_addr", required_argument, NULL, 'a' },
+ { "help", no_argument, NULL, 'h' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "quiet", no_argument, NULL, 'q' },
+ { NULL, 0, NULL, 0 }
+};
+
+static int
+sprint_sockaddr(char *str, socklen_t strlen, struct sockaddr *sa)
+{
+ int retval = 0;
+
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in*)sa;
+ char str4[INET_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, &sin->sin_addr, str4, sizeof(str4));
+
+ retval = snprintf(str, strlen, "%s:%u", str4, ntohs(sin->sin_port));
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
+ char str6[INET6_ADDRSTRLEN];
+ char ifname[IF_NAMESIZE];
+ char scopestr[2 + IF_NAMESIZE];
+
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str6, sizeof(str6));
+
+ if (sin6->sin6_scope_id == 0)
+ *scopestr = '\0';
+ else {
+ if_indextoname(sin6->sin6_scope_id, ifname);
+ snprintf(scopestr, sizeof(scopestr), "%%%s", ifname);
+ }
+
+ retval = snprintf(str, strlen, "%s%s:%u",
+ str6,
+ scopestr,
+ ntohs(sin6->sin6_port));
+ }
+ return (retval);
+}
+
+int main(int argc, char * const *argv)
+{
+ int sockfd, portno;
+ ssize_t n;
+ int reqlen = 256;
+ int rsplen = 256;
+ int ntimes = 1;
+ char *buffer = NULL;
+ char *buffer1;
+ char *buffer2;
+ char *buffer3;
+ struct addrinfo *ares = NULL, ahints;
+ struct addrinfo *altres = NULL;
+ int retval = 0;
+ int which_buf = 0;
+ sae_connid_t cid1, cid2;
+ int iter;
+ int bytes_to_rdwr;
+ int ch;
+ const char *host_arg = NULL;
+ const char *port_arg = NULL;
+ const char *reqlen_arg = "256";
+ const char *rsplen_arg = "256";
+ const char *ntimes_arg = "1";
+ const char *alt_addr_arg = NULL;
+ const char *alt_port_arg = "0";
+ int gotopt = 0;
+
+ thiszone = gmt2local(0);
+
+ while ((ch = getopt_long(argc, argv, "a:c:hn:p:qr:R:v", longopts, NULL)) != -1) {
+ gotopt = 1;
+ switch (ch) {
+ case 'a':
+ alt_addr_arg = optarg;
+ break;
+ case 'c':
+ host_arg = optarg;
+ break;
+ case 'n':
+ ntimes_arg = optarg;
+ break;
+ case 'p':
+ port_arg = optarg;
+ break;
+ case 'q':
+ verbose--;
+ break;
+ case 'r':
+ reqlen_arg = optarg;
+ break;
+ case 'R':
+ rsplen_arg = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+ }
+
+ if (gotopt == 0) {
+ if (argc == 12) {
+ host_arg = argv[1];
+ port_arg = argv[2];
+ reqlen_arg = argv[3];
+ rsplen_arg = argv[4];
+ ntimes_arg = argv[5];
+ alt_addr_arg = argv[6];
+ } else {
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+ }
+
+ if (host_arg == NULL)
+ errx(EX_USAGE, "missing required host option\n");
+
+ if (port_arg == NULL)
+ errx(EX_USAGE, "missing required port option\n");
+ portno = atoi(port_arg);
+ if (portno < 0 || portno > 65535)
+ errx(EX_USAGE, "invalid port %s\n", port_arg);
+
+ if (reqlen_arg != NULL) {
+ reqlen = atoi(reqlen_arg);
+ if (reqlen < 0 || reqlen > 1024 * 1024)
+ errx(EX_USAGE, "invalid request length %s\n", reqlen_arg);
+ }
+
+ if (rsplen_arg != NULL) {
+ rsplen = atoi(rsplen_arg);
+ if (rsplen < 0 || rsplen > 1024 * 1024)
+ errx(EX_USAGE, "invalid response length %s\n", rsplen_arg);
+ }
+
+ if (ntimes_arg != NULL) {
+ ntimes = atoi(ntimes_arg);
+ if (ntimes < 1)
+ errx(EX_USAGE, "invalid ntimes option %s\n", ntimes_arg);
+ }
+
+ buffer1 = setup_buffer1(reqlen);
+ if (!buffer1) {
+ printf("client: failed to alloc buffer space \n");
+ return -1;
+ }
+
+ buffer2 = setup_buffer2(reqlen);
+ if (!buffer2) {
+ printf("client: failed to alloc buffer space \n");
+ return -1;
+ }
+
+ buffer3 = setup_buffer3(rsplen);
+ if (!buffer3) {
+ printf("client: failed to alloc buffer space \n");
+ return -1;
+ }
+
+ if (verbose > 0)
+ printf("host: %s port: %s reqlen: %d rsplen: %d ntimes: %d alt_addr: %s\n",
+ host_arg, port_arg, reqlen, rsplen, ntimes, alt_addr_arg);
+
+ sockfd = socket(AF_MULTIPATH, SOCK_STREAM, 0);
+ if (sockfd < 0)
+ err(EX_OSERR, "ERROR opening socket");
+
+ memset(&ahints, 0, sizeof(struct addrinfo));
+ ahints.ai_family = AF_INET;
+ ahints.ai_socktype = SOCK_STREAM;
+ ahints.ai_protocol = IPPROTO_TCP;
+
+ retval = getaddrinfo(host_arg, port_arg, &ahints, &ares);
+ if (retval != 0)
+ printf("getaddrinfo(%s, %s) failed %d\n", host_arg, port_arg, retval);
+
+ bytes_to_rdwr = reqlen;
+
+ cid1 = cid2 = SAE_CONNID_ANY;
+ int ifscope = 0;
+ int error = 0;
+
+ if (verbose > 0) {
+ char str[2 * INET6_ADDRSTRLEN];
+
+ ts_print();
+
+ sprint_sockaddr(str, sizeof(str), ares->ai_addr);
+ printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
+ }
+ sa_endpoints_t sa;
+ bzero(&sa, sizeof(sa));
+ sa.sae_dstaddr = ares->ai_addr;
+ sa.sae_dstaddrlen = ares->ai_addrlen;
+ sa.sae_srcif = ifscope;
+
+ error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid1);
+ if (error != 0)
+ err(EX_OSERR, "ERROR connecting");
+
+ iter = 0;
+
+ while (ntimes) {
+ if (iter == 0) {
+ /* Add alternate path if available */
+
+ if (alt_addr_arg && alt_addr_arg[0] != 0) {
+ retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres);
+
+ if (retval != 0)
+ printf("client: alternate address resolution failed. \n");
+ else {
+ printf("client: connecting to alternate address (ifscope %d)\n", ifscope);
+
+ if (verbose > 0) {
+ char str[2 * INET6_ADDRSTRLEN];
+
+ ts_print();
+
+ sprint_sockaddr(str, sizeof(str), altres->ai_addr);
+ printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
+ }
+ sa_endpoints_t sa;
+ bzero(&sa, sizeof(sa));
+ sa.sae_srcif = ifscope;
+ sa.sae_srcaddr = altres->ai_addr;
+ sa.sae_srcaddrlen = altres->ai_addrlen;
+ sa.sae_dstaddr = ares->ai_addr;
+ sa.sae_dstaddrlen = ares->ai_addrlen;
+
+ error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid2);
+ if (error < 0) {
+ err(EX_OSERR, "ERROR setting up alternate path");
+ }
+ }
+ }
+ }
+
+ if (which_buf == 0) {
+ buffer = buffer1;
+ which_buf = 1;
+ } else {
+ buffer = buffer2;
+ which_buf = 0;
+ }
+
+ while (bytes_to_rdwr) {
+ if (verbose) {
+ ts_print();
+ printf("writing %d bytes\n", bytes_to_rdwr);
+ }
+ n = write(sockfd, buffer, bytes_to_rdwr);
+ if (n <= 0) {
+ err(EX_OSERR, "ERROR writing to socket");
+ }
+ if (n <= bytes_to_rdwr)
+ bytes_to_rdwr -= n;
+ else {
+ errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr);
+ }
+ }
+ bytes_to_rdwr = rsplen;
+ while (bytes_to_rdwr) {
+ if (verbose) {
+ ts_print();
+ printf("reading %d bytes\n", rsplen);
+ }
+ n = read(sockfd, buffer3, rsplen);
+
+ if (n <= 0) {
+ err(EX_OSERR, "ERROR reading from socket");
+ }
+ if (n <= bytes_to_rdwr)
+ bytes_to_rdwr -= n;
+ else {
+ errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr);
+ }
+ }
+ bytes_to_rdwr = reqlen;
+ ntimes--;
+ iter++;
+ }
+
+ printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter);
+
+ showmpinfo(sockfd);
+
+ if (verbose) {
+ ts_print();
+ printf("close(%d)\n", sockfd);
+ }
+ close(sockfd);
+
+ freeaddrinfo(ares);
+ if (altres)
+ freeaddrinfo(altres);
+ return 0;
+}
+
+#define CIF_BITS \
+"\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\
+"\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \
+"\13MP_DEGRADED"
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+static void
+printb(const char *s, unsigned v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else {
+ for (; *bits > 32; bits++)
+ ;
+ }
+ }
+ putchar('>');
+ }
+}
+
+static int
+showconninfo(int s, sae_connid_t cid)
+{
+ char buf[INET6_ADDRSTRLEN];
+ conninfo_t *cfo = NULL;
+ int err;
+
+ err = copyconninfo(s, cid, &cfo);
+ if (err != 0) {
+ printf("getconninfo failed for cid %d\n", cid);
+ goto out;
+ }
+
+ printf("%6d:\t", cid);
+ printb("flags", cfo->ci_flags, CIF_BITS);
+ printf("\n");
+
+ if (cfo->ci_src != NULL) {
+ printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family,
+ (cfo->ci_src->sa_family == AF_INET) ?
+ (void *)&((struct sockaddr_in *)cfo->ci_src)->
+ sin_addr.s_addr :
+ (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr,
+ buf, sizeof (buf)),
+ (cfo->ci_src->sa_family == AF_INET) ?
+ ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) :
+ ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port));
+ }
+ if (cfo->ci_dst != NULL) {
+ printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family,
+ (cfo->ci_dst->sa_family == AF_INET) ?
+ (void *)&((struct sockaddr_in *)cfo->ci_dst)->
+ sin_addr.s_addr :
+ (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr,
+ buf, sizeof (buf)),
+ (cfo->ci_dst->sa_family == AF_INET) ?
+ ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) :
+ ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port));
+ }
+ if (cfo->ci_aux_data != NULL) {
+ switch (cfo->ci_aux_type) {
+ case CIAUX_TCP:
+ printf("\tTCP aux info available\n");
+ break;
+ default:
+ printf("\tUnknown aux type %d\n", cfo->ci_aux_type);
+ break;
+ }
+ }
+out:
+ if (cfo != NULL)
+ freeconninfo(cfo);
+
+ return (err);
+}
+
+static void
+showmpinfo(int s)
+{
+ uint32_t aid_cnt = 0, cid_cnt = 0;
+ sae_associd_t *aid = NULL;
+ sae_connid_t *cid = NULL;
+ int i, error = 0;
+
+ error = copyassocids(s, &aid, &aid_cnt);
+ if (error != 0) {
+ printf("copyassocids failed\n");
+ goto done;
+ } else {
+ printf("found %d associations", aid_cnt);
+ if (aid_cnt > 0) {
+ printf(" with IDs:");
+ for (i = 0; i < aid_cnt; i++)
+ printf(" %d\n", aid[i]);
+ }
+ printf("\n");
+ }
+
+ /* just do an association for now */
+ error = copyconnids(s, SAE_ASSOCID_ANY, &cid, &cid_cnt);
+ if (error != 0) {
+ warn("getconnids failed\n");
+ goto done;
+ } else {
+ printf("found %d connections", cid_cnt);
+ if (cid_cnt > 0) {
+ printf(":\n");
+ for (i = 0; i < cid_cnt; i++) {
+ if (showconninfo(s, cid[i]) != 0)
+ break;
+ }
+ }
+ printf("\n");
+ }
+
+done:
+ if (aid != NULL)
+ freeassocids(aid);
+ if (cid != NULL)
+ freeconnids(cid);
+}
diff --git a/network_cmds/mtest.tproj/COPYING b/network_cmds/mtest.tproj/COPYING
new file mode 100644
index 0000000..77bafa4
--- /dev/null
+++ b/network_cmds/mtest.tproj/COPYING
@@ -0,0 +1,27 @@
+Copyright (c) 2007-2009 Bruce Simpson.
+Copyright (c) 2000 Wilbert De Graaf.
+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.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
+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. \ No newline at end of file
diff --git a/network_cmds/mtest.tproj/mtest.8 b/network_cmds/mtest.tproj/mtest.8
new file mode 100644
index 0000000..b618cc0
--- /dev/null
+++ b/network_cmds/mtest.tproj/mtest.8
@@ -0,0 +1,175 @@
+.\"
+.\" Copyright (c) 2007-2009 Bruce Simpson.
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/mtest/mtest.8,v 1.11 2009/04/29 09:50:04 bms Exp $
+.\"
+.Dd April 29, 2009
+.Os
+.Dt MTEST 8
+.Sh NAME
+.Nm mtest
+.Nd test multicast socket operations
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility
+is a small program for testing multicast socket operations.
+.Pp
+It accepts the following commands, interactively, or as part of a scripted
+input file (useful for automated testing):
+.Bl -tag -width "a ifname e.e.e.e e.e.e.e" -compact -offset indent
+.Pp
+.\"
+.It Ic a Ar ifname Ar mac-addr
+Join the link-layer group address
+.Ar mac-addr
+on interface
+.Ar ifname .
+The group address should be in IEEE 802 MAC format,
+delimited by colon (':') characters.
+.It Ic d Ar ifname Ar mac-addr
+Leave the link-layer group address
+.Ar mac-addr
+on interface
+.Ar ifname .
+.It Ic m Ar ifname Ar 1/0
+Set or reset ALLMULTI mode on interface
+.Ar ifname .
+This option is deprecated and is now a no-op.
+.\".It Ic p Ar ifname Ar 1/0
+.\"Set or reset promiscuous mode on interface
+.\".Ar ifname .
+.Pp
+.It Ic j Ar mcast-addr Ar ifname Op Ar source-addr
+Join the multicast address
+.Ar mcast-addr
+on the interface with name
+.Ar ifname .
+.Pp
+If an optional source
+.Ar source-addr
+is specified, a source-specific join will be performed;
+if
+.Nm
+is already joined to the multicast address, the source
+will be added to its filter list.
+.Pp
+.It Ic l Ar mcast-addr Ar ifname Op Ar source-addr
+Leave the multicast address
+.Ar mcast-addr
+on the interface with address
+.Ar ifname .
+If a source
+.Ar source-addr
+is specified, only that source will be left.
+.\"
+.It Ic i Ar mcast-addr Ar ifname Ar n Ar source-addr ...
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to include filter mode, and add
+.Ar n
+sources beginning with
+.Ar source-addr
+to the inclusion filter list.
+.\"
+.It Ic e Ar mcast-addr Ar ifname Ar n Ar source-addr ...
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to exclude filter mode, and add
+.Ar n
+sources beginning with
+.Ar source-addr
+to the exclusion filter list.
+.\"
+.It Ic t Ar mcast-addr Ar ifname Ar source-addr
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to block traffic from source
+.Ar source-addr .
+.\"
+.It Ic b Ar mcast-addr Ar ifname Ar source-addr
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to allow traffic from source
+.Ar source-addr .
+.\"
+.Pp
+.It Ic g Ar mcast-addr Ar ifname Ar n
+Print
+.Ar n
+source filter entries for
+.An mcast-addr
+on interface
+.An ifname .
+.\"
+.Pp
+.It Ic f Ar filename
+Read commands from the file
+.Ar filename .
+.It Ic s Ar n
+Sleep for
+.Ar n
+seconds.
+.It Ic ?\&
+List legal commands.
+.It Ic q
+Quit the program.
+.El
+.Sh IMPLEMENTATION NOTES
+For each command implemented by
+.Nm ,
+the address family of each argument must be identical; it is not possible
+to mix IPv4 multicast memberships with IPv6, for example.
+.Pp
+To support IPv6, all commands have now changed to accept an interface
+name rather than an interface address.
+For IPv4, the program will perform
+a lookup of the primary IP address based on the interface name.
+This may fail if no primary IP address is assigned.
+.Pp
+.Sh SEE ALSO
+.Rs
+.%A D. Thaler
+.%A B. Fenner
+.%A B. Quinn
+.%T "Socket Interface Extensions for Multicast Filters"
+.%O RFC 3678
+.Re
+.Sh AUTHORS
+.An -split
+.An "Bruce Simpson"
+.An "Steve Deering"
+.An "Wilbert De Graaf"
diff --git a/network_cmds/mtest.tproj/mtest.c b/network_cmds/mtest.tproj/mtest.c
new file mode 100644
index 0000000..9c1614e
--- /dev/null
+++ b/network_cmds/mtest.tproj/mtest.c
@@ -0,0 +1,825 @@
+/*-
+ * Copyright (c) 2007-2009 Bruce Simpson.
+ * Copyright (c) 2000 Wilbert De Graaf.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
+ * 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.
+ */
+
+/*
+ * Diagnostic and test utility for multicast sockets.
+ * TODO: Support embedded KAME Scope ID in IPv6 group addresses.
+ * TODO: Use IPv4 link-local address when source address selection
+ * is implemented; use MCAST_JOIN_SOURCE for IPv4.
+ */
+
+#define INET6
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+
+#ifdef IP_ADD_SOURCE_MEMBERSHIP
+#define HAS_SSM 1
+#endif
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+};
+typedef union sockunion sockunion_t;
+
+union mrequnion {
+ struct ip_mreq mr;
+#ifdef HAS_SSM
+ struct ip_mreq_source mrs;
+#endif
+#ifdef INET6
+ struct ipv6_mreq mr6;
+#ifdef HAS_SSM
+ struct group_source_req gr;
+#endif
+#endif
+};
+typedef union mrequnion mrequnion_t;
+
+#define MAX_ADDRS 20
+#define STR_SIZE 64
+#define LINE_LENGTH 80
+
+static int __ifindex_to_primary_ip(const uint32_t, struct in_addr *);
+static uint32_t parse_cmd_args(sockunion_t *, sockunion_t *,
+ const char *, const char *, const char *);
+static void process_file(char *, int, int);
+static void process_cmd(char*, int, int, FILE *);
+static int su_cmp(const void *, const void *);
+static void usage(void);
+
+/*
+ * Ordering predicate for qsort().
+ */
+static int
+su_cmp(const void *a, const void *b)
+{
+ const sockunion_t *sua = (const sockunion_t *)a;
+ const sockunion_t *sub = (const sockunion_t *)b;
+
+ assert(sua->sa.sa_family == sub->sa.sa_family);
+
+ switch (sua->sa.sa_family) {
+ case AF_INET:
+ return ((int)(sua->sin.sin_addr.s_addr -
+ sub->sin.sin_addr.s_addr));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ return (memcmp(&sua->sin6.sin6_addr, &sub->sin6.sin6_addr,
+ sizeof(struct in6_addr)));
+ break;
+#endif
+ default:
+ break;
+ }
+
+ assert(sua->sa.sa_len == sub->sa.sa_len);
+ return (memcmp(sua, sub, sua->sa.sa_len));
+}
+
+/*
+ * Internal: Map an interface index to primary IPv4 address.
+ * This is somewhat inefficient. This is a useful enough operation
+ * that it probably belongs in the C library.
+ * Return zero if found, -1 on error, 1 on not found.
+ */
+static int
+__ifindex_to_primary_ip(const uint32_t ifindex, struct in_addr *pina)
+{
+ char ifname[IFNAMSIZ];
+ struct ifaddrs *ifa;
+ struct ifaddrs *ifaddrs;
+ sockunion_t *psu;
+ int retval;
+
+ assert(ifindex != 0);
+
+ retval = -1;
+ if (if_indextoname(ifindex, ifname) == NULL)
+ return (retval);
+ if (getifaddrs(&ifaddrs) < 0)
+ return (retval);
+
+ /*
+ * Find the ifaddr entry corresponding to the interface name,
+ * and return the first matching IPv4 address.
+ */
+ retval = 1;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (strcmp(ifa->ifa_name, ifname) != 0)
+ continue;
+ psu = (sockunion_t *)ifa->ifa_addr;
+ if (psu && psu->sa.sa_family == AF_INET) {
+ retval = 0;
+ memcpy(pina, &psu->sin.sin_addr,
+ sizeof(struct in_addr));
+ break;
+ }
+ }
+
+ if (retval != 0)
+ errno = EADDRNOTAVAIL; /* XXX */
+
+ freeifaddrs(ifaddrs);
+ return (retval);
+}
+
+int
+main(int argc, char **argv)
+{
+ char line[LINE_LENGTH];
+ char *p;
+ int i, s, s6;
+
+ s = -1;
+ s6 = -1;
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1)
+ err(1, "can't open IPv4 socket");
+#ifdef INET6
+ s6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s6 == -1)
+ err(1, "can't open IPv6 socket");
+#endif
+
+ if (argc < 2) {
+ if (isatty(STDIN_FILENO)) {
+ printf("multicast membership test program; "
+ "enter ? for list of commands\n");
+ }
+ do {
+ if (fgets(line, sizeof(line), stdin) != NULL) {
+ if (line[0] != 'f')
+ process_cmd(line, s, s6, stdin);
+ else {
+ /* Get the filename */
+ for (i = 1; isblank(line[i]); i++);
+ if ((p = (char*)strchr(line, '\n'))
+ != NULL)
+ *p = '\0';
+ process_file(&line[i], s, s6);
+ }
+ }
+ } while (!feof(stdin));
+ } else {
+ for (i = 1; i < argc; i++) {
+ process_file(argv[i], s, s6);
+ }
+ }
+
+ if (s != -1)
+ close(s);
+ if (s6 != -1)
+ close(s6);
+
+ exit (0);
+}
+
+static void
+process_file(char *fname, int s, int s6)
+{
+ char line[80];
+ FILE *fp;
+ char *lineptr;
+
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ warn("fopen");
+ return;
+ }
+
+ /* Skip comments and empty lines. */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ lineptr = line;
+ while (isblank(*lineptr))
+ lineptr++;
+ if (*lineptr != '#' && *lineptr != '\n')
+ process_cmd(lineptr, s, s6, fp);
+ }
+
+ fclose(fp);
+}
+
+/*
+ * Parse join/leave/allow/block arguments, given:
+ * str1: group (as AF_INET or AF_INET6 printable)
+ * str2: ifname
+ * str3: optional source address (may be NULL).
+ * This argument must have the same parsed address family as str1.
+ * Return the ifindex of ifname, or 0 if any parse element failed.
+ */
+static uint32_t
+parse_cmd_args(sockunion_t *psu, sockunion_t *psu2,
+ const char *str1, const char *str2, const char *str3)
+{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ uint32_t ifindex;
+ int af, error;
+
+ assert(psu != NULL);
+ assert(str1 != NULL);
+ assert(str2 != NULL);
+
+ af = AF_UNSPEC;
+
+ ifindex = if_nametoindex(str2);
+ if (ifindex == 0)
+ return (0);
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ memset(psu, 0, sizeof(sockunion_t));
+ psu->sa.sa_family = AF_UNSPEC;
+
+ error = getaddrinfo(str1, "0", &hints, &res);
+ if (error) {
+ warnx("getaddrinfo: %s", gai_strerror(error));
+ return (0);
+ }
+ assert(res != NULL);
+ af = res->ai_family;
+ memcpy(psu, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+
+ /* sscanf() may pass the empty string. */
+ if (psu2 != NULL && str3 != NULL && *str3 != '\0') {
+ memset(psu2, 0, sizeof(sockunion_t));
+ psu2->sa.sa_family = AF_UNSPEC;
+
+ /* look for following address family; str3 is *optional*. */
+ hints.ai_family = af;
+ error = getaddrinfo(str3, "0", &hints, &res);
+ if (error) {
+ warnx("getaddrinfo: %s", gai_strerror(error));
+ ifindex = 0;
+ } else {
+ if (af != res->ai_family) {
+ errno = EINVAL; /* XXX */
+ ifindex = 0;
+ }
+ memcpy(psu2, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ }
+ }
+
+ return (ifindex);
+}
+
+static __inline int
+af2sock(const int af, int s, int s6)
+{
+
+ if (af == AF_INET)
+ return (s);
+#ifdef INET6
+ if (af == AF_INET6)
+ return (s6);
+#endif
+ return (-1);
+}
+
+static void
+process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused)
+{
+ char str1[STR_SIZE];
+ char str2[STR_SIZE];
+ char str3[STR_SIZE];
+ mrequnion_t mr;
+ sockunion_t su, su2;
+ struct ifreq ifr;
+ char *line;
+ char *toptname;
+ void *optval;
+ uint32_t fmode, ifindex;
+ socklen_t optlen;
+ int af, error, i, level, n = 0, optname;
+#ifndef __APPLE__
+ int f, flags;
+#endif /* __APPLE__ */
+
+ af = AF_UNSPEC;
+ su.sa.sa_family = AF_UNSPEC;
+ su2.sa.sa_family = AF_UNSPEC;
+
+ line = cmd;
+ while (isblank(*++line))
+ ; /* Skip whitespace. */
+
+ switch (*cmd) {
+ case '?':
+ usage();
+ break;
+
+ case 'q':
+ close(s);
+ exit(0);
+
+ case 's':
+ if ((sscanf(line, "%d", &n) != 1) || (n < 1)) {
+ printf("-1\n");
+ break;
+ }
+ sleep(n);
+ printf("ok\n");
+ break;
+
+ case 'j':
+ case 'l':
+ str3[0] = '\0';
+ toptname = "";
+ sscanf(line, "%s %s %s", str1, str2, str3);
+ ifindex = parse_cmd_args(&su, &su2, str1, str2, str3);
+ if (ifindex == 0) {
+ printf("-1\n");
+ break;
+ }
+ af = su.sa.sa_family;
+ if (af == AF_INET) {
+ struct in_addr ina;
+
+ error = __ifindex_to_primary_ip(ifindex, &ina);
+ if (error != 0) {
+ warn("primary_ip_lookup %s", str2);
+ printf("-1\n");
+ break;
+ }
+ level = IPPROTO_IP;
+
+#ifdef HAS_SSM
+ if (su2.sa.sa_family != AF_UNSPEC) {
+ mr.mrs.imr_multiaddr = su.sin.sin_addr;
+ mr.mrs.imr_sourceaddr = su2.sin.sin_addr;
+ mr.mrs.imr_interface = ina;
+ optname = (*cmd == 'j') ?
+ IP_ADD_SOURCE_MEMBERSHIP :
+ IP_DROP_SOURCE_MEMBERSHIP;
+ toptname = (*cmd == 'j') ?
+ "IP_ADD_SOURCE_MEMBERSHIP" :
+ "IP_DROP_SOURCE_MEMBERSHIP";
+ optval = (void *)&mr.mrs;
+ optlen = sizeof(mr.mrs);
+ } else {
+#endif
+ mr.mr.imr_multiaddr = su.sin.sin_addr;
+ mr.mr.imr_interface = ina;
+ optname = (*cmd == 'j') ?
+ IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ toptname = (*cmd == 'j') ?
+ "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP";
+ optval = (void *)&mr.mr;
+ optlen = sizeof(mr.mr);
+#ifdef HAS_SSM
+ }
+#endif
+ if (setsockopt(s, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#ifdef INET6
+ else
+#endif /* INET6 */
+#ifdef INET6
+ if (af == AF_INET6) {
+ level = IPPROTO_IPV6;
+#ifdef HAS_SSM
+ if (su2.sa.sa_family != AF_UNSPEC) {
+ mr.gr.gsr_interface = ifindex;
+ mr.gr.gsr_group = su.ss;
+ mr.gr.gsr_source = su2.ss;
+ optname = (*cmd == 'j') ?
+ MCAST_JOIN_SOURCE_GROUP:
+ MCAST_LEAVE_SOURCE_GROUP;
+ toptname = (*cmd == 'j') ?
+ "MCAST_JOIN_SOURCE_GROUP":
+ "MCAST_LEAVE_SOURCE_GROUP";
+ optval = (void *)&mr.gr;
+ optlen = sizeof(mr.gr);
+ } else {
+#endif
+ mr.mr6.ipv6mr_multiaddr = su.sin6.sin6_addr;
+ mr.mr6.ipv6mr_interface = ifindex;
+ optname = (*cmd == 'j') ?
+ IPV6_JOIN_GROUP :
+ IPV6_LEAVE_GROUP;
+ toptname = (*cmd == 'j') ?
+ "IPV6_JOIN_GROUP" :
+ "IPV6_LEAVE_GROUP";
+ optval = (void *)&mr.mr6;
+ optlen = sizeof(mr.mr6);
+#ifdef HAS_SSM
+ }
+#endif
+ if (setsockopt(s6, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#endif /* INET6 */
+ /* FALLTHROUGH */
+ printf("-1\n");
+ break;
+
+#ifdef HAS_SSM
+ /*
+ * Set the socket to include or exclude filter mode, and
+ * add some sources to the filterlist, using the full-state API.
+ */
+ case 'i':
+ case 'e': {
+ sockunion_t sources[MAX_ADDRS];
+ struct addrinfo hints;
+ struct addrinfo *res;
+ char *cp;
+ int af1;
+
+ n = 0;
+ fmode = (*cmd == 'i') ? MCAST_INCLUDE : MCAST_EXCLUDE;
+ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) {
+ printf("-1\n");
+ break;
+ }
+
+ ifindex = parse_cmd_args(&su, NULL, str1, str2, NULL);
+ if (ifindex == 0 || n < 0 || n > MAX_ADDRS) {
+ printf("-1\n");
+ break;
+ }
+ af = su.sa.sa_family;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ for (i = 0; i < n; i++) {
+ sockunion_t *psu = (sockunion_t *)&sources[i];
+ /*
+ * Trim trailing whitespace, as getaddrinfo()
+ * can't cope with it.
+ */
+ fgets(str1, sizeof(str1), fp);
+ cp = strchr(str1, '\n');
+ if (cp != NULL)
+ *cp = '\0';
+
+ res = NULL;
+ error = getaddrinfo(str1, "0", &hints, &res);
+ if (error)
+ break;
+ assert(res != NULL);
+
+ memset(psu, 0, sizeof(sockunion_t));
+ af1 = res->ai_family;
+ if (af1 == af)
+ memcpy(psu, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ if (af1 != af)
+ break;
+ }
+ if (i < n) {
+ if (error)
+ warnx("getaddrinfo: %s", gai_strerror(error));
+ printf("-1\n");
+ break;
+ }
+ if (setsourcefilter(af2sock(af, s, s6), ifindex,
+ &su.sa, su.sa.sa_len, fmode, n, &sources[0].ss) != 0)
+ warn("setsourcefilter");
+ else
+ printf("ok\n");
+ } break;
+
+ /*
+ * Allow or block traffic from a source, using the
+ * delta based api.
+ */
+ case 't':
+ case 'b': {
+ str3[0] = '\0';
+ toptname = "";
+ sscanf(line, "%s %s %s", str1, str2, str3);
+ ifindex = parse_cmd_args(&su, &su2, str1, str2, str3);
+ if (ifindex == 0 || su2.sa.sa_family == AF_UNSPEC) {
+ printf("-1\n");
+ break;
+ }
+ af = su.sa.sa_family;
+
+ /* First determine our current filter mode. */
+ n = 0;
+ if (getsourcefilter(af2sock(af, s, s6), ifindex,
+ &su.sa, su.sa.sa_len, &fmode, (uint32_t *)&n, NULL) != 0) {
+ warn("getsourcefilter");
+ break;
+ }
+ if (af == AF_INET) {
+ struct in_addr ina;
+
+ error = __ifindex_to_primary_ip(ifindex, &ina);
+ if (error != 0) {
+ warn("primary_ip_lookup %s", str2);
+ printf("-1\n");
+ break;
+ }
+ level = IPPROTO_IP;
+ optval = (void *)&mr.mrs;
+ optlen = sizeof(mr.mrs);
+ mr.mrs.imr_multiaddr = su.sin.sin_addr;
+ mr.mrs.imr_sourceaddr = su2.sin.sin_addr;
+ mr.mrs.imr_interface = ina;
+ if (fmode == MCAST_EXCLUDE) {
+ /* Any-source mode socket membership. */
+ optname = (*cmd == 't') ?
+ IP_UNBLOCK_SOURCE :
+ IP_BLOCK_SOURCE;
+ toptname = (*cmd == 't') ?
+ "IP_UNBLOCK_SOURCE" :
+ "IP_BLOCK_SOURCE";
+ } else {
+ /* Source-specific mode socket membership. */
+ optname = (*cmd == 't') ?
+ IP_ADD_SOURCE_MEMBERSHIP :
+ IP_DROP_SOURCE_MEMBERSHIP;
+ toptname = (*cmd == 't') ?
+ "IP_ADD_SOURCE_MEMBERSHIP" :
+ "IP_DROP_SOURCE_MEMBERSHIP";
+ }
+ if (setsockopt(s, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#ifdef INET6
+ else
+#endif /* INET6 */
+#ifdef INET6
+ if (af == AF_INET6) {
+ level = IPPROTO_IPV6;
+ mr.gr.gsr_interface = ifindex;
+ mr.gr.gsr_group = su.ss;
+ mr.gr.gsr_source = su2.ss;
+ if (fmode == MCAST_EXCLUDE) {
+ /* Any-source mode socket membership. */
+ optname = (*cmd == 't') ?
+ MCAST_UNBLOCK_SOURCE :
+ MCAST_BLOCK_SOURCE;
+ toptname = (*cmd == 't') ?
+ "MCAST_UNBLOCK_SOURCE" :
+ "MCAST_BLOCK_SOURCE";
+ } else {
+ /* Source-specific mode socket membership. */
+ optname = (*cmd == 't') ?
+ MCAST_JOIN_SOURCE_GROUP :
+ MCAST_LEAVE_SOURCE_GROUP;
+ toptname = (*cmd == 't') ?
+ "MCAST_JOIN_SOURCE_GROUP":
+ "MCAST_LEAVE_SOURCE_GROUP";
+ }
+ optval = (void *)&mr.gr;
+ optlen = sizeof(mr.gr);
+ if (setsockopt(s6, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#endif /* INET6 */
+ /* FALLTHROUGH */
+ printf("-1\n");
+ } break;
+
+ case 'g': {
+ sockunion_t sources[MAX_ADDRS];
+ char addrbuf[NI_MAXHOST];
+ int nreqsrc, nsrc;
+
+ if ((sscanf(line, "%s %s %d", str1, str2, &nreqsrc)) != 3) {
+ printf("-1\n");
+ break;
+ }
+ ifindex = parse_cmd_args(&su, NULL, str1, str2, NULL);
+ if (ifindex == 0 || (n < 0 || n > MAX_ADDRS)) {
+ printf("-1\n");
+ break;
+ }
+
+ af = su.sa.sa_family;
+ nsrc = nreqsrc;
+ if (getsourcefilter(af2sock(af, s, s6), ifindex, &su.sa,
+ su.sa.sa_len, &fmode, (uint32_t *)&nsrc,
+ &sources[0].ss) != 0) {
+ warn("getsourcefilter");
+ printf("-1\n");
+ break;
+ }
+ printf("%s\n", (fmode == MCAST_INCLUDE) ? "include" :
+ "exclude");
+ printf("%d\n", nsrc);
+
+ nsrc = MIN(nreqsrc, nsrc);
+ fprintf(stderr, "hexdump of sources:\n");
+ uint8_t *bp = (uint8_t *)&sources[0];
+ for (i = 0; i < (nsrc * sizeof(sources[0])); i++) {
+ fprintf(stderr, "%02x", bp[i]);
+ }
+ fprintf(stderr, "\nend hexdump\n");
+
+ qsort(sources, nsrc, sizeof (sockunion_t), su_cmp);
+ for (i = 0; i < nsrc; i++) {
+ sockunion_t *psu = (sockunion_t *)&sources[i];
+ addrbuf[0] = '\0';
+ error = getnameinfo(&psu->sa, psu->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error)
+ warnx("getnameinfo: %s", gai_strerror(error));
+ else
+ printf("%s\n", addrbuf);
+ }
+ printf("ok\n");
+ } break;
+#endif
+ /* link-layer stuff follows. */
+
+ case 'a':
+ case 'd': {
+ struct sockaddr_dl *dlp;
+ struct ether_addr *ep;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ dlp = (struct sockaddr_dl *)&ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETHER_ADDR_LEN;
+ dlp->sdl_slen = 0;
+ if (sscanf(line, "%s %s", str1, str2) != 2) {
+ warnc(EINVAL, "sscanf");
+ break;
+ }
+ ep = ether_aton(str2);
+ if (ep == NULL) {
+ warnc(EINVAL, "ether_aton");
+ break;
+ }
+ strlcpy(ifr.ifr_name, str1, sizeof(ifr.ifr_name));
+ memcpy(LLADDR(dlp), ep, ETHER_ADDR_LEN);
+ if (ioctl(s, (*cmd == 'a') ? SIOCADDMULTI : SIOCDELMULTI,
+ &ifr) == -1) {
+ warn("ioctl SIOCADDMULTI/SIOCDELMULTI");
+ printf("-1\n");
+ } else
+ printf("ok\n");
+ break;
+ }
+
+ case 'm':
+ fprintf(stderr,
+ "warning: IFF_ALLMULTI cannot be set from userland "
+ "in Darwin; command ignored.\n");
+ printf("-1\n");
+ break;
+
+#ifndef __APPLE__
+ case 'p':
+ if (sscanf(line, "%s %u", ifr.ifr_name, &f) != 2) {
+ printf("-1\n");
+ break;
+ }
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
+ warn("ioctl SIOCGIFFLAGS");
+ break;
+ }
+ flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
+ if (f == 0) {
+ flags &= ~IFF_PPROMISC;
+ } else {
+ flags |= IFF_PPROMISC;
+ }
+ ifr.ifr_flags = flags & 0xffff;
+ ifr.ifr_flagshigh = flags >> 16;
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1)
+ warn("ioctl SIOCGIFFLAGS");
+ else
+ printf( "changed to 0x%08x\n", flags );
+ break;
+#endif /* __APPLE__ */
+ case '\n':
+ break;
+ default:
+ printf("invalid command\n");
+ break;
+ }
+}
+
+static void
+usage(void)
+{
+
+#ifndef HAS_SSM
+ printf("j mcast-addr ifname - join IP multicast group\n");
+ printf("l mcast-addr ifname - leave IP multicast group\n");
+#else /* HAS_SSM */
+ printf("j mcast-addr ifname [src-addr] - join IP multicast group\n");
+ printf("l mcast-addr ifname [src-addr] - leave IP multicast group\n");
+ printf(
+ "i mcast-addr ifname n - set n include mode src filter\n");
+ printf(
+ "e mcast-addr ifname n - set n exclude mode src filter\n");
+ printf("t mcast-addr ifname src-addr - allow traffic from src\n");
+ printf("b mcast-addr ifname src-addr - block traffic from src\n");
+ printf("g mcast-addr ifname n - get and show n src filters\n");
+#endif
+ printf("a ifname mac-addr - add link multicast filter\n");
+ printf("d ifname mac-addr - delete link multicast filter\n");
+ printf("m ifname 1/0 - set/clear ether allmulti flag\n");
+#ifndef __APPLE__
+ printf("p ifname 1/0 - set/clear ether promisc flag\n");
+#endif /* __APPLE__ */
+ printf("f filename - read command(s) from file\n");
+ printf("s seconds - sleep for some time\n");
+ printf("q - quit\n");
+}
+
diff --git a/network_cmds/ndp.tproj/gnuc.h b/network_cmds/ndp.tproj/gnuc.h
new file mode 100644
index 0000000..5c6b29e
--- /dev/null
+++ b/network_cmds/ndp.tproj/gnuc.h
@@ -0,0 +1,2 @@
+/* $FreeBSD: src/usr.sbin/ndp/gnuc.h,v 1.1 2000/01/06 12:40:40 shin Exp $ */
+/* this is dummy to pacify gmt2local.c. */
diff --git a/network_cmds/ndp.tproj/ndp.8 b/network_cmds/ndp.tproj/ndp.8
new file mode 100644
index 0000000..b1217eb
--- /dev/null
+++ b/network_cmds/ndp.tproj/ndp.8
@@ -0,0 +1,236 @@
+.\" Copyright (c) 2012-2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" 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.
+.\"
+.Dd May 17, 1998
+.Dt NDP 8
+.Os
+.\"
+.Sh NAME
+.Nm ndp
+.Nd control/diagnose IPv6 neighbor discovery protocol
+.\"
+.Sh SYNOPSIS
+.Nm
+.Fl a
+.Op Fl lnt
+.Nm
+.Fl A Ar wait
+.Op Fl nt
+.Nm
+.Fl c
+.Op Fl nt
+.Nm
+.Fl d
+.Op Fl nt
+.Ar hostname
+.Nm
+.Fl f
+.Op Fl nt
+.Ar filename
+.Nm
+.Fl H
+.Nm
+.Fl I
+.Op Cm delete | Ar interface
+.Nm
+.Fl i
+.Ar interface
+.Op Ar flags...
+.Nm
+.Fl p
+.Nm
+.Fl P
+.Nm
+.Fl r
+.Nm
+.Fl R
+.Nm
+.Fl s
+.Op Fl nt
+.Ar nodename
+.Ar ether_addr
+.Op Li temp
+.Op Li proxy
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+command manipulates the address mapping table
+used by Neighbor Discovery Protocol (NDP).
+.Bl -tag -width Ds
+.It Fl a
+Dump the currently existing NDP entries.
+.It Fl A Ar wait
+Repeat
+.Fl a
+(dump NDP entries)
+every
+.Ar wait
+seconds.
+.It Fl c
+Erase all the NDP entries.
+.It Fl d
+Delete specified NDP entry.
+.It Fl f
+Parse the file specified by
+.Ar filename .
+.It Fl H
+Harmonize consistency between the routing table and the default router
+list; install the top entry of the list into the kernel routing table.
+.It Fl I Op Cm delete | Ar interface
+Shows or specifies the default interface used as the default route when
+there is no default router.
+If no argument is given to the option,
+the current default interface will be shown.
+If an
+.Ar interface
+is specified, the interface will be used as the default.
+If a special keyword
+.Ic delete
+is specified, the current default interface will be deleted from the kernel.
+.It Fl i Ar interface Op Ar flags...
+View ND information for the specified interface.
+If additional arguments
+.Ar flags
+are given,
+.Nm
+sets or clears the specified flags for the interface.
+Possible flags are as follows.
+All of the flags can begin with the
+special character
+.Ql - ,
+which means the flag should be cleared.
+.\"
+.Bl -tag -width Ds -compact
+.It Xo
+.Ic nud
+.Xc
+turn on or off NUD (Neighbor Unreachability Detection) on the
+interface.
+NUD is usually turned on by default.
+.It Xo
+.Ic disabled
+.Xc
+IPv6 can be disabled separately from other network protocols. This flag can be
+turned on automatically when Duplicate Address Detection (DAD) indicates that
+another device on the network is using the same link-local address.
+.It Xo
+.Ic proxy_prefixes
+.Xc
+the interface is enabled to proxy neighbor discovery for global scope prefixes
+matching those on link at other interfaces.
+.It Xo
+.Ic insecure
+do not use cryptographically generated addresses (CGA) on this interface.
+.Xc
+.It Xo
+.Ic replicated
+Address autoconfiguration proceeds under the assumption that interface
+configuration is replicated by a sleep proxy at another node on the link.
+Disables optimistic DAD and sends unsolicited NA with O=1 when DAD completes.
+Ignores DAD failures from other hardware addresses.
+.Xc
+.El
+.It Fl l
+Show link-layer reachability information.
+.It Fl n
+Do not try to resolve numeric address to hostname.
+.It Fl p
+Show prefix list.
+.It Fl P
+Flush all the entries in the prefix list.
+.It Fl r
+Show default router list.
+.It Fl R
+Flush all the entries in the default router list.
+.It Fl s
+Register an NDP entry for a node.
+The entry will be permanent unless the word
+.Li temp
+is given in the command.
+If the word
+.Li proxy
+is given, this system will act as an proxy NDP server,
+responding to requests for
+.Ar hostname
+even though the host address is not its own.
+.It Fl t
+Print timestamp on each entries,
+to make it possible to merge output with
+.Xr tcpdump 1 .
+Most useful when used with
+.Fl A .
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl l
+flag.
+.It Fl w
+Show the cryptographically generated address (CGA) parameters for the node.
+.El
+.\"
+.Sh RETURN VALUES
+The
+.Nm
+command will exit with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr arp 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\"
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/network_cmds/ndp.tproj/ndp.c b/network_cmds/ndp.tproj/ndp.c
new file mode 100644
index 0000000..b485fa1
--- /dev/null
+++ b/network_cmds/ndp.tproj/ndp.c
@@ -0,0 +1,1696 @@
+/*
+ * Copyright (c) 2009-2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sun Microsystems, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Based on:
+ * "@(#) Copyright (c) 1984, 1993\n\
+ * The Regents of the University of California. All rights reserved.\n";
+ *
+ * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
+ */
+
+/*
+ * ndp - display, set, delete and flush neighbor cache
+ */
+
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/icmp6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <string.h>
+#include <paths.h>
+#include <err.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* packing rule for routing socket */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof (uint32_t) - 1))) : \
+ sizeof (uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static int pid;
+static int cflag;
+static int nflag;
+static int tflag;
+static int32_t thiszone = 0; /* time difference with gmt */
+static int s = -1;
+static int repeat = 0;
+
+static char host_buf[NI_MAXHOST]; /* getnameinfo() */
+static char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
+
+static int file(char *);
+static void getsocket(void);
+static int set(int, char **);
+static void get(char *);
+static int delete(char *);
+static void dump(struct in6_addr *);
+static void dump_ext(struct in6_addr *, int);
+static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
+static char *ether_str(struct sockaddr_dl *);
+static int ndp_ether_aton(char *, u_char *);
+static void usage(void);
+static int rtmsg(int);
+static void ifinfo(int, char **);
+static void rtrlist(void);
+static void plist(void);
+static void pfx_flush(void);
+static void rtrlist(void);
+static void rtr_flush(void);
+static void harmonize_rtr(void);
+static void getdefif(void);
+static void setdefif(char *);
+static char *sec2str(time_t);
+static char *ether_str(struct sockaddr_dl *);
+static void ts_print(const struct timeval *);
+static void read_cga_parameters(void);
+static void write_cga_parameters(const char[]);
+
+static char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+};
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ int aflag = 0, dflag = 0, sflag = 0, Hflag = 0, pflag = 0, rflag = 0,
+ Pflag = 0, Rflag = 0, lflag = 0, xflag = 0, wflag = 0;
+
+ pid = getpid();
+ while ((ch = getopt(argc, argv, "acndfIilprstA:HPRxwW")) != -1)
+ switch ((char) ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'I':
+ if (argc > 2)
+ setdefif(argv[2]);
+ getdefif(); /* always call it to print the result */
+ exit(0);
+ case 'i' :
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage();
+ ifinfo(argc, argv);
+ exit(0);
+ case 'n':
+ nflag = 1;
+ continue;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'f' :
+ if (argc != 3)
+ usage();
+ file(argv[2]);
+ exit(0);
+ case 'l' :
+ lflag = 1;
+ break;
+ case 'r' :
+ rflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'A':
+ aflag = 1;
+ repeat = atoi(optarg);
+ if (repeat < 0)
+ usage();
+ break;
+ case 'H' :
+ Hflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ lflag = 1;
+ break;
+ case 'w':
+ wflag = 1;
+ break;
+ case 'W':
+ if (argc != 3)
+ usage();
+ write_cga_parameters(argv[2]);
+ exit(0);
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (aflag || cflag) {
+ if (lflag)
+ dump_ext(0, xflag);
+ else
+ dump(0);
+ exit(0);
+ }
+ if (dflag) {
+ if (argc != 1)
+ usage();
+ delete(argv[0]);
+ exit(0);
+ }
+ if (pflag) {
+ plist();
+ exit(0);
+ }
+ if (rflag) {
+ rtrlist();
+ exit(0);
+ }
+ if (sflag) {
+ if (argc < 2 || argc > 4)
+ usage();
+ exit(set(argc, argv) ? 1 : 0);
+ }
+ if (Hflag) {
+ harmonize_rtr();
+ exit(0);
+ }
+ if (Pflag) {
+ pfx_flush();
+ exit(0);
+ }
+ if (Rflag) {
+ rtr_flush();
+ exit(0);
+ }
+ if (wflag) {
+ read_cga_parameters();
+ exit(0);
+ }
+
+ if (argc != 1)
+ usage();
+ get(argv[0]);
+ exit(0);
+}
+
+/*
+ * Process a file to set standard ndp entries
+ */
+static int
+file(char *name)
+{
+ FILE *fp;
+ int i, retval;
+ char line[100], arg[5][50], *args[5];
+
+ if ((fp = fopen(name, "r")) == NULL) {
+ fprintf(stderr, "ndp: cannot open %s\n", name);
+ exit(1);
+ }
+ args[0] = &arg[0][0];
+ args[1] = &arg[1][0];
+ args[2] = &arg[2][0];
+ args[3] = &arg[3][0];
+ args[4] = &arg[4][0];
+ retval = 0;
+ while (fgets(line, 100, fp) != NULL) {
+ i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
+ arg[3], arg[4]);
+ if (i < 2) {
+ fprintf(stderr, "ndp: bad line: %s\n", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+static void
+getsocket(void)
+{
+ if (s < 0) {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ }
+}
+
+struct sockaddr_in6 so_mask = {sizeof (so_mask), AF_INET6 };
+struct sockaddr_in6 blank_sin = {sizeof (blank_sin), AF_INET6 }, sin_m;
+struct sockaddr_dl blank_sdl = {sizeof (blank_sdl), AF_LINK }, sdl_m;
+int expire_time, flags, found_entry;
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+/*
+ * Set an individual neighbor cache entry
+ */
+static int
+set(int argc, char **argv)
+{
+ register struct sockaddr_in6 *sin = &sin_m;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ struct addrinfo hints, *res;
+ int gai_error;
+ u_char *ea;
+ char *host = argv[0], *eaddr = argv[1];
+ int ealen;
+
+ getsocket();
+ argc -= 2;
+ argv += 2;
+ sdl_m = blank_sdl;
+ sin_m = blank_sin;
+
+ bzero(&hints, sizeof (hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return (1);
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
+ htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
+ }
+#endif
+ ea = (u_char *)LLADDR(&sdl_m);
+
+ ealen = ndp_ether_aton(eaddr, ea);
+ if (ealen != -1)
+ sdl_m.sdl_alen = ealen;
+ flags = expire_time = 0;
+ while (argc-- > 0) {
+ if (strncmp(argv[0], "temp", 4) == 0) {
+ struct timeval time;
+ gettimeofday(&time, 0);
+ expire_time = time.tv_sec + 20 * 60;
+ } else if (strncmp(argv[0], "proxy", 5) == 0)
+ flags |= RTF_ANNOUNCE;
+ argv++;
+ }
+ if (rtmsg(RTM_GET) < 0) {
+ perror(host);
+ return (1);
+ }
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
+ if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ case IFT_6LOWPAN:
+ goto overwrite;
+ }
+ /*
+ * IPv4 arp command retries with sin_other = SIN_PROXY here.
+ */
+ fprintf(stderr, "set: cannot configure a new entry\n");
+ return (1);
+ }
+
+overwrite:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot intuit interface index and type for %s\n", host);
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD));
+}
+
+/*
+ * Display an individual neighbor cache entry
+ */
+static void
+get(char *host)
+{
+ struct sockaddr_in6 *sin = &sin_m;
+ struct addrinfo hints, *res;
+ int gai_error;
+
+ sin_m = blank_sin;
+ bzero(&hints, sizeof (hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return;
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
+ htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
+ }
+#endif
+ dump(&sin->sin6_addr);
+ if (found_entry == 0) {
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0, NI_WITHSCOPEID | (nflag ?
+ NI_NUMERICHOST : 0));
+ printf("%s (%s) -- no entry\n", host, host_buf);
+ exit(1);
+ }
+}
+
+/*
+ * Delete a neighbor cache entry
+ */
+static int
+delete(char *host)
+{
+ struct sockaddr_in6 *sin = &sin_m;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ struct sockaddr_dl *sdl;
+ struct addrinfo hints, *res;
+ int gai_error;
+
+ getsocket();
+ sin_m = blank_sin;
+
+ bzero(&hints, sizeof (hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return (1);
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
+ htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
+ }
+#endif
+ if (rtmsg(RTM_GET) < 0) {
+ perror(host);
+ return (1);
+ }
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
+ if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) {
+ goto delete;
+ }
+ /*
+ * IPv4 arp command retries with sin_other = SIN_PROXY here.
+ */
+ fprintf(stderr, "delete: cannot delete non-NDP entry\n");
+ return (1);
+ }
+
+delete:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot locate %s\n", host);
+ return (1);
+ }
+ if (rtmsg(RTM_DELETE) == 0) {
+ struct sockaddr_in6 s6 = *sin;
+
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
+ s6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
+ *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
+ }
+#endif
+ getnameinfo((struct sockaddr *)&s6,
+ s6.sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ printf("%s (%s) deleted\n", host, host_buf);
+ }
+
+ return (0);
+}
+
+#define W_ADDR 31
+#define W_LL 17
+#define W_IF 6
+
+/*
+ * Dump the entire neighbor cache
+ */
+static void
+dump(struct in6_addr *addr)
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_in6 *sin;
+ struct sockaddr_dl *sdl;
+ struct in6_nbrinfo *nbi;
+ struct timeval time;
+ int addrwidth;
+ int llwidth;
+ int ifwidth;
+ char flgbuf[8];
+ char *ifname;
+
+ /* Print header */
+ if (!tflag && !cflag)
+ printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
+ W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
+ W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs");
+
+again:;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE estimate)");
+ if (needed > 0) {
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
+ lim = buf + needed;
+ } else
+ buf = lim = NULL;
+
+ for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
+ int isrouter = 0, prbs = 0;
+
+ rtm = (struct rt_msghdr *)next;
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin +
+ ROUNDUP(sin->sin6_len));
+
+ /*
+ * Some OSes can produce a route that has the LINK flag but
+ * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
+ * and BSD/OS, where xx is not the interface identifier on
+ * lo0). Such routes entry would annoy getnbrinfo() below,
+ * so we skip them.
+ * XXX: such routes should have the GATEWAY flag, not the
+ * LINK flag. However, there are rotten routing software
+ * that advertises all routes that have the GATEWAY flag.
+ * Thus, KAME kernel intentionally does not set the LINK flag.
+ * What is to be fixed is not ndp, but such routing software
+ * (and the kernel workaround)...
+ */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+
+ if (addr) {
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
+ continue;
+ found_entry = 1;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
+ /* should scope id be filled in the kernel? */
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = sdl->sdl_index;
+#ifdef __KAME__
+ /* KAME specific hack; removed the embedded id */
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
+#endif
+ }
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ if (cflag == 1) {
+ if (rtm->rtm_flags & RTF_WASCLONED)
+ delete(host_buf);
+ continue;
+ }
+ gettimeofday(&time, 0);
+ if (tflag)
+ ts_print(&time);
+
+ addrwidth = strlen(host_buf);
+ if (addrwidth < W_ADDR)
+ addrwidth = W_ADDR;
+ llwidth = strlen(ether_str(sdl));
+ if (W_ADDR + W_LL - addrwidth > llwidth)
+ llwidth = W_ADDR + W_LL - addrwidth;
+ ifname = if_indextoname(sdl->sdl_index, ifix_buf);
+ if (!ifname)
+ ifname = "?";
+ ifwidth = strlen(ifname);
+ if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
+ ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
+
+ printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
+ llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
+
+ /* Print neighbor discovery specific informations */
+ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
+ if (nbi) {
+ if (nbi->expire > time.tv_sec) {
+ printf(" %-9.9s", sec2str(nbi->expire -
+ time.tv_sec));
+ } else if (nbi->expire == 0)
+ printf(" %-9.9s", "permanent");
+ else
+ printf(" %-9.9s", "expired");
+
+ switch (nbi->state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
+ }
+
+ isrouter = nbi->isrouter;
+ prbs = nbi->asked;
+ } else {
+ warnx("failed to get neighbor information");
+ printf(" ");
+ }
+ putchar(' ');
+
+ /*
+ * other flags. R: router, P: proxy, W: ??
+ */
+ if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s",
+ isrouter ? "R" : "",
+ (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ } else {
+ sin = (struct sockaddr_in6 *)
+ (sdl->sdl_len + (char *)sdl);
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
+ isrouter ? "R" : "",
+ !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
+ ? "P" : "",
+ (sin->sin6_len != sizeof (struct sockaddr_in6))
+ ? "W" : "",
+ (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ }
+ printf(" %-4.4s", flgbuf);
+
+ if (prbs)
+ printf(" %4d", prbs);
+
+ printf("\n");
+ }
+ if (buf != NULL)
+ free(buf);
+
+ if (repeat) {
+ printf("\n");
+ sleep(repeat);
+ goto again;
+ }
+}
+
+/*
+ * Dump the entire neighbor cache (extended)
+ */
+void
+dump_ext(addr, xflag)
+ struct in6_addr *addr;
+ int xflag;
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *next;
+ struct rt_msghdr_ext *ertm;
+ struct sockaddr_in6 *sin;
+ struct sockaddr_dl *sdl;
+ struct in6_nbrinfo *nbi;
+ struct timeval time;
+ int addrwidth;
+ int llwidth;
+ int ifwidth;
+ char flgbuf[8];
+ char *ifname;
+
+ /* Print header */
+ if (!tflag && !cflag) {
+ printf("%-*.*s %-*.*s %*.*s %-9.9s %-9.9s %2s %4s %4s",
+ W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
+ W_IF, W_IF, "Netif", "Expire(O)", "Expire(I)", "St",
+ "Flgs", "Prbs");
+ if (xflag)
+ printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
+ printf("\n");
+ }
+
+again:;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_DUMPX_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE estimate)");
+ if (needed > 0) {
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
+ lim = buf + needed;
+ } else
+ buf = lim = NULL;
+
+ for (next = buf; next && next < lim; next += ertm->rtm_msglen) {
+ int isrouter = 0, prbs = 0;
+
+ ertm = (struct rt_msghdr_ext *)next;
+ sin = (struct sockaddr_in6 *)(ertm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin +
+ ROUNDUP(sin->sin6_len));
+
+ /*
+ * Some OSes can produce a route that has the LINK flag but
+ * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
+ * and BSD/OS, where xx is not the interface identifier on
+ * lo0). Such routes entry would annoy getnbrinfo() below,
+ * so we skip them.
+ * XXX: such routes should have the GATEWAY flag, not the
+ * LINK flag. However, there are rotten routing software
+ * that advertises all routes that have the GATEWAY flag.
+ * Thus, KAME kernel intentionally does not set the LINK flag.
+ * What is to be fixed is not ndp, but such routing software
+ * (and the kernel workaround)...
+ */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+
+ if (addr) {
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
+ continue;
+ found_entry = 1;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
+ /* should scope id be filled in the kernel? */
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = sdl->sdl_index;
+#ifdef __KAME__
+ /* KAME specific hack; removed the embedded id */
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
+#endif
+ }
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ if (cflag == 1) {
+ if (ertm->rtm_flags & RTF_WASCLONED)
+ delete(host_buf);
+ continue;
+ }
+ gettimeofday(&time, 0);
+ if (tflag)
+ ts_print(&time);
+
+ addrwidth = strlen(host_buf);
+ if (addrwidth < W_ADDR)
+ addrwidth = W_ADDR;
+ llwidth = strlen(ether_str(sdl));
+ if (W_ADDR + W_LL - addrwidth > llwidth)
+ llwidth = W_ADDR + W_LL - addrwidth;
+ ifname = if_indextoname(sdl->sdl_index, ifix_buf);
+ if (!ifname)
+ ifname = "?";
+ ifwidth = strlen(ifname);
+ if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
+ ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
+
+ printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
+ llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
+
+ if (ertm->rtm_ri.ri_refcnt == 0 ||
+ ertm->rtm_ri.ri_snd_expire == 0)
+ printf(" %-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
+ printf(" %-9.9s",
+ sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
+ else
+ printf(" %-9.9s", "expired");
+
+ if (ertm->rtm_ri.ri_refcnt == 0 ||
+ ertm->rtm_ri.ri_rcv_expire == 0)
+ printf(" %-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
+ printf(" %-9.9s",
+ sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
+ else
+ printf(" %-9.9s", "expired");
+
+ /* Print neighbor discovery specific informations */
+ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
+ if (nbi) {
+ switch (nbi->state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
+ }
+
+ isrouter = nbi->isrouter;
+ prbs = nbi->asked;
+ } else {
+ warnx("failed to get neighbor information");
+ printf(" ");
+ }
+ putchar(' ');
+
+ /*
+ * other flags. R: router, P: proxy, W: ??
+ */
+ if ((ertm->rtm_addrs & RTA_NETMASK) == 0) {
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s",
+ isrouter ? "R" : "",
+ (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ } else {
+ sin = (struct sockaddr_in6 *)
+ (sdl->sdl_len + (char *)sdl);
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
+ isrouter ? "R" : "",
+ !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
+ ? "P" : "",
+ (sin->sin6_len != sizeof (struct sockaddr_in6))
+ ? "W" : "",
+ (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ }
+ printf(" %-4.4s", flgbuf);
+
+ if (prbs)
+ printf(" %4d", prbs);
+
+ if (xflag) {
+ if (!prbs)
+ printf(" %-4.4s", "none");
+
+ if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", ertm->rtm_ri.ri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (ertm->rtm_ri.ri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_lqm);
+ break;
+ }
+
+ switch (ertm->rtm_ri.ri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_npm);
+ break;
+ }
+ }
+
+ printf("\n");
+ }
+ if (buf != NULL)
+ free(buf);
+
+ if (repeat) {
+ printf("\n");
+ sleep(repeat);
+ goto again;
+ }
+}
+
+static struct in6_nbrinfo *
+getnbrinfo(addr, ifindex, warning)
+ struct in6_addr *addr;
+ int ifindex;
+ int warning;
+{
+ static struct in6_nbrinfo nbi;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ bzero(&nbi, sizeof (nbi));
+ if_indextoname(ifindex, nbi.ifname);
+ nbi.addr = *addr;
+ if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
+ if (warning)
+ warn("ioctl(SIOCGNBRINFO_IN6)");
+ close(s);
+ return (NULL);
+ }
+
+ close(s);
+ return (&nbi);
+}
+
+static char *
+ether_str(struct sockaddr_dl *sdl)
+{
+ static char ebuf[32];
+ u_char *cp;
+
+ if (sdl->sdl_alen) {
+ cp = (u_char *)LLADDR(sdl);
+ snprintf(ebuf, sizeof (ebuf), "%x:%x:%x:%x:%x:%x",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ } else {
+ snprintf(ebuf, sizeof (ebuf), "(incomplete)");
+ }
+
+ return (ebuf);
+}
+
+static int
+ndp_ether_aton(char *a, u_char *n)
+{
+ int i, o[8];
+ int len;
+
+ len = sscanf(a, "%x:%x:%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4],
+ &o[5], &o[6], &o[7]);
+ if (len != 6 && len != 8) {
+ fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
+ return (-1);
+ }
+ for (i = 0; i < len; i++)
+ n[i] = o[i];
+ return (len);
+}
+
+static void
+usage(void)
+{
+ printf("usage: ndp hostname\n");
+ printf(" ndp -a[lnt]\n");
+ printf(" ndp [-nt] -A wait\n");
+ printf(" ndp -c[nt]\n");
+ printf(" ndp -d[nt] hostname\n");
+ printf(" ndp -f[nt] filename\n");
+ printf(" ndp -i interface [flags...]\n");
+ printf(" ndp -I [interface|delete]\n");
+ printf(" ndp -p\n");
+ printf(" ndp -r\n");
+ printf(" ndp -s hostname ether_addr [temp] [proxy]\n");
+ printf(" ndp -H\n");
+ printf(" ndp -P\n");
+ printf(" ndp -R\n");
+ printf(" ndp -w\n");
+ printf(" ndp -W cfgfile\n");
+ exit(1);
+}
+
+static int
+rtmsg(int cmd)
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+ errno = 0;
+ if (cmd == RTM_DELETE)
+ goto doit;
+ bzero((char *)&m_rtmsg, sizeof (m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ fprintf(stderr, "ndp: internal wrong cmd\n");
+ exit(1);
+ case RTM_ADD:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ if (rtm->rtm_flags & RTF_ANNOUNCE) {
+ rtm->rtm_flags &= ~RTF_HOST;
+ rtm->rtm_flags |= RTA_NETMASK;
+ }
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if (rtm->rtm_addrs & (w)) { \
+ bcopy((char *)&s, cp, sizeof (s)); cp += sizeof (s); \
+ }
+
+ NEXTADDR(RTA_DST, sin_m);
+ NEXTADDR(RTA_GATEWAY, sdl_m);
+ memset(&so_mask.sin6_addr, 0xff, sizeof (so_mask.sin6_addr));
+ NEXTADDR(RTA_NETMASK, so_mask);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+doit:
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if (errno != ESRCH || cmd != RTM_DELETE) {
+ perror("writing to routing socket");
+ return (-1);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+ if (l < 0)
+ (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
+ strerror(errno));
+ return (0);
+}
+
+static void
+ifinfo(int argc, char **argv)
+{
+ struct in6_ndireq nd;
+ int i, s;
+ char *ifname = argv[0];
+ u_int32_t newflags;
+ u_int8_t nullbuf[8];
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ bzero(&nd, sizeof (nd));
+ strlcpy(nd.ifname, ifname, sizeof (nd.ifname));
+ if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
+ perror("ioctl (SIOCGIFINFO_IN6)");
+ exit(1);
+ }
+#define ND nd.ndi
+ newflags = ND.flags;
+ for (i = 1; i < argc; i++) {
+ int clear = 0;
+ char *cp = argv[i];
+
+ if (*cp == '-') {
+ clear = 1;
+ cp++;
+ }
+
+#define SETFLAG(s, f) \
+ do {\
+ if (strcmp(cp, (s)) == 0) {\
+ if (clear)\
+ newflags &= ~(f);\
+ else\
+ newflags |= (f);\
+ }\
+ } while (0)
+ SETFLAG("nud", ND6_IFF_PERFORMNUD);
+ SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES);
+ SETFLAG("disabled", ND6_IFF_IFDISABLED);
+ SETFLAG("insecure", ND6_IFF_INSECURE);
+ SETFLAG("replicated", ND6_IFF_REPLICATED);
+
+ ND.flags = newflags;
+ if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
+ perror("ioctl(SIOCSIFINFO_FLAGS)");
+ exit(1);
+ }
+#undef SETFLAG
+ }
+
+ printf("linkmtu=%d", ND.linkmtu);
+ printf(", curhlim=%d", ND.chlim);
+ printf(", basereachable=%ds%dms", ND.basereachable / 1000,
+ ND.basereachable % 1000);
+ printf(", reachable=%ds", ND.reachable);
+ printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
+ memset(nullbuf, 0, sizeof (nullbuf));
+ if (memcmp(nullbuf, ND.randomid, sizeof (nullbuf)) != 0) {
+ int j;
+ u_int8_t *rbuf = NULL;
+
+ for (i = 0; i < 3; i++) {
+ switch (i) {
+ case 0:
+ printf("\nRandom seed(0): ");
+ rbuf = ND.randomseed0;
+ break;
+ case 1:
+ printf("\nRandom seed(1): ");
+ rbuf = ND.randomseed1;
+ break;
+ case 2:
+ printf("\nRandom ID: ");
+ rbuf = ND.randomid;
+ break;
+ }
+ for (j = 0; j < 8; j++)
+ printf("%02x", rbuf[j]);
+ }
+ }
+ if (ND.flags) {
+ printf("\nFlags: 0x%x ", ND.flags);
+ if ((ND.flags & ND6_IFF_IFDISABLED) != 0)
+ printf("IFDISABLED ");
+ if ((ND.flags & ND6_IFF_INSECURE) != 0)
+ printf("INSECURE ");
+ if ((ND.flags & ND6_IFF_PERFORMNUD) != 0)
+ printf("PERFORMNUD ");
+ if ((ND.flags & ND6_IFF_PROXY_PREFIXES) != 0)
+ printf("PROXY_PREFIXES ");
+ if ((ND.flags & ND6_IFF_REPLICATED) != 0)
+ printf("REPLICATED ");
+ if ((ND.flags & ND6_IFF_DAD) != 0)
+ printf("DAD ");
+ }
+ putc('\n', stdout);
+#undef ND
+
+ close(s);
+}
+
+#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+#endif
+
+static void
+rtrlist(void)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
+ char *buf;
+ struct in6_defrouter *p, *ep;
+ size_t l;
+ struct timeval time;
+
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
+ < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
+ /*NOTREACHED*/
+ }
+ buf = malloc(l);
+ if (!buf) {
+ errx(1, "not enough core");
+ /*NOTREACHED*/
+ }
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0) < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
+ /*NOTREACHED*/
+ }
+
+ ep = (struct in6_defrouter *)(buf + l);
+ for (p = (struct in6_defrouter *)buf; p < ep; p++) {
+ int rtpref;
+
+ if (getnameinfo((struct sockaddr *)&p->rtaddr,
+ p->rtaddr.sin6_len, host_buf, sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0)
+ strlcpy(host_buf, "?", sizeof (host_buf));
+
+ printf("%s if=%s", host_buf, if_indextoname(p->if_index,
+ ifix_buf));
+ printf(", flags=%s%s%s%s%s",
+ p->stateflags & NDDRF_IFSCOPE ? "I" : "",
+ p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
+ p->flags & ND_RA_FLAG_OTHER ? "O" : "",
+ p->stateflags & NDDRF_STATIC ? "S" : "",
+ p->stateflags & NDDRF_INSTALLED ? "T" : "");
+ rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
+ printf(", pref=%s", rtpref_str[rtpref]);
+
+ gettimeofday(&time, 0);
+ if (p->expire == 0)
+ printf(", expire=Never\n");
+ else
+ printf(", expire=%s\n",
+ sec2str(p->expire - time.tv_sec));
+ }
+ free(buf);
+}
+
+static void
+plist(void)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
+ char *buf;
+ struct in6_prefix *p, *ep, *n;
+ struct sockaddr_in6 *advrtr;
+ size_t l;
+ struct timeval time;
+ const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
+ int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID;
+ char namebuf[NI_MAXHOST];
+
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
+ < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
+ /*NOTREACHED*/
+ }
+ buf = malloc(l);
+ if (!buf) {
+ errx(1, "not enough core");
+ /*NOTREACHED*/
+ }
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0)
+ < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
+ /*NOTREACHED*/
+ }
+
+ ep = (struct in6_prefix *)(buf + l);
+ for (p = (struct in6_prefix *)buf; p < ep; p = n) {
+ advrtr = (struct sockaddr_in6 *)(p + 1);
+ n = (struct in6_prefix *)&advrtr[p->advrtrs];
+
+ if (getnameinfo((struct sockaddr *)&p->prefix,
+ p->prefix.sin6_len, namebuf, sizeof (namebuf),
+ NULL, 0, niflags) != 0)
+ strlcpy(namebuf, "?", sizeof (namebuf));
+ printf("%s/%d if=%s\n", namebuf, p->prefixlen,
+ if_indextoname(p->if_index, ifix_buf));
+
+ gettimeofday(&time, 0);
+ /*
+ * meaning of fields, especially flags, is very different
+ * by origin. notify the difference to the users.
+ */
+ printf("flags=%s%s%s%s%s%s%s",
+ p->raflags.autonomous ? "A" : "",
+ (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
+ (p->flags & NDPRF_IFSCOPE) != 0 ? "I" : "",
+ p->raflags.onlink ? "L" : "",
+ (p->flags & NDPRF_STATIC) != 0 ? "S" : "",
+ (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
+ (p->flags & NDPRF_PRPROXY) != 0 ? "Y" : "");
+ if (p->vltime == ND6_INFINITE_LIFETIME)
+ printf(" vltime=infinity");
+ else
+ printf(" vltime=%ld", (long)p->vltime);
+ if (p->pltime == ND6_INFINITE_LIFETIME)
+ printf(", pltime=infinity");
+ else
+ printf(", pltime=%ld", (long)p->pltime);
+ if (p->expire == 0)
+ printf(", expire=Never");
+ else if (p->expire >= time.tv_sec)
+ printf(", expire=%s",
+ sec2str(p->expire - time.tv_sec));
+ else
+ printf(", expired");
+ printf(", ref=%d", p->refcnt);
+ printf("\n");
+ /*
+ * "advertising router" list is meaningful only if the prefix
+ * information is from RA.
+ */
+ if (p->advrtrs) {
+ int j;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)(p + 1);
+ printf(" advertised by\n");
+ for (j = 0; j < p->advrtrs; j++) {
+ struct in6_nbrinfo *nbi;
+
+ if (getnameinfo((struct sockaddr *)sin6,
+ sin6->sin6_len, namebuf, sizeof (namebuf),
+ NULL, 0, ninflags) != 0)
+ strlcpy(namebuf, "?", sizeof (namebuf));
+ printf(" %s", namebuf);
+
+ nbi = getnbrinfo(&sin6->sin6_addr, p->if_index,
+ 0);
+ if (nbi) {
+ switch (nbi->state) {
+ case ND6_LLINFO_REACHABLE:
+ case ND6_LLINFO_STALE:
+ case ND6_LLINFO_DELAY:
+ case ND6_LLINFO_PROBE:
+ printf(" (reachable)\n");
+ break;
+ default:
+ printf(" (unreachable)\n");
+ }
+ } else
+ printf(" (no neighbor state)\n");
+ sin6++;
+ }
+ } else
+ printf(" No advertising router\n");
+ }
+ free(buf);
+}
+
+static void
+pfx_flush(void)
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
+ if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
+}
+
+static void
+rtr_flush(void)
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
+ if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
+
+ close(s);
+}
+
+static void
+harmonize_rtr(void)
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
+ if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl (SIOCSNDFLUSH_IN6)");
+
+ close(s);
+}
+
+static void
+setdefif(char *ifname)
+{
+ struct in6_ndifreq ndifreq;
+ unsigned int ifindex;
+
+ if (strcasecmp(ifname, "delete") == 0)
+ ifindex = 0;
+ else {
+ if ((ifindex = if_nametoindex(ifname)) == 0)
+ err(1, "failed to resolve i/f index for %s", ifname);
+ }
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
+ ndifreq.ifindex = ifindex;
+
+ if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
+ err(1, "ioctl (SIOCSDEFIFACE_IN6)");
+
+ close(s);
+}
+
+static void
+getdefif(void)
+{
+ struct in6_ndifreq ndifreq;
+ char ifname[IFNAMSIZ+8];
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ memset(&ndifreq, 0, sizeof (ndifreq));
+ strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
+
+ if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
+ err(1, "ioctl (SIOCGDEFIFACE_IN6)");
+
+ if (ndifreq.ifindex == 0)
+ printf("No default interface.\n");
+ else {
+ if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
+ err(1, "failed to resolve ifname for index %lu",
+ ndifreq.ifindex);
+ printf("ND default interface = %s\n", ifname);
+ }
+
+ close(s);
+}
+
+static char *
+sec2str(time_t total)
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof (result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof (result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins)
+ p += snprintf(p, sizeof (result) - (p - result), "%dm", mins);
+ snprintf(p, sizeof (result) - (p - result), "%ds", secs);
+
+ return (result);
+}
+
+/*
+ * Print the timestamp
+ * from tcpdump/util.c
+ */
+static void
+ts_print(const struct timeval *tvp)
+{
+ int s;
+
+ /* Default */
+ s = (tvp->tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tvp->tv_usec);
+}
+
+#define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
+ 2 * (sizeof (size_t) + IN6_CGA_KEY_MAXSIZE) + \
+ sizeof (struct in6_cga_prepare)
+
+static void
+read_cga_parameters(void)
+{
+ static char oldb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
+
+ int error;
+ struct in6_cga_nodecfg cfg;
+ struct iovec *iov;
+ const char *oldp;
+ const char *finp;
+ size_t oldn;
+ unsigned int column;
+ uint16_t u16;
+
+ oldn = sizeof oldb;
+ error = sysctlbyname("net.inet6.send.cga_parameters", oldb, &oldn,
+ NULL, NULL);
+ if (error != 0)
+ err(1, "sysctlbyname");
+
+ if (oldn == 0) {
+ printf("No CGA parameters.\n");
+ exit(0);
+ }
+
+ oldp = oldb;
+ finp = &oldb[oldn];
+ memset(&cfg, 0, sizeof (cfg));
+
+ if (oldp + sizeof (cfg.cga_prepare) > finp)
+ err(1, "format error[1]");
+
+ memcpy(&cfg.cga_prepare, oldp, sizeof (cfg.cga_prepare));
+ oldp += sizeof (cfg.cga_prepare);
+
+ iov = &cfg.cga_pubkey;
+
+ if (oldp + sizeof (u16) > finp)
+ err(1, "format error[2]");
+
+ memcpy(&u16, oldp, sizeof (u16));
+ oldp += sizeof (u16);
+ iov->iov_len = u16;
+
+ if (oldp + iov->iov_len > finp)
+ err(1, "format error[3]");
+
+ iov->iov_base = (void *)oldp;
+ oldp += iov->iov_len;
+
+ if (oldp != finp)
+ err(1, "format error[4]");
+
+ puts("Public Key:");
+ finp = &iov->iov_base[iov->iov_len];
+ column = 0;
+ oldp = iov->iov_base;
+ while (oldp < finp) {
+ if (column++ != 0)
+ putchar(':');
+ printf("%02x", (unsigned char) *oldp++);
+ if (column >= 32) {
+ column = 0;
+ puts("");
+ }
+ }
+ if (column < 32)
+ puts("");
+ puts("");
+ puts("Modifier:");
+ oldp = (const char*) cfg.cga_prepare.cga_modifier.octets;
+ finp = &oldp[sizeof (cfg.cga_prepare.cga_modifier.octets)];
+ column = 0;
+ while (oldp < finp) {
+ if (column++ != 0)
+ putchar(':');
+ printf("%02x", (unsigned char) *oldp++);
+ }
+ puts("\n");
+ printf("Security Level: %u\n", cfg.cga_prepare.cga_security_level);
+}
+
+static void
+write_cga_parameters(const char filename[])
+{
+ static char newb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
+
+ int error;
+ FILE* fp;
+ size_t oldn, newn;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ err(1, "opening '%s' for reading.", filename);
+
+ newn = fread(newb, 1, sizeof (newb), fp);
+ if (feof(fp) == 0)
+ err(1, "parameters too large");
+
+ if (fclose(fp) != 0)
+ err(1, "closing file.");
+
+ oldn = 0;
+ error = sysctlbyname("net.inet6.send.cga_parameters", NULL, NULL, newb,
+ newn);
+ if (error != 0)
+ err(1, "sysctlbyname");
+}
diff --git a/network_cmds/netstat.tproj/DERIVED_FILES b/network_cmds/netstat.tproj/DERIVED_FILES
new file mode 100644
index 0000000..a4fa6c9
--- /dev/null
+++ b/network_cmds/netstat.tproj/DERIVED_FILES
@@ -0,0 +1 @@
+unix/bsd/netiso/tp_astring.c
diff --git a/network_cmds/netstat.tproj/data.c b/network_cmds/netstat.tproj/data.c
new file mode 100644
index 0000000..9e0bbe2
--- /dev/null
+++ b/network_cmds/netstat.tproj/data.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* NeXT */
+#ifndef EXTERN
+#define EXTERN
+#endif
+#include "netstat.h"
diff --git a/network_cmds/netstat.tproj/if.c b/network_cmds/netstat.tproj/if.c
new file mode 100644
index 0000000..2fe6182
--- /dev/null
+++ b/network_cmds/netstat.tproj/if.c
@@ -0,0 +1,2259 @@
+/*
+ * Copyright (c) 2008-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/kern_control.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_mib.h>
+#include <net/if_llreach.h>
+#include <net/ethernet.h>
+#include <net/route.h>
+#include <net/ntstat.h>
+
+#include <net/pktsched/pktsched.h>
+#include <net/classq/if_classq.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <assert.h>
+
+#include "netstat.h"
+
+#define YES 1
+#define NO 0
+
+#define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a))
+
+#define NEXT_SA(p) (struct sockaddr *) \
+ ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(uint32_t)) : \
+ sizeof(uint32_t)))
+
+static void sidewaysintpr ();
+static void catchalarm (int);
+static char *sec2str(time_t);
+static void llreach_sysctl(uint32_t);
+static char *nsec_to_str(unsigned long long);
+static char *sched2str(unsigned int);
+static char *pri2str(unsigned int i);
+
+#define AVGN_MAX 8
+
+struct queue_stats {
+ int avgn;
+ double avg_bytes;
+ double avg_packets;
+ u_int64_t prev_bytes;
+ u_int64_t prev_packets;
+ unsigned int handle;
+};
+
+static void update_avg(struct if_ifclassq_stats *, struct queue_stats *);
+static void print_fq_codel_stats(int slot, struct fq_codel_classstats *,
+ struct queue_stats *);
+
+struct queue_stats qstats[IFCQ_SC_MAX];
+
+#ifdef INET6
+char *netname6 (struct sockaddr_in6 *, struct sockaddr *);
+static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
+#endif
+
+/*
+ * Display a formatted value, or a '-' in the same space.
+ */
+static void
+show_stat(const char *fmt, int width, u_int64_t value, short showvalue)
+{
+ char newfmt[32];
+
+ /* Construct the format string */
+ if (showvalue) {
+ snprintf(newfmt, sizeof(newfmt), "%%%d%s", width, fmt);
+ printf(newfmt, value);
+ } else {
+ snprintf(newfmt, sizeof(newfmt), "%%%ds", width);
+ printf(newfmt, "-");
+ }
+}
+
+size_t
+get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+ size_t len = 0;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ if (sa->sa_len < sizeof(struct sockaddr))
+ len += sizeof(struct sockaddr);
+ else
+ len += sa->sa_len;
+ sa = NEXT_SA(sa);
+ } else {
+ rti_info[i] = NULL;
+ }
+ }
+ return len;
+}
+
+static void
+multipr(int family, char *buf, char *lim)
+{
+ char *next;
+
+ for (next = buf; next < lim; ) {
+ struct ifma_msghdr2 *ifmam = (struct ifma_msghdr2 *)next;
+ struct sockaddr *rti_info[RTAX_MAX];
+ struct sockaddr *sa;
+ const char *fmt = 0;
+
+ next += ifmam->ifmam_msglen;
+ if (ifmam->ifmam_type == RTM_IFINFO2)
+ break;
+ else if (ifmam->ifmam_type != RTM_NEWMADDR2)
+ continue;
+ get_rti_info(ifmam->ifmam_addrs, (struct sockaddr*)(ifmam + 1), rti_info);
+ sa = rti_info[RTAX_IFA];
+
+ if (sa->sa_family != family)
+ continue;
+ switch (sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ fmt = routename(sin->sin_addr.s_addr);
+ break;
+ }
+ #ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+
+ memcpy(&sin6, sa, sizeof(struct sockaddr_in6));
+
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) {
+ sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+
+ printf("%23s %-19.19s(refs: %d)\n", "",
+ inet_ntop(AF_INET6, &sin6.sin6_addr,
+ ntop_buf, sizeof(ntop_buf)),
+ ifmam->ifmam_refcount);
+ break;
+ }
+ #endif /* INET6 */
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ fmt = ether_ntoa((struct ether_addr *)
+ LLADDR(sdl));
+ break;
+ }
+ break;
+ }
+ }
+ if (fmt)
+ printf("%23s %s\n", "", fmt);
+ }
+}
+
+/*
+ * Print a description of the network interfaces.
+ */
+void
+intpr(void (*pfunc)(char *))
+{
+ u_int64_t opackets = 0;
+ u_int64_t ipackets = 0;
+ u_int64_t obytes = 0;
+ u_int64_t ibytes = 0;
+ u_int64_t oerrors = 0;
+ u_int64_t ierrors = 0;
+ u_int64_t collisions = 0;
+ u_int64_t fpackets = 0;
+ u_int64_t fbytes = 0;
+ uint32_t mtu = 0;
+ int timer = 0;
+ int drops = 0;
+ struct sockaddr *sa = NULL;
+ char name[32];
+ short network_layer;
+ short link_layer;
+ int mib[6];
+ char *buf = NULL, *lim, *next;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *rti_info[RTAX_MAX];
+ unsigned int ifindex = 0;
+
+ if (interval) {
+ sidewaysintpr();
+ return;
+ }
+
+ if (interface != 0)
+ ifindex = if_nametoindex(interface);
+
+ mib[0] = CTL_NET; // networking subsystem
+ mib[1] = PF_ROUTE; // type of information
+ mib[2] = 0; // protocol (IPPROTO_xxx)
+ mib[3] = 0; // address family
+ mib[4] = NET_RT_IFLIST2; // operation
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return;
+ if ((buf = malloc(len)) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ if (buf)
+ free(buf);
+ return;
+ }
+
+ if (!pfunc) {
+ if (lflag) {
+ printf("%-10.10s %-5.5s %-39.39s %-39.39s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ } else {
+ printf("%-10.10s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ }
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Itcpkts", "Ipvpkts");
+ if (bflag) {
+ printf(" %10.10s","Ibytes");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Itcbytes", "Ipvbytes");
+ }
+ printf(" %8.8s %5.5s", "Opkts", "Oerrs");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Otcpkts", "Opvpkts");
+ if (bflag) {
+ printf(" %10.10s","Obytes");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Otcbytes", "Opvbytes");
+ }
+ printf(" %5s", "Coll");
+ if (tflag)
+ printf(" %s", "Time");
+ if (dflag)
+ printf(" %s", "Drop");
+ if (Fflag) {
+ printf(" %8.8s", "Fpkts");
+ if (bflag)
+ printf(" %10.10s", "Fbytes");
+ }
+ putchar('\n');
+ }
+ lim = buf + len;
+ for (next = buf; next < lim; ) {
+ char *cp;
+ int n, m;
+ struct ifmibdata_supplemental ifmsupp;
+ u_int64_t ift_itcp = 0; /* input tc packets */
+ u_int64_t ift_itcb = 0; /* input tc bytes */
+ u_int64_t ift_otcp = 0; /* output tc packets */
+ u_int64_t ift_otcb = 0; /* output tc bytes */
+ u_int64_t ift_ipvp = 0; /* input priv tc packets */
+ u_int64_t ift_ipvb = 0; /* input priv tc bytes */
+ u_int64_t ift_opvp = 0; /* output priv tc packets */
+ u_int64_t ift_opvb = 0; /* output priv tc bytes */
+
+ bzero(&ifmsupp, sizeof(struct ifmibdata_supplemental));
+
+ network_layer = 0;
+ link_layer = 0;
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+
+ if (ifm->ifm_type == RTM_IFINFO2) {
+ struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)(if2m + 1);
+ int mibname[6];
+ size_t miblen = sizeof(struct ifmibdata_supplemental);
+
+ if (interface != 0 && if2m->ifm_index != ifindex)
+ continue;
+
+ /* The interface name is not a zero-ended string */
+ memcpy(name, sdl->sdl_data, MIN(sizeof(name) - 1, sdl->sdl_nlen));
+ name[MIN(sizeof(name) - 1, sdl->sdl_nlen)] = 0;
+
+ if (pfunc) {
+ (*pfunc)(name);
+ continue;
+ }
+
+ cp = index(name, '\0');
+ if ((if2m->ifm_flags & IFF_UP) == 0)
+ *cp++ = '*';
+ *cp = '\0';
+
+ /*
+ * Get the interface stats. These may get
+ * overriden below on a per-interface basis.
+ */
+ opackets = if2m->ifm_data.ifi_opackets;
+ ipackets = if2m->ifm_data.ifi_ipackets;
+ obytes = if2m->ifm_data.ifi_obytes;
+ ibytes = if2m->ifm_data.ifi_ibytes;
+ oerrors =if2m->ifm_data.ifi_oerrors;
+ ierrors = if2m->ifm_data.ifi_ierrors;
+ collisions = if2m->ifm_data.ifi_collisions;
+ timer = if2m->ifm_timer;
+ drops = if2m->ifm_snd_drops;
+ mtu = if2m->ifm_data.ifi_mtu;
+
+ /* Common OID prefix */
+ mibname[0] = CTL_NET;
+ mibname[1] = PF_LINK;
+ mibname[2] = NETLINK_GENERIC;
+ mibname[3] = IFMIB_IFDATA;
+ mibname[4] = if2m->ifm_index;
+ mibname[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(mibname, 6, &ifmsupp, &miblen, NULL, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ fpackets = ifmsupp.ifmd_data_extended.ifi_fpackets;
+ fbytes = ifmsupp.ifmd_data_extended.ifi_fbytes;
+
+ if (prioflag >= 0) {
+ switch (prioflag) {
+ case SO_TC_BE:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibepackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibebytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obepackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ ift_itcp = 0;
+ ift_itcb = 0;
+ ift_otcp = 0;
+ ift_otcb = 0;
+ ift_ipvp = 0;
+ ift_ipvb = 0;
+ ift_opvp = 0;
+ ift_opvb = 0;
+ break;
+ }
+ ift_ipvp = ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
+ ift_ipvb = ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
+ ift_opvp = ifmsupp.ifmd_traffic_class.ifi_opvpackets;
+ ift_opvb = ifmsupp.ifmd_traffic_class.ifi_opvbytes;
+ }
+
+ get_rti_info(if2m->ifm_addrs,
+ (struct sockaddr*)(if2m + 1), rti_info);
+ sa = rti_info[RTAX_IFP];
+ } else if (ifm->ifm_type == RTM_NEWADDR) {
+ struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+
+ if (interface != 0 && ifam->ifam_index != ifindex)
+ continue;
+ get_rti_info(ifam->ifam_addrs,
+ (struct sockaddr*)(ifam + 1), rti_info);
+ sa = rti_info[RTAX_IFA];
+ } else {
+ continue;
+ }
+ if (lflag) {
+ printf("%-10.10s %-5u ", name, mtu);
+ } else {
+ printf("%-5.5s %-5u ", name, mtu);
+ }
+
+ if (sa == 0) {
+ printf(lflag ? "%-39.39s " : "%-13.13s ", "none");
+ printf(lflag ? "%-39.39s " : "%-15.15s ", "none");
+ } else {
+ switch (sa->sa_family) {
+ case AF_UNSPEC:
+ printf(lflag ? "%-39.39s " : "%-13.13s ", "none");
+ printf(lflag ? "%-39.39s " : "%-15.15s ", "none");
+ break;
+
+ case AF_INET: {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in *)sa;
+ struct sockaddr_in mask;
+
+ mask.sin_addr.s_addr = 0;
+ memcpy(&mask, rti_info[RTAX_NETMASK],
+ ((struct sockaddr_in *)
+ rti_info[RTAX_NETMASK])->sin_len);
+
+ printf(lflag ? "%-39.39s " : "%-13.13s ",
+ netname(sin->sin_addr.s_addr &
+ mask.sin_addr.s_addr,
+ ntohl(mask.sin_addr.s_addr)));
+
+ printf(lflag ? "%-39.39s " : "%-15.15s ",
+ routename(sin->sin_addr.s_addr));
+
+ network_layer = 1;
+ break;
+ }
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)sa;
+ struct sockaddr *mask =
+ (struct sockaddr *)rti_info[RTAX_NETMASK];
+
+ printf(lflag ? "%-39.39s " : "%-11.11s ", netname6(sin6, mask));
+ printf(lflag ? "%-39.39s " : "%-17.17s ", (char *)inet_ntop(AF_INET6,
+ &sin6->sin6_addr, ntop_buf,
+ sizeof(ntop_buf)));
+
+ network_layer = 1;
+ break;
+ }
+#endif /*INET6*/
+ case AF_LINK: {
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)sa;
+ char linknum[10];
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ snprintf(linknum, sizeof(linknum),
+ "<Link#%d>", sdl->sdl_index);
+ m = printf(lflag ? "%-39.39s " : "%-11.11s ", linknum);
+ goto hexprint;
+ }
+
+ default:
+ m = printf("(%d)", sa->sa_family);
+ for (cp = sa->sa_len + (char *)sa;
+ --cp > sa->sa_data && (*cp == 0);) {}
+ n = cp - sa->sa_data + 1;
+ cp = sa->sa_data;
+ hexprint:
+ while (--n >= 0)
+ m += printf("%02x%c", *cp++ & 0xff,
+ n > 0 ? ':' : ' ');
+ m = (lflag ? 80 : 30) - m;
+ while (m-- > 0)
+ putchar(' ');
+
+ link_layer = 1;
+ break;
+ }
+ }
+
+ show_stat("llu", 8, ipackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 5, ierrors, link_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_itcp, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_ipvp, link_layer|network_layer);
+ printf(" ");
+ }
+ if (bflag) {
+ show_stat("llu", 10, ibytes, link_layer|network_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_itcb, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_ipvb, link_layer|network_layer);
+ printf(" ");
+ }
+ }
+ show_stat("llu", 8, opackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 5, oerrors, link_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_otcp, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_opvp, link_layer|network_layer);
+ printf(" ");
+ }
+ if (bflag) {
+ show_stat("llu", 10, obytes, link_layer|network_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_otcb, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_opvb, link_layer|network_layer);
+ printf(" ");
+ }
+ }
+ show_stat("llu", 5, collisions, link_layer);
+ if (tflag) {
+ printf(" ");
+ show_stat("d", 3, timer, link_layer);
+ }
+ if (dflag) {
+ printf(" ");
+ show_stat("d", 3, drops, link_layer);
+ }
+ if (Fflag) {
+ printf(" ");
+ show_stat("llu", 8, fpackets, link_layer|network_layer);
+ if (bflag) {
+ printf(" ");
+ show_stat("llu", 10, fbytes,
+ link_layer|network_layer);
+ }
+ }
+ putchar('\n');
+
+ if (aflag)
+ multipr(sa->sa_family, next, lim);
+ }
+ free(buf);
+}
+
+struct iftot {
+ SLIST_ENTRY(iftot) chain;
+ char ift_name[16]; /* interface name */
+ u_int64_t ift_ip; /* input packets */
+ u_int64_t ift_ie; /* input errors */
+ u_int64_t ift_op; /* output packets */
+ u_int64_t ift_oe; /* output errors */
+ u_int64_t ift_co; /* collisions */
+ u_int64_t ift_dr; /* drops */
+ u_int64_t ift_ib; /* input bytes */
+ u_int64_t ift_ob; /* output bytes */
+ u_int64_t ift_itcp; /* input tc packets */
+ u_int64_t ift_itcb; /* input tc bytes */
+ u_int64_t ift_otcp; /* output tc packets */
+ u_int64_t ift_otcb; /* output tc bytes */
+ u_int64_t ift_ipvp; /* input priv tc packets */
+ u_int64_t ift_ipvb; /* input priv tc bytes */
+ u_int64_t ift_opvp; /* output priv tc packets */
+ u_int64_t ift_opvb; /* output priv tc bytes */
+ u_int64_t ift_fp; /* forwarded packets */
+ u_int64_t ift_fb; /* forwarded bytes */
+};
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ * XXX - should be rewritten to use ifmib(4).
+ */
+static void
+sidewaysintpr()
+{
+ struct iftot *total, *sum, *interesting;
+ register int line;
+ int first;
+ int name[6];
+ size_t len;
+ unsigned int ifcount, i;
+ struct ifmibdata *ifmdall = 0;
+ int interesting_row;
+ sigset_t sigset, oldsigset;
+ struct itimerval timer_interval;
+
+ /* Common OID prefix */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+
+ len = sizeof(int);
+ name[3] = IFMIB_SYSTEM;
+ name[4] = IFMIB_IFCOUNT;
+ if (sysctl(name, 5, &ifcount, &len, 0, 0) == 1)
+ err(1, "sysctl IFMIB_IFCOUNT");
+
+ len = ifcount * sizeof(struct ifmibdata);
+ ifmdall = malloc(len);
+ if (ifmdall == 0)
+ err(1, "malloc failed");
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA");
+
+ interesting = NULL;
+ interesting_row = 0;
+ for (i = 0; i < ifcount; i++) {
+ struct ifmibdata *ifmd = ifmdall + i;
+
+ if (interface && strcmp(ifmd->ifmd_name, interface) == 0) {
+ if ((interesting = calloc(ifcount,
+ sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+ interesting_row = if_nametoindex(interface);
+ snprintf(interesting->ift_name, 16, "(%s)",
+ ifmd->ifmd_name);;
+ }
+ }
+ if ((total = calloc(1, sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+
+ if ((sum = calloc(1, sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void)signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void)setitimer(ITIMER_REAL, &timer_interval, NULL);
+ first = 1;
+banner:
+ if (vflag > 0)
+ printf("%9s", " ");
+
+ if (prioflag >= 0)
+ printf("%39s %39s %36s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ else
+ printf("%17s %14s %16s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ putchar('\n');
+
+ if (vflag > 0)
+ printf("%9s", " ");
+
+ printf("%10s %5s %10s ", "packets", "errs", "bytes");
+ if (prioflag >= 0)
+ printf(" %10s %10s %10s %10s",
+ "tcpkts", "tcbytes", "pvpkts", "pvbytes");
+ printf("%10s %5s %10s %5s", "packets", "errs", "bytes", "colls");
+ if (dflag)
+ printf(" %5.5s", "drops");
+ if (prioflag >= 0)
+ printf(" %10s %10s %10s %10s",
+ "tcpkts", "tcbytes", "pvpkts", "pvbytes");
+ if (Fflag)
+ printf(" %10s %10s", "fpackets", "fbytes");
+ putchar('\n');
+ fflush(stdout);
+ line = 0;
+loop:
+ if (vflag && !first)
+ print_time();
+
+ if (interesting != NULL) {
+ struct ifmibdata ifmd;
+ struct ifmibdata_supplemental ifmsupp;
+
+ len = sizeof(struct ifmibdata);
+ name[3] = IFMIB_IFDATA;
+ name[4] = interesting_row;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_GENERAL %d", interesting_row);
+
+ len = sizeof(struct ifmibdata_supplemental);
+ name[3] = IFMIB_IFDATA;
+ name[4] = interesting_row;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, &ifmsupp, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL %d",
+ interesting_row);
+
+ if (!first) {
+ printf("%10llu %5llu %10llu ",
+ ifmd.ifmd_data.ifi_ipackets - interesting->ift_ip,
+ ifmd.ifmd_data.ifi_ierrors - interesting->ift_ie,
+ ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib);
+ switch (prioflag) {
+ case SO_TC_BE:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ibepackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ibebytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_BK:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ibkpackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ibkbytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_VI:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ivipackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ivibytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_VO:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ivopackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ivobytes -
+ interesting->ift_itcb);
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ipvpackets -
+ interesting->ift_ipvp,
+ ifmsupp.ifmd_traffic_class.ifi_ipvbytes -
+ interesting->ift_ipvb);
+ }
+ printf("%10llu %5llu %10llu %5llu",
+ ifmd.ifmd_data.ifi_opackets - interesting->ift_op,
+ ifmd.ifmd_data.ifi_oerrors - interesting->ift_oe,
+ ifmd.ifmd_data.ifi_obytes - interesting->ift_ob,
+ ifmd.ifmd_data.ifi_collisions - interesting->ift_co);
+ if (dflag)
+ printf(" %5llu",
+ ifmd.ifmd_snd_drops - interesting->ift_dr);
+ switch (prioflag) {
+ case SO_TC_BE:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_obepackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_obebytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_BK:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_obkpackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_obkbytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_VI:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_ovipackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_ovibytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_VO:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_ovopackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_ovobytes -
+ interesting->ift_otcb);
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_opvpackets -
+ interesting->ift_opvp,
+ ifmsupp.ifmd_traffic_class.ifi_opvbytes -
+ interesting->ift_opvb);
+ }
+ if (Fflag) {
+ printf("%10llu %10llu",
+ ifmsupp.ifmd_data_extended.ifi_fpackets -
+ interesting->ift_fp,
+ ifmsupp.ifmd_data_extended.ifi_fbytes -
+ interesting->ift_fb);
+ }
+ }
+ interesting->ift_ip = ifmd.ifmd_data.ifi_ipackets;
+ interesting->ift_ie = ifmd.ifmd_data.ifi_ierrors;
+ interesting->ift_ib = ifmd.ifmd_data.ifi_ibytes;
+ interesting->ift_op = ifmd.ifmd_data.ifi_opackets;
+ interesting->ift_oe = ifmd.ifmd_data.ifi_oerrors;
+ interesting->ift_ob = ifmd.ifmd_data.ifi_obytes;
+ interesting->ift_co = ifmd.ifmd_data.ifi_collisions;
+ interesting->ift_dr = ifmd.ifmd_snd_drops;
+
+ /* private counters */
+ switch (prioflag) {
+ case SO_TC_BE:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ibepackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ibebytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_obepackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ interesting->ift_ipvp =
+ ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
+ interesting->ift_ipvb =
+ ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
+ interesting->ift_opvp =
+ ifmsupp.ifmd_traffic_class.ifi_opvpackets;
+ interesting->ift_opvb =
+ ifmsupp.ifmd_traffic_class.ifi_opvbytes;
+ }
+ interesting->ift_fp = ifmsupp.ifmd_data_extended.ifi_fpackets;
+ interesting->ift_fb = ifmsupp.ifmd_data_extended.ifi_fbytes;
+ } else {
+ unsigned int latest_ifcount;
+ struct ifmibdata_supplemental *ifmsuppall = NULL;
+
+ len = sizeof(int);
+ name[3] = IFMIB_SYSTEM;
+ name[4] = IFMIB_IFCOUNT;
+ if (sysctl(name, 5, &latest_ifcount, &len, 0, 0) == 1)
+ err(1, "sysctl IFMIB_IFCOUNT");
+ if (latest_ifcount > ifcount) {
+ ifcount = latest_ifcount;
+ len = ifcount * sizeof(struct ifmibdata);
+ free(ifmdall);
+ ifmdall = malloc(len);
+ if (ifmdall == 0)
+ err(1, "malloc ifmdall failed");
+ } else if (latest_ifcount > ifcount) {
+ ifcount = latest_ifcount;
+ len = ifcount * sizeof(struct ifmibdata);
+ }
+ len = ifcount * sizeof(struct ifmibdata);
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA");
+
+ len = ifcount * sizeof(struct ifmibdata_supplemental);
+ ifmsuppall = malloc(len);
+ if (ifmsuppall == NULL)
+ err(1, "malloc ifmsuppall failed");
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, ifmsuppall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA SUPPLEMENTAL");
+
+ sum->ift_ip = 0;
+ sum->ift_ie = 0;
+ sum->ift_ib = 0;
+ sum->ift_op = 0;
+ sum->ift_oe = 0;
+ sum->ift_ob = 0;
+ sum->ift_co = 0;
+ sum->ift_dr = 0;
+ sum->ift_itcp = 0;
+ sum->ift_itcb = 0;
+ sum->ift_otcp = 0;
+ sum->ift_otcb = 0;
+ sum->ift_ipvp = 0;
+ sum->ift_ipvb = 0;
+ sum->ift_opvp = 0;
+ sum->ift_opvb = 0;
+ sum->ift_fp = 0;
+ sum->ift_fb = 0;
+ for (i = 0; i < ifcount; i++) {
+ struct ifmibdata *ifmd = ifmdall + i;
+ struct ifmibdata_supplemental *ifmsupp = ifmsuppall + i;
+
+ sum->ift_ip += ifmd->ifmd_data.ifi_ipackets;
+ sum->ift_ie += ifmd->ifmd_data.ifi_ierrors;
+ sum->ift_ib += ifmd->ifmd_data.ifi_ibytes;
+ sum->ift_op += ifmd->ifmd_data.ifi_opackets;
+ sum->ift_oe += ifmd->ifmd_data.ifi_oerrors;
+ sum->ift_ob += ifmd->ifmd_data.ifi_obytes;
+ sum->ift_co += ifmd->ifmd_data.ifi_collisions;
+ sum->ift_dr += ifmd->ifmd_snd_drops;
+ /* private counters */
+ if (prioflag >= 0) {
+ switch (prioflag) {
+ case SO_TC_BE:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibepackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibebytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obepackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibkpackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibkbytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obkpackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivipackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivibytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovipackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivopackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivobytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovopackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ break;
+ }
+ sum->ift_ipvp += ifmsupp->ifmd_traffic_class.ifi_ipvpackets;
+ sum->ift_ipvb += ifmsupp->ifmd_traffic_class.ifi_ipvbytes;
+ sum->ift_opvp += ifmsupp->ifmd_traffic_class.ifi_opvpackets;
+ sum->ift_opvb += ifmsupp->ifmd_traffic_class.ifi_opvbytes;
+ }
+ sum->ift_fp += ifmsupp->ifmd_data_extended.ifi_fpackets;
+ sum->ift_fb += ifmsupp->ifmd_data_extended.ifi_fbytes;
+ }
+ if (!first) {
+ printf("%10llu %5llu %10llu ",
+ sum->ift_ip - total->ift_ip,
+ sum->ift_ie - total->ift_ie,
+ sum->ift_ib - total->ift_ib);
+ if (prioflag >= 0)
+ printf(" %10llu %10llu %10llu %10llu",
+ sum->ift_itcp - total->ift_itcp,
+ sum->ift_itcb - total->ift_itcb,
+ sum->ift_ipvp - total->ift_ipvp,
+ sum->ift_ipvb - total->ift_ipvb);
+ printf("%10llu %5llu %10llu %5llu",
+ sum->ift_op - total->ift_op,
+ sum->ift_oe - total->ift_oe,
+ sum->ift_ob - total->ift_ob,
+ sum->ift_co - total->ift_co);
+ if (dflag)
+ printf(" %5llu", sum->ift_dr - total->ift_dr);
+ if (prioflag >= 0)
+ printf(" %10llu %10llu %10llu %10llu",
+ sum->ift_otcp - total->ift_otcp,
+ sum->ift_otcb - total->ift_otcb,
+ sum->ift_opvp - total->ift_opvp,
+ sum->ift_opvb - total->ift_opvb);
+ if (Fflag)
+ printf(" %10llu %10llu",
+ sum->ift_fp - total->ift_fp,
+ sum->ift_fb - total->ift_fb);
+ }
+ *total = *sum;
+
+ free(ifmsuppall);
+ }
+ if (!first)
+ putchar('\n');
+ fflush(stdout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void)sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void)sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ line++;
+ first = 0;
+ if (line == 21)
+ goto banner;
+ else
+ goto loop;
+ /*NOTREACHED*/
+}
+
+void
+intervalpr(void (*pr)(uint32_t, char *, int), uint32_t off, char *name , int af)
+{
+ struct itimerval timer_interval;
+ sigset_t sigset, oldsigset;
+
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+
+ for (;;) {
+ pr(off, name, af);
+
+ fflush(stdout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ signalled = NO;
+ }
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+static void
+catchalarm(int signo )
+{
+ signalled = YES;
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
+
+void
+intpr_ri(void (*pfunc)(char *))
+{
+ int mib[6];
+ char *buf = NULL, *lim, *next;
+ size_t len;
+ unsigned int ifindex = 0;
+ struct if_msghdr2 *if2m;
+
+ if (interface != 0) {
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ printf("interface name is not valid: %s\n", interface);
+ exit(1);
+ }
+ }
+
+ mib[0] = CTL_NET; /* networking subsystem */
+ mib[1] = PF_ROUTE; /* type of information */
+ mib[2] = 0; /* protocol (IPPROTO_xxx) */
+ mib[3] = 0; /* address family */
+ mib[4] = NET_RT_IFLIST2; /* operation */
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return;
+ if ((buf = malloc(len)) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return;
+ }
+
+ printf("%-6s %-17s %8.8s %-9.9s %4s %4s",
+ "Proto", "Linklayer Address", "Netif", "Expire", "Refs",
+ "Prbs");
+ if (xflag)
+ printf(" %7s %7s %7s", "RSSI", "LQM", "NPM");
+ printf("\n");
+
+ lim = buf + len;
+ if2m = (struct if_msghdr2 *)buf;
+
+ for (next = buf; next < lim; ) {
+ if2m = (struct if_msghdr2 *)next;
+ next += if2m->ifm_msglen;
+
+ if (if2m->ifm_type != RTM_IFINFO2)
+ continue;
+ else if (interface != 0 && if2m->ifm_index != ifindex)
+ continue;
+
+ llreach_sysctl(if2m->ifm_index);
+ }
+ free(buf);
+}
+
+static void
+llreach_sysctl(uint32_t ifindex)
+{
+#define MAX_SYSCTL_TRY 5
+ int mib[6], i, ntry = 0;
+ size_t mibsize, len, needed, cnt;
+ struct if_llreach_info *lri;
+ struct timeval time;
+ char *buf;
+ char ifname[IF_NAMESIZE];
+
+ bzero(&mib, sizeof (mib));
+ mibsize = sizeof (mib) / sizeof (mib[0]);
+ if (sysctlnametomib("net.link.generic.system.llreach_info", mib,
+ &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+
+ mibsize = sizeof (mib) / sizeof (mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.link.generic.system.llreach_info");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ cnt = len / sizeof (*lri);
+ lri = (struct if_llreach_info *)buf;
+
+ gettimeofday(&time, 0);
+ if (if_indextoname(ifindex, ifname) == NULL)
+ snprintf(ifname, sizeof (ifname), "%s", "?");
+
+ for (i = 0; i < cnt; i++, lri++) {
+ printf("0x%-4x %-17s %8.8s ", lri->lri_proto,
+ ether_ntoa((struct ether_addr *)lri->lri_addr), ifname);
+
+ if (lri->lri_expire > time.tv_sec)
+ printf("%-9.9s", sec2str(lri->lri_expire - time.tv_sec));
+ else if (lri->lri_expire == 0)
+ printf("%-9.9s", "permanent");
+ else
+ printf("%-9.9s", "expired");
+
+ printf(" %4d", lri->lri_refcnt);
+ if (lri->lri_probes)
+ printf(" %4d", lri->lri_probes);
+
+ if (xflag) {
+ if (!lri->lri_probes)
+ printf(" %-4.4s", "none");
+
+ if (lri->lri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", lri->lri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (lri->lri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", lri->lri_lqm);
+ break;
+ }
+
+ switch (lri->lri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", lri->lri_npm);
+ break;
+ }
+ }
+
+ printf("\n");
+ len -= sizeof (*lri);
+ }
+
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.link.generic.system.llreach_info");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+void
+aqstatpr(void)
+{
+ unsigned int ifindex;
+ struct itimerval timer_interval;
+ struct if_qstatsreq ifqr;
+ struct if_ifclassq_stats *ifcqs;
+ sigset_t sigset, oldsigset;
+ u_int32_t scheduler;
+ int s, n;
+
+ if (cq < -1 || cq >= IFCQ_SC_MAX) {
+ fprintf(stderr, "Invalid classq index (range is 0-%d)\n",
+ IFCQ_SC_MAX-1);
+ return;
+ }
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ ifcqs = malloc(sizeof (*ifcqs));
+ if (ifcqs == NULL) {
+ fprintf(stderr, "Unable to allocate memory\n");
+ return;
+ }
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET)");
+ free(ifcqs);
+ return;
+ }
+
+ bzero(&ifqr, sizeof (ifqr));
+ strlcpy(ifqr.ifqr_name, interface, sizeof (ifqr.ifqr_name));
+ ifqr.ifqr_buf = ifcqs;
+ ifqr.ifqr_len = sizeof (*ifcqs);
+
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ ifqr.ifqr_slot = 0;
+ if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
+ if (errno == ENXIO) {
+ printf("Queue statistics are not available on %s\n",
+ interface);
+ } else {
+ perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
+ }
+ goto done;
+ }
+ scheduler = ifcqs->ifqs_scheduler;
+
+ printf("%s:\n"
+ " [ sched: %9s qlength: %3d/%3d ]\n",
+ interface, sched2str(ifcqs->ifqs_scheduler),
+ ifcqs->ifqs_len, ifcqs->ifqs_maxlen);
+ printf(" [ pkts: %10llu bytes: %10llu "
+ " dropped pkts: %6llu bytes: %6llu ]\n",
+ ifcqs->ifqs_xmitcnt.packets, ifcqs->ifqs_xmitcnt.bytes,
+ ifcqs->ifqs_dropcnt.packets, ifcqs->ifqs_dropcnt.bytes);
+
+ for (n = 0; n < IFCQ_SC_MAX && scheduler != PKTSCHEDT_NONE; n++) {
+ if (cq >= 0 && cq != n)
+ continue;
+
+ ifqr.ifqr_slot = n;
+ if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
+ perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
+ goto done;
+ }
+
+ update_avg(ifcqs, &qstats[n]);
+
+ switch (scheduler) {
+ case PKTSCHEDT_FQ_CODEL:
+ print_fq_codel_stats(n,
+ &ifcqs->ifqs_fq_codel_stats,
+ &qstats[n]);
+ break;
+ case PKTSCHEDT_NONE:
+ default:
+ break;
+ }
+ }
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+
+done:
+ free(ifcqs);
+ close(s);
+}
+
+static void
+print_fq_codel_stats(int pri, struct fq_codel_classstats *fqst,
+ struct queue_stats *qs)
+{
+ int i = 0;
+
+ if (fqst->fcls_service_class == 0 && fqst->fcls_pri == 0)
+ return;
+ printf("=====================================================\n");
+ printf(" [ pri: %s (%d)\tsrv_cl: 0x%x\tquantum: %d\tdrr_max: %d ]\n",
+ pri2str(fqst->fcls_pri), fqst->fcls_pri,
+ fqst->fcls_service_class, fqst->fcls_quantum,
+ fqst->fcls_drr_max);
+ printf(" [ queued pkts: %llu\tbytes: %llu ]\n",
+ fqst->fcls_pkt_cnt, fqst->fcls_byte_cnt);
+ printf(" [ dequeued pkts: %llu\tbytes: %llu ]\n",
+ fqst->fcls_dequeue, fqst->fcls_dequeue_bytes);
+ printf(" [ budget: %lld\ttarget qdelay: %10s\t",
+ fqst->fcls_budget, nsec_to_str(fqst->fcls_target_qdelay));
+ printf("update interval:%10s ]\n",
+ nsec_to_str(fqst->fcls_update_interval));
+ printf(" [ flow control: %u\tfeedback: %u\tstalls: %u\tfailed: %u ]\n",
+ fqst->fcls_flow_control, fqst->fcls_flow_feedback,
+ fqst->fcls_dequeue_stall, fqst->fcls_flow_control_fail);
+ printf(" [ drop overflow: %llu\tearly: %llu\tmemfail: %u\tduprexmt:%u ]\n",
+ fqst->fcls_drop_overflow, fqst->fcls_drop_early,
+ fqst->fcls_drop_memfailure, fqst->fcls_dup_rexmts);
+ printf(" [ flows total: %u\tnew: %u\told: %u ]\n",
+ fqst->fcls_flows_cnt,
+ fqst->fcls_newflows_cnt, fqst->fcls_oldflows_cnt);
+ printf(" [ throttle on: %u\toff: %u\tdrop: %u ]\n",
+ fqst->fcls_throttle_on, fqst->fcls_throttle_off,
+ fqst->fcls_throttle_drops);
+ printf(" [ compressible pkts: %u compressed pkts: %u]\n",
+ fqst->fcls_pkts_compressible, fqst->fcls_pkts_compressed);
+
+ if (qflag < 2)
+ return;
+
+ if (fqst->fcls_flowstats_cnt > 0) {
+ printf("Flowhash\tBytes\tMin qdelay\tFlags\t\n");
+ for (i = 0; i < fqst->fcls_flowstats_cnt; i++) {
+ printf("%u\t%u\t%14s\t",
+ fqst->fcls_flowstats[i].fqst_flowhash,
+ fqst->fcls_flowstats[i].fqst_bytes,
+ nsec_to_str(fqst->fcls_flowstats[i].fqst_min_qdelay));
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_OLD_FLOW)
+ printf("O");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_NEW_FLOW)
+ printf("N");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_LARGE_FLOW)
+ printf("L");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_DELAY_HIGH)
+ printf("D");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_FLOWCTL_ON)
+ printf("F");
+ printf("\n");
+ }
+ }
+}
+
+static void
+update_avg(struct if_ifclassq_stats *ifcqs, struct queue_stats *qs)
+{
+ u_int64_t b, p;
+ int n;
+
+ n = qs->avgn;
+
+ switch (ifcqs->ifqs_scheduler) {
+ case PKTSCHEDT_FQ_CODEL:
+ b = ifcqs->ifqs_fq_codel_stats.fcls_dequeue_bytes;
+ p = ifcqs->ifqs_fq_codel_stats.fcls_dequeue;
+ break;
+ default:
+ b = 0;
+ p = 0;
+ break;
+ }
+
+ if (n == 0) {
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ qs->avgn++;
+ return;
+ }
+
+ if (b >= qs->prev_bytes)
+ qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
+ (b - qs->prev_bytes)) / n;
+
+ if (p >= qs->prev_packets)
+ qs->avg_packets = ((qs->avg_packets * (n - 1)) +
+ (p - qs->prev_packets)) / n;
+
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ if (n < AVGN_MAX)
+ qs->avgn++;
+}
+
+#define NSEC_PER_SEC 1000000000 /* nanoseconds per second */
+#define USEC_PER_SEC 1000000 /* microseconds per second */
+#define MSEC_PER_SEC 1000 /* milliseconds per second */
+
+static char *
+nsec_to_str(unsigned long long nsec)
+{
+ static char buf[32];
+ const char *u;
+ long double n = nsec, t;
+
+ if (nsec >= NSEC_PER_SEC) {
+ t = n / NSEC_PER_SEC;
+ u = "sec ";
+ } else if (n >= USEC_PER_SEC) {
+ t = n / USEC_PER_SEC;
+ u = "msec";
+ } else if (n >= MSEC_PER_SEC) {
+ t = n / MSEC_PER_SEC;
+ u = "usec";
+ } else {
+ t = n;
+ u = "nsec";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+static char *
+sched2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case PKTSCHEDT_NONE:
+ c = "NONE";
+ break;
+ case PKTSCHEDT_FQ_CODEL:
+ c = "FQ_CODEL";
+ break;
+ default:
+ c = "UNKNOWN";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+pri2str(unsigned int i)
+{
+ char *c;
+ switch (i) {
+ case 9:
+ c = "BK_SYS";
+ break;
+ case 8:
+ c = "BK";
+ break;
+ case 7:
+ c = "BE";
+ break;
+ case 6:
+ c = "RD";
+ break;
+ case 5:
+ c = "OAM";
+ break;
+ case 4:
+ c = "AV";
+ break;
+ case 3:
+ c = "RV";
+ break;
+ case 2:
+ c = "VI";
+ break;
+ case 1:
+ c = "VO";
+ break;
+ case 0:
+ c = "CTL";
+ break;
+ default:
+ c = "?";
+ break;
+ }
+ return (c);
+}
+
+void
+rxpollstatpr(void)
+{
+ struct ifmibdata_supplemental ifmsupp;
+ size_t miblen = sizeof (ifmsupp);
+ struct itimerval timer_interval;
+ struct if_rxpoll_stats *sp;
+ struct if_netif_stats *np;
+ sigset_t sigset, oldsigset;
+ unsigned int ifindex;
+ int name[6];
+
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ bzero(&ifmsupp, sizeof (struct ifmibdata_supplemental));
+
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ /* Common OID prefix */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = ifindex;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, &ifmsupp, &miblen, NULL, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ sp = &ifmsupp.ifmd_rxpoll_stats;
+
+ printf("%-4s [ poll on requests: %15u errors: %27u ]\n",
+ interface, sp->ifi_poll_on_req, sp->ifi_poll_on_err);
+ printf(" [ poll off requests: %15u errors: %27u ]\n",
+ sp->ifi_poll_off_req, sp->ifi_poll_off_err);
+ printf(" [ polled packets: %18llu per poll limit: %19u ]\n",
+ sp->ifi_poll_packets, sp->ifi_poll_packets_limit);
+ printf(" [ polled bytes: %20llu ]\n", sp->ifi_poll_bytes);
+ printf(" [ poll interval: %14llu nsec ]\n",
+ sp->ifi_poll_interval_time);
+ printf(" [ sampled packets avg/min/max: %12u / %12u / %12u ]\n",
+ sp->ifi_poll_packets_avg, sp->ifi_poll_packets_min,
+ sp->ifi_poll_packets_max);
+ printf(" [ sampled bytes avg/min/max: %12u / %12u / %12u ]\n",
+ sp->ifi_poll_bytes_avg, sp->ifi_poll_bytes_min,
+ sp->ifi_poll_bytes_max);
+ printf(" [ sampled wakeups avg: %12u ]\n",
+ sp->ifi_poll_wakeups_avg);
+ printf(" [ packets lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_packets_lowat, sp->ifi_poll_packets_hiwat);
+ printf(" [ bytes lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_bytes_lowat, sp->ifi_poll_bytes_hiwat);
+ printf(" [ wakeups lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_wakeups_lowat, sp->ifi_poll_wakeups_hiwat);
+
+ np = &ifmsupp.ifmd_netif_stats;
+ printf(" [ mit mode: %24U cfg idx: %26u ]\n",
+ np->ifn_rx_mit_mode, np->ifn_rx_mit_cfg_idx);
+ printf(" [ cfg packets lo/hi threshold: %12u / %12u ]\n",
+ np->ifn_rx_mit_cfg_packets_lowat, np->ifn_rx_mit_cfg_packets_hiwat);
+ printf(" [ cfg bytes lo/hi threshold: %12u / %12u ]\n",
+ np->ifn_rx_mit_cfg_bytes_lowat, np->ifn_rx_mit_cfg_bytes_hiwat);
+ printf(" [ cfg interval: %15u nsec ]\n",
+ np->ifn_rx_mit_cfg_interval);
+ printf(" [ mit interval: %15llu nsec ]\n",
+ np->ifn_rx_mit_interval);
+ printf(" [ mit packets avg/min/max: %12u / %12u / %12u ]\n",
+ np->ifn_rx_mit_packets_avg, np->ifn_rx_mit_packets_min,
+ np->ifn_rx_mit_packets_max);
+ printf(" [ mit bytes avg/min/max: %12u / %12u / %12u ]\n",
+ np->ifn_rx_mit_bytes_avg, np->ifn_rx_mit_bytes_min,
+ np->ifn_rx_mit_bytes_max);
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+}
+
+static int
+create_control_socket(const char *control_name)
+{
+ struct sockaddr_ctl sc;
+ struct ctl_info ctl;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (fd == -1) {
+ perror("socket(PF_SYSTEM)");
+ return fd;
+ }
+
+ /* Get the control ID for statistics */
+ bzero(&ctl, sizeof(ctl));
+ strlcpy(ctl.ctl_name, control_name, sizeof(ctl.ctl_name));
+ if (ioctl(fd, CTLIOCGINFO, &ctl) == -1)
+ {
+ perror("ioctl(CTLIOCGINFO)");
+ close(fd);
+ return -1;
+ }
+
+ /* Connect to the statistics control */
+ bzero(&sc, sizeof(sc));
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = SYSPROTO_CONTROL;
+ sc.sc_id = ctl.ctl_id;
+ sc.sc_unit = 0;
+ if (connect(fd, (struct sockaddr*)&sc, sc.sc_len) != 0)
+ {
+ perror("connect(SYSPROTO_CONTROL)");
+ close(fd);
+ return -1;
+ }
+
+ /* Set socket to non-blocking operation */
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) {
+ perror("fcnt(F_SETFL,O_NONBLOCK)");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static int
+add_nstat_src(int fd, const nstat_ifnet_add_param *ifparam,
+ nstat_src_ref_t *outsrc)
+{
+ nstat_msg_add_src_req *addreq;
+ nstat_msg_src_added *addedmsg;
+ nstat_ifnet_add_param *param;
+ char buffer[sizeof(*addreq) + sizeof(*param)];
+ ssize_t result;
+ const u_int32_t addreqsize =
+ offsetof(struct nstat_msg_add_src, param) + sizeof(*param);
+
+ /* Setup the add source request */
+ addreq = (nstat_msg_add_src_req *)buffer;
+ param = (nstat_ifnet_add_param*)addreq->param;
+ bzero(addreq, addreqsize);
+ addreq->hdr.context = (uintptr_t)&buffer;
+ addreq->hdr.type = NSTAT_MSG_TYPE_ADD_SRC;
+ addreq->provider = NSTAT_PROVIDER_IFNET;
+ bzero(param, sizeof(*param));
+ param->ifindex = ifparam->ifindex;
+ param->threshold = ifparam->threshold;
+
+ /* Send the add source request */
+ result = send(fd, addreq, addreqsize, 0);
+ if (result != addreqsize)
+ {
+ if (result == -1)
+ perror("send(NSTAT_ADD_SRC_REQ)");
+ else
+ fprintf(stderr, "%s: could only sent %ld out of %d\n",
+ __func__, result, addreqsize);
+ return -1;
+ }
+
+ /* Receive the response */
+ addedmsg = (nstat_msg_src_added *)buffer;
+ result = recv(fd, addedmsg, sizeof(buffer), 0);
+ if (result < sizeof(*addedmsg))
+ {
+ if (result == -1)
+ perror("recv(NSTAT_ADD_SRC_RSP)");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %lu\n", __func__, result,
+ sizeof(*addedmsg));
+ return -1;
+ }
+
+ if (addedmsg->hdr.type != NSTAT_MSG_TYPE_SRC_ADDED)
+ {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, addedmsg->hdr.type,
+ NSTAT_MSG_TYPE_SRC_ADDED);
+ return -1;
+ }
+
+ if (addedmsg->hdr.context != (uintptr_t)&buffer)
+ {
+ fprintf(stderr, "%s: received wrong context, received %llu "
+ "expected %lu\n", __func__, addedmsg->hdr.context,
+ (uintptr_t)&buffer);
+ return -1;
+ }
+ *outsrc = addedmsg->srcref;
+ return 0;
+}
+
+static int
+rem_nstat_src(int fd, nstat_src_ref_t sref)
+{
+ nstat_msg_rem_src_req *remreq;
+ nstat_msg_src_removed *remrsp;
+ char buffer[sizeof(*remreq)];
+ ssize_t result;
+
+ /* Setup the add source request */
+ remreq = (nstat_msg_rem_src_req *)buffer;
+ bzero(remreq, sizeof(*remreq));
+ remreq->hdr.type = NSTAT_MSG_TYPE_REM_SRC;
+ remreq->srcref = sref;
+
+ /* Send the remove source request */
+ result = send(fd, remreq, sizeof(*remreq), 0);
+ if (result != sizeof(*remreq)) {
+ if (result == -1)
+ perror("send(NSTAT_REM_SRC_REQ)");
+ else
+ fprintf(stderr, "%s: could only sent %ld out of %lu\n",
+ __func__, result, sizeof(*remreq));
+ return -1;
+ }
+
+ /* Receive the response */
+ remrsp = (nstat_msg_src_removed *)buffer;
+ result = recv(fd, remrsp, sizeof(buffer), 0);
+ if (result < sizeof(*remrsp)) {
+ if (result == -1)
+ perror("recv(NSTAT_REM_SRC_RSP)");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %lu\n", __func__, result,
+ sizeof(*remrsp));
+ return -1;
+ }
+
+ if (remrsp->hdr.type != NSTAT_MSG_TYPE_SRC_REMOVED) {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, remrsp->hdr.type,
+ NSTAT_MSG_TYPE_SRC_REMOVED);
+ return -1;
+ }
+
+ if (remrsp->srcref != sref) {
+ fprintf(stderr, "%s: received invalid srcref, received %llu "
+ "expected %llu\n", __func__, remrsp->srcref, sref);
+ }
+ return 0;
+}
+
+static int
+get_src_decsription(int fd, nstat_src_ref_t srcref,
+ struct nstat_ifnet_descriptor *ifdesc)
+{
+ nstat_msg_get_src_description *dreq;
+ nstat_msg_src_description *drsp;
+ char buffer[sizeof(*drsp) + sizeof(*ifdesc)];
+ ssize_t result;
+ const u_int32_t descsize =
+ offsetof(struct nstat_msg_src_description, data) +
+ sizeof(nstat_ifnet_descriptor);
+
+ dreq = (nstat_msg_get_src_description *)buffer;
+ bzero(dreq, sizeof(*dreq));
+ dreq->hdr.type = NSTAT_MSG_TYPE_GET_SRC_DESC;
+ dreq->srcref = srcref;
+ result = send(fd, dreq, sizeof(*dreq), 0);
+ if (result != sizeof(*dreq))
+ {
+ if (result == -1)
+ perror("send(NSTAT_GET_SRC_DESC_REQ)");
+ else
+ fprintf(stderr, "%s: sent %ld out of %lu\n",
+ __func__, result, sizeof(*dreq));
+ return -1;
+ }
+
+ /* Receive the source description response */
+ drsp = (nstat_msg_src_description *)buffer;
+ result = recv(fd, drsp, sizeof(buffer), 0);
+ if (result < descsize)
+ {
+ if (result == -1)
+ perror("recv(NSTAT_GET_SRC_DESC_RSP");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %u\n", __func__, result, descsize);
+ return -1;
+ }
+
+ if (drsp->hdr.type != NSTAT_MSG_TYPE_SRC_DESC)
+ {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, drsp->hdr.type,
+ NSTAT_MSG_TYPE_SRC_DESC);
+ return -1;
+ }
+
+ if (drsp->srcref != srcref)
+ {
+ fprintf(stderr, "%s: received message for wrong source, "
+ "received 0x%llx expected 0x%llx\n",
+ __func__, drsp->srcref, srcref);
+ return -1;
+ }
+
+ bcopy(drsp->data, ifdesc, sizeof(*ifdesc));
+ return 0;
+}
+
+static void
+print_wifi_status(nstat_ifnet_desc_wifi_status *status)
+{
+ int tmp;
+#define val(x, f) \
+ ((status->valid_bitmask & NSTAT_IFNET_DESC_WIFI_ ## f ## _VALID) ?\
+ status->x : -1)
+#define parg(n, un) #n, val(n, un)
+#define pretxtl(n, un) \
+ (((tmp = val(n, un)) == -1) ? "(not valid)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_NONE) ? "(none)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_LOW) ? "(low)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_HIGH) ? "(high)" : \
+ "(?)")))))
+
+ printf("\nwifi status:\n");
+ printf(
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d%s\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n",
+ parg(link_quality_metric, LINK_QUALITY_METRIC),
+ parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH),
+ parg(ul_max_bandwidth, UL_MAX_BANDWIDTH),
+ parg(ul_min_latency, UL_MIN_LATENCY),
+ parg(ul_effective_latency, UL_EFFECTIVE_LATENCY),
+ parg(ul_max_latency, UL_MAX_LATENCY),
+ parg(ul_retxt_level, UL_RETXT_LEVEL),
+ pretxtl(ul_retxt_level, UL_RETXT_LEVEL),
+ parg(ul_bytes_lost, UL_BYTES_LOST),
+ parg(ul_error_rate, UL_ERROR_RATE),
+ parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH),
+ parg(dl_max_bandwidth, DL_MAX_BANDWIDTH),
+ parg(dl_min_latency, DL_MIN_LATENCY),
+ parg(dl_effective_latency, DL_EFFECTIVE_LATENCY),
+ parg(dl_max_latency, DL_MAX_LATENCY),
+ parg(dl_error_rate, DL_ERROR_RATE),
+ parg(config_frequency, CONFIG_FREQUENCY),
+ parg(config_multicast_rate, CONFIG_MULTICAST_RATE),
+ parg(scan_count, CONFIG_SCAN_COUNT),
+ parg(scan_duration, CONFIG_SCAN_DURATION)
+ );
+#undef pretxtl
+#undef parg
+#undef val
+}
+
+static void
+print_cellular_status(nstat_ifnet_desc_cellular_status *status)
+{
+ int tmp, tmp_mss;
+#define val(x, f) \
+ ((status->valid_bitmask & NSTAT_IFNET_DESC_CELL_ ## f ## _VALID) ?\
+ status->x : -1)
+#define parg(n, un) #n, val(n, un)
+#define pretxtl(n, un) \
+ (((tmp = val(n, un)) == -1) ? "(not valid)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_NONE) ? "(none)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_LOW) ? "(low)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_HIGH) ? "(high)" : \
+ "(?)")))))
+#define pretxtm(n, un) \
+ (((tmp_mss = val(n,un)) == -1) ? "(not valid)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_NONE) ? "(none)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_MEDIUM) ? "(medium)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_LOW) ? "(low)" : \
+ "(?)"))))
+
+ printf("\ncellular status:\n");
+ printf(
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d%s\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d %s\n",
+ parg(link_quality_metric, LINK_QUALITY_METRIC),
+ parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH),
+ parg(ul_max_bandwidth, UL_MAX_BANDWIDTH),
+ parg(ul_min_latency, UL_MIN_LATENCY),
+ parg(ul_effective_latency, UL_EFFECTIVE_LATENCY),
+ parg(ul_max_latency, UL_MAX_LATENCY),
+ parg(ul_retxt_level, UL_RETXT_LEVEL),
+ pretxtl(ul_retxt_level, UL_RETXT_LEVEL),
+ parg(ul_bytes_lost, UL_BYTES_LOST),
+ parg(ul_min_queue_size, UL_MIN_QUEUE_SIZE),
+ parg(ul_avg_queue_size, UL_AVG_QUEUE_SIZE),
+ parg(ul_max_queue_size, UL_MAX_QUEUE_SIZE),
+ parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH),
+ parg(dl_max_bandwidth, DL_MAX_BANDWIDTH),
+ parg(config_inactivity_time, CONFIG_INACTIVITY_TIME),
+ parg(config_backoff_time, CONFIG_BACKOFF_TIME),
+ parg(mss_recommended, MSS_RECOMMENDED),
+ pretxtm(mss_recommended, MSS_RECOMMENDED)
+ );
+#undef pretxtl
+#undef parg
+#undef val
+}
+
+static int
+get_interface_state(int fd, const char *ifname, struct ifreq *ifr)
+{
+ bzero(ifr, sizeof(*ifr));
+ snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), "%s", ifname);
+
+ if (ioctl(fd, SIOCGIFINTERFACESTATE, ifr) == -1) {
+ perror("ioctl(CTLIOCGINFO)");
+ return -1;
+ }
+ return 0;
+}
+
+static void
+print_interface_state(struct ifreq *ifr)
+{
+ int lqm, rrc, avail;
+
+ printf("\ninterface state:\n");
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_LQM_STATE_VALID) {
+ printf("\tlqm: ");
+ lqm = ifr->ifr_interface_state.lqm_state;
+ if (lqm == IFNET_LQM_THRESH_GOOD)
+ printf("\"good\"");
+ else if (lqm == IFNET_LQM_THRESH_POOR)
+ printf("\"poor\"");
+ else if (lqm == IFNET_LQM_THRESH_BAD)
+ printf("\"bad\"");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("\"unknown\"");
+ else if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("\"off\"");
+ else
+ printf("invalid(%d)", lqm);
+ }
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_RRC_STATE_VALID) {
+ printf("\trrc: ");
+ rrc = ifr->ifr_interface_state.rrc_state;
+ if (rrc == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
+ printf("\"connected\"");
+ else if (rrc == IF_INTERFACE_STATE_RRC_STATE_IDLE)
+ printf("\"idle\"");
+ else
+ printf("\"invalid(%d)\"", rrc);
+ }
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
+ printf("\tavailability: ");
+ avail = ifr->ifr_interface_state.interface_availability;
+ if (avail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
+ printf("\"true\"");
+ else if (rrc == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
+ printf("\"false\"");
+ else
+ printf("\"invalid(%d)\"", avail);
+ }
+}
+
+void
+print_link_status(const char *ifname)
+{
+ unsigned int ifindex;
+ struct itimerval timer_interval;
+ sigset_t sigset, oldsigset;
+ struct nstat_ifnet_descriptor ifdesc;
+ nstat_ifnet_add_param ifparam;
+ nstat_src_ref_t sref = 0;
+ struct ifreq ifr;
+ int ctl_fd;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ if ((ctl_fd = create_control_socket(NET_STAT_CONTROL_NAME)) < 0)
+ return;
+
+ ifparam.ifindex = ifindex;
+ ifparam.threshold = UINT64_MAX;
+ if (add_nstat_src(ctl_fd, &ifparam, &sref))
+ goto done;
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval
+ * seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ /* get interface state */
+ if (get_interface_state(ctl_fd, ifname, &ifr))
+ goto done;
+
+ /* get ntstat interface description */
+ if (get_src_decsription(ctl_fd, sref, &ifdesc))
+ goto done;
+
+ /* print time */
+ printf("\n%s: ", ifname);
+ print_time();
+
+ /* print interface state */
+ print_interface_state(&ifr);
+
+ /* print ntsat interface link status */
+ if (ifdesc.link_status.link_status_type ==
+ NSTAT_IFNET_DESC_LINK_STATUS_TYPE_CELLULAR)
+ print_cellular_status(&ifdesc.link_status.u.cellular);
+ else if (ifdesc.link_status.link_status_type ==
+ NSTAT_IFNET_DESC_LINK_STATUS_TYPE_WIFI)
+ print_wifi_status(&ifdesc.link_status.u.wifi);
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+done:
+ if (sref)
+ rem_nstat_src(ctl_fd, sref);
+ close(ctl_fd);
+}
diff --git a/network_cmds/netstat.tproj/inet.c b/network_cmds/netstat.tproj/inet.c
new file mode 100644
index 0000000..68e4ddb
--- /dev/null
+++ b/network_cmds/netstat.tproj/inet.c
@@ -0,0 +1,1361 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ ** @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993, 1995
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if_arp.h>
+#include <net/net_perf.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
+#include <netinet/in_pcb.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/igmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_seq.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#define ROUNDUP64(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
+#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
+
+char *inetname (struct in_addr *);
+void inetprint (struct in_addr *, int, char *, int);
+#ifdef INET6
+extern void inet6print (struct in6_addr *, int, char *, int);
+static int udp_done, tcp_done;
+extern int mptcp_done;
+#endif /* INET6 */
+
+#ifdef SRVCACHE
+typedef struct __table_private table_t;
+
+extern table_t *_nc_table_new(uint32_t n);
+extern void _nc_table_free(table_t *tin);
+
+extern void _nc_table_insert(table_t *t, const char *key, void *datum);
+extern void *_nc_table_find(table_t *t, const char *key);
+extern void _nc_table_delete(table_t *t, const char *key);
+
+static table_t *_serv_cache = NULL;
+
+/*
+ * Read and cache all known services
+ */
+static void
+_serv_cache_open()
+{
+ struct servent *s;
+ char *key, *name, *test;
+
+ if (_serv_cache != NULL) return;
+
+ _serv_cache = _nc_table_new(8192);
+ setservent(0);
+
+ while (NULL != (s = getservent()))
+ {
+ if (s->s_name == NULL) continue;
+ key = NULL;
+ asprintf(&key, "%hu/%s", (unsigned short)ntohs(s->s_port), s->s_proto);
+ name = strdup(s->s_name);
+ test = _nc_table_find(_serv_cache, key);
+ if (test == NULL) _nc_table_insert(_serv_cache, key, name);
+ free(key);
+ }
+
+ endservent();
+}
+
+void
+_serv_cache_close()
+{
+ _nc_table_free(_serv_cache);
+ _serv_cache = NULL;
+}
+
+struct servent *
+_serv_cache_getservbyport(int port, char *proto)
+{
+ static struct servent s;
+ char *key;
+ unsigned short p;
+
+ _serv_cache_open();
+
+ memset(&s, 0, sizeof(struct servent));
+ asprintf(&key, "%u/%s", port, (proto == NULL) ? "udp" : proto);
+
+ s.s_name = _nc_table_find(_serv_cache, key);
+ free(key);
+ if (s.s_name == NULL) return NULL;
+
+ p = port;
+ s.s_port = htons(p);
+ s.s_proto = proto;
+ return &s;
+}
+
+#endif /* SRVCACHE */
+
+/*
+ * Print a summary of connections related to an Internet
+ * protocol. For TCP, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+struct xgen_n {
+ u_int32_t xgn_len; /* length of this structure */
+ u_int32_t xgn_kind; /* number of PCBs at this time */
+};
+
+#define ALL_XGN_KIND_INP (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_INPCB)
+#define ALL_XGN_KIND_TCP (ALL_XGN_KIND_INP | XSO_TCPCB)
+
+void
+protopr(uint32_t proto, /* for sysctl version we pass proto # */
+ char *name, int af)
+{
+ int istcp;
+ static int first = 1;
+ char *buf, *next;
+ const char *mibvar;
+ struct xinpgen *xig, *oxig;
+ struct xgen_n *xgn;
+ size_t len;
+ struct xtcpcb_n *tp = NULL;
+ struct xinpcb_n *inp = NULL;
+ struct xsocket_n *so = NULL;
+ struct xsockbuf_n *so_rcv = NULL;
+ struct xsockbuf_n *so_snd = NULL;
+ struct xsockstat_n *so_stat = NULL;
+ int which = 0;
+
+ istcp = 0;
+ switch (proto) {
+ case IPPROTO_TCP:
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+ istcp = 1;
+ mibvar = "net.inet.tcp.pcblist_n";
+ break;
+ case IPPROTO_UDP:
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+ mibvar = "net.inet.udp.pcblist_n";
+ break;
+ case IPPROTO_DIVERT:
+ mibvar = "net.inet.divert.pcblist_n";
+ break;
+ default:
+ mibvar = "net.inet.raw.pcblist_n";
+ break;
+ }
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= sizeof(struct xinpgen)) {
+ free(buf);
+ return;
+ }
+
+ oxig = xig = (struct xinpgen *)buf;
+ for (next = buf + ROUNDUP64(xig->xig_len); next < buf + len; next += ROUNDUP64(xgn->xgn_len)) {
+
+ xgn = (struct xgen_n*)next;
+ if (xgn->xgn_len <= sizeof(struct xinpgen))
+ break;
+
+ if ((which & xgn->xgn_kind) == 0) {
+ which |= xgn->xgn_kind;
+ switch (xgn->xgn_kind) {
+ case XSO_SOCKET:
+ so = (struct xsocket_n *)xgn;
+ break;
+ case XSO_RCVBUF:
+ so_rcv = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_SNDBUF:
+ so_snd = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_STATS:
+ so_stat = (struct xsockstat_n *)xgn;
+ break;
+ case XSO_INPCB:
+ inp = (struct xinpcb_n *)xgn;
+ break;
+ case XSO_TCPCB:
+ tp = (struct xtcpcb_n *)xgn;
+ break;
+ default:
+ printf("unexpected kind %d\n", xgn->xgn_kind);
+ break;
+ }
+ } else {
+ if (vflag)
+ printf("got %d twice\n", xgn->xgn_kind);
+ }
+
+ if ((istcp && which != ALL_XGN_KIND_TCP) || (!istcp && which != ALL_XGN_KIND_INP))
+ continue;
+ which = 0;
+
+ /* Ignore sockets for protocols other than the desired one. */
+ if (so->xso_protocol != (int)proto)
+ continue;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (inp->inp_gencnt > oxig->xig_gen)
+ continue;
+
+ if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
+#ifdef INET6
+ || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
+#endif /* INET6 */
+ || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
+#ifdef INET6
+ && (inp->inp_vflag &
+ INP_IPV6) == 0
+#endif /* INET6 */
+ ))
+ )
+ continue;
+
+ /*
+ * Local address is not an indication of listening socket or
+ * server sockey but just rather the socket has been bound.
+ * That why many UDP sockets were not displayed in the original code.
+ */
+ if (!aflag && istcp && tp->t_state <= TCPS_LISTEN)
+ continue;
+
+ if (Lflag && !so->so_qlimit)
+ continue;
+
+ if (first) {
+ if (!Lflag) {
+ printf("Active Internet connections");
+ if (aflag)
+ printf(" (including servers)");
+ } else
+ printf(
+ "Current listen queue sizes (qlen/incqlen/maxqlen)");
+ putchar('\n');
+ if (Aflag) {
+ printf("%-16.16s ", "Socket");
+ printf("%-9.9s", "Flowhash");
+ }
+ if (Lflag)
+ printf("%-14.14s %-22.22s\n",
+ "Listen", "Local Address");
+ else {
+ printf((Aflag && !Wflag) ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "(state)");
+ if (bflag > 0)
+ printf(" %10.10s %10.10s", "rxbytes", "txbytes");
+ if (prioflag >= 0)
+ printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
+ if (vflag > 0)
+ printf(" %6.6s %6.6s %6.6s %6.6s %6s %10s",
+ "rhiwat", "shiwat", "pid", "epid", "state", "options");
+ printf("\n");
+ }
+ first = 0;
+ }
+ if (Aflag) {
+ if (istcp)
+ printf("%16lx ", (u_long)inp->inp_ppcb);
+ else
+ printf("%16lx ", (u_long)so->so_pcb);
+ printf("%8x ", inp->inp_flowhash);
+ }
+ if (Lflag) {
+ char buf[15];
+
+ snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
+ so->so_incqlen, so->so_qlimit);
+ printf("%-14.14s ", buf);
+ }
+ else {
+ const char *vchar;
+
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV6) != 0)
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "46" : "6 ";
+ else
+#endif
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "4 " : " ";
+
+ printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ }
+ if (nflag) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 1);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 1);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else if (inp->inp_flags & INP_ANONPORT) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 0);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 0);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 0);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 0);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ }
+ if (istcp && !Lflag) {
+ if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
+ printf("%-11d", tp->t_state);
+ else {
+ printf("%-11s", tcpstates[tp->t_state]);
+ }
+ }
+ if (!istcp)
+ printf("%-11s", " ");
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+
+ printf(" %10llu %10llu", rxbytes, txbytes);
+ }
+ if (prioflag >= 0) {
+ printf(" %10llu %10llu",
+ prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
+ prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
+ }
+ if (vflag > 0) {
+ printf(" %6u %6u %6u %6u 0x%04x 0x%08x",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid,
+ so->so_state,
+ so->so_options);
+ }
+ putchar('\n');
+ }
+ if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
+ if (oxig->xig_count > xig->xig_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xig_count < xig->xig_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ name);
+ }
+ }
+ free(buf);
+}
+
+/*
+ * Dump TCP statistics structure.
+ */
+void
+tcp_stats(uint32_t off , char *name, int af)
+{
+ static struct tcpstat ptcpstat;
+ struct tcpstat tcpstat;
+ size_t len = sizeof tcpstat;
+ static uint32_t r_swcsum, pr_swcsum;
+ static uint32_t t_swcsum, pt_swcsum;
+
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (tcp_done != 0 && interval == 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
+#define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
+#define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f))
+#define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
+ printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
+#define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
+ printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
+#define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
+
+ p(tcps_sndtotal, "\t%u packet%s sent\n");
+ p2(tcps_sndpack,tcps_sndbyte,
+ "\t\t%u data packet%s (%u byte%s)\n");
+ p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
+ "\t\t%u data packet%s (%u byte%s) retransmitted\n");
+ p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
+ p2a(tcps_sndacks, tcps_delack,
+ "\t\t%u ack-only packet%s (%u delayed)\n");
+ p(tcps_sndurg, "\t\t%u URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%u window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%u control packet%s\n");
+ p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
+ p(tcps_synchallenge, "\t\t%u challenge ACK%s sent due to unexpected SYN\n");
+ p(tcps_rstchallenge, "\t\t%u challenge ACK%s sent due to unexpected RST\n");
+ t_swcsum = tcpstat.tcps_snd_swcsum + tcpstat.tcps_snd6_swcsum;
+ if ((t_swcsum - pt_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
+ p2(tcps_snd_swcsum, tcps_snd_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(tcps_snd6_swcsum, tcps_snd6_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p(tcps_rcvtotal, "\t%u packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
+ p2(tcps_rcvpack, tcps_rcvbyte,
+ "\t\t%u packet%s (%u byte%s) received in-sequence\n");
+ p2(tcps_rcvduppack, tcps_rcvdupbyte,
+ "\t\t%u completely duplicate packet%s (%u byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
+ p(tcps_rcvmemdrop, "\t\t%u received packet%s dropped due to low memory\n");
+ p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
+ "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
+ p2(tcps_rcvoopack, tcps_rcvoobyte,
+ "\t\t%u out-of-order packet%s (%u byte%s)\n");
+ p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
+ "\t\t%u packet%s (%u byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
+ p(tcps_recovered_pkts, "\t\t%u packet%s recovered after loss\n");
+ p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
+ p(tcps_badrst, "\t\t%u bad reset%s\n");
+ p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
+ r_swcsum = tcpstat.tcps_rcv_swcsum + tcpstat.tcps_rcv6_swcsum;
+ if ((r_swcsum - pr_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n",
+ (r_swcsum - pr_swcsum));
+ p2(tcps_rcv_swcsum, tcps_rcv_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(tcps_rcv6_swcsum, tcps_rcv6_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
+ p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
+ p(tcps_connattempt, "\t%u connection request%s\n");
+ p(tcps_accepts, "\t%u connection accept%s\n");
+ p(tcps_badsyn, "\t%u bad connection attempt%s\n");
+ p(tcps_listendrop, "\t%u listen queue overflow%s\n");
+ p(tcps_connects, "\t%u connection%s established (including accepts)\n");
+ p2(tcps_closed, tcps_drops,
+ "\t%u connection%s closed (including %u drop%s)\n");
+ p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
+ p(tcps_cachedrttvar,
+ "\t\t%u connection%s updated cached RTT variance on close\n");
+ p(tcps_cachedssthresh,
+ "\t\t%u connection%s updated cached ssthresh on close\n");
+ p(tcps_usedrtt, "\t\t%u connection%s initialized RTT from route cache\n");
+ p(tcps_usedrttvar,
+ "\t\t%u connection%s initialized RTT variance from route cache\n");
+ p(tcps_usedssthresh,
+ "\t\t%u connection%s initialized ssthresh from route cache\n");
+ p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
+ p2(tcps_rttupdated, tcps_segstimed,
+ "\t%u segment%s updated rtt (of %u attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
+ p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
+ p(tcps_sndrexmitbad, "\t\t%u unnecessary packet retransmissions%s\n");
+ p(tcps_persisttimeo, "\t%u persist timeout%s\n");
+ p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
+ p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
+ p(tcps_ka_offload_drops, "\t\t%u connection%s dropped by keepalive offload\n");
+ p(tcps_predack, "\t%u correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
+#ifdef TCP_MAX_SACK
+ /* TCP_MAX_SACK indicates the header has the SACK structures */
+ p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
+ p(tcps_sack_rexmits,
+ "\t%u segment rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rexmit_bytes,
+ "\t%u byte rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rcv_blocks,
+ "\t%u SACK option%s (SACK blocks) received\n");
+ p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
+ p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
+#endif /* TCP_MAX_SACK */
+ p(tcps_limited_txt, "\t%u limited transmit%s done\n");
+ p(tcps_early_rexmt, "\t%u early retransmit%s done\n");
+ p(tcps_sack_ackadv, "\t%u time%s cumulative ack advanced along with SACK\n");
+ p(tcps_pto, "\t%u probe timeout%s\n");
+ p(tcps_rto_after_pto, "\t\t%u time%s retransmit timeout triggered after probe\n");
+ p(tcps_probe_if, "\t\t%u time%s probe packets were sent for an interface\n");
+ p(tcps_probe_if_conflict, "\t\t%u time%s couldn't send probe packets for an interface\n");
+ p(tcps_tlp_recovery, "\t\t%u time%s fast recovery after tail loss\n");
+ p(tcps_tlp_recoverlastpkt, "\t\t%u time%s recovered last packet \n");
+ p(tcps_pto_in_recovery, "\t\t%u SACK based rescue retransmit%s\n");
+ p(tcps_ecn_client_setup, "\t%u client connection%s attempted to negotiate ECN\n");
+ p(tcps_ecn_client_success, "\t\t%u client connection%s successfully negotiated ECN\n");
+ p(tcps_ecn_not_supported, "\t\t%u time%s graceful fallback to Non-ECN connection\n");
+ p(tcps_ecn_lost_syn, "\t\t%u time%s lost ECN negotiating SYN, followed by retransmission\n");
+ p(tcps_ecn_server_setup, "\t\t%u server connection%s attempted to negotiate ECN\n");
+ p(tcps_ecn_server_success, "\t\t%u server connection%s successfully negotiated ECN\n");
+ p(tcps_ecn_lost_synack, "\t\t%u time%s lost ECN negotiating SYN-ACK, followed by retransmission\n");
+ p(tcps_ecn_recv_ce, "\t\t%u time%s received congestion experienced (CE) notification\n");
+ p(tcps_ecn_recv_ece, "\t\t%u time%s CWR was sent in response to ECE\n");
+ p(tcps_ecn_sent_ece, "\t\t%u time%s sent ECE notification\n");
+ p(tcps_ecn_conn_recv_ce, "\t\t%u connection%s received CE atleast once\n");
+ p(tcps_ecn_conn_recv_ece, "\t\t%u connection%s received ECE atleast once\n");
+ p(tcps_ecn_conn_plnoce, "\t\t%u connection%s using ECN have seen packet loss but no CE\n");
+ p(tcps_ecn_conn_pl_ce, "\t\t%u connection%s using ECN have seen packet loss and CE\n");
+ p(tcps_ecn_conn_nopl_ce, "\t\t%u connection%s using ECN received CE but no packet loss\n");
+ p(tcps_ecn_fallback_synloss, "\t\t%u connection%s fell back to non-ECN due to SYN-loss\n");
+ p(tcps_ecn_fallback_reorder, "\t\t%u connection%s fell back to non-ECN due to reordering\n");
+ p(tcps_ecn_fallback_ce, "\t\t%u connection%s fell back to non-ECN due to excessive CE-markings\n");
+ p(tcps_ecn_fallback_droprst, "\t\t%u connection%s fell back caused by connection drop due to RST\n");
+ p(tcps_ecn_fallback_droprxmt, "\t\t%u connection%s fell back due to drop after multiple retransmits \n");
+ p(tcps_ecn_fallback_synrst, "\t\t%u connection%s fell back due to RST after SYN\n");
+
+ p(tcps_detect_reordering, "\t%u time%s packet reordering was detected on a connection\n");
+ p(tcps_reordered_pkts, "\t\t%u time%s transmitted packets were reordered\n");
+ p(tcps_delay_recovery, "\t\t%u time%s fast recovery was delayed to handle reordering\n");
+ p(tcps_avoid_rxmt, "\t\t%u time%s retransmission was avoided by delaying recovery\n");
+ p(tcps_unnecessary_rxmt, "\t\t%u retransmission%s not needed \n");
+ p(tcps_tailloss_rto, "\t%u retransmission%s due to tail loss\n");
+ p(tcps_dsack_sent, "\t%u time%s DSACK option was sent\n");
+ p(tcps_dsack_recvd, "\t\t%u time%s DSACK option was received\n");
+ p(tcps_dsack_disable, "\t\t%u time%s DSACK was disabled on a connection\n");
+ p(tcps_dsack_badrexmt, "\t\t%u time%s recovered from bad retransmission using DSACK\n");
+ p(tcps_dsack_ackloss,"\t\t%u time%s ignored DSACK due to ack loss\n");
+ p(tcps_dsack_recvd_old,"\t\t%u time%s ignored old DSACK options\n");
+ p(tcps_pmtudbh_reverted, "\t%u time%s PMTU Blackhole detection, size reverted\n");
+ p(tcps_drop_after_sleep, "\t%u connection%s were dropped after long sleep\n");
+ p(tcps_nostretchack, "\t%u connection%s had stretch ack algorithm disabled\n");
+
+ p(tcps_tfo_cookie_sent,"\t%u time%s a TFO-cookie has been announced\n");
+ p(tcps_tfo_syn_data_rcv,"\t%u SYN%s with data and a valid TFO-cookie have been received\n");
+ p(tcps_tfo_cookie_req_rcv,"\t%u SYN%s with TFO-cookie-request received\n");
+ p(tcps_tfo_cookie_invalid,"\t%u time%s an invalid TFO-cookie has been received\n");
+ p(tcps_tfo_cookie_req,"\t%u time%s we requested a TFO-cookie\n");
+ p(tcps_tfo_cookie_rcv,"\t\t%u time%s the peer announced a TFO-cookie\n");
+ p(tcps_tfo_syn_data_sent,"\t%u time%s we combined SYN with data and a TFO-cookie\n");
+ p(tcps_tfo_syn_data_acked,"\t\t%u time%s our SYN with data has been acknowledged\n");
+ p(tcps_tfo_syn_loss,"\t%u time%s a connection-attempt with TFO fell back to regular TCP\n");
+ p(tcps_tfo_blackhole,"\t%u time%s a TFO-connection blackhole'd\n");
+ p(tcps_tfo_cookie_wrong,"\t%u time%s a TFO-cookie we sent was wrong\n");
+ p(tcps_tfo_no_cookie_rcv,"\t%u time%s did not received a TFO-cookie we asked for\n");
+ p(tcps_tfo_heuristics_disable,"\t%u time%s TFO got disabled due to heuristicsn\n");
+ p(tcps_tfo_sndblackhole,"\t%u time%s TFO got blackholed in the sending direction\n");
+
+ p(tcps_mss_to_default,"\t%u time%s maximum segment size was changed to default\n");
+ p(tcps_mss_to_medium,"\t%u time%s maximum segment size was changed to medium\n");
+ p(tcps_mss_to_low,"\t%u time%s maximum segment size was changed to low\n");
+
+ p(tcps_timer_drift_le_1_ms,"\t%u timer drift%s less or equal to 1 ms\n");
+ p(tcps_timer_drift_le_10_ms,"\t%u timer drift%s less or equal to 10 ms\n");
+ p(tcps_timer_drift_le_20_ms,"\t%u timer drift%s less or equal to 20 ms\n");
+ p(tcps_timer_drift_le_50_ms,"\t%u timer drift%s less or equal to 50 ms\n");
+ p(tcps_timer_drift_le_100_ms,"\t%u timer drift%s less or equal to 100 ms\n");
+ p(tcps_timer_drift_le_200_ms,"\t%u timer drift%s less or equal to 200 ms\n");
+ p(tcps_timer_drift_le_500_ms,"\t%u timer drift%s less or equal to 500 ms\n");
+ p(tcps_timer_drift_le_1000_ms,"\t%u timer drift%s less or equal to 1000 ms\n");
+ p(tcps_timer_drift_gt_1000_ms,"\t%u timer drift%s greater than to 1000 ms\n");
+
+ if (interval > 0) {
+ bcopy(&tcpstat, &ptcpstat, len);
+ pr_swcsum = r_swcsum;
+ pt_swcsum = t_swcsum;
+ }
+
+#undef TCPDIFF
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump MPTCP statistics
+ */
+void
+mptcp_stats(uint32_t off , char *name, int af)
+{
+ static struct tcpstat ptcpstat;
+ struct tcpstat tcpstat;
+ size_t len = sizeof tcpstat;
+
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (mptcp_done != 0 && interval == 0)
+ return;
+ else
+ mptcp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
+#define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
+#define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f))
+#define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
+ MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
+#define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
+#define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
+
+ p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
+ p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
+ p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
+ p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
+ p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
+ p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
+ p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
+ "TCP\n");
+ p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
+ "TCP\n");
+ p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
+ p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
+ p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
+ p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
+ p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
+ p3(tcps_mp_switches, "\t%u subflow switch%s\n");
+ p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n");
+ p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n");
+ p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n");
+ p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n");
+ p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n");
+
+ if (interval > 0) {
+ bcopy(&tcpstat, &ptcpstat, len);
+ }
+
+#undef MPTCPDIFF
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump UDP statistics structure.
+ */
+void
+udp_stats(uint32_t off , char *name, int af )
+{
+ static struct udpstat pudpstat;
+ struct udpstat udpstat;
+ size_t len = sizeof udpstat;
+ uint32_t delivered;
+ static uint32_t r_swcsum, pr_swcsum;
+ static uint32_t t_swcsum, pt_swcsum;
+
+ if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.udp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (udp_done != 0 && interval == 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define UDPDIFF(f) (udpstat.f - pudpstat.f)
+#define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
+ printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
+#define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
+ printf(m, UDPDIFF(f))
+#define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
+ printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
+ p(udps_ipackets, "\t%u datagram%s received\n");
+ p1a(udps_hdrops, "\t\t%u with incomplete header\n");
+ p1a(udps_badlen, "\t\t%u with bad data length field\n");
+ p1a(udps_badsum, "\t\t%u with bad checksum\n");
+ p1a(udps_nosum, "\t\t%u with no checksum\n");
+ r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
+ if ((r_swcsum - pr_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
+ p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p1a(udps_noport, "\t\t%u dropped due to no socket\n");
+ p(udps_noportbcast,
+ "\t\t%u broadcast/multicast datagram%s undelivered\n");
+ /* the next statistic is cumulative in udps_noportbcast */
+ p(udps_filtermcast,
+ "\t\t%u time%s multicast source filter matched\n");
+ p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
+ p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
+ delivered = UDPDIFF(udps_ipackets) -
+ UDPDIFF(udps_hdrops) -
+ UDPDIFF(udps_badlen) -
+ UDPDIFF(udps_badsum) -
+ UDPDIFF(udps_noport) -
+ UDPDIFF(udps_noportbcast) -
+ UDPDIFF(udps_fullsock);
+ if (delivered || sflag <= 1)
+ printf("\t\t%u delivered\n", delivered);
+ p(udps_opackets, "\t%u datagram%s output\n");
+ t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
+ if ((t_swcsum - pt_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
+ p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+
+ if (interval > 0) {
+ bcopy(&udpstat, &pudpstat, len);
+ pr_swcsum = r_swcsum;
+ pt_swcsum = t_swcsum;
+ }
+
+#undef UDPDIFF
+#undef p
+#undef p1a
+#undef p2
+}
+
+/*
+ * Dump IP statistics structure.
+ */
+void
+ip_stats(uint32_t off , char *name, int af )
+{
+ static struct ipstat pipstat;
+ struct ipstat ipstat;
+ size_t ipstat_len = sizeof ipstat;
+
+ static net_perf_t pout_net_perf, pin_net_perf;
+ net_perf_t out_net_perf, in_net_perf;
+ size_t out_net_perf_len = sizeof (out_net_perf);
+ size_t in_net_perf_len = sizeof (in_net_perf);
+
+ if (sysctlbyname("net.inet.ip.stats", &ipstat, &ipstat_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.stats");
+ return;
+ }
+
+ if (sysctlbyname("net.inet.ip.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.output_perf_data");
+ bzero(&out_net_perf, out_net_perf_len);
+ }
+
+ if (sysctlbyname("net.inet.ip.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.input_perf_data");
+ bzero(&in_net_perf, in_net_perf_len);
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IPDIFF(f) (ipstat.f - pipstat.f)
+#define p(f, m) if (IPDIFF(f) || sflag <= 1) \
+ printf(m, IPDIFF(f), plural(IPDIFF(f)))
+#define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
+ printf(m, IPDIFF(f))
+#define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
+ printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
+
+ p(ips_total, "\t%u total packet%s received\n");
+ p(ips_badsum, "\t\t%u bad header checksum%s\n");
+ p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
+ "\t\t%u header%s (%u byte%s) checksummed in software\n");
+ p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
+ p1a(ips_tooshort, "\t\t%u with data size < data length\n");
+ p1a(ips_adj, "\t\t%u with data size > data length\n");
+ p(ips_adj_hwcsum_clr,
+ "\t\t\t%u packet%s forced to software checksum\n");
+ p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
+ p1a(ips_badhlen, "\t\t%u with header length < data size\n");
+ p1a(ips_badlen, "\t\t%u with data length < header length\n");
+ p1a(ips_badoptions, "\t\t%u with bad options\n");
+ p1a(ips_badvers, "\t\t%u with incorrect version number\n");
+ p(ips_fragments, "\t\t%u fragment%s received\n");
+ p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
+ p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
+ p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
+ p(ips_delivered, "\t\t%u packet%s for this host\n");
+ p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
+ p(ips_forward, "\t\t%u packet%s forwarded");
+ p(ips_fastforward, " (%u packet%s fast forwarded)");
+ if (IPDIFF(ips_forward) || sflag <= 1)
+ putchar('\n');
+ p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
+ p(ips_notmember,
+ "\t\t%u packet%s received for unknown multicast group\n");
+ p(ips_redirectsent, "\t\t%u redirect%s sent\n");
+ p(ips_rxc_collisions, "\t\t%u input packet%s not chained due to collision\n");
+ p(ips_rxc_chained, "\t\t%u input packet%s processed in a chain\n");
+ p(ips_rxc_notchain, "\t\t%u input packet%s unable to chain\n");
+ p(ips_rxc_chainsz_gt2,
+ "\t\t%u input packet chain%s processed with length greater than 2\n");
+ p(ips_rxc_chainsz_gt4,
+ "\t\t%u input packet chain%s processed with length greater than 4\n");
+ p(ips_rxc_notlist,
+ "\t\t%u input packet%s did not go through list processing path\n");
+
+ p(ips_rcv_if_weak_match,
+ "\t\t%u input packet%s that passed the weak ES interface address match\n");
+ p(ips_rcv_if_no_match,
+ "\t\t%u input packet%s with no interface address match\n");
+
+#define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
+ if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
+ printf("\tInput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
+ INPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
+ INPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
+ INPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
+ INPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
+ }
+#undef INPERFDIFF
+
+ p(ips_localout, "\t%u packet%s sent from this host\n");
+ p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
+ p(ips_odropped,
+ "\t\t%u output packet%s dropped due to no bufs, etc.\n");
+ p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
+ p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
+ p(ips_ofragments, "\t\t%u fragment%s created\n");
+ p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
+ p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
+ p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
+ p(ips_pktdropcntrl,
+ "\t\t%u packet%s dropped due to no bufs for control data\n");
+ p(ips_necp_policy_drop, "\t\t%u packet%s dropped due to NECP policy\n");
+ p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
+ "\t\t%u header%s (%u byte%s) checksummed in software\n");
+
+#define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
+ if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
+ printf("\tOutput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
+ OUTPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
+ OUTPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
+ OUTPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
+ OUTPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
+ }
+#undef OUTPERFDIFF
+
+ if (interval > 0) {
+ bcopy(&ipstat, &pipstat, ipstat_len);
+ bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
+ bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
+ }
+
+#undef IPDIFF
+#undef p
+#undef p1a
+#undef p2
+}
+
+/*
+ * Dump ARP statistics structure.
+ */
+void
+arp_stats(uint32_t off, char *name, int af)
+{
+ static struct arpstat parpstat;
+ struct arpstat arpstat;
+ size_t len = sizeof (arpstat);
+
+ if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
+ &len, 0, 0) < 0) {
+ warn("sysctl: net.link.ether.inet.stats");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ARPDIFF(f) (arpstat.f - parpstat.f)
+#define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
+#define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
+#define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f)))
+
+ p(txrequests, "\t%u broadast ARP request%s sent\n");
+ p(txurequests, "\t%u unicast ARP request%s sent\n");
+ p2(txreplies, "\t%u ARP repl%s sent\n");
+ p(txannounces, "\t%u ARP announcement%s sent\n");
+ p(rxrequests, "\t%u ARP request%s received\n");
+ p2(rxreplies, "\t%u ARP repl%s received\n");
+ p(received, "\t%u total ARP packet%s received\n");
+ p(txconflicts, "\t%u ARP conflict probe%s sent\n");
+ p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
+ p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
+ p3(held, "\t%u total packet%s held awaiting ARP repl%s\n");
+ p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
+ p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
+ p2(timeouts, "\t%u ARP entr%s timed out\n");
+ p(dupips, "\t%u Duplicate IP%s seen\n");
+
+ if (interval > 0)
+ bcopy(&arpstat, &parpstat, len);
+
+#undef ARPDIFF
+#undef p
+#undef p2
+}
+
+static char *icmpnames[] = {
+ "echo reply",
+ "#1",
+ "#2",
+ "destination unreachable",
+ "source quench",
+ "routing redirect",
+ "#6",
+ "#7",
+ "echo",
+ "router advertisement",
+ "router solicitation",
+ "time exceeded",
+ "parameter problem",
+ "time stamp",
+ "time stamp reply",
+ "information request",
+ "information request reply",
+ "address mask request",
+ "address mask reply",
+};
+
+/*
+ * Dump ICMP statistics.
+ */
+void
+icmp_stats(uint32_t off , char *name, int af )
+{
+ static struct icmpstat picmpstat;
+ struct icmpstat icmpstat;
+ int i, first;
+ int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_ICMP;
+ mib[3] = ICMPCTL_STATS;
+
+ len = sizeof icmpstat;
+ memset(&icmpstat, 0, len);
+ if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
+ return; /* XXX should complain, but not traditional */
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
+#define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
+ printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
+#define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
+ printf(m, ICMPDIFF(f))
+
+ p(icps_error, "\t%u call%s to icmp_error\n");
+ p(icps_oldicmp,
+ "\t%u error%s not generated 'cuz old message was icmp\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (ICMPDIFF(icps_outhist[i]) != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ ICMPDIFF(icps_outhist[i]));
+ }
+ p(icps_badcode, "\t%u message%s with bad code fields\n");
+ p(icps_tooshort, "\t%u message%s < minimum length\n");
+ p(icps_checksum, "\t%u bad checksum%s\n");
+ p(icps_badlen, "\t%u message%s with bad length\n");
+ p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
+ p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (ICMPDIFF(icps_inhist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ ICMPDIFF(icps_inhist[i]));
+ }
+ p(icps_reflect, "\t%u message response%s generated\n");
+
+#undef ICMPDIFF
+#undef p
+#undef p1a
+ mib[3] = ICMPCTL_MASKREPL;
+ len = sizeof i;
+ if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
+ return;
+ printf("\tICMP address mask responses are %sabled\n",
+ i ? "en" : "dis");
+
+ if (interval > 0)
+ bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
+}
+
+/*
+ * Dump IGMP statistics structure.
+ */
+void
+igmp_stats(uint32_t off , char *name, int af )
+{
+ static struct igmpstat_v3 pigmpstat;
+ struct igmpstat_v3 igmpstat;
+ size_t len = sizeof igmpstat;
+
+ if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.igmp.v3stats");
+ return;
+ }
+
+ if (igmpstat.igps_version != IGPS_VERSION_3) {
+ warnx("%s: version mismatch (%d != %d)", __func__,
+ igmpstat.igps_version, IGPS_VERSION_3);
+ }
+ if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
+ warnx("%s: size mismatch (%d != %d)", __func__,
+ igmpstat.igps_len, IGPS_VERSION3_LEN);
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
+#define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
+ printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
+#define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
+ printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
+
+ p64(igps_rcv_total, "\t%ju message%s received\n");
+ p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
+ p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
+ p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
+ py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
+ py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
+ py64(igps_rcv_badqueries,
+ "\t%ju membership quer%s received with invalid field(s)\n");
+ py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
+ py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
+ py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
+ py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
+ p64(igps_rcv_reports, "\t%ju membership report%s received\n");
+ p64(igps_rcv_badreports,
+ "\t%ju membership report%s received with invalid field(s)\n");
+ p64(igps_rcv_ourreports,
+"\t%ju membership report%s received for groups to which we belong\n");
+ p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
+ p64(igps_snd_reports, "\t%ju membership report%s sent\n");
+
+ if (interval > 0)
+ bcopy(&igmpstat, &pigmpstat, len);
+
+#undef IGMPDIFF
+#undef p64
+#undef py64
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ */
+void
+inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ if (Wflag)
+ snprintf(line, sizeof(line), "%s.", inetname(in));
+ else
+ snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
+ cp = index(line, '\0');
+ if (!numeric_port && port)
+#ifdef _SERVICE_CACHE_
+ sp = _serv_cache_getservbyport(port, proto);
+#else
+ sp = getservbyport((int)port, proto);
+#endif
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
+ width = (Aflag && !Wflag) ? 18 : 22;
+ if (Wflag)
+ printf("%-*s ", width, line);
+ else
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(struct in_addr *inp)
+{
+ register char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+ struct netent *np;
+
+ cp = 0;
+ if (!nflag && inp->s_addr != INADDR_ANY) {
+ int net = inet_netof(*inp);
+ int lna = inet_lnaof(*inp);
+
+ if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp == 0) {
+ hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ }
+ if (inp->s_addr == INADDR_ANY)
+ strlcpy(line, "*", sizeof(line));
+ else if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+ inp->s_addr = ntohl(inp->s_addr);
+#define C(x) ((u_int)((x) & 0xff))
+ snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
+ C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
+ }
+ return (line);
+}
diff --git a/network_cmds/netstat.tproj/inet6.c b/network_cmds/netstat.tproj/inet6.c
new file mode 100644
index 0000000..4bc757c
--- /dev/null
+++ b/network_cmds/netstat.tproj/inet6.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
+/*
+ * Copyright (c) 1983, 1988, 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.
+ *
+ * $FreeBSD: src/usr.bin/netstat/inet6.c,v 1.3.2.9 2001/08/10 09:07:09 ru Exp $
+ */
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/net_perf.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/in_systm.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/raw_ip6.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#if defined(__APPLE__) && !defined(__unused)
+#define __unused
+#endif
+
+char *inet6name (struct in6_addr *);
+void inet6print (struct in6_addr *, int, char *, int);
+
+static char *ip6nh[] = {
+ "hop by hop",
+ "ICMP",
+ "IGMP",
+ "#3",
+ "IP",
+ "#5",
+ "TCP",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "UDP",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "IDP",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "TP",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "IP6",
+ "#42",
+ "routing",
+ "fragment",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "ESP",
+ "AH",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "ICMP6",
+ "no next header",
+ "destination option",
+ "#61",
+ "mobility",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "ISOIP",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "OSPF",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "Ethernet",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "PIM",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "#128",
+ "#129",
+ "#130",
+ "#131",
+ "#132",
+ "#133",
+ "#134",
+ "#135",
+ "#136",
+ "#137",
+ "#138",
+ "#139",
+ "#140",
+ "#141",
+ "#142",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+
+static const char *srcrulenames[IP6S_SRCRULE_COUNT] = {
+ "default", // IP6S_SRCRULE_0
+ "prefer same address", // IP6S_SRCRULE_1
+ "prefer appropriate scope", // IP6S_SRCRULE_2
+ "avoid deprecated addresses", // IP6S_SRCRULE_3
+ "prefer home addresses", // IP6S_SRCRULE_4
+ "prefer outgoing interface", // IP6S_SRCRULE_5
+ "prefer matching label", // IP6S_SRCRULE_6
+ "prefer temporary addresses", // IP6S_SRCRULE_7
+ "prefer addresses on alive interfaces", // IP6S_SRCRULE_7x
+ "use longest matching prefix", // IP6S_SRCRULE_8
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Dump IP6 statistics structure.
+ */
+void
+ip6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct ip6stat pip6stat;
+ struct ip6stat ip6stat;
+ int first, i;
+ int mib[4];
+ size_t len;
+ static net_perf_t pout_net_perf, pin_net_perf;
+ net_perf_t out_net_perf, in_net_perf;
+ size_t out_net_perf_len = sizeof (out_net_perf);
+ size_t in_net_perf_len = sizeof (in_net_perf);
+
+ if (sysctlbyname("net.inet6.ip6.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
+ perror("sysctl: net.inet6.ip6.output_perf_data");
+ return;
+ }
+
+ if (sysctlbyname("net.inet6.ip6.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
+ perror("sysctl: net.inet6.ip6.input_perf_data");
+ return;
+ }
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_STATS;
+
+ len = sizeof ip6stat;
+ memset(&ip6stat, 0, len);
+ if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IP6DIFF(f) (ip6stat.f - pip6stat.f)
+#define p(f, m) if (IP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)IP6DIFF(f), plural(IP6DIFF(f)))
+#define p1a(f, m) if (IP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)IP6DIFF(f))
+
+ p(ip6s_total, "\t%llu total packet%s received\n");
+ p1a(ip6s_toosmall, "\t\t%llu with size smaller than minimum\n");
+ p1a(ip6s_tooshort, "\t\t%llu with data size < data length\n");
+ p1a(ip6s_adj, "\t\t%llu with data size > data length\n");
+ p(ip6s_adj_hwcsum_clr,
+ "\t\t\t%llu packet%s forced to software checksum\n");
+ p1a(ip6s_badoptions, "\t\t%llu with bad options\n");
+ p1a(ip6s_badvers, "\t\t%llu with incorrect version number\n");
+ p(ip6s_fragments, "\t\t%llu fragment%s received\n");
+ p1a(ip6s_fragdropped,
+ "\t\t\t%llu dropped (dup or out of space)\n");
+ p1a(ip6s_fragtimeout, "\t\t\t%llu dropped after timeout\n");
+ p1a(ip6s_fragoverflow, "\t\t\t%llu exceeded limit\n");
+ p1a(ip6s_reassembled, "\t\t\t%llu reassembled ok\n");
+ p1a(ip6s_atmfrag_rcvd, "\t\t\t%llu atomic fragments received\n");
+ p(ip6s_delivered, "\t\t%llu packet%s for this host\n");
+ p(ip6s_forward, "\t\t%llu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t\t%llu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t\t%llu redirect%s sent\n");
+ p(ip6s_notmember, "\t\t%llu multicast packet%s which we don't join\n");
+ p(ip6s_exthdrtoolong,
+ "\t\t%llu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t\t%llu tunneling packet%s that can't find gif\n");
+ p(ip6s_toomanyhdr,
+ "\t\t%llu packet%s discarded due to too may headers\n");
+ p1a(ip6s_forward_cachehit, "\t\t%llu forward cache hit\n");
+ p1a(ip6s_forward_cachemiss, "\t\t%llu forward cache miss\n");
+ p(ip6s_pktdropcntrl,
+ "\t\t%llu packet%s dropped due to no bufs for control data\n");
+ /* CLAT46 input stats */
+ p(ip6s_clat464_in_tooshort_drop,
+ "\t\t%llu input packet%s dropped due to too short length \n");
+ p(ip6s_clat464_in_nov6addr_drop,
+ "\t\t%llu input packet%s dropped due to missing CLAT46 IPv6 address\n");
+ p(ip6s_clat464_in_nov4addr_drop,
+ "\t\t%llu input packet%s dropped due to missing CLAT46 IPv4 address\n");
+ p(ip6s_clat464_in_v4synthfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 IPv4 address derivation failure\n");
+ p(ip6s_clat464_in_64transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 IP header translation failure\n");
+ p(ip6s_clat464_in_64proto_transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 protocol translation failure\n");
+ p(ip6s_clat464_in_64frag_transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 fragment translation failure\n");
+ p(ip6s_clat464_in_invalpbuf_drop,
+ "\t\t%llu input packet%s dropped due to invalid pbuf\n");
+ p(ip6s_clat464_in_v4_drop,
+ "\t\t%llu input IPv4 packet%s dropped on CLAT46 enabled interface\n");
+ p(ip6s_clat464_in_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 failures\n");
+ p(ip6s_clat464_in_success,
+ "\t\t%llu input packet%s successfully translated from IPv6 to IPv4\n");
+
+#define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
+ if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
+ printf("\tInput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
+ printf("\t\tPerformance Histogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
+ INPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
+ INPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
+ INPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
+ INPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
+ }
+#undef INPERFDIFF
+
+ p(ip6s_localout, "\t%llu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t\t%llu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped,
+ "\t\t%llu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t\t%llu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t\t%llu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t\t%llu fragment%s created\n");
+ p(ip6s_cantfrag, "\t\t%llu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t\t%llu packet%s that violated scope rules\n");
+ p(ip6s_necp_policy_drop, "\t\t%llu packet%s dropped due to NECP policy\n");
+ /* CLAT46 output stats */
+ p(ip6s_clat464_out_nov6addr_drop,
+ "\t\t%llu output packet%s dropped due to missing CLAT46 IPv6 address\n");
+ p(ip6s_clat464_out_v6synthfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 IPv6 address synthesis failure\n");
+ p(ip6s_clat464_out_46transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 IP header translation failure\n");
+ p(ip6s_clat464_out_46proto_transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 protocol translation failure\n");
+ p(ip6s_clat464_out_46frag_transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 fragment translation failure\n");
+ p(ip6s_clat464_out_invalpbuf_drop,
+ "\t\t%llu output packet%s dropped due to invalid pbuf\n");
+ p(ip6s_clat464_out_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 failures\n");
+ p(ip6s_clat464_out_success,
+ "\t\t%llu output packet%s successfully translated from IPv4 to IPv6\n");
+ p(ip6s_rcv_if_weak_match,
+ "\t\t%llu input packet%s that passed the weak ES interface address match\n");
+ p(ip6s_rcv_if_no_match,
+ "\t\t%llu input packet%s with no interface address match\n");
+
+#define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
+ if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
+ printf("\tOutput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
+ OUTPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
+ OUTPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
+ OUTPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
+ OUTPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
+ }
+#undef OUTPERFDIFF
+
+ for (first = 1, i = 0; i < 256; i++)
+ if (IP6DIFF(ip6s_nxthist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", ip6nh[i],
+ (unsigned long long)IP6DIFF(ip6s_nxthist[i]));
+ }
+ printf("\tMbuf statistics:\n");
+ printf("\t\t%llu one mbuf\n", (unsigned long long)IP6DIFF(ip6s_m1));
+ for (first = 1, i = 0; i < 32; i++) {
+ char ifbuf[IFNAMSIZ];
+ if (IP6DIFF(ip6s_m2m[i]) != 0) {
+ if (first) {
+ printf("\t\ttwo or more mbuf:\n");
+ first = 0;
+ }
+ printf("\t\t\t%s= %llu\n",
+ if_indextoname(i, ifbuf),
+ (unsigned long long)IP6DIFF(ip6s_m2m[i]));
+ }
+ }
+ printf("\t\t%llu one ext mbuf\n",
+ (unsigned long long)IP6DIFF(ip6s_mext1));
+ printf("\t\t%llu two or more ext mbuf\n",
+ (unsigned long long)IP6DIFF(ip6s_mext2m));
+
+ /* for debugging source address selection */
+#define PRINT_SCOPESTAT(s,i) do {\
+ switch(i) { /* XXX hardcoding in each case */\
+ case 1:\
+ p(s, "\t\t\t%llu node-local%s\n");\
+ break;\
+ case 2:\
+ p(s,"\t\t\t%llu link-local%s\n");\
+ break;\
+ case 5:\
+ p(s,"\t\t\t%llu site-local%s\n");\
+ break;\
+ case 14:\
+ p(s,"\t\t\t%llu global%s\n");\
+ break;\
+ default:\
+ printf("\t\t\t%llu addresses scope=%x\n",\
+ (unsigned long long)IP6DIFF(s), i);\
+ }\
+ } while (0);
+
+ p(ip6s_sources_none,
+ "\t\t%llu failure%s of source address selection\n");
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_sameif[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses on an outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_otherif[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses on a non-outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_samescope[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses of same scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_otherscope[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses of a different scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_deprecated[i]) || 1) {
+ if (first) {
+ printf("\t\tdeprecated source addresses\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
+ }
+ }
+#define PRINT_SRCRULESTAT(s,i) do {\
+ if (srcrulenames[i] != NULL) \
+ printf("\t\t\t%llu rule%s %s\n", \
+ (unsigned long long)IP6DIFF(s), \
+ plural(IP6DIFF(s)), \
+ srcrulenames[i]); \
+} while (0);
+
+ for (first = 1, i = 0; i < IP6S_SRCRULE_COUNT; i++) {
+ if (IP6DIFF(ip6s_sources_rule[i]) || 1) {
+ if (first) {
+ printf("\t\tsource address selection\n");
+ first = 0;
+ }
+ PRINT_SRCRULESTAT(ip6s_sources_rule[i], i);
+ }
+ }
+
+ p(ip6s_dad_collide, "\t\t%llu duplicate address detection collision%s\n");
+
+ p(ip6s_dad_loopcount, "\t\t%llu duplicate address detection NS loop%s\n");
+
+ p(ip6s_sources_skip_expensive_secondary_if, "\t\t%llu time%s ignored source on secondary expensive I/F\n");
+
+ if (interval > 0) {
+ bcopy(&ip6stat, &pip6stat, len);
+ bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
+ bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
+ }
+#undef IP6DIFF
+#undef p
+#undef p1a
+}
+
+/*
+ * Dump IPv6 per-interface statistics based on RFC 2465.
+ */
+void
+ip6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
+#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ip6stat.f)
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ printf("ip6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
+ goto end;
+ }
+
+ p(ifs6_in_receive, "\t%llu total input datagram%s\n");
+ p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
+ p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
+ p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
+ p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
+ p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
+ p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
+ p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
+ p(ifs6_in_deliver,
+ "\t%llu datagram%s delivered to an upper layer protocol\n");
+ p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
+ p(ifs6_out_request,
+ "\t%llu datagram%s sent from an upper layer protocol\n");
+ p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
+ p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
+ p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
+ p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
+ p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
+ p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
+ p(ifs6_atmfrag_rcvd, "\t%llu atomic fragments%s received\n");
+ p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
+ p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
+ p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
+
+ p(ifs6_cantfoward_icmp6, "\t%llu ICMPv6 packet%s received for unreachable destination\n");
+ p(ifs6_addr_expiry_cnt, "\t%llu address expiry event%s reported\n");
+ p(ifs6_pfx_expiry_cnt, "\t%llu prefix expiry event%s reported\n");
+ p(ifs6_defrtr_expiry_cnt, "\t%llu default router expiry event%s reported\n");
+ end:
+ close(s);
+
+#undef p
+#undef p_5
+}
+
+static char *icmp6names[] = {
+ "#0",
+ "unreach",
+ "packet too big",
+ "time exceed",
+ "parameter problem",
+ "#5",
+ "#6",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "#17",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "#22",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "#29",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "#41",
+ "#42",
+ "#43",
+ "#44",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "#50",
+ "#51",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "#58",
+ "#59",
+ "#60",
+ "#61",
+ "#62",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "#80",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "#89",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "#97",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "#103",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "echo",
+ "echo reply",
+ "multicast listener query",
+ "MLDv1 listener report",
+ "MLDv1 listener done",
+ "router solicitation",
+ "router advertisement",
+ "neighbor solicitation",
+ "neighbor advertisement",
+ "redirect",
+ "router renumbering",
+ "node information request",
+ "node information reply",
+ "inverse neighbor solicitation",
+ "inverse neighbor advertisement",
+ "MLDv2 listener report",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+/*
+ * Dump ICMP6 statistics.
+ */
+void
+icmp6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct icmp6stat picmp6stat;
+ struct icmp6stat icmp6stat;
+ register int i, first;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_ICMPV6;
+ mib[3] = ICMPV6CTL_STATS;
+
+ len = sizeof icmp6stat;
+ memset(&icmp6stat, 0, len);
+ if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ICMP6DIFF(f) (icmp6stat.f - picmp6stat.f)
+#define p(f, m) if (ICMP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)ICMP6DIFF(f), plural(ICMP6DIFF(f)))
+#define p_5(f, m) printf(m, (unsigned long long)ICMP6DIFF(f))
+
+ p(icp6s_error, "\t%llu call%s to icmp_error\n");
+ p(icp6s_canterror,
+ "\t%llu error%s not generated because old message was icmp error or so\n");
+ p(icp6s_toofreq,
+ "\t%llu error%s not generated because rate limitation\n");
+#define NELEM (sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (ICMP6DIFF(icp6s_outhist[i]) != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)ICMP6DIFF(icp6s_outhist[i]));
+ }
+#undef NELEM
+ p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%llu bad checksum%s\n");
+ p(icp6s_badlen, "\t%llu message%s with bad length\n");
+#define NELEM (sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (ICMP6DIFF(icp6s_inhist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)ICMP6DIFF(icp6s_inhist[i]));
+ }
+#undef NELEM
+ printf("\tHistogram of error messages to be generated:\n");
+ p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
+ p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
+ p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
+ p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
+ p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
+ p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
+ p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
+ p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
+ p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
+ p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
+ p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
+ p_5(icp6s_oredirect, "\t\t%llu redirect\n");
+ p_5(icp6s_ounknown, "\t\t%llu unknown\n");
+
+ p(icp6s_reflect, "\t%llu message response%s generated\n");
+ p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
+ p(icp6s_nd_badopt, "\t%qu message%s with bad ND options\n");
+ p(icp6s_badns, "\t%qu bad neighbor solicitation message%s\n");
+ p(icp6s_badna, "\t%qu bad neighbor advertisement message%s\n");
+ p(icp6s_badrs, "\t%qu bad router solicitation message%s\n");
+ p(icp6s_badra, "\t%qu bad router advertisement message%s\n");
+ p(icp6s_badredirect, "\t%qu bad redirect message%s\n");
+ p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
+ p(icp6s_rfc6980_drop, "\t%qu dropped fragmented NDP message%s\n");
+
+ if (interval > 0)
+ bcopy(&icmp6stat, &picmp6stat, len);
+
+#undef ICMP6DIFF
+#undef p
+#undef p_5
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics based on RFC 2466.
+ */
+void
+icmp6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ printf("icmp6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
+ goto end;
+ }
+
+ p(ifs6_in_msg, "\t%llu total input message%s\n");
+ p(ifs6_in_error, "\t%llu total input error message%s\n");
+ p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
+ p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
+ p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
+ p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
+ p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
+ p(ifs6_in_echo, "\t%llu input echo request%s\n");
+ p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
+ p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
+ p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
+ p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
+ p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
+ p(ifs6_in_redirect, "\t%llu input redirect%s\n");
+ p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
+ p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
+ p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
+
+ p(ifs6_out_msg, "\t%llu total output message%s\n");
+ p(ifs6_out_error, "\t%llu total output error message%s\n");
+ p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
+ p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
+ p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
+ p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
+ p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
+ p(ifs6_out_echo, "\t%llu output echo request%s\n");
+ p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
+ p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
+ p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
+ p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
+ p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
+ p(ifs6_out_redirect, "\t%llu output redirect%s\n");
+ p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
+ p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
+ p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
+
+ end:
+ close(s);
+#undef p
+}
+
+/*
+ * Dump raw ip6 statistics structure.
+ */
+void
+rip6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct rip6stat prip6stat;
+ struct rip6stat rip6stat;
+ u_quad_t delivered;
+ int mib[4];
+ size_t l;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_RIP6STATS;
+ l = sizeof(rip6stat);
+ if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) {
+ perror("Warning: sysctl(net.inet6.ip6.rip6stats)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define RIP6DIFF(f) (rip6stat.f - prip6stat.f)
+#define p(f, m) if (RIP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)RIP6DIFF(f), plural(RIP6DIFF(f)))
+ p(rip6s_ipackets, "\t%llu message%s received\n");
+ p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
+ p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
+ p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
+ p(rip6s_nosockmcast,
+ "\t%llu multicast message%s dropped due to no socket\n");
+ p(rip6s_fullsock,
+ "\t%llu message%s dropped due to full socket buffers\n");
+ delivered = RIP6DIFF(rip6s_ipackets) -
+ RIP6DIFF(rip6s_badsum) -
+ RIP6DIFF(rip6s_nosock) -
+ RIP6DIFF(rip6s_nosockmcast) -
+ RIP6DIFF(rip6s_fullsock);
+ if (delivered || sflag <= 1)
+ printf("\t%llu delivered\n", (unsigned long long)delivered);
+ p(rip6s_opackets, "\t%llu datagram%s output\n");
+
+ if (interval > 0)
+ bcopy(&rip6stat, &prip6stat, l);
+
+#undef RIP6DIFF
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+#ifdef SRVCACHE
+extern struct servent * _serv_cache_getservbyport(int port, char *proto);
+
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = _serv_cache_getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = _serv_cache_getservbyport((int)(port), "udp");\
+ else\
+ (ret) = _serv_cache_getservbyport((int)(port), (proto));\
+};
+#else
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = getservbyport((int)(port), "udp");\
+ else\
+ (ret) = getservbyport((int)(port), (proto));\
+};
+#endif
+void
+inet6print(struct in6_addr *in6, int port, char *proto, int numeric)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ snprintf(line, sizeof(line), "%.*s.", lflag ? 39 :
+ (Aflag && !numeric) ? 12 : 16, inet6name(in6));
+ cp = index(line, '\0');
+ if (!numeric && port)
+ GETSERVBYPORT6(port, proto, sp);
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.15s", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d", ntohs((u_short)port));
+ width = lflag ? 45 : Aflag ? 18 : 22;
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(struct in6_addr *in6p)
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN];
+ static int first = 1;
+ char hbuf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+ const int niflag = NI_NUMERICHOST;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
+ hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(in6p))
+ strlcpy(line, "*", sizeof(line));
+ else if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *in6p;
+
+ if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
+ IN6_IS_ADDR_MC_NODELOCAL(in6p) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6p)) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ strlcpy(line, hbuf, sizeof(line));
+ }
+ return (line);
+}
+#endif /*INET6*/
diff --git a/network_cmds/netstat.tproj/ipsec.c b/network_cmds/netstat.tproj/ipsec.c
new file mode 100644
index 0000000..0eab162
--- /dev/null
+++ b/network_cmds/netstat.tproj/ipsec.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/* $FreeBSD: src/usr.bin/netstat/ipsec.c,v 1.1.2.3 2001/08/10 09:07:09 ru Exp $ */
+/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */
+/* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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) 1983, 1988, 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.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#include <netkey/keysock.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#if defined(__APPLE__) && !defined(__unused)
+#define __unused
+#endif
+/*
+ * portability issues:
+ * - bsdi[34] uses PLURAL(), not plural().
+ * - freebsd2 can't print "unsigned long long" properly.
+ */
+/*
+ * XXX see PORTABILITY for the twist
+ */
+#define LLU "%llu"
+#define CAST unsigned long long
+
+#ifdef IPSEC
+struct val2str {
+ int val;
+ const char *str;
+};
+
+static struct val2str ipsec_ahnames[] = {
+ { SADB_AALG_NONE, "none", },
+ { SADB_AALG_MD5HMAC, "hmac-md5", },
+ { SADB_AALG_SHA1HMAC, "hmac-sha1", },
+ { SADB_X_AALG_MD5, "md5", },
+ { SADB_X_AALG_SHA, "sha", },
+ { SADB_X_AALG_NULL, "null", },
+#ifdef SADB_X_AALG_SHA2_256
+ { SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
+#endif
+#ifdef SADB_X_AALG_SHA2_384
+ { SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
+#endif
+#ifdef SADB_X_AALG_SHA2_512
+ { SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_espnames[] = {
+ { SADB_EALG_NONE, "none", },
+ { SADB_EALG_DESCBC, "des-cbc", },
+ { SADB_EALG_3DESCBC, "3des-cbc", },
+ { SADB_EALG_NULL, "null", },
+#ifdef SADB_X_EALG_RC5CBC
+ { SADB_X_EALG_RC5CBC, "rc5-cbc", },
+#endif
+ { SADB_X_EALG_CAST128CBC, "cast128-cbc", },
+ { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
+#ifdef SADB_X_EALG_RIJNDAELCBC
+ { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_compnames[] = {
+ { SADB_X_CALG_NONE, "none", },
+ { SADB_X_CALG_OUI, "oui", },
+ { SADB_X_CALG_DEFLATE, "deflate", },
+ { SADB_X_CALG_LZS, "lzs", },
+ { -1, NULL },
+};
+
+static const char *pfkey_msgtypenames[] = {
+ "reserved", "getspi", "update", "add", "delete",
+ "get", "acquire", "register", "expire", "flush",
+ "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd",
+ "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush",
+ "x_spdsetidx", "x_spdexpire", "x_spddelete2"
+};
+
+static struct ipsecstat pipsecstat;
+static struct ipsecstat ipsecstat;
+
+static void print_ipsecstats (void);
+static const char *pfkey_msgtype_names (int);
+static void ipsec_hist (const u_quad_t *, const u_quad_t *, size_t,
+ const struct val2str *, const char *);
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+static void
+ipsec_hist(const u_quad_t *hist,
+ const u_quad_t *phist,
+ size_t histmax,
+ const struct val2str *name,
+ const char *title)
+{
+ int first;
+ size_t proto;
+ const struct val2str *p;
+
+ first = 1;
+ for (proto = 0; proto < histmax; proto++) {
+ if ((hist[proto] - phist[proto]) <= 0)
+ continue;
+ if (first) {
+ printf("\t%s histogram:\n", title);
+ first = 0;
+ }
+ for (p = name; p && p->str; p++) {
+ if (p->val == (int)proto)
+ break;
+ }
+ if (p && p->str) {
+ printf("\t\t%s: " LLU "\n", p->str,
+ (CAST)hist[proto] - (CAST)phist[proto]);
+ } else {
+ printf("\t\t#%ld: " LLU "\n", (long)proto,
+ (CAST)hist[proto] - (CAST)phist[proto]);
+ }
+ }
+}
+
+static void
+print_ipsecstats(void)
+{
+#define IPSECDIFF(f) (ipsecstat.f - pipsecstat.f)
+#define p(f, m) if (IPSECDIFF(f) || sflag <= 1) \
+ printf(m, (CAST)IPSECDIFF(f), plural(IPSECDIFF(f)))
+#define hist(f, n, t) \
+ ipsec_hist(ipsecstat.f, pipsecstat.f, \
+ sizeof(ipsecstat.f)/sizeof(ipsecstat.f[0]), (n), (t));
+
+ if (interval && vflag > 0)
+ print_time();
+
+ p(in_success, "\t" LLU " inbound packet%s processed successfully\n");
+ p(in_polvio, "\t" LLU " inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t" LLU " inbound packet%s with no SA available\n");
+ p(in_inval, "\t" LLU " invalid inbound packet%s\n");
+ p(in_nomem, "\t" LLU " inbound packet%s failed due to insufficient memory\n");
+ p(in_badspi, "\t" LLU " inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t" LLU " inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t" LLU " inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t" LLU " inbound packet%s considered authentic\n");
+ p(in_ahauthfail, "\t" LLU " inbound packet%s failed on authentication\n");
+ hist(in_ahhist, ipsec_ahnames, "AH input");
+ hist(in_esphist, ipsec_espnames, "ESP input");
+ hist(in_comphist, ipsec_compnames, "IPComp input");
+
+ p(out_success, "\t" LLU " outbound packet%s processed successfully\n");
+ p(out_polvio, "\t" LLU " outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t" LLU " outbound packet%s with no SA available\n");
+ p(out_inval, "\t" LLU " invalid outbound packet%s\n");
+ p(out_nomem, "\t" LLU " outbound packet%s failed due to insufficient memory\n");
+ p(out_noroute, "\t" LLU " outbound packet%s with no route\n");
+ hist(out_ahhist, ipsec_ahnames, "AH output");
+ hist(out_esphist, ipsec_espnames, "ESP output");
+ hist(out_comphist, ipsec_compnames, "IPComp output");
+#undef IPSECDIFF
+#undef p
+#undef hist
+}
+
+void
+ipsec_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ size_t len;
+
+ len = sizeof(struct ipsecstat);
+ if (strcmp(name, "ipsec") == 0) {
+ if (sysctlbyname("net.inet.ipsec.stats", &ipsecstat, &len, 0, 0) == -1)
+ return;
+ } else if (strcmp(name, "ipsec6") == 0) {
+ if (sysctlbyname("net.inet6.ipsec6.stats", &ipsecstat, &len, 0, 0) == -1)
+ return;
+ } else
+ return;
+ printf ("%s:\n", name);
+
+ print_ipsecstats();
+
+ if (interval > 0)
+ bcopy(&ipsecstat, &pipsecstat, len);
+}
+
+static const char *
+pfkey_msgtype_names(int x)
+{
+ const int max =
+ sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]);
+ static char buf[10];
+
+ if (x < max && pfkey_msgtypenames[x])
+ return pfkey_msgtypenames[x];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+pfkey_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct pfkeystat ppfkeystat;
+ struct pfkeystat pfkeystat;
+ unsigned first, type;
+ size_t len;
+
+ len = sizeof(struct pfkeystat);
+ if (sysctlbyname("net.key.pfkeystat", &pfkeystat, &len, 0, 0) == -1)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define PFKEYDIFF(f) (pfkeystat.f - ppfkeystat.f)
+#define p(f, m) if (PFKEYDIFF(f) || sflag <= 1) \
+ printf(m, (CAST)PFKEYDIFF(f), plural(PFKEYDIFF(f)))
+
+ /* kernel -> userland */
+ p(out_total, "\t" LLU " request%s sent to userland\n");
+ p(out_bytes, "\t" LLU " byte%s sent to userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]);
+ type++) {
+ if (PFKEYDIFF(out_msgtype[type]) <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)PFKEYDIFF(out_msgtype[type]));
+ }
+ p(out_invlen, "\t" LLU " message%s with invalid length field\n");
+ p(out_invver, "\t" LLU " message%s with invalid version field\n");
+ p(out_invmsgtype, "\t" LLU " message%s with invalid message type field\n");
+ p(out_tooshort, "\t" LLU " message%s too short\n");
+ p(out_nomem, "\t" LLU " message%s with memory allocation failure\n");
+ p(out_dupext, "\t" LLU " message%s with duplicate extension\n");
+ p(out_invexttype, "\t" LLU " message%s with invalid extension type\n");
+ p(out_invsatype, "\t" LLU " message%s with invalid sa type\n");
+ p(out_invaddr, "\t" LLU " message%s with invalid address extension\n");
+
+ /* userland -> kernel */
+ p(in_total, "\t" LLU " request%s sent from userland\n");
+ p(in_bytes, "\t" LLU " byte%s sent from userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]);
+ type++) {
+ if (PFKEYDIFF(in_msgtype[type]) <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)PFKEYDIFF(in_msgtype[type]));
+ }
+ p(in_msgtarget[KEY_SENDUP_ONE],
+ "\t" LLU " message%s toward single socket\n");
+ p(in_msgtarget[KEY_SENDUP_ALL],
+ "\t" LLU " message%s toward all sockets\n");
+ p(in_msgtarget[KEY_SENDUP_REGISTERED],
+ "\t" LLU " message%s toward registered sockets\n");
+ p(in_nomem, "\t" LLU " message%s with memory allocation failure\n");
+
+ if (interval > 0)
+ bcopy(&pfkeystat, &ppfkeystat, len);
+#undef PFKEYDIFF
+#undef p
+}
+#endif /*IPSEC*/
diff --git a/network_cmds/netstat.tproj/main.c b/network_cmds/netstat.tproj/main.c
new file mode 100644
index 0000000..1b8381e
--- /dev/null
+++ b/network_cmds/netstat.tproj/main.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * 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.
+ */
+
+#ifndef lint
+char const copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/sys_domain.h>
+
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id: main.c,v 1.8 2004/10/14 22:24:09 lindak Exp $
+ *
+ */
+
+struct protox {
+ void (*pr_cblocks)(uint32_t, char *, int);
+ /* control blocks printing routine */
+ void (*pr_stats)(uint32_t, char *, int);
+ /* statistics printing routine */
+ void (*pr_istats)(char *); /* per/if statistics printing routine */
+ char *pr_name; /* well-known name */
+ int pr_protocol;
+} protox[] = {
+ { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
+ { protopr, NULL, NULL, "divert", IPPROTO_DIVERT },
+ { protopr, ip_stats, NULL, "ip", IPPROTO_RAW },
+ { protopr, icmp_stats, NULL, "icmp", IPPROTO_ICMP },
+ { protopr, igmp_stats, NULL, "igmp", IPPROTO_IGMP },
+#ifdef IPSEC
+ { NULL, ipsec_stats, NULL, "ipsec", IPPROTO_ESP},
+#endif
+ { NULL, arp_stats, NULL, "arp", 0 },
+ { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+#ifdef INET6
+struct protox ip6protox[] = {
+ { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
+ { protopr, ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW },
+ { protopr, icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 },
+#ifdef IPSEC
+ { NULL, ipsec_stats, NULL, "ipsec6", IPPROTO_ESP },
+#endif
+ { NULL, rip6_stats, NULL, "rip6", IPPROTO_RAW },
+ { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif /*INET6*/
+
+#ifdef IPSEC
+struct protox pfkeyprotox[] = {
+ { NULL, pfkey_stats, NULL, "pfkey", PF_KEY_V2 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif
+
+
+struct protox systmprotox[] = {
+ { systmpr, NULL, NULL, "reg", 0 },
+ { systmpr, kevt_stats, NULL, "kevt", SYSPROTO_EVENT },
+ { systmpr, kctl_stats, NULL, "kctl", SYSPROTO_CONTROL },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox nstatprotox[] = {
+ { NULL, print_nstat_stats, NULL, "nstat", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox ipcprotox[] = {
+ { NULL, print_extbkidle_stats, NULL, "xbkidle", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox kernprotox[] = {
+ { NULL, print_net_api_stats, NULL, "net_api", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+#ifdef AF_VSOCK
+struct protox vsockprotox[] = {
+ { vsockpr, NULL, NULL, "vsock", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif
+
+struct protox *protoprotox[] = {
+ protox,
+#ifdef INET6
+ ip6protox,
+#endif
+#ifdef IPSEC
+ pfkeyprotox,
+#endif
+ systmprotox,
+ nstatprotox,
+ ipcprotox,
+ kernprotox,
+#ifdef AF_VSOCK
+ vsockprotox,
+#endif
+ NULL
+};
+
+static void printproto (struct protox *, char *);
+static void usage (void);
+static struct protox *name2protox (char *);
+static struct protox *knownname (char *);
+#ifdef SRVCACHE
+extern void _serv_cache_close();
+#endif
+
+int Aflag; /* show addresses of protocol control block */
+int aflag; /* show all sockets (including servers) */
+int bflag; /* show i/f total bytes in/out */
+int cflag; /* show specific classq */
+int dflag; /* show i/f dropped packets */
+int Fflag; /* show i/f forwarded packets */
+#if defined(__APPLE__)
+int gflag; /* show group (multicast) routing or stats */
+#endif
+int iflag; /* show interfaces */
+int lflag; /* show routing table with more information */
+int Lflag; /* show size of listen queues */
+int mflag; /* show memory stats */
+int nflag; /* show addresses numerically */
+static int pflag; /* show given protocol */
+int prioflag = -1; /* show packet priority statistics */
+int Rflag; /* show reachability information */
+int rflag; /* show routing tables (or routing stats) */
+int sflag; /* show protocol statistics */
+int Sflag; /* show additional i/f link status */
+int tflag; /* show i/f watchdog timers */
+int vflag; /* more verbose */
+int Wflag; /* wide display */
+int qflag; /* classq stats display */
+int Qflag; /* opportunistic polling stats display */
+int xflag; /* show extended link-layer reachability information */
+int zflag; /* show only entries with non zero rtt metrics */
+
+int cq = -1; /* send classq index (-1 for all) */
+int interval; /* repeat interval for i/f stats */
+
+char *interface; /* desired i/f for stats, or NULL for all i/fs */
+int unit; /* unit number for above */
+
+int af; /* address family */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct protox *tp = NULL; /* for printing cblocks & stats */
+ int ch;
+
+ af = AF_UNSPEC;
+
+ while ((ch = getopt(argc, argv, "Aabc:dFf:gI:ikLlmnP:p:qQrRsStuvWw:xz")) != -1)
+ switch(ch) {
+ case 'A':
+ Aflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ cq = atoi(optarg);
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'f':
+ if (strcmp(optarg, "ipx") == 0)
+ af = AF_IPX;
+ else if (strcmp(optarg, "inet") == 0)
+ af = AF_INET;
+#ifdef INET6
+ else if (strcmp(optarg, "inet6") == 0)
+ af = AF_INET6;
+#endif /*INET6*/
+#ifdef INET6
+ else if (strcmp(optarg, "pfkey") == 0)
+ af = PF_KEY;
+#endif /*INET6*/
+ else if (strcmp(optarg, "unix") == 0)
+ af = AF_UNIX;
+ else if (strcmp(optarg, "systm") == 0)
+ af = AF_SYSTEM;
+ else {
+ errx(1, "%s: unknown address family", optarg);
+ }
+ break;
+#if defined(__APPLE__)
+ case 'g':
+ gflag = 1;
+ break;
+#endif
+ case 'I': {
+ char *cp;
+
+ iflag = 1;
+ for (cp = interface = optarg; isalpha(*cp); cp++)
+ continue;
+ unit = atoi(cp);
+ break;
+ }
+ case 'i':
+ iflag = 1;
+ break;
+ case 'l':
+ lflag += 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ break;
+ case 'm':
+ mflag++;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'P':
+ prioflag = atoi(optarg);
+ break;
+ case 'p':
+ if ((tp = name2protox(optarg)) == NULL) {
+ errx(1,
+ "%s: unknown or uninstrumented protocol",
+ optarg);
+ }
+ pflag = 1;
+ break;
+ case 'q':
+ qflag++;
+ break;
+ case 'Q':
+ Qflag++;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ ++sflag;
+ break;
+ case 'S':
+ Sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ af = AF_UNIX;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'W':
+ Wflag = 1;
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ iflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ Rflag = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+#define BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ if (isdigit(**argv)) {
+ interval = atoi(*argv);
+ if (interval <= 0)
+ usage();
+ ++argv;
+ iflag = 1;
+ }
+ }
+#endif
+
+ if (mflag) {
+ mbpr();
+ exit(0);
+ }
+ if (iflag && !sflag && !Sflag && !gflag && !qflag && !Qflag) {
+ if (Rflag)
+ intpr_ri(NULL);
+ else
+ intpr(NULL);
+ exit(0);
+ }
+ if (rflag) {
+ if (sflag)
+ rt_stats();
+ else
+ routepr();
+ exit(0);
+ }
+ if (qflag || Qflag) {
+ if (interface == NULL) {
+ fprintf(stderr, "%s statistics option "
+ "requires interface name\n", qflag ? "Queue" :
+ "Polling");
+ } else if (qflag) {
+ aqstatpr();
+ } else {
+ rxpollstatpr();
+ }
+ exit(0);
+ }
+ if (Sflag) {
+ if (interface == NULL) {
+ fprintf(stderr, "additional link status option"
+ " requires interface name\n");
+ } else {
+ print_link_status(interface);
+ }
+ exit(0);
+ }
+
+#if defined(__APPLE__)
+ if (gflag) {
+ ifmalist_dump();
+ exit(0);
+ }
+#endif
+
+ if (tp) {
+ printproto(tp, tp->pr_name);
+ exit(0);
+ }
+ if (af == AF_INET || af == AF_UNSPEC)
+ for (tp = protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ for (tp = ip6protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*INET6*/
+#ifdef IPSEC
+ if (af == PF_KEY || af == AF_UNSPEC)
+ for (tp = pfkeyprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*IPSEC*/
+ if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
+ unixpr();
+
+ if ((af == AF_SYSTEM || af == AF_UNSPEC) && !Lflag)
+ for (tp = systmprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#if TARGET_OS_IPHONE
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = nstatprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /* TARGET_OS_IPHONE */
+
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = ipcprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = kernprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+
+#ifdef AF_VSOCK
+ if (af == AF_VSOCK || af == AF_UNSPEC)
+ for (tp = vsockprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*AF_VSOCK*/
+
+#ifdef SRVCACHE
+ _serv_cache_close();
+#endif
+ exit(0);
+}
+
+/*
+ * Print out protocol statistics or control blocks (per sflag).
+ * If the interface was not specifically requested, and the symbol
+ * is not in the namelist, ignore this one.
+ */
+static void
+printproto(tp, name)
+ register struct protox *tp;
+ char *name;
+{
+ void (*pr)(uint32_t, char *, int);
+ uint32_t off;
+
+ if (sflag) {
+ if (iflag && !pflag) {
+ if (tp->pr_istats)
+ intpr(tp->pr_istats);
+ else if (vflag)
+ printf("%s: no per-interface stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ else {
+ pr = tp->pr_stats;
+ if (!pr) {
+ if (pflag && vflag)
+ printf("%s: no stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ off = tp->pr_protocol;
+ }
+ } else {
+ pr = tp->pr_cblocks;
+ if (!pr) {
+ if (pflag && vflag)
+ printf("%s: no PCB routine\n", tp->pr_name);
+ return;
+ }
+ off = tp->pr_protocol;
+ }
+ if (pr != NULL) {
+ if (sflag && iflag && pflag)
+ intervalpr(pr, off, name, af);
+ else
+ (*pr)(off, name, af);
+ } else {
+ printf("### no stats for %s\n", name);
+ }
+}
+
+char *
+plural(int n)
+{
+ return (n > 1 ? "s" : "");
+}
+
+char *
+plurales(int n)
+{
+ return (n > 1 ? "es" : "");
+}
+
+char *
+pluralies(int n)
+{
+ return (n > 1 ? "ies" : "y");
+}
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+static struct protox *
+knownname(char *name)
+{
+ struct protox **tpp, *tp;
+
+ for (tpp = protoprotox; *tpp; tpp++)
+ for (tp = *tpp; tp->pr_name; tp++)
+ if (strcmp(tp->pr_name, name) == 0)
+ return (tp);
+ return (NULL);
+}
+
+/*
+ * Find the protox corresponding to name.
+ */
+static struct protox *
+name2protox(char *name)
+{
+ struct protox *tp;
+ char **alias; /* alias from p->aliases */
+ struct protoent *p;
+
+ /*
+ * Try to find the name in the list of "well-known" names. If that
+ * fails, check if name is an alias for an Internet protocol.
+ */
+ if ((tp = knownname(name)) != NULL)
+ return (tp);
+
+ setprotoent(1); /* make protocol lookup cheaper */
+ while ((p = getprotoent()) != NULL) {
+ /* assert: name not same as p->name */
+ for (alias = p->p_aliases; *alias; alias++)
+ if (strcmp(name, *alias) == 0) {
+ endprotoent();
+ return (knownname(p->p_name));
+ }
+ }
+ endprotoent();
+ return (NULL);
+}
+
+#define NETSTAT_USAGE "\
+Usage: netstat [-AaLlnW] [-f address_family | -p protocol]\n\
+ netstat [-gilns] [-f address_family]\n\
+ netstat -i | -I interface [-w wait] [-abdgRtS]\n\
+ netstat -s [-s] [-f address_family | -p protocol] [-w wait]\n\
+ netstat -i | -I interface -s [-f address_family | -p protocol]\n\
+ netstat -m [-m]\n\
+ netstat -r [-Aaln] [-f address_family]\n\
+ netstat -rs [-s]\n\
+"
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "%s\n", NETSTAT_USAGE);
+ exit(1);
+}
+
+int
+print_time(void)
+{
+ time_t now;
+ struct tm tm;
+ int num_written = 0;
+
+ (void) time(&now);
+ (void) localtime_r(&now, &tm);
+
+ num_written += printf("%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return (num_written);
+}
+
diff --git a/network_cmds/netstat.tproj/mbuf.c b/network_cmds/netstat.tproj/mbuf.c
new file mode 100644
index 0000000..38645e9
--- /dev/null
+++ b/network_cmds/netstat.tproj/mbuf.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 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.
+ */
+
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "netstat.h"
+
+#define YES 1
+typedef int bool;
+
+struct mbstat mbstat;
+
+static struct mbtypes {
+ int mt_type;
+ char *mt_name;
+} mbtypes[] = {
+ { MT_DATA, "data" },
+ { MT_OOBDATA, "oob data" },
+ { MT_CONTROL, "ancillary data" },
+ { MT_HEADER, "packet headers" },
+ { MT_SOCKET, "socket structures" }, /* XXX */
+ { MT_PCB, "protocol control blocks" }, /* XXX */
+ { MT_RTABLE, "routing table entries" }, /* XXX */
+ { MT_HTABLE, "IMP host table entries" }, /* XXX */
+ { MT_ATABLE, "address resolution tables" },
+ { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
+ { MT_SONAME, "socket names and addresses" },
+ { MT_SOOPTS, "socket options" },
+ { MT_RIGHTS, "access rights" },
+ { MT_IFADDR, "interface addresses" }, /* XXX */
+ { MT_TAG, "packet tags" }, /* XXX */
+ { 0, 0 }
+};
+
+int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
+bool seen[256]; /* "have we seen this type yet?" */
+
+mb_stat_t *mb_stat;
+unsigned int njcl, njclbytes;
+mleak_stat_t *mleak_stat;
+struct mleak_table table;
+
+#define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
+#define KERN_IPC_NJCL "kern.ipc.njcl"
+#define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
+#define KERN_IPC_MLEAK_TABLE "kern.ipc.mleak_table"
+#define KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace"
+
+#define MB_STAT_HDR1 "\
+class buf active ctotal total cache cached uncached memory\n\
+name size bufs bufs bufs state bufs bufs usage\n\
+---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
+"
+
+#define MB_STAT_HDR2 "\n\
+class waiter notify purge wretry nwretry failure\n\
+name count count count count count count\n\
+---------- -------- -------- -------- -------- -------- --------\n\
+"
+
+#define MB_LEAK_HDR "\n\
+ calltrace [1] calltrace [2] calltrace [3] calltrace [4] calltrace [5] \n\
+ ------------------ ------------------ ------------------ ------------------ ------------------ \n\
+"
+
+#define MB_LEAK_SPACING " "
+static const char *mbpr_state(int);
+static const char *mbpr_mem(u_int32_t);
+static int mbpr_getdata(void);
+
+/*
+ * Print mbuf statistics.
+ */
+void
+mbpr(void)
+{
+ unsigned long totmem = 0, totfree = 0, totmbufs, totused, totreturned = 0;
+ double totpct;
+ u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
+ u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
+ u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0;
+ int i;
+ struct mbtypes *mp;
+ mb_class_stat_t *cp;
+
+ if (mbpr_getdata() != 0)
+ return;
+
+ m_msize = mbstat.m_msize;
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ if (cp->mbcl_size == m_msize) {
+ m_mbufs = cp->mbcl_active;
+ } else if (cp->mbcl_size == mbstat.m_mclbytes) {
+ m_clfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (cp->mbcl_size == mbstat.m_bigmclbytes) {
+ m_bigclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (njcl > 0 && cp->mbcl_size == njclbytes) {
+ m_16kclfree = cp->mbcl_total - cp->mbcl_active;
+ m_16kclusters = cp->mbcl_total;
+ } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) {
+ m_mbufclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) {
+ m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) {
+ m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active;
+ }
+ }
+
+ /* adjust free counts to include composite caches */
+ m_clfree += m_mbufclfree;
+ m_bigclfree += m_mbufbigclfree;
+ m_16kclfree += m_mbuf16kclfree;
+
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ u_int32_t mem;
+
+ mem = cp->mbcl_ctotal * cp->mbcl_size;
+ totmem += mem;
+ totreturned += cp->mbcl_release_cnt;
+ totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
+ cp->mbcl_size;
+ if (mflag > 1) {
+ if (i == 0)
+ printf(MB_STAT_HDR1);
+
+ if (njcl == 0 &&
+ cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
+ continue;
+
+ printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
+ cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active,
+ cp->mbcl_ctotal, cp->mbcl_total,
+ mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached,
+ cp->mbcl_infree, mbpr_mem(mem));
+ }
+ }
+
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ if (mflag > 2) {
+ if (i == 0)
+ printf(MB_STAT_HDR2);
+
+ if (njcl == 0 &&
+ cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
+ continue;
+
+ printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
+ cp->mbcl_cname, cp->mbcl_mc_waiter_cnt,
+ cp->mbcl_notified, cp->mbcl_purge_cnt,
+ cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt,
+ cp->mbcl_fail_cnt);
+ }
+ }
+
+ if (mflag > 1)
+ printf("\n");
+
+ totmbufs = 0;
+ for (mp = mbtypes; mp->mt_name; mp++)
+ totmbufs += mbstat.m_mtypes[mp->mt_type];
+ /*
+ * These stats are not updated atomically in the kernel;
+ * adjust the total as neeeded.
+ */
+ if (totmbufs > m_mbufs)
+ totmbufs = m_mbufs;
+ printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
+ for (mp = mbtypes; mp->mt_name; mp++)
+ if (mbstat.m_mtypes[mp->mt_type]) {
+ seen[mp->mt_type] = YES;
+ printf("\t%u mbufs allocated to %s\n",
+ mbstat.m_mtypes[mp->mt_type], mp->mt_name);
+ }
+ seen[MT_FREE] = YES;
+ for (i = 0; i < nmbtypes; i++)
+ if (!seen[i] && mbstat.m_mtypes[i]) {
+ printf("\t%u mbufs allocated to <mbuf type %d>\n",
+ mbstat.m_mtypes[i], i);
+ }
+ if ((m_mbufs - totmbufs) > 0)
+ printf("\t%lu mbufs allocated to caches\n",
+ m_mbufs - totmbufs);
+ printf("%u/%u mbuf 2KB clusters in use\n",
+ (unsigned int)(mbstat.m_clusters - m_clfree),
+ (unsigned int)mbstat.m_clusters);
+ printf("%u/%u mbuf 4KB clusters in use\n",
+ (unsigned int)(mbstat.m_bigclusters - m_bigclfree),
+ (unsigned int)mbstat.m_bigclusters);
+ if (njcl > 0) {
+ printf("%u/%u mbuf %uKB clusters in use\n",
+ m_16kclusters - m_16kclfree, m_16kclusters,
+ njclbytes/1024);
+ }
+ totused = totmem - totfree;
+ if (totmem == 0)
+ totpct = 0;
+ else if (totused < (ULONG_MAX/100))
+ totpct = (totused * 100)/(double)totmem;
+ else {
+ u_long totmem1 = totmem/100;
+ u_long totused1 = totused/100;
+ totpct = (totused1 * 100)/(double)totmem1;
+ }
+ printf("%lu KB allocated to network (%.1f%% in use)\n",
+ totmem / 1024, totpct);
+ printf("%lu KB returned to the system\n", totreturned / 1024);
+
+ printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
+ printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
+ printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
+
+ free(mb_stat);
+ mb_stat = NULL;
+
+ if (mleak_stat != NULL) {
+ mleak_trace_stat_t *mltr;
+
+ printf("\nmbuf leak detection table:\n");
+ printf("\ttotal captured: %u (one per %u)\n"
+ "\ttotal allocs outstanding: %llu\n"
+ "\tnew hash recorded: %llu allocs, %llu traces\n"
+ "\thash collisions: %llu allocs, %llu traces\n"
+ "\toverwrites: %llu allocs, %llu traces\n"
+ "\tlock conflicts: %llu\n\n",
+ table.mleak_capture / table.mleak_sample_factor,
+ table.mleak_sample_factor,
+ table.outstanding_allocs,
+ table.alloc_recorded, table.trace_recorded,
+ table.alloc_collisions, table.trace_collisions,
+ table.alloc_overwrites, table.trace_overwrites,
+ table.total_conflicts);
+
+ printf("top %d outstanding traces:\n", mleak_stat->ml_cnt);
+ for (i = 0; i < mleak_stat->ml_cnt; i++) {
+ mltr = &mleak_stat->ml_trace[i];
+ printf("[%d] %llu outstanding alloc(s), "
+ "%llu hit(s), %llu collision(s)\n", (i + 1),
+ mltr->mltr_allocs, mltr->mltr_hitcount,
+ mltr->mltr_collisions);
+ }
+
+ printf(MB_LEAK_HDR);
+ for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
+ int j;
+
+ printf("%2d: ", (i + 1));
+ for (j = 0; j < mleak_stat->ml_cnt; j++) {
+ mltr = &mleak_stat->ml_trace[j];
+ if (i < mltr->mltr_depth) {
+ if (mleak_stat->ml_isaddr64) {
+ printf("0x%0llx ",
+ mltr->mltr_addr[i]);
+ } else {
+ printf("0x%08x ",
+ (u_int32_t)mltr->mltr_addr[i]);
+ }
+ } else {
+ printf(MB_LEAK_SPACING);
+ }
+ }
+ printf("\n");
+ }
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+}
+
+static const char *
+mbpr_state(int state)
+{
+ char *msg = "?";
+
+ switch (state) {
+ case MCS_DISABLED:
+ msg = "dis";
+ break;
+
+ case MCS_ONLINE:
+ msg = "on";
+ break;
+
+ case MCS_PURGING:
+ msg = "purge";
+ break;
+
+ case MCS_OFFLINE:
+ msg = "off";
+ break;
+ }
+ return (msg);
+}
+
+static const char *
+mbpr_mem(u_int32_t bytes)
+{
+ static char buf[33];
+ double mem = bytes;
+
+ if (mem < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
+ } else if ((mem /= 1024) < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
+ } else {
+ mem /= 1024;
+ (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
+ }
+ return (buf);
+}
+
+static int
+mbpr_getdata(void)
+{
+ size_t len;
+ int error = -1;
+
+ if (nmbtypes != 256) {
+ (void) fprintf(stderr,
+ "netstat: unexpected change to mbstat; check source\n");
+ goto done;
+ }
+
+ len = sizeof(mbstat);
+ if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
+ goto done;
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ mb_stat = calloc(1, len);
+ if (mb_stat == NULL) {
+ (void) fprintf(stderr,
+ "Error allocating %lu bytes for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ if (mb_stat->mbs_cnt == 0) {
+ (void) fprintf(stderr,
+ "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
+ goto done;
+ }
+
+ /* mbuf leak detection! */
+ if (mflag > 3) {
+ errno = 0;
+ len = sizeof (table);
+ if (sysctlbyname(KERN_IPC_MLEAK_TABLE, &table, &len, 0, 0) ==
+ -1 && errno != ENXIO) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TABLE);
+ goto done;
+ } else if (errno == ENXIO) {
+ (void) fprintf(stderr, "mbuf leak detection is not "
+ "enabled in the kernel.\n");
+ goto skip;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, NULL, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "Error retrieving length for "
+ "%s: %d\n", KERN_IPC_MB_STAT, errno);
+ goto done;
+ }
+
+ mleak_stat = calloc(1, len);
+ if (mleak_stat == NULL) {
+ (void) fprintf(stderr, "Error allocating %lu bytes "
+ "for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, mleak_stat, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TOP_TRACE);
+ goto done;
+ }
+ }
+
+skip:
+ len = sizeof (njcl);
+ (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
+ len = sizeof (njclbytes);
+ (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
+
+ error = 0;
+
+done:
+ if (error != 0 && mb_stat != NULL) {
+ free(mb_stat);
+ mb_stat = NULL;
+ }
+
+ if (error != 0 && mleak_stat != NULL) {
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+
+ return (error);
+}
diff --git a/network_cmds/netstat.tproj/mcast.c b/network_cmds/netstat.tproj/mcast.c
new file mode 100644
index 0000000..3637f4d
--- /dev/null
+++ b/network_cmds/netstat.tproj/mcast.c
@@ -0,0 +1,887 @@
+/*
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 2007 Bruce M. Simpson <bms@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * Print the running system's current multicast group memberships.
+ * As this relies on getifmaddrs(), it may not be used with a core file.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/igmp_var.h>
+#include <netinet6/mld6_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <ifaddrs.h>
+#include <sysexits.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+
+#include "netstat.h"
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+typedef union sockunion sockunion_t;
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+//struct ifmaddrs {
+// struct ifmaddrs *ifma_next;
+// struct sockaddr *ifma_name;
+// struct sockaddr *ifma_addr;
+// struct sockaddr *ifma_lladdr;
+//};
+
+void ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af);
+static int ifmalist_dump_mcstat(struct ifmaddrs *);
+static void in_ifinfo(struct igmp_ifinfo *);
+static const char *inm_mode(u_int);
+static void inm_print_sources_sysctl(uint32_t, struct in_addr);
+#ifdef INET6
+static void in6_ifinfo(struct mld_ifinfo *);
+static void in6m_print_sources_sysctl(uint32_t, struct in6_addr *);
+static const char *inet6_n2a(struct in6_addr *);
+#endif
+static void printb(const char *, unsigned int, const char *);
+static const char *sdl_addr_to_hex(const struct sockaddr_dl *, char *, int);
+
+extern char *routename6(struct sockaddr_in6 *);
+
+#define sa_equal(a1, a2) \
+ (bcmp((a1), (a2), ((a1))->sa_len) == 0)
+
+#define sa_dl_equal(a1, a2) \
+ ((((struct sockaddr_dl *)(a1))->sdl_len == \
+ ((struct sockaddr_dl *)(a2))->sdl_len) && \
+ (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \
+ LLADDR((struct sockaddr_dl *)(a2)), \
+ ((struct sockaddr_dl *)(a1))->sdl_alen) == 0))
+
+#define SALIGN (sizeof(uint32_t) - 1)
+#define SA_RLEN(sa) (sa ? ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+ (SALIGN + 1)) : 0)
+#define MAX_SYSCTL_TRY 5
+#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+void
+ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af)
+{
+ const struct ifmaddrs *ifma;
+ sockunion_t *psa;
+ char myifname[IFNAMSIZ];
+ char *pcolon;
+ char *pafname, *pifname, *plladdr = NULL, *pgroup = NULL;
+
+ switch (af) {
+ case AF_INET:
+ pafname = "IPv4";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pafname = "IPv6";
+ break;
+#endif
+ case AF_LINK:
+ pafname = "Link-layer";
+ break;
+ default:
+ return; /* XXX */
+ }
+
+ fprintf(stdout, "%s Multicast Group Memberships\n", pafname);
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", "Group", "Link-layer Address",
+ "Netif");
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ /* Group address */
+ psa = (sockunion_t *)ifma->ifma_addr;
+ if (psa->sa.sa_family != af)
+ continue;
+
+ switch (psa->sa.sa_family) {
+ case AF_INET:
+ pgroup = inet_ntoa(psa->sin.sin_addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pgroup = routename6(&(psa->sin6));
+ break;
+#endif
+ case AF_LINK:
+ if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
+ (psa->sdl.sdl_type == IFT_ETHER)) {
+ pgroup =
+ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+#ifdef notyet
+ } else {
+ pgroup = addr2ascii(AF_LINK,
+ &psa->sdl,
+ sizeof(struct sockaddr_dl),
+ addrbuf);
+#endif
+ }
+ break;
+ default:
+ continue; /* XXX */
+ }
+
+ /* Link-layer mapping, if any */
+ psa = (sockunion_t *)ifma->ifma_lladdr;
+ if (psa != NULL) {
+ if (psa->sa.sa_family == AF_LINK) {
+ if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
+ (psa->sdl.sdl_type == IFT_ETHER)) {
+ /* IEEE 802 */
+ plladdr =
+ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+#ifdef notyet
+ } else {
+ /* something more exotic */
+ plladdr = addr2ascii(AF_LINK,
+ &psa->sdl,
+ sizeof(struct sockaddr_dl),
+ addrbuf);
+#endif
+ }
+ } else {
+ int i;
+
+ /* not a link-layer address */
+ plladdr = "<invalid>";
+
+ for (i = 0; psa->sa.sa_len > 2 && i < psa->sa.sa_len - 2; i++)
+ printf("0x%x ", psa->sa.sa_data[i]);
+ printf("\n");
+ }
+ } else {
+ plladdr = "<none>";
+ }
+
+ /* Interface upon which the membership exists */
+ psa = (sockunion_t *)ifma->ifma_name;
+ if (psa != NULL && psa->sa.sa_family == AF_LINK) {
+ strlcpy(myifname, link_ntoa(&psa->sdl), sizeof(myifname));
+ pcolon = strchr(myifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+ pifname = myifname;
+ } else {
+ pifname = "";
+ }
+
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", pgroup, plladdr, pifname);
+ }
+}
+
+void
+ifmalist_dump(void)
+{
+ struct ifmaddrs *ifmap;
+
+ if (getifmaddrs(&ifmap))
+ err(EX_OSERR, "getifmaddrs");
+
+ ifmalist_dump_af(ifmap, AF_LINK);
+ fputs("\n", stdout);
+ ifmalist_dump_af(ifmap, AF_INET);
+#ifdef INET6
+ fputs("\n", stdout);
+ ifmalist_dump_af(ifmap, AF_INET6);
+#endif
+ if (sflag) {
+ fputs("\n", stdout);
+ ifmalist_dump_mcstat(ifmap);
+ }
+
+ freeifmaddrs(ifmap);
+}
+
+static int
+ifmalist_dump_mcstat(struct ifmaddrs *ifmap)
+{
+ char thisifname[IFNAMSIZ];
+ char addrbuf[NI_MAXHOST];
+ struct ifaddrs *ifap, *ifa;
+ struct ifmaddrs *ifma;
+ sockunion_t lastifasa;
+ sockunion_t *psa, *pgsa, *pllsa, *pifasa;
+ char *pcolon;
+ char *pafname;
+ uint32_t lastifindex, thisifindex;
+ int error;
+ uint32_t ifindex = 0;
+
+ if (interface != NULL)
+ ifindex = if_nametoindex(interface);
+
+ error = 0;
+ ifap = NULL;
+ lastifindex = 0;
+ thisifindex = 0;
+ lastifasa.ss.ss_family = AF_UNSPEC;
+
+ if (getifaddrs(&ifap) != 0) {
+ warn("getifmaddrs");
+ return (-1);
+ }
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+ error = 0;
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ psa = (sockunion_t *)ifma->ifma_name;
+ if (psa->sa.sa_family != AF_LINK) {
+ fprintf(stderr,
+ "WARNING: Kernel returned invalid data.\n");
+ error = -1;
+ break;
+ }
+
+ /* Filter on interface name. */
+ thisifindex = psa->sdl.sdl_index;
+ if (ifindex != 0 && thisifindex != ifindex)
+ continue;
+
+ /* Filter on address family. */
+ pgsa = (sockunion_t *)ifma->ifma_addr;
+ if (af != 0 && pgsa->sa.sa_family != af)
+ continue;
+
+ strlcpy(thisifname, link_ntoa(&psa->sdl), sizeof(thisifname));
+ pcolon = strchr(thisifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+
+ /* Only print the banner for the first ifmaddrs entry. */
+ if (lastifindex == 0 || lastifindex != thisifindex) {
+ lastifindex = thisifindex;
+ fprintf(stdout, "%s:\n", thisifname);
+ }
+
+ /*
+ * Currently, multicast joins only take place on the
+ * primary IPv4 address, and only on the link-local IPv6
+ * address, as per IGMPv2/3 and MLDv1/2 semantics.
+ * Therefore, we only look up the primary address on
+ * the first pass.
+ */
+ pifasa = NULL;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if ((strcmp(ifa->ifa_name, thisifname) != 0) ||
+ (ifa->ifa_addr == NULL) ||
+ (ifa->ifa_addr->sa_family != pgsa->sa.sa_family))
+ continue;
+ /*
+ * For AF_INET6 only the link-local address should
+ * be returned. If built without IPv6 support,
+ * skip this address entirely.
+ */
+ pifasa = (sockunion_t *)ifa->ifa_addr;
+ if (pifasa->sa.sa_family == AF_INET6
+#ifdef INET6
+ && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)
+#endif
+ ) {
+ pifasa = NULL;
+ continue;
+ }
+ break;
+ }
+ if (pifasa == NULL)
+ continue; /* primary address not found */
+
+ if (!vflag && pifasa->sa.sa_family == AF_LINK)
+ continue;
+
+ /* Parse and print primary address, if not already printed. */
+ if (lastifasa.ss.ss_family == AF_UNSPEC ||
+ ((lastifasa.ss.ss_family == AF_LINK &&
+ !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) ||
+ !sa_equal(&lastifasa.sa, &pifasa->sa))) {
+
+ switch (pifasa->sa.sa_family) {
+ case AF_INET:
+ pafname = "inet";
+ break;
+ case AF_INET6:
+ pafname = "inet6";
+ break;
+ case AF_LINK:
+ pafname = "link";
+ break;
+ default:
+ pafname = "unknown";
+ break;
+ }
+
+ switch (pifasa->sa.sa_family) {
+ case AF_INET6:
+#ifdef INET6
+ {
+ const char *p =
+ inet6_n2a(&pifasa->sin6.sin6_addr);
+ strlcpy(addrbuf, p, sizeof(addrbuf));
+ break;
+ }
+#else
+ /* FALLTHROUGH */
+#endif
+ case AF_INET:
+ error = getnameinfo(&pifasa->sa,
+ pifasa->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error)
+ printf("getnameinfo: %s\n",
+ gai_strerror(error));
+ break;
+ case AF_LINK: {
+ (void) sdl_addr_to_hex(&pifasa->sdl, addrbuf,
+ sizeof (addrbuf));
+ break;
+ }
+ default:
+ addrbuf[0] = '\0';
+ break;
+ }
+
+ fprintf(stdout, "\t%s %s\n", pafname, addrbuf);
+ /*
+ * Print per-link IGMP information, if available.
+ */
+ if (pifasa->sa.sa_family == AF_INET) {
+ struct igmp_ifinfo igi;
+ size_t mibsize, len;
+ int mib[5];
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.igmp.ifinfo",
+ mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ goto next_ifnet;
+ }
+ mib[mibsize] = thisifindex;
+ len = sizeof(struct igmp_ifinfo);
+ if (sysctl(mib, mibsize + 1, &igi, &len, NULL,
+ 0) == -1) {
+ perror("sysctl net.inet.igmp.ifinfo");
+ goto next_ifnet;
+ }
+ in_ifinfo(&igi);
+ }
+#ifdef INET6
+ /*
+ * Print per-link MLD information, if available.
+ */
+ if (pifasa->sa.sa_family == AF_INET6) {
+ struct mld_ifinfo mli;
+ size_t mibsize, len;
+ int mib[5];
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet6.mld.ifinfo",
+ mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ goto next_ifnet;
+ }
+ mib[mibsize] = thisifindex;
+ len = sizeof(struct mld_ifinfo);
+ if (sysctl(mib, mibsize + 1, &mli, &len, NULL,
+ 0) == -1) {
+ perror("sysctl net.inet6.mld.ifinfo");
+ goto next_ifnet;
+ }
+ in6_ifinfo(&mli);
+ }
+#endif /* INET6 */
+#if defined(INET6)
+next_ifnet:
+#endif
+ lastifasa = *pifasa;
+ }
+
+ /* Print this group address. */
+#ifdef INET6
+ if (pgsa->sa.sa_family == AF_INET6) {
+ const char *p = inet6_n2a(&pgsa->sin6.sin6_addr);
+ strlcpy(addrbuf, p, sizeof(addrbuf));
+ } else
+#endif
+ if (pgsa->sa.sa_family == AF_INET) {
+ error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
+ if (error)
+ printf("getnameinfo: %s\n",
+ gai_strerror(error));
+ } else {
+ (void) sdl_addr_to_hex(&pgsa->sdl, addrbuf,
+ sizeof (addrbuf));
+ }
+
+ fprintf(stdout, "\t\tgroup %s", addrbuf);
+ if (pgsa->sa.sa_family == AF_INET) {
+ inm_print_sources_sysctl(thisifindex,
+ pgsa->sin.sin_addr);
+ }
+#ifdef INET6
+ if (pgsa->sa.sa_family == AF_INET6) {
+ in6m_print_sources_sysctl(thisifindex,
+ &pgsa->sin6.sin6_addr);
+ }
+#endif
+ fprintf(stdout, "\n");
+
+ /* Link-layer mapping, if present. */
+ pllsa = (sockunion_t *)ifma->ifma_lladdr;
+ if (pllsa != NULL) {
+ (void) sdl_addr_to_hex(&pllsa->sdl, addrbuf,
+ sizeof (addrbuf));
+ fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf);
+ }
+ }
+
+ if (ifap != NULL)
+ freeifaddrs(ifap);
+
+ return (error);
+}
+
+static void
+in_ifinfo(struct igmp_ifinfo *igi)
+{
+
+ printf("\t");
+ switch (igi->igi_version) {
+ case IGMP_VERSION_1:
+ case IGMP_VERSION_2:
+ case IGMP_VERSION_3:
+ printf("igmpv%d", igi->igi_version);
+ break;
+ default:
+ printf("igmpv?(%d)", igi->igi_version);
+ break;
+ }
+ printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK");
+ if (igi->igi_version == IGMP_VERSION_3) {
+ printf(" rv %u qi %u qri %u uri %u",
+ igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri);
+ }
+ if (vflag >= 2) {
+ printf(" v1timer %u v2timer %u v3timer %u",
+ igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer);
+ }
+ printf("\n");
+}
+
+static const char *inm_modes[] = {
+ "undefined",
+ "include",
+ "exclude",
+};
+
+static const char *
+inm_mode(u_int mode)
+{
+
+ if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE)
+ return (inm_modes[mode]);
+ return (NULL);
+}
+
+/*
+ * Retrieve per-group source filter mode and lists via sysctl.
+ */
+static void
+inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina)
+{
+#define MAX_SYSCTL_TRY 5
+ int mib[7];
+ int ntry = 0;
+ size_t mibsize;
+ size_t len;
+ size_t needed;
+ size_t cnt;
+ int i;
+ char *buf;
+ struct in_addr *pina;
+ uint32_t *p;
+ uint32_t fmode;
+ const char *modestr;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+ mib[6] = gina.s_addr; /* 32 bits wide */
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.inet.ip.mcast.filters");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ if (len < sizeof(uint32_t)) {
+ perror("sysctl");
+ goto out_free;
+ }
+
+ p = (uint32_t *)buf;
+ fmode = *p++;
+ len -= sizeof(uint32_t);
+
+ modestr = inm_mode(fmode);
+ if (modestr)
+ printf(" mode %s", modestr);
+ else
+ printf(" mode (%u)", fmode);
+
+ if (vflag == 0)
+ goto out_free;
+
+ cnt = len / sizeof(struct in_addr);
+ pina = (struct in_addr *)p;
+
+ for (i = 0; i < cnt; i++) {
+ if (i == 0)
+ printf(" srcs ");
+ fprintf(stdout, "%s%s", (i == 0 ? "" : ","),
+ inet_ntoa(*pina++));
+ len -= sizeof(struct in_addr);
+ }
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.inet.ip.mcast.filters");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+#ifdef INET6
+
+static void
+in6_ifinfo(struct mld_ifinfo *mli)
+{
+
+ printf("\t");
+ switch (mli->mli_version) {
+ case MLD_VERSION_1:
+ case MLD_VERSION_2:
+ printf("mldv%d", mli->mli_version);
+ break;
+ default:
+ printf("mldv?(%d)", mli->mli_version);
+ break;
+ }
+ printb(" flags", mli->mli_flags, "\020\1SILENT");
+ if (mli->mli_version == MLD_VERSION_2) {
+ printf(" rv %u qi %u qri %u uri %u",
+ mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri);
+ }
+ if (vflag >= 2) {
+ printf(" v1timer %u v2timer %u", mli->mli_v1_timer,
+ mli->mli_v2_timer);
+ }
+ printf("\n");
+}
+
+/*
+ * Retrieve MLD per-group source filter mode and lists via sysctl.
+ *
+ * Note: The 128-bit IPv6 group addres needs to be segmented into
+ * 32-bit pieces for marshaling to sysctl. So the MIB name ends
+ * up looking like this:
+ * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3]
+ * Assumes that pgroup originated from the kernel, so its components
+ * are already in network-byte order.
+ */
+static void
+in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup)
+{
+#define MAX_SYSCTL_TRY 5
+ char addrbuf[INET6_ADDRSTRLEN];
+ int mib[10];
+ int ntry = 0;
+ int *pi;
+ size_t mibsize;
+ size_t len;
+ size_t needed;
+ size_t cnt;
+ int i;
+ char *buf;
+ struct in6_addr *pina;
+ uint32_t *p;
+ uint32_t fmode;
+ const char *modestr;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib,
+ &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+ pi = (int *)pgroup;
+ for (i = 0; i < 4; i++)
+ mib[6 + i] = *pi++;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.inet6.ip6.mcast.filters");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ if (len < sizeof(uint32_t)) {
+ perror("sysctl");
+ goto out_free;
+ }
+
+ p = (uint32_t *)buf;
+ fmode = *p++;
+ len -= sizeof(uint32_t);
+
+ modestr = inm_mode(fmode);
+ if (modestr)
+ printf(" mode %s", modestr);
+ else
+ printf(" mode (%u)", fmode);
+
+ if (vflag == 0)
+ goto out_free;
+
+ cnt = len / sizeof(struct in6_addr);
+ pina = (struct in6_addr *)p;
+
+ for (i = 0; i < cnt; i++) {
+ if (i == 0)
+ printf(" srcs ");
+ inet_ntop(AF_INET6, (const char *)pina++, addrbuf,
+ INET6_ADDRSTRLEN);
+ fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf);
+ len -= sizeof(struct in6_addr);
+ }
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.inet6.ip6.mcast.filters");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+static const char *
+inet6_n2a(struct in6_addr *p)
+{
+ static char buf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+ u_int32_t scopeid;
+ const int niflags = NI_NUMERICHOST;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *p;
+ if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
+ IN6_IS_ADDR_MC_NODELOCAL(p)) {
+ scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ if (scopeid) {
+ sin6.sin6_scope_id = scopeid;
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+ }
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ buf, sizeof(buf), NULL, 0, niflags) == 0) {
+ return (buf);
+ } else {
+ return ("(invalid)");
+ }
+}
+#endif /* INET6 */
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+void
+printb(const char *s, unsigned int v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}
+
+/*
+ * convert hardware address to hex string for logging errors.
+ */
+static const char *
+sdl_addr_to_hex(const struct sockaddr_dl *sdl, char *orig_buf, int buflen)
+{
+ char *buf = orig_buf;
+ int i;
+ const u_char *lladdr;
+ int maxbytes = buflen / 3;
+
+ lladdr = (u_char *)(size_t)sdl->sdl_data + sdl->sdl_nlen;
+
+ if (maxbytes > sdl->sdl_alen) {
+ maxbytes = sdl->sdl_alen;
+ }
+ *buf = '\0';
+ for (i = 0; i < maxbytes; i++) {
+ snprintf(buf, 3, "%02x", lladdr[i]);
+ buf += 2;
+ *buf = (i == maxbytes - 1) ? '\0' : ':';
+ buf++;
+ }
+ return (orig_buf);
+}
+
diff --git a/network_cmds/netstat.tproj/misc.c b/network_cmds/netstat.tproj/misc.c
new file mode 100644
index 0000000..ac2a2ca
--- /dev/null
+++ b/network_cmds/netstat.tproj/misc.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/sysctl.h>
+
+#include <net/net_api_stats.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "netstat.h"
+
+void
+print_net_api_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct net_api_stats pnet_api_stats;
+ struct net_api_stats net_api_stats;
+ size_t len = sizeof(struct net_api_stats);
+ const char *mibvar = "net.api_stats";
+
+ if (sysctlbyname(mibvar, &net_api_stats, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (net_api_stats.f - pnet_api_stats.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p(nas_iflt_attach_count, "\t%lld interface filter%s currently attached\n");
+ p(nas_iflt_attach_total, "\t%lld interface filter%s attached since boot\n");
+ p(nas_iflt_attach_os_total, "\t%lld interface filter%s attached since boot by OS\n");
+
+ p(nas_ipf_add_count, "\t%lld IP filter%s currently attached\n");
+ p(nas_ipf_add_total, "\t%lld IP filter%s attached since boot\n");
+ p(nas_ipf_add_os_total, "\t%lld IP filter%s attached since boot by OS\n");
+
+ p(nas_sfltr_register_count, "\t%lld socket filter%s currently attached\n");
+ p(nas_sfltr_register_total, "\t%lld socket filter%s attached since boot\n");
+ p(nas_sfltr_register_os_total, "\t%lld socket filter%s attached since boot by OS\n");
+
+ p(nas_socket_alloc_total, "\t%lld socket%s allocated since boot\n");
+ p(nas_socket_in_kernel_total, "\t%lld socket%s allocated in-kernel since boot\n");
+ p(nas_socket_in_kernel_os_total, "\t%lld socket%s allocated in-kernel by OS\n");
+ p(nas_socket_necp_clientuuid_total, "\t%lld socket%s with NECP client UUID since boot\n");
+
+ p(nas_socket_domain_local_total, "\t%lld local domain socket%s allocated since boot\n");
+ p(nas_socket_domain_route_total, "\t%lld route domain socket%s allocated since boot\n");
+ p(nas_socket_domain_inet_total, "\t%lld inet domain socket%s allocated since boot\n");
+ p(nas_socket_domain_inet6_total, "\t%lld inet6 domain socket%s allocated since boot\n");
+ p(nas_socket_domain_system_total, "\t%lld system domain socket%s allocated since boot\n");
+ p(nas_socket_domain_multipath_total, "\t%lld multipath domain socket%s allocated since boot\n");
+ p(nas_socket_domain_key_total, "\t%lld key domain socket%s allocated since boot\n");
+ p(nas_socket_domain_ndrv_total, "\t%lld ndrv domain socket%s allocated since boot\n");
+ p(nas_socket_domain_other_total, "\t%lld other domains socket%s allocated since boot\n");
+
+ p(nas_socket_inet_stream_total, "\t%lld IPv4 stream socket%s created since boot\n");
+ p(nas_socket_inet_dgram_total, "\t%lld IPv4 datagram socket%s created since boot\n");
+ p(nas_socket_inet_dgram_connected, "\t%lld IPv4 datagram socket%s connected\n");
+ p(nas_socket_inet_dgram_dns, "\t%lld IPv4 DNS socket%s\n");
+ p(nas_socket_inet_dgram_no_data, "\t%lld IPv4 datagram socket%s without data\n");
+
+ p(nas_socket_inet6_stream_total, "\t%lld IPv6 stream socket%s created since boot\n");
+ p(nas_socket_inet6_dgram_total, "\t%lld IPv6 datagram socket%s created since boot\n");
+ p(nas_socket_inet6_dgram_connected, "\t%lld IPv6 datagram socket%s connected\n");
+ p(nas_socket_inet6_dgram_dns, "\t%lld IPv6 DNS socket%s\n");
+ p(nas_socket_inet6_dgram_no_data, "\t%lld IPv6 datagram socket%s without data\n");
+
+ p(nas_socket_mcast_join_total, "\t%lld socket multicast join%s since boot\n");
+ p(nas_socket_mcast_join_os_total, "\t%lld socket multicast join%s since boot by OS\n");
+
+ p(nas_nx_flow_inet_stream_total, "\t%lld IPv4 stream nexus flow%s added since boot\n");
+ p(nas_nx_flow_inet_dgram_total, "\t%lld IPv4 datagram nexus flow%s added since boot\n");
+
+ p(nas_nx_flow_inet6_stream_total, "\t%lld IPv6 stream nexus flow%s added since boot\n");
+ p(nas_nx_flow_inet6_dgram_total, "\t%lld IPv6 datagram nexus flow%s added since boot\n");
+
+ p(nas_ifnet_alloc_count, "\t%lld interface%s currently allocated\n");
+ p(nas_ifnet_alloc_total, "\t%lld interface%s allocated since boot\n");
+ p(nas_ifnet_alloc_os_count, "\t%lld interface%s currently allocated by OS\n");
+ p(nas_ifnet_alloc_os_total, "\t%lld extended interface%s allocated since boot by OS\n");
+
+ p(nas_pf_addrule_total, "\t%lld PF addrule operation%s since boot\n");
+ p(nas_pf_addrule_os, "\t%lld PF addrule operation%s since boot by OS\n");
+
+ p(nas_vmnet_total, "\t%lld vmnet start%s since boot\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
+
diff --git a/network_cmds/netstat.tproj/mptcp.c b/network_cmds/netstat.tproj/mptcp.c
new file mode 100644
index 0000000..70be928
--- /dev/null
+++ b/network_cmds/netstat.tproj/mptcp.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include <stdio.h>
+#include <err.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <inttypes.h>
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/mptcp_var.h>
+
+#include <arpa/inet.h>
+
+#include "netstat.h"
+
+/* XXX we can't include tcp_fsm.h because inet.c already includes it. */
+static const char *tcpstates[] = {
+ "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD",
+ "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING",
+ "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT"
+};
+
+static const char *mptcpstates[] = {
+ "CLOSED", "LISTEN", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1",
+ "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", "TERMINATE"
+};
+
+int mptcp_done = 0;
+extern void inetprint (struct in_addr *, int, char *, int);
+extern void inet6print (struct in6_addr *, int, char *, int);
+
+static void
+printmptcp(int id, conninfo_mptcp_t *mptcp)
+{
+ int i;
+ conninfo_tcp_t *tcpci;
+ struct sockaddr_storage *src, *dst;
+ mptcp_flow_t *flow;
+ int af;
+
+ printf("mptcp/%-2.2d %-8.8x/%-8.8x %50s \n"
+ " [tok(%#"PRIx32") snd(%#"PRIx64") rcv(%#"PRIx64") "
+ "aid(%d)]\n", id,
+ mptcp->mptcpci_mpte_flags, mptcp->mptcpci_flags,
+ mptcpstates[mptcp->mptcpci_state], mptcp->mptcpci_rtoken,
+ mptcp->mptcpci_sndnxt, mptcp->mptcpci_rcvnxt,
+ mptcp->mptcpci_mpte_addrid);
+
+ flow = (mptcp_flow_t*)((caddr_t)mptcp + mptcp->mptcpci_flow_offset);
+
+ for (i = 0; i < mptcp->mptcpci_nflows; i++) {
+ src = &flow->flow_src;
+ dst = &flow->flow_dst;
+ af = src->ss_family;
+ printf(" tcp%d/%-2.2d ", af == AF_INET ? 4 : 6,
+ flow->flow_cid);
+ printf("%-8.8x ", flow->flow_flags);
+#define SIN(x) ((struct sockaddr_in *)(x))
+#define SIN6(x) ((struct sockaddr_in6 *)(x))
+ switch (af) {
+ case AF_INET:
+ inetprint(&SIN(src)->sin_addr, SIN(src)->sin_port,
+ "tcp", nflag);
+ inetprint(&SIN(dst)->sin_addr, SIN(dst)->sin_port,
+ "tcp", nflag);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ inet6print(&SIN6(src)->sin6_addr, SIN6(src)->sin6_port,
+ "tcp", nflag);
+ inet6print(&SIN6(dst)->sin6_addr, SIN6(dst)->sin6_port,
+ "tcp", nflag);
+ break;
+ }
+#endif
+#undef SIN
+#undef SIN6
+ tcpci = (conninfo_tcp_t*)((caddr_t)flow +
+ flow->flow_tcpci_offset);
+ printf("%s \n"
+ " [relseq(%-4.4d), err(%d)]\n",
+ tcpstates[tcpci->tcpci_tcp_info.tcpi_state],
+ flow->flow_relseq,
+ flow->flow_soerror);
+
+ flow = (mptcp_flow_t*)((caddr_t)flow + flow->flow_len);
+ }
+}
+
+void
+mptcppr(uint32_t off, char *name, int af)
+{
+#pragma unused(off, name, af)
+ const char *mibvar = "net.inet.mptcp.pcblist";
+ size_t len = 0;
+ conninfo_mptcp_t *mptcp;
+ char *buf, *bufp;
+ int id = 0;
+
+ if (Lflag || Aflag || mptcp_done)
+ return;
+ mptcp_done = 1;
+
+ if (sysctlbyname(mibvar, 0, &len, NULL, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == NULL) {
+ warn("malloc");
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, NULL, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ printf("Active Multipath Internet connections\n");
+ printf("%-8.8s %-9.9s %-22.22s %-22.22s %-11.11s\n",
+ "Proto/ID", "Flags",
+ "Local Address", "Foreign Address",
+ "(state)");
+
+ bufp = buf;
+ while (bufp < buf + len) {
+ /* Sanity check */
+ if (buf + len - bufp < sizeof(conninfo_mptcp_t))
+ break;
+ mptcp = (conninfo_mptcp_t *)bufp;
+ printmptcp(id++, mptcp);
+ bufp += mptcp->mptcpci_len;
+ }
+ free(buf);
+}
diff --git a/network_cmds/netstat.tproj/netstat.1 b/network_cmds/netstat.tproj/netstat.1
new file mode 100644
index 0000000..61ab843
--- /dev/null
+++ b/network_cmds/netstat.tproj/netstat.1
@@ -0,0 +1,445 @@
+.\" Copyright (c) 2015 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1983, 1990, 1992, 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.
+.\"
+.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/netstat/netstat.1,v 1.22.2.7 2001/08/10 09:07:09 ru Exp $
+.\"
+.Dd June 15, 2001
+.Dt NETSTAT 1
+.Os Darwin
+.Sh NAME
+.Nm netstat
+.Nd show network status
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaLlnW
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Nm
+.Op Fl gilns
+.Op Fl v
+.Op Fl f Ar address_family
+.Op Fl I Ar interface
+.Nm
+.Fl i | I Ar interface
+.Op Fl w Ar wait
+.Op Fl c Ar queue
+.Op Fl abdgqRtS
+.Nm
+.Fl s Op Fl s
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Op Fl w Ar wait
+.Nm
+.Fl i | I Ar interface Fl s
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Nm
+.Fl m
+.Op Fl m
+.Nm
+.Fl r
+.Op Fl Aaln
+.Op Fl f Ar address_family
+.Nm
+.Fl rs
+.Op Fl s
+.\"-----------------------------------------------------------------------------------------
+.Sh DESCRIPTION
+.\"-----------------------------------------------------------------------------------------
+The
+.Nm
+command symbolically displays the contents of various network-related data structures.
+There are a number of output formats, depending on the options for the information presented.
+The first form of the command displays a list of active sockets for each protocol.
+The second form presents the contents of one of the other network data structures according
+to the option selected. Using the third form, with a
+.Ar wait
+interval specified,
+.Nm
+will continuously display the information regarding packet traffic on the configured network
+interfaces. The fourth form displays statistics for the specified protocol or address family. If a
+.Ar wait
+interval is specified, the protocol information over the last interval seconds will be displayed.
+The fifth form displays per-interface statistics for the specified protocol or address family.
+The sixth form displays
+.Xr mbuf 9
+statistics. The seventh form displays routing table for the specified address family. The
+eighth form displays routing statistics.
+.Pp
+The options have the following meaning:
+.Bl -tag -width flag
+.It Fl A
+With the default display, show the address of any protocol control blocks associated with
+sockets and the flow hash; used for debugging.
+.It Fl a
+With the default display, show the state of all sockets; normally sockets used by server
+processes are not shown. With the routing table display (option
+.Fl r ,
+as described below), show protocol-cloned routes (routes generated by a
+.Dv RTF_PRCLONING
+parent route); normally these routes are not shown.
+.It Fl b
+With the interface display (option
+.Fl i ,
+as described below), show the number of bytes in and out.
+.It Fl c Ar queue
+With the queue statistics (option
+.Fl q ,
+as described below), show only those for the specified
+.Ar queue .
+.It Fl d
+With either interface display (option
+.Fl i
+or an interval, as described below), show the number of dropped packets.
+.It Fl f Ar address_family
+Limit statistics or address control block reports to those of the specified
+.Ar address family .
+The following address families are recognized:
+.Ar inet ,
+for
+.Dv AF_INET ,
+.Ar inet6 ,
+for
+.Dv AF_INET6
+and
+.Ar unix ,
+for
+.Dv AF_UNIX .
+.It Fl g
+Show information related to multicast (group address) membership. If the
+.Fl s
+option is also present, show extended interface group management statistics. If the
+.Fl v
+option is specified, show link-layer memberships; they are suppressed by default.
+Source lists for each group will also be printed. Specifiying
+.Fl v
+twice will print the control plane timers for each interface and the source list counters
+for each group. If the
+.Fl i
+is specified, only that interface will be shown. If the
+.Fl f
+is specified, only information for the address family will be displayed.
+.It Fl I Ar interface
+Show information about the specified interface; used with a
+.Ar wait
+interval as described below.
+If the
+.Fl s
+option is present, show per-interface protocol statistics on the
+.Ar interface
+for the specified
+.Ar address_family
+or
+.Ar protocol ,
+or for all protocol families.
+.It Fl i
+Show the state of interfaces which have been auto-configured (interfaces statically
+configured into a system, but not located at boot time are not shown). If the
+.Fl a
+options is also present, multicast addresses currently in use are shown for each
+Ethernet interface and for each IP interface address. Multicast addresses are shown
+on separate lines following the interface address with which they are associated.
+If the
+.Fl s
+option is present, show per-interface statistics on all interfaces for the specified
+.Ar address_family
+or
+.Ar protocol ,
+or for all protocol families.
+.It Fl L
+Show the size of the various listen queues. The first count shows the number of
+unaccepted connections. The second count shows the amount of unaccepted incomplete
+connections. The third count is the maximum number of queued connections.
+.It Fl l
+Print full IPv6 address.
+.It Fl m
+Show statistics recorded by the memory management routines (the network stack manages a private pool of memory buffers). More detailed information about the buffers, which includes their cache related statistics, can be obtained by using
+.Fl mm
+or
+.Fl m
+.Fl m
+option.
+.It Fl n
+Show network addresses as numbers (normally
+.Nm
+interprets addresses and attempts to display them symbolically). This option may be
+used with any of the display formats.
+.It Fl p Ar protocol
+Show statistics about
+.Ar protocol ,
+which is either a well-known name for a protocol or an alias for it. Some protocol
+names and aliases are listed in the file
+.Pa /etc/protocols .
+The special protocol name
+.Dq bdg
+is used to show bridging statistics. A null response typically means that there are
+no interesting numbers to report. The program will complain if
+.Ar protocol
+is unknown or if there is no statistics routine for it.
+.It Fl q
+Show network interface send queue statistics. By default all queues are displayed, unless
+specified with
+.Fl c .
+This option requires specifying an interface with
+.Fl I
+option. More detailed information about the queues, which includes their queueing algorithm related statistics, can be obtained by using
+.Fl qq
+or
+.Fl q
+.Fl q
+option.
+.It Fl r
+Show the routing tables. Use with
+.Fl a
+to show protocol-cloned routes. When
+.Fl s
+is also present, show routing statistics instead. When
+.Fl l
+is also present,
+.Nm
+assumes more columns are there and the maximum transmission unit.
+More detailed information about the route metrics are displayed with
+.Fl ll
+for TCP round trip times
+.Fl lll
+for all metrics.
+Use the
+.Fl z
+flags to display only entries with non-zero RTT values.
+.Pq Dq mtu
+are also displayed.
+.It Fl R
+Show reachability information. Use with
+.Fl i
+to show link-layer reachability information for a given interface.
+.It Fl s
+Show per-protocol statistics. If this option is repeated, counters with a value of
+zero are suppressed. For security reasons, root privileges are required to read TCP statistics and in the absence of such privileges all TCP counters will be reported as zero.
+.It Fl S
+Show interface link status and interface state information about the specified interface. This option requires specifying an interface with
+.Fl I
+option.
+.It Fl v
+Increase verbosity level.
+.It Fl W
+In certain displays, avoid truncating addresses even if this causes some fields to
+overflow.
+.It Fl w Ar wait
+Show network interface or protocol statistics at intervals of
+.Ar wait
+seconds.
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl R
+flag.
+.El
+.Pp
+.\"-------------------------------------------------------------------------------
+.Sh OUTPUT
+.\"-------------------------------------------------------------------------------
+The default display, for active sockets, shows the local and remote addresses,
+send and receive queue sizes (in bytes), protocol, and the internal state of
+the protocol. Address formats are of the form
+.Dq host.port
+or
+.Dq network.port
+if a socket's address specifies a network but no specific host address.
+If known, the host and network addresses are displayed symbolically
+according to the databases
+.Pa /etc/hosts
+and
+.Pa /etc/networks ,
+respectively. If a symbolic name for an address is unknown, or if the
+.Fl n
+option is specified, the address is printed numerically, according to the
+address family. For more information regarding the Internet
+.Dq dot format ,
+refer to
+.Xr inet 3 ) .
+Unspecified,
+or
+.Dq wildcard ,
+addresses and ports appear as
+.Dq * .
+.Pp
+Internet domain socket states:
+.Bl -column X LISTEN
+CLOSED: The socket is not in use.
+.Pp
+LISTEN: The socket is listening for incoming connections. Unconnected
+listening sockets like these are only displayed when using the -a option.
+.Pp
+SYN_SENT: The socket is actively trying to establish a connection to a
+remote peer.
+.Pp
+SYN_RCVD: The socket has passively received a connection request from a
+remote peer.
+.Pp
+ESTABLISHED: The socket has an established connection between a local
+application and a remote peer.
+.Pp
+CLOSE_WAIT: The socket connection has been closed by the remote peer,
+and the system is waiting for the local application to close its half of
+the connection.
+.Pp
+LAST_ACK: The socket connection has been closed by the remote peer, the
+local application has closed its half of the connection, and the system
+is waiting for the remote peer to acknowledge the close.
+.Pp
+FIN_WAIT_1: The socket connection has been closed by the local
+application, the remote peer has not yet acknowledged the close, and the
+system is waiting for it to close its half of the connection.
+.Pp
+FIN_WAIT_2: The socket connection has been closed by the local
+application, the remote peer has acknowledged the close, and the system
+is waiting for it to close its half of the connection.
+.Pp
+CLOSING: The socket connection has been closed by the local application
+and the remote peer simultaneously, and the remote peer has not yet
+acknowledged the close attempt of the local application.
+.Pp
+TIME_WAIT: The socket connection has been closed by the local
+application, the remote peer has closed its half of the connection, and
+the system is waiting to be sure that the remote peer received the last
+acknowledgement.
+.El
+.Pp
+The interface display provides a table of cumulative statistics regarding
+packets transferred, errors, and collisions. The network addresses of the
+interface and the maximum transmission unit
+.Pq Dq mtu
+are also displayed.
+.Pp
+The routing table display indicates the available routes and their status.
+Each route consists of a destination host or network and a gateway to use
+in forwarding packets. The flags field shows a collection of information
+about the route stored as binary choices. The individual flags are discussed
+in more detail in the
+.Xr route 8
+and
+.Xr route 4
+manual pages. The mapping between letters and flags is:
+.Bl -column XXXX RTF_BLACKHOLE
+1 RTF_PROTO1 Protocol specific routing flag #1
+2 RTF_PROTO2 Protocol specific routing flag #2
+3 RTF_PROTO3 Protocol specific routing flag #3
+B RTF_BLACKHOLE Just discard packets (during updates)
+b RTF_BROADCAST The route represents a broadcast address
+C RTF_CLONING Generate new routes on use
+c RTF_PRCLONING Protocol-specified generate new routes on use
+D RTF_DYNAMIC Created dynamically (by redirect)
+G RTF_GATEWAY Destination requires forwarding by intermediary
+H RTF_HOST Host entry (net otherwise)
+I RTF_IFSCOPE Route is associated with an interface scope
+i RTF_IFREF Route is holding a reference to the interface
+L RTF_LLINFO Valid protocol to link address translation
+M RTF_MODIFIED Modified dynamically (by redirect)
+m RTF_MULTICAST The route represents a multicast address
+R RTF_REJECT Host or net unreachable
+r RTF_ROUTER Host is a default router
+S RTF_STATIC Manually added
+U RTF_UP Route usable
+W RTF_WASCLONED Route was generated as a result of cloning
+X RTF_XRESOLVE External daemon translates proto to link address
+Y RTF_PROXY Proxying; cloned routes will not be scoped
+.El
+.Pp
+Direct routes are created for each interface attached to the local host;
+the gateway field for such entries shows the address of the outgoing
+interface. The refcnt field gives the current number of active uses of
+the route. Connection oriented protocols normally hold on to a single
+route for the duration of a connection while connectionless protocols
+obtain a route while sending to the same destination. The use field
+provides a count of the number of packets sent using that route. The
+interface entry indicates the network interface utilized for the route.
+A route which is marked with the RTF_IFSCOPE flag is instantiated for
+the corresponding interface. A cloning route which is marked with the
+RTF_PROXY flag will not generate new routes that are associated
+with its interface scope.
+.Pp
+When
+.Nm netstat
+is invoked with the
+.Fl w
+option and a
+.Ar wait
+interval argument, it displays a running count of statistics related to
+network interfaces or protocols. An obsolete version of this option used a numeric
+parameter with no option, and is currently supported for backward
+compatibility. By default, this display summarizes information for all
+interfaces. Information for a specific interface may be displayed with the
+.Fl I
+option.
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr inet 4 ,
+.Xr unix 4 ,
+.Xr hosts 5 ,
+.Xr networks 5 ,
+.Xr protocols 5 ,
+.Xr route 8 ,
+.Xr services 5 ,
+.Xr iostat 8 ,
+.Sh HISTORY
+The
+.Nm netstat
+command appeared in
+.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
+.Sh BUGS
+The notion of errors is ill-defined.
diff --git a/network_cmds/netstat.tproj/netstat.h b/network_cmds/netstat.tproj/netstat.h
new file mode 100644
index 0000000..68511da
--- /dev/null
+++ b/network_cmds/netstat.tproj/netstat.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1992, 1993
+ * 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.
+ *
+ * @(#)netstat.h 8.2 (Berkeley) 1/4/94
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <TargetConditionals.h>
+
+extern int Aflag; /* show addresses of protocol control block */
+extern int aflag; /* show all sockets (including servers) */
+extern int bflag; /* show i/f total bytes in/out */
+extern int cflag; /* show specific classq */
+extern int dflag; /* show i/f dropped packets */
+extern int Fflag; /* show i/f forwarded packets */
+extern int gflag; /* show group (multicast) routing or stats */
+extern int iflag; /* show interfaces */
+extern int lflag; /* show routing table with use and ref */
+extern int Lflag; /* show size of listen queues */
+extern int mflag; /* show memory stats */
+extern int nflag; /* show addresses numerically */
+extern int Rflag; /* show reachability information */
+extern int rflag; /* show routing tables (or routing stats) */
+extern int sflag; /* show protocol statistics */
+extern int prioflag; /* show packet priority statistics */
+extern int tflag; /* show i/f watchdog timers */
+extern int vflag; /* more verbose */
+extern int Wflag; /* wide display */
+extern int qflag; /* Display ifclassq stats */
+extern int Qflag; /* Display opportunistic polling stats */
+extern int xflag; /* show extended link-layer reachability information */
+extern int zflag; /* show only entries with non zero rtt metrics */
+
+extern int cq; /* send classq index (-1 for all) */
+extern int interval; /* repeat interval for i/f stats */
+
+extern char *interface; /* desired i/f for stats, or NULL for all i/fs */
+extern int unit; /* unit number for above */
+
+extern int af; /* address family */
+
+extern char *plural(int);
+extern char *plurales(int);
+extern char *pluralies(int);
+
+extern void protopr(uint32_t, char *, int);
+extern void mptcppr(uint32_t, char *, int);
+extern void tcp_stats(uint32_t, char *, int);
+extern void mptcp_stats(uint32_t, char *, int);
+extern void udp_stats(uint32_t, char *, int);
+extern void ip_stats(uint32_t, char *, int);
+extern void icmp_stats(uint32_t, char *, int);
+extern void igmp_stats(uint32_t, char *, int);
+extern void arp_stats(uint32_t, char *, int);
+#ifdef IPSEC
+extern void ipsec_stats(uint32_t, char *, int);
+#endif
+
+#ifdef INET6
+extern void ip6_stats(uint32_t, char *, int);
+extern void ip6_ifstats(char *);
+extern void icmp6_stats(uint32_t, char *, int);
+extern void icmp6_ifstats(char *);
+extern void rip6_stats(uint32_t, char *, int);
+
+/* forward references */
+struct sockaddr_in6;
+struct in6_addr;
+struct sockaddr;
+
+extern char *routename6(struct sockaddr_in6 *);
+extern char *netname6(struct sockaddr_in6 *, struct sockaddr *);
+#endif /*INET6*/
+
+#ifdef IPSEC
+extern void pfkey_stats(uint32_t, char *, int);
+#endif
+
+extern void systmpr(uint32_t, char *, int);
+extern void kctl_stats(uint32_t, char *, int);
+extern void kevt_stats(uint32_t, char *, int);
+
+extern void mbpr(void);
+
+extern void intpr(void (*)(char *));
+extern void intpr_ri(void (*)(char *));
+extern void intervalpr(void (*)(uint32_t, char *, int), uint32_t,
+ char *, int);
+
+extern void pr_rthdr(int);
+extern void pr_family(int);
+extern void rt_stats(void);
+extern void upHex(char *);
+extern char *routename(uint32_t);
+extern char *netname(uint32_t, uint32_t);
+extern void routepr(void);
+
+extern void unixpr(void);
+extern void aqstatpr(void);
+extern void rxpollstatpr(void);
+extern void vsockpr(uint32_t,char *,int);
+
+extern void ifmalist_dump(void);
+
+extern int print_time(void);
+extern void print_link_status(const char *);
+
+extern void print_extbkidle_stats(uint32_t, char *, int);
+extern void print_nstat_stats(uint32_t, char *, int);
+extern void print_net_api_stats(uint32_t, char *, int);
+
diff --git a/network_cmds/netstat.tproj/route.c b/network_cmds/netstat.tproj/route.c
new file mode 100644
index 0000000..943e3c8
--- /dev/null
+++ b/network_cmds/netstat.tproj/route.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright (c) 2008-2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 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.
+ */
+
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/radix.h>
+
+#include <netinet/in.h>
+
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <time.h>
+#include "netstat.h"
+
+/* alignment constraint for routing socket */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+/*
+ * Definitions for showing gateway flags.
+ */
+struct bits {
+ uint32_t b_mask;
+ char b_val;
+} bits[] = {
+ { RTF_UP, 'U' },
+ { RTF_GATEWAY, 'G' },
+ { RTF_HOST, 'H' },
+ { RTF_REJECT, 'R' },
+ { RTF_DYNAMIC, 'D' },
+ { RTF_MODIFIED, 'M' },
+ { RTF_MULTICAST,'m' },
+ { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_STATIC, 'S' },
+ { RTF_PROTO1, '1' },
+ { RTF_PROTO2, '2' },
+ { RTF_WASCLONED,'W' },
+ { RTF_PRCLONING,'c' },
+ { RTF_PROTO3, '3' },
+ { RTF_BLACKHOLE,'B' },
+ { RTF_BROADCAST,'b' },
+ { RTF_IFSCOPE, 'I' },
+ { RTF_IFREF, 'i' },
+ { RTF_PROXY, 'Y' },
+ { RTF_ROUTER, 'r' },
+ { 0 }
+};
+
+typedef union {
+ uint32_t dummy; /* Helps align structure. */
+ struct sockaddr u_sa;
+ u_short u_data[128];
+} sa_u;
+
+static void np_rtentry __P((struct rt_msghdr2 *));
+static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
+static void p_flags __P((int, char *));
+static uint32_t forgemask __P((uint32_t));
+static void domask __P((char *, uint32_t, uint32_t));
+
+/*
+ * Print address family header before a section of the routing table.
+ */
+void
+pr_family(int af)
+{
+ char *afname;
+
+ switch (af) {
+ case AF_INET:
+ afname = "Internet";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif /*INET6*/
+ case AF_IPX:
+ afname = "IPX";
+ break;
+ default:
+ afname = NULL;
+ break;
+ }
+ if (afname)
+ printf("\n%s:\n", afname);
+ else
+ printf("\nProtocol Family %d:\n", af);
+}
+
+/* column widths; each followed by one space */
+#ifndef INET6
+#define WID_DST(af) 18 /* width of destination column */
+#define WID_GW(af) 18 /* width of gateway column */
+#define WID_RT_IFA(af) 18 /* width of source column */
+#define WID_IF(af) 7 /* width of netif column */
+#else
+#define WID_DST(af) \
+ ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18)
+#define WID_GW(af) \
+ ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18)
+#define WID_RT_IFA(af) \
+ ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39 : 18)) : 18)
+#define WID_IF(af) ((af) == AF_INET6 ? 8 : 7)
+#endif /*INET6*/
+
+/*
+ * Print header for routing table columns.
+ */
+void
+pr_rthdr(int af)
+{
+ if (lflag) {
+ if (lflag > 2)
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+ "%10s %10s %8s %8s %8s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire",
+ "rtt(ms)", "rttvar(ms)", "recvpipe", "sendpipe", "ssthresh");
+ else if (lflag > 1)
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+ "%10s %10s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire",
+ "rtt(ms)", "rttvar(ms)");
+ else
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire");
+ } else {
+ printf("%-*.*s %-*.*s %-10.10s %*.*s %6s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ "Flags", WID_IF(af), WID_IF(af), "Netif", "Expire");
+ }
+}
+
+/*
+ * Print routing tables.
+ */
+void
+routepr(void)
+{
+ size_t extra_space;
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ struct rt_msghdr2 *rtm;
+ int try = 1;
+
+ printf("Routing tables\n");
+
+ again:
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP2;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump estimate");
+ }
+ /* allocate extra space in case the table grows */
+ extra_space = needed / 2;
+ if (needed <= (SIZE_MAX - extra_space)) {
+ needed += extra_space;
+ }
+ if ((buf = malloc(needed)) == 0) {
+ err(2, "malloc(%lu)", (unsigned long)needed);
+ }
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+#define MAX_TRIES 10
+ if (errno == ENOMEM && try < MAX_TRIES) {
+ /* the buffer we provided was too small, try again */
+ free(buf);
+ try++;
+ goto again;
+ }
+ err(1, "sysctl: net.route.0.0.dump");
+ }
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr2 *)next;
+ np_rtentry(rtm);
+ }
+}
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
+ } else {
+ rti_info[i] = NULL;
+ }
+}
+}
+
+static void
+np_rtentry(struct rt_msghdr2 *rtm)
+{
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+ struct sockaddr *rti_info[RTAX_MAX];
+ static int old_fam;
+ int fam = 0;
+ u_short lastindex = 0xffff;
+ static char ifname[IFNAMSIZ + 1];
+ sa_u addr, mask;
+
+ /*
+ * Don't print protocol-cloned routes unless -a.
+ */
+ if ((rtm->rtm_flags & RTF_WASCLONED) &&
+ (rtm->rtm_parentflags & RTF_PRCLONING) &&
+ !aflag) {
+ return;
+ }
+
+ if (lflag > 1 && zflag != 0 && rtm->rtm_rmx.rmx_rtt == 0 && rtm->rtm_rmx.rmx_rttvar == 0)
+ return;
+ fam = sa->sa_family;
+ if (af != AF_UNSPEC && af != fam)
+ return;
+ if (fam != old_fam) {
+ pr_family(fam);
+ pr_rthdr(fam);
+ old_fam = fam;
+ }
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ bzero(&addr, sizeof(addr));
+ if ((rtm->rtm_addrs & RTA_DST))
+ bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
+ bzero(&mask, sizeof(mask));
+ if ((rtm->rtm_addrs & RTA_NETMASK))
+ bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
+ p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags,
+ WID_DST(addr.u_sa.sa_family));
+
+ p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
+ WID_GW(addr.u_sa.sa_family));
+
+ if (lflag && (rtm->rtm_addrs & RTA_IFA)) {
+ p_sockaddr(rti_info[RTAX_IFA], NULL, RTF_HOST,
+ WID_RT_IFA(addr.u_sa.sa_family));
+ }
+
+ p_flags(rtm->rtm_flags, "%-10.10s ");
+
+ if (lflag) {
+ printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use);
+ if (rtm->rtm_rmx.rmx_mtu != 0)
+ printf("%6u ", rtm->rtm_rmx.rmx_mtu);
+ else
+ printf("%6s ", "");
+ }
+
+ if (rtm->rtm_index != lastindex) {
+ if_indextoname(rtm->rtm_index, ifname);
+ lastindex = rtm->rtm_index;
+ }
+ printf("%*.*s", WID_IF(addr.u_sa.sa_family),
+ WID_IF(addr.u_sa.sa_family), ifname);
+
+ if (rtm->rtm_rmx.rmx_expire) {
+ time_t expire_time;
+
+ if ((expire_time =
+ rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0)
+ printf(" %6d", (int)expire_time);
+ else
+ printf(" %6s", "!");
+ } else {
+ printf(" %6s", "");
+ }
+ if (lflag > 1) {
+ if (rtm->rtm_rmx.rmx_rtt != 0)
+ printf(" %6u.%03u", rtm->rtm_rmx.rmx_rtt / 1000,
+ rtm->rtm_rmx.rmx_rtt % 1000);
+ else
+ printf(" %10s", "");
+ if (rtm->rtm_rmx.rmx_rttvar != 0)
+ printf(" %6u.%03u", rtm->rtm_rmx.rmx_rttvar / 1000,
+ rtm->rtm_rmx.rmx_rttvar % 1000);
+ else
+ printf(" %10s", "");
+ if (lflag > 2) {
+ if (rtm->rtm_rmx.rmx_recvpipe != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_recvpipe);
+ else
+ printf(" %8s", "");
+ if (rtm->rtm_rmx.rmx_sendpipe != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_sendpipe);
+ else
+ printf(" %8s", "");
+ if (rtm->rtm_rmx.rmx_ssthresh != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_ssthresh);
+ else
+ printf(" %8s", "");
+ }
+ }
+ putchar('\n');
+}
+
+static void
+p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
+{
+ char workbuf[128], *cplim;
+ char *cp = workbuf;
+
+ switch(sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if ((sin->sin_addr.s_addr == INADDR_ANY) &&
+ mask &&
+ (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0))
+ cp = "default" ;
+ else if (flags & RTF_HOST)
+ cp = routename(sin->sin_addr.s_addr);
+ else if (mask)
+ cp = netname(sin->sin_addr.s_addr,
+ ntohl(((struct sockaddr_in *)mask)->
+ sin_addr.s_addr));
+ else
+ cp = netname(sin->sin_addr.s_addr, 0L);
+ break;
+ }
+
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ struct in6_addr *in6 = &sa6->sin6_addr;
+
+ /*
+ * XXX: This is a special workaround for KAME kernels.
+ * sin6_scope_id field of SA should be set in the future.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(in6) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+ /* XXX: override is ok? */
+ sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+ *(u_short *)&in6->s6_addr[2] = 0;
+ }
+
+ if (flags & RTF_HOST)
+ cp = routename6(sa6);
+ else if (mask)
+ cp = netname6(sa6, mask);
+ else
+ cp = netname6(sa6, NULL);
+ break;
+ }
+#endif /*INET6*/
+
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index);
+ } else {
+ switch (sdl->sdl_type) {
+
+ case IFT_ETHER: {
+ int i;
+ u_char *lla = (u_char *)sdl->sdl_data +
+ sdl->sdl_nlen;
+
+ cplim = "";
+ for (i = 0; i < sdl->sdl_alen; i++, lla++) {
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla);
+ cplim = ":";
+ }
+ cp = workbuf;
+ break;
+ }
+
+ default:
+ cp = link_ntoa(sdl);
+ break;
+ }
+ }
+ break;
+ }
+
+ default: {
+ u_char *s = (u_char *)sa->sa_data, *slim;
+
+ slim = sa->sa_len + (u_char *) sa;
+ cplim = cp + sizeof(workbuf) - 6;
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family);
+ while (s < slim && cp < cplim) {
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++);
+ if (s < slim)
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++);
+ }
+ cp = workbuf;
+ }
+ }
+ if (width < 0 ) {
+ printf("%s ", cp);
+ } else {
+ if (nflag)
+ printf("%-*s ", width, cp);
+ else
+ printf("%-*.*s ", width, width, cp);
+ }
+}
+
+static void
+p_flags(int f, char *format)
+{
+ char name[33], *flags;
+ struct bits *p = bits;
+
+ for (flags = name; p->b_mask; p++)
+ if (p->b_mask & f)
+ *flags++ = p->b_val;
+ *flags = '\0';
+ printf(format, name);
+}
+
+char *
+routename(uint32_t in)
+{
+ char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+
+ cp = 0;
+ if (!nflag) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+#define C(x) ((x) & 0xff)
+ in = ntohl(in);
+ snprintf(line, sizeof(line), "%u.%u.%u.%u",
+ C(in >> 24), C(in >> 16), C(in >> 8), C(in));
+ }
+ return (line);
+}
+
+static uint32_t
+forgemask(uint32_t a)
+{
+ uint32_t m;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+ else if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+ else
+ m = IN_CLASSC_NET;
+ return (m);
+}
+
+static void
+domask(char *dst, uint32_t addr, uint32_t mask)
+{
+ int b, i;
+
+ if (!mask || (forgemask(addr) == mask)) {
+ *dst = '\0';
+ return;
+ }
+ i = 0;
+ for (b = 0; b < 32; b++)
+ if (mask & (1 << b)) {
+ int bb;
+
+ i = b;
+ for (bb = b+1; bb < 32; bb++)
+ if (!(mask & (1 << bb))) {
+ i = -1; /* noncontig */
+ break;
+ }
+ break;
+ }
+ if (i == -1)
+ snprintf(dst, sizeof(dst), "&0x%x", mask);
+ else
+ snprintf(dst, sizeof(dst), "/%d", 32-i);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+char *
+netname(uint32_t in, uint32_t mask)
+{
+ char *cp = 0;
+ static char line[MAXHOSTNAMELEN];
+ struct netent *np = 0;
+ uint32_t net, omask, dmask;
+ uint32_t i;
+
+ i = ntohl(in);
+ dmask = forgemask(i);
+ omask = mask;
+ if (!nflag && i) {
+ net = i & dmask;
+ if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
+ np = getnetbyaddr(net, AF_INET);
+ if (np) {
+ cp = np->n_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ switch (dmask) {
+ case IN_CLASSA_NET:
+ if ((i & IN_CLASSA_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u", C(i >> 24));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSB_NET:
+ if ((i & IN_CLASSB_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u.%u",
+ C(i >> 24), C(i >> 16));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSC_NET:
+ if ((i & IN_CLASSC_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u.%u.%u",
+ C(i >> 24), C(i >> 16), C(i >> 8));
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ snprintf(line, sizeof(line), "%u.%u.%u.%u",
+ C(i >> 24), C(i >> 16), C(i >> 8), C(i));
+ break;
+ }
+ }
+ domask(line+strlen(line), i, omask);
+ return (line);
+}
+
+#ifdef INET6
+char *
+netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam)
+{
+ static char line[MAXHOSTNAMELEN];
+ u_char *lim;
+ int masklen, illegal = 0, flag = NI_WITHSCOPEID;
+ struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0;
+
+ if (sam && sam->sa_len == 0) {
+ masklen = 0;
+ } else if (mask) {
+ u_char *p = (u_char *)mask;
+ for (masklen = 0, lim = p + 16; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ illegal ++;
+ break;
+ }
+ }
+ if (illegal)
+ fprintf(stderr, "illegal prefixlen\n");
+ } else {
+ masklen = 128;
+ }
+ if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+ return("default");
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+
+ if (nflag)
+ snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen);
+
+ return line;
+}
+
+char *
+routename6(struct sockaddr_in6 *sa6)
+{
+ static char line[MAXHOSTNAMELEN];
+ int flag = NI_WITHSCOPEID;
+ /* use local variable for safety */
+ struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, };
+
+ sa6_local.sin6_addr = sa6->sin6_addr;
+ sa6_local.sin6_scope_id = sa6->sin6_scope_id;
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+
+ getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
+ line, sizeof(line), NULL, 0, flag);
+
+ return line;
+}
+#endif /*INET6*/
+
+/*
+ * Print routing statistics
+ */
+void
+rt_stats(void)
+{
+ struct rtstat rtstat;
+ int rttrash;
+ int mib[6];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_STAT;
+ mib[5] = 0;
+ len = sizeof(struct rtstat);
+ if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1)
+ return;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_TRASH;
+ mib[5] = 0;
+ len = sizeof(rttrash);
+ if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1)
+ return;
+
+ printf("routing:\n");
+
+#define p(f, m) if (rtstat.f || sflag <= 1) \
+ printf(m, rtstat.f, plural(rtstat.f))
+
+ p(rts_badredirect, "\t%u bad routing redirect%s\n");
+ p(rts_dynamic, "\t%u dynamically created route%s\n");
+ p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
+ p(rts_unreach, "\t%u destination%s found unreachable\n");
+ p(rts_wildcard, "\t%u use%s of a wildcard route\n");
+ p(rts_badrtgwroute, "\t%u lookup%s returned indirect "
+ "routes pointing to indirect gateway route\n");
+#undef p
+
+ if (rttrash || sflag <= 1)
+ printf("\t%u route%s not in table but not freed\n",
+ rttrash, plural(rttrash));
+}
+
+void
+upHex(char *p0)
+{
+ char *p = p0;
+
+ for (; *p; p++)
+ switch (*p) {
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ *p += ('A' - 'a');
+ break;
+ }
+}
diff --git a/network_cmds/netstat.tproj/systm.c b/network_cmds/netstat.tproj/systm.c
new file mode 100644
index 0000000..3e076ca
--- /dev/null
+++ b/network_cmds/netstat.tproj/systm.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1983, 1988, 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.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/sys_domain.h>
+#include <sys/kern_control.h>
+#include <sys/kern_event.h>
+#include <net/ntstat.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "netstat.h"
+
+#define ROUNDUP64(a) \
+((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
+#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
+
+struct xgen_n {
+ u_int32_t xgn_len; /* length of this structure */
+ u_int32_t xgn_kind; /* number of PCBs at this time */
+};
+
+#define ALL_XGN_KIND_KCREG (XSO_KCREG)
+#define ALL_XGN_KIND_EVT (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_EVT)
+#define ALL_XGN_KIND_KCB (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_KCB)
+
+void
+systmpr(uint32_t proto,
+ char *name, int af)
+{
+ const char *mibvar;
+ size_t len;
+ char *buf, *next;
+ struct xsystmgen *xig, *oxig;
+ struct xgen_n *xgn;
+ int which = 0;
+ struct xsocket_n *so = NULL;
+ struct xsockbuf_n *so_rcv = NULL;
+ struct xsockbuf_n *so_snd = NULL;
+ struct xsockstat_n *so_stat = NULL;
+ struct xkctl_reg *kctl = NULL;
+ struct xkctlpcb *kcb = NULL;
+ struct xkevtpcb *kevb = NULL;
+ int first = 1;
+
+ switch (proto) {
+ case SYSPROTO_EVENT:
+ mibvar = "net.systm.kevt.pcblist";
+ break;
+ case SYSPROTO_CONTROL:
+ mibvar = "net.systm.kctl.pcblist";
+ break;
+ case 0:
+ mibvar = "net.systm.kctl.reg_list";
+ break;
+ default:
+ mibvar = NULL;
+ break;
+ }
+ if (mibvar == NULL)
+ return;
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= sizeof(struct xsystmgen)) {
+ free(buf);
+ return;
+ }
+ oxig = xig = (struct xsystmgen *)buf;
+ for (next = buf + ROUNDUP64(xig->xg_len); next < buf + len;
+ next += ROUNDUP64(xgn->xgn_len)) {
+ xgn = (struct xgen_n*)next;
+ if (xgn->xgn_len <= sizeof(struct xsystmgen))
+ break;
+
+ if ((which & xgn->xgn_kind) == 0) {
+ which |= xgn->xgn_kind;
+ switch (xgn->xgn_kind) {
+ case XSO_SOCKET:
+ so = (struct xsocket_n *)xgn;
+ break;
+ case XSO_RCVBUF:
+ so_rcv = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_SNDBUF:
+ so_snd = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_STATS:
+ so_stat = (struct xsockstat_n *)xgn;
+ break;
+ case XSO_KCREG:
+ kctl = (struct xkctl_reg *)xgn;
+ break;
+ case XSO_KCB:
+ kcb = (struct xkctlpcb *)xgn;
+ break;
+ case XSO_EVT:
+ kevb = (struct xkevtpcb *)xgn;
+ break;
+ default:
+ printf("unexpected kind %d\n", xgn->xgn_kind);
+ break;
+ }
+ } else {
+ if (vflag)
+ printf("got %d twice\n", xgn->xgn_kind);
+ }
+
+ if (which == ALL_XGN_KIND_KCREG) {
+ which = 0;
+
+ if (first) {
+ printf("Registered kernel control modules\n");
+ if (Aflag)
+ printf("%-16.16s ", "kctlref");
+ printf("%-8.8s ", "id");
+ if (Aflag)
+ printf("%-8.8s ", "unit");
+ printf("%-8.8s ", "flags");
+ printf("%-8.8s ", "pcbcount");
+ printf("%-8.8s ", "rcvbuf");
+ printf("%-8.8s ", "sndbuf");
+ printf("%s ", "name");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kctl->xkr_kctlref);
+ printf("%8x ", kctl->xkr_id);
+ if (Aflag)
+ printf("%8d ", kctl->xkr_reg_unit);
+ printf("%8x ", kctl->xkr_flags);
+ printf("%8d ", kctl->xkr_pcbcount);
+ printf("%8d ", kctl->xkr_recvbufsize);
+ printf("%8d ", kctl->xkr_sendbufsize);
+ printf("%s ", kctl->xkr_name);
+ printf("\n");
+ } else if (which == ALL_XGN_KIND_KCB) {
+ which = 0;
+
+ if (first) {
+ printf("Active kernel control sockets\n");
+ if (Aflag)
+ printf("%16.16s ", "pcb");
+ printf("%-5.5s %-6.6s %-6.6s ",
+ "Proto", "Recv-Q", "Send-Q");
+ if (bflag > 0)
+ printf("%10.10s %10.10s ",
+ "rxbytes", "txbytes");
+ if (vflag > 0)
+ printf("%6.6s %6.6s %6.6s %6.6s ",
+ "rhiwat", "shiwat", "pid", "epid");
+ printf("%6.6s ", "unit");
+ printf("%6.6s ", "id");
+ printf("%s", "name");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kcb->xkp_kctpcb);
+ printf("%-5.5s %6u %6u ", name,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+ printf("%10llu %10llu ", rxbytes, txbytes);
+ }
+ if (vflag > 0) {
+ printf("%6u %6u %6u %6u ",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid);
+ }
+ printf("%6d ", kcb->xkp_unit);
+ printf("%6d ", kcb->xkp_kctlid);
+ printf("%s", kcb->xkp_kctlname);
+ printf("\n");
+
+ } else if (which == ALL_XGN_KIND_EVT) {
+ which = 0;
+ if (first) {
+ printf("Active kernel event sockets\n");
+ if (Aflag)
+ printf("%16.16s ", "pcb");
+ printf("%-5.5s %-6.6s %-6.6s ",
+ "Proto", "Recv-Q", "Send-Q");
+ printf("%6.6s ", "vendor");
+ printf("%6.6s ", "class");
+ printf("%6.6s", "subclass");
+ if (bflag > 0)
+ printf("%10.10s %10.10s ",
+ "rxbytes", "txbytes");
+ if (vflag > 0)
+ printf("%6.6s %6.6s %6.6s %6.6s",
+ "rhiwat", "shiwat", "pid", "epid");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kevb->kep_evtpcb);
+ printf("%-5.5s %6u %6u ", name,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ printf("%6d ", kevb->kep_vendor_code_filter);
+ printf("%6d ", kevb->kep_class_filter);
+ printf("%6d", kevb->kep_subclass_filter);
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+ printf("%10llu %10llu ", rxbytes, txbytes);
+ }
+ if (vflag > 0) {
+ printf("%6u %6u %6u %6u",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid);
+ }
+ printf("\n");
+ }
+
+ }
+ if (xig != oxig && xig->xg_gen != oxig->xg_gen) {
+ if (oxig->xg_count > xig->xg_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xg_count < xig->xg_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ name);
+ }
+ }
+ free(buf);
+}
+
+void
+kctl_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct kctlstat pkctlstat;
+ struct kctlstat kctlstat;
+ size_t len = sizeof(struct kctlstat);
+ const char *mibvar = "net.systm.kctl.stats";
+
+ if (sysctlbyname(mibvar, &kctlstat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define STATDIFF(f) (kctlstat.f - pkctlstat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ p(kcs_reg_total, "\t%llu total kernel control module%s registered\n");
+ p(kcs_reg_count, "\t%llu current kernel control module%s registered\n");
+ p(kcs_pcbcount, "\t%llu current kernel control socket%s\n");
+ p1a(kcs_gencnt, "\t%llu kernel control generation count\n");
+ p(kcs_connections, "\t%llu connection attempt%s\n");
+ p(kcs_conn_fail, "\t%llu connection failure%s\n");
+ p(kcs_send_fail, "\t%llu send failure%s\n");
+ p(kcs_send_list_fail, "\t%llu send list failure%s\n");
+ p(kcs_enqueue_fail, "\t%llu enqueue failure%s\n");
+ p(kcs_enqueue_fullsock, "\t%llu packet%s dropped due to full socket buffers\n");
+ p(kcs_bad_kctlref, "\t%llu failure%s with bad kern_ctl_ref\n");
+ p(kcs_tbl_size_too_big, "\t%llu register failure%s because of too many kern_ctl_ref\n");
+ p(kcs_enqdata_mb_alloc_fail, "\t%llu enqueuedata failure%s because could not allocate a packet\n");
+ p(kcs_enqdata_sbappend_fail, "\t%llu enqueuedata failure%s due to full socket buffers\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+
+ if (interval > 0)
+ bcopy(&kctlstat, &pkctlstat, len);
+}
+
+void
+kevt_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct kevtstat pkevtstat;
+ struct kevtstat kevtstat;
+ size_t len = sizeof(struct kevtstat);
+ const char *mibvar = "net.systm.kevt.stats";
+
+ if (sysctlbyname(mibvar, &kevtstat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define STATDIFF(f) (kevtstat.f - pkevtstat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ p(kes_pcbcount, "\t%llu current kernel control socket%s\n");
+ p1a(kes_gencnt, "\t%llu kernel control generation count\n");
+ p(kes_badvendor, "\t%llu bad vendor failure%s\n");
+ p(kes_toobig, "\t%llu message too big failure%s\n");
+ p(kes_nomem, "\t%llu out of memory failure%s\n");
+ p(kes_fullsock, "\t%llu message%s dropped due to full socket buffers\n");
+ p(kes_posted, "\t%llu message%s posted\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+
+ if (interval > 0)
+ bcopy(&kevtstat, &pkevtstat, len);
+}
+
+void
+print_extbkidle_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct soextbkidlestat psoextbkidlestat;
+ struct soextbkidlestat soextbkidlestat;
+ size_t len = sizeof(struct soextbkidlestat);
+ const char *mibvar = "kern.ipc.extbkidlestat";
+
+ if (sysctlbyname(mibvar, &soextbkidlestat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (soextbkidlestat.f - psoextbkidlestat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p1a(so_xbkidle_maxperproc, "\t%u max per process\n");
+ p1a(so_xbkidle_time, "\t%u maximum time (seconds)\n");
+ p1a(so_xbkidle_rcvhiwat, "\t%u high water mark\n");
+ p(so_xbkidle_notsupp, "\t%u socket option not supported failure%s\n");
+ p(so_xbkidle_toomany, "\t%u too many sockets failure%s\n");
+ p(so_xbkidle_wantok, "\t%u total socket%s requested OK\n");
+ p(so_xbkidle_active, "\t%u extended bk idle socket%s\n");
+ p(so_xbkidle_nocell, "\t%u no cellular failure%s\n");
+ p(so_xbkidle_notime, "\t%u no time failures%s\n");
+ p(so_xbkidle_forced, "\t%u forced defunct socket%s\n");
+ p(so_xbkidle_resumed, "\t%u resumed socket%s\n");
+ p(so_xbkidle_expired, "\t%u timeout expired failure%s\n");
+ p1a(so_xbkidle_expired, "\t%u timer rescheduled\n");
+ p(so_xbkidle_nodlgtd, "\t%u no delegated failure%s\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
+
+void
+print_nstat_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct nstat_stats pnstat_stats;
+ struct nstat_stats nstat_stats;
+ size_t len = sizeof(struct nstat_stats);
+ const char *mibvar = "net.stats.stats";
+
+ if (sysctlbyname(mibvar, &nstat_stats, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (nstat_stats.f - pnstat_stats.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p(nstat_successmsgfailures, "\t%u enqueue success message failure%s\n");
+ p(nstat_sendcountfailures, "\t%u enqueue source counts message failure%s\n");
+ p(nstat_sysinfofailures, "\t%u enqueue sysinfo message failure%s\n");
+ p(nstat_srcupatefailures, "\t%u enqueue source udpate message failure%s\n");
+ p(nstat_descriptionfailures, "\t%u enqueue description message failure%s\n");
+ p(nstat_msgremovedfailures, "\t%u enqueue remove message failure%s\n");
+ p(nstat_srcaddedfailures, "\t%u enqueue source added message failure%s\n");
+ p(nstat_msgerrorfailures, "\t%u enqueue error message failure%s\n");
+ p(nstat_copy_descriptor_failures, "\t%u copy descriptor failure%s\n");
+ p(nstat_provider_counts_failures, "\t%u provider counts failure%s\n");
+ p(nstat_control_send_description_failures, "\t%u control send description failure%s\n");
+ p(nstat_control_send_goodbye_failures, "\t%u control send goodbye failure%s\n");
+ p(nstat_flush_accumulated_msgs_failures, "\t%u flush accumulated messages failure%s\n");
+ p(nstat_accumulate_msg_failures, "\t%u accumulated message failure%s\n");
+ p(nstat_control_cleanup_source_failures, "\t%u control cleanup source failure%s\n");
+ p(nstat_handle_msg_failures, "\t%u handle message failure%s\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
diff --git a/network_cmds/netstat.tproj/tp_astring.c b/network_cmds/netstat.tproj/tp_astring.c
new file mode 100644
index 0000000..af08ceb
--- /dev/null
+++ b/network_cmds/netstat.tproj/tp_astring.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1991, 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.
+ *
+ * @(#)tp_astring.c 8.1 (Berkeley) 6/10/93
+ */
+
+char *tp_sstring[] = {
+"ST_ERROR(0x0)",
+"TP_CLOSED(0x1)",
+"TP_CRSENT(0x2)",
+"TP_AKWAIT(0x3)",
+"TP_OPEN(0x4)",
+"TP_CLOSING(0x5)",
+"TP_REFWAIT(0x6)",
+"TP_LISTENING(0x7)",
+"TP_CONFIRMING(0x8)",
+};
+
+char *tp_estring[] = {
+"TM_inact(0x0)",
+"TM_retrans(0x1)",
+"TM_sendack(0x2)",
+"TM_notused(0x3)",
+"TM_reference(0x4)",
+"TM_data_retrans(0x5)",
+"ER_TPDU(0x6)",
+"CR_TPDU(0x7)",
+"DR_TPDU(0x8)",
+"DC_TPDU(0x9)",
+"CC_TPDU(0xa)",
+"AK_TPDU(0xb)",
+"DT_TPDU(0xc)",
+"XPD_TPDU(0xd)",
+"XAK_TPDU(0xe)",
+"T_CONN_req(0xf)",
+"T_DISC_req(0x10)",
+"T_LISTEN_req(0x11)",
+"T_DATA_req(0x12)",
+"T_XPD_req(0x13)",
+"T_USR_rcvd(0x14)",
+"T_USR_Xrcvd(0x15)",
+"T_DETACH(0x16)",
+"T_NETRESET(0x17)",
+"T_ACPT_req(0x18)",
+};
diff --git a/network_cmds/netstat.tproj/unix.c b/network_cmds/netstat.tproj/unix.c
new file mode 100644
index 0000000..eece65a
--- /dev/null
+++ b/network_cmds/netstat.tproj/unix.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1983, 1988, 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.
+ */
+
+/*
+ * Display protocol blocks in the unix domain.
+ */
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+static void unixdomainpr __P((struct xunpcb64 *, struct xsocket64 *));
+#else
+static void unixdomainpr __P((struct xunpcb *, struct xsocket *));
+#endif
+
+static const char *const socktype[] =
+ { "#0", "stream", "dgram", "raw" };
+
+void
+unixpr()
+{
+ char *buf;
+ int type;
+ size_t len;
+ struct xunpgen *xug, *oxug;
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct xsocket64 *so;
+ struct xunpcb64 *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist64"];
+#else
+ struct xsocket *so;
+ struct xunpcb *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist"];
+#endif
+
+ for (type = SOCK_STREAM; type <= SOCK_RAW; type++) {
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist64", socktype[type]);
+#else
+ snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist", socktype[type]);
+#endif
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ continue;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ oxug = xug = (struct xunpgen *)buf;
+ for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
+ xug->xug_len > sizeof(struct xunpgen);
+ xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ xunp = (struct xunpcb64 *)xug;
+#else
+ xunp = (struct xunpcb *)xug;
+#endif
+ so = &xunp->xu_socket;
+
+ /* Ignore PCBs which were freed during copyout. */
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (xunp->xunp_gencnt > oxug->xug_gen)
+#else
+ if (xunp->xu_unp.unp_gencnt > oxug->xug_gen)
+#endif
+ continue;
+ unixdomainpr(xunp, so);
+ }
+ if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
+ if (oxug->xug_count > xug->xug_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ socktype[type]);
+ } else if (oxug->xug_count < xug->xug_count) {
+ printf("Some %s sockets may have been created.\n",
+ socktype[type]);
+ } else {
+ printf("Some %s sockets may have been created or deleted\n",
+ socktype[type]);
+ }
+ }
+ free(buf);
+ }
+}
+
+static void
+unixdomainpr(xunp, so)
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct xunpcb64 *xunp;
+ struct xsocket64 *so;
+#else
+ struct xunpcb *xunp;
+ struct xsocket *so;
+#endif
+{
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct unpcb *unp;
+#endif
+ struct sockaddr_un *sa;
+ static int first = 1;
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ sa = &xunp->xu_addr;
+#else
+ unp = &xunp->xu_unp;
+ if (unp->unp_addr)
+ sa = &xunp->xu_addr;
+ else
+ sa = (struct sockaddr_un *)0;
+#endif
+
+ if (first) {
+ printf("Active LOCAL (UNIX) domain sockets\n");
+ printf(
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+"%-16.16s %-6.6s %-6.6s %-6.6s %16.16s %16.16s %16.16s %16.16s Addr\n",
+#else
+"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
+#endif
+ "Address", "Type", "Recv-Q", "Send-Q",
+ "Inode", "Conn", "Refs", "Nextref");
+ first = 0;
+ }
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ printf("%16lx %-6.6s %6u %6u %16lx %16lx %16lx %16lx",
+ (long)xunp->xu_unpp, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)xunp->xunp_vnode, (long)xunp->xunp_conn,
+ (long)xunp->xunp_refs, (long)xunp->xunp_reflink.le_next);
+#else
+ printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx",
+ (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)unp->unp_vnode, (long)unp->unp_conn,
+ (long)unp->unp_refs.lh_first, (long)unp->unp_reflink.le_next);
+#endif
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (sa->sun_len)
+#else
+ if (sa)
+#endif
+ printf(" %.*s",
+ (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
+ sa->sun_path);
+ putchar('\n');
+}
diff --git a/network_cmds/netstat.tproj/vsock.c b/network_cmds/netstat.tproj/vsock.c
new file mode 100644
index 0000000..b52dc5e
--- /dev/null
+++ b/network_cmds/netstat.tproj/vsock.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Display protocol blocks in the vsock domain.
+ */
+#include <sys/proc_info.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/vsock.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+#ifdef AF_VSOCK
+
+static void vsockdomainpr __P((struct xvsockpcb *));
+
+void
+vsockpr(uint32_t proto,
+char *name, int af)
+{
+ char *buf, *next;
+ size_t len;
+ struct xvsockpgen *xvg, *oxvg;
+ struct xvsockpcb *xpcb;
+
+ const char* mibvar = "net.vsock.pcblist";
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= 2 * sizeof(struct xvsockpgen)) {
+ free(buf);
+ return;
+ }
+
+ oxvg = (struct xvsockpgen *)buf;
+
+ // Save room for the last xvsockpgen.
+ len -= oxvg->xvg_len;
+
+ for (next = buf + oxvg->xvg_len; next < buf + len; next += xpcb->xv_len) {
+ xpcb = (struct xvsockpcb *)next;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (xpcb->xvp_gencnt > oxvg->xvg_gen)
+ continue;
+ vsockdomainpr(xpcb);
+ }
+ xvg = (struct xvsockpgen *)next;
+ if (xvg != oxvg && xvg->xvg_gen != oxvg->xvg_gen) {
+ if (oxvg->xvg_count > xvg->xvg_count) {
+ printf("Some vsock sockets may have been deleted.\n");
+ } else if (oxvg->xvg_count < xvg->xvg_count) {
+ printf("Some vsock sockets may have been created.\n");
+ } else {
+ printf("Some vsock sockets may have been created or deleted.\n");
+ }
+ }
+ free(buf);
+}
+
+static void
+vsock_print_addr(buf, cid, port)
+ char *buf;
+ uint32_t cid;
+ uint32_t port;
+{
+ if (cid == VMADDR_CID_ANY && port == VMADDR_PORT_ANY) {
+ (void) sprintf(buf, "*:*");
+ } else if (cid == VMADDR_CID_ANY) {
+ (void) sprintf(buf, "*:%u", port);
+ } else if (port == VMADDR_PORT_ANY) {
+ (void) sprintf(buf, "%u:*", cid);
+ } else {
+ (void) sprintf(buf, "%u:%u", cid, port);
+ }
+}
+
+static void
+vsockdomainpr(xpcb)
+ struct xvsockpcb *xpcb;
+{
+ static int first = 1;
+
+ if (first) {
+ printf("Active VSock sockets\n");
+ printf("%-5.5s %-6.6s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s",
+ "Proto", "Type",
+ "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "State");
+ if (vflag > 0)
+ printf(" %10.10s %10.10s %10.10s %10.10s %6.6s %6.6s %6.6s %6s %10s",
+ "rxcnt", "txcnt", "peer_rxcnt", "peer_rxhiwat",
+ "rxhiwat", "txhiwat", "pid", "state", "options");
+ printf("\n");
+ first = 0;
+ }
+
+ struct xsocket *so = &xpcb->xv_socket;
+
+ char srcAddr[50];
+ char dstAddr[50];
+
+ vsock_print_addr(srcAddr, xpcb->xvp_local_cid, xpcb->xvp_local_port);
+ vsock_print_addr(dstAddr, xpcb->xvp_remote_cid, xpcb->xvp_remote_port);
+
+ // Determine the vsock socket state.
+ char *state;
+ if (so->so_state & SOI_S_ISCONNECTING) {
+ state = "CONNECTING";
+ } else if (so->so_state & SOI_S_ISCONNECTED) {
+ state = "ESTABLISHED";
+ } else if (so->so_state & SOI_S_ISDISCONNECTING) {
+ state = "CLOSING";
+ } else if (so->so_options & SO_ACCEPTCONN) {
+ state = "LISTEN";
+ } else {
+ state = "CLOSED";
+ }
+
+ printf("%-5.5s %-6.6s %6u %6u %-18s %-18s %-11s",
+ "vsock", "stream",
+ so->so_rcv.sb_cc, so->so_snd.sb_cc,
+ srcAddr, dstAddr,
+ state);
+ if (vflag > 0)
+ printf(" %10u %10u %10u %10u %6u %6u %6u 0x%04x 0x%08x",
+ xpcb->xvp_rxcnt,
+ xpcb->xvp_txcnt,
+ xpcb->xvp_peer_rxcnt,
+ xpcb->xvp_peer_rxhiwat,
+ so->so_rcv.sb_hiwat,
+ so->so_snd.sb_hiwat,
+ xpcb->xvp_last_pid,
+ so->so_state,
+ so->so_options);
+ printf("\n");
+}
+
+#endif /* AF_VSOCK */
diff --git a/network_cmds/network-client-server-entitlements.plist b/network_cmds/network-client-server-entitlements.plist
new file mode 100644
index 0000000..c326c83
--- /dev/null
+++ b/network_cmds/network-client-server-entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.network.client</key>
+ <true/>
+ <key>com.apple.security.network.server</key>
+ <true/>
+</dict>
+</plist>
diff --git a/network_cmds/network_cmds.plist b/network_cmds/network_cmds.plist
new file mode 100644
index 0000000..9d6cf73
--- /dev/null
+++ b/network_cmds/network_cmds.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>mtest</string>
+ <key>OpenSourceVersion</key>
+ <string>1.11</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.sbin/mtest/</string>
+ <key>OpenSourceURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/usr.sbin/mtest/mtest.c?rev=1.11;content-type=text%2Fplain</string>
+ <key>OpenSourceSHA1</key>
+ <string></string>
+ <key>OpenSourceMD5</key>
+ <string></string>
+ <key>OpenSourceImportDate</key>
+ <string>2011-01-13</string>
+ <key>OpenSourceLicense</key>
+ <string>Other</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>network_cmds.txt</string>
+ </dict>
+</array>
+</plist>
diff --git a/network_cmds/network_cmds.xcodeproj/project.pbxproj b/network_cmds/network_cmds.xcodeproj/project.pbxproj
new file mode 100755
index 0000000..cce64f8
--- /dev/null
+++ b/network_cmds/network_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,5098 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 72570DA20EE8EBF3000F4CFB /* All-Embedded */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 72570DA60EE8EC0F000F4CFB /* Build configuration list for PBXAggregateTarget "All-Embedded" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 034E4464100BDCA3009CA3DC /* PBXTargetDependency */,
+ 72B732EB1899B19A0060E6D4 /* PBXTargetDependency */,
+ 72179EAE146233390098FB3E /* PBXTargetDependency */,
+ 7282BA571AFBDEAD005DE836 /* PBXTargetDependency */,
+ 72946F4C1BBF063800087E35 /* PBXTargetDependency */,
+ 034E4469100BDD00009CA3DC /* PBXTargetDependency */,
+ 565825AF13392239003E5FA5 /* PBXTargetDependency */,
+ 72311F4D194A34F500EB4788 /* PBXTargetDependency */,
+ 690D97BC12DE7151004323A7 /* PBXTargetDependency */,
+ 03B2DBD1100BE626005349BC /* PBXTargetDependency */,
+ 034E4475100BDEC6009CA3DC /* PBXTargetDependency */,
+ 7250E1491616642900A11A76 /* PBXTargetDependency */,
+ 7200F3051958A4FA0033E22C /* PBXTargetDependency */,
+ 034E447B100BDF0D009CA3DC /* PBXTargetDependency */,
+ 03B2DBD3100BE645005349BC /* PBXTargetDependency */,
+ 18515B85133D1DBF000148A4 /* PBXTargetDependency */,
+ 034E447F100BDF54009CA3DC /* PBXTargetDependency */,
+ 03B2DBDB100BE6D2005349BC /* PBXTargetDependency */,
+ 034E4485100BE15F009CA3DC /* PBXTargetDependency */,
+ 03B2DBDD100BE6D5005349BC /* PBXTargetDependency */,
+ );
+ name = "All-Embedded";
+ productName = "All-Embedded";
+ };
+ 726121430EE8717500AFED1B /* All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 7261214B0EE8717D00AFED1B /* Build configuration list for PBXAggregateTarget "All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 726121490EE8717B00AFED1B /* PBXTargetDependency */,
+ 72B732E91899B18F0060E6D4 /* PBXTargetDependency */,
+ 723C7074142BB003007C87E9 /* PBXTargetDependency */,
+ 7282BA5B1AFBDED3005DE836 /* PBXTargetDependency */,
+ 7263724B1BCC709900E4B026 /* PBXTargetDependency */,
+ 7261217D0EE8896800AFED1B /* PBXTargetDependency */,
+ 4D2B05141208C6BB0004A3F3 /* PBXTargetDependency */,
+ 724DABC30EE890A6008900D0 /* PBXTargetDependency */,
+ 565825AD13392232003E5FA5 /* PBXTargetDependency */,
+ 72311F4B194A34EB00EB4788 /* PBXTargetDependency */,
+ 690D97BE12DE7166004323A7 /* PBXTargetDependency */,
+ 724DAC240EE89525008900D0 /* PBXTargetDependency */,
+ 7216D2670EE8978F00AE70E4 /* PBXTargetDependency */,
+ 7250E1471616642000A11A76 /* PBXTargetDependency */,
+ 7200F3031958A4F10033E22C /* PBXTargetDependency */,
+ 7216D2C00EE89ADF00AE70E4 /* PBXTargetDependency */,
+ 7216D2C20EE89ADF00AE70E4 /* PBXTargetDependency */,
+ 7216D2DA0EE89BE900AE70E4 /* PBXTargetDependency */,
+ 7216D3060EE89D9A00AE70E4 /* PBXTargetDependency */,
+ 7216D34D0EE89FEC00AE70E4 /* PBXTargetDependency */,
+ 7216D37F0EE8A0B300AE70E4 /* PBXTargetDependency */,
+ 7294F0EA0EE8BAC80052EC88 /* PBXTargetDependency */,
+ 7294F1210EE8BCC20052EC88 /* PBXTargetDependency */,
+ 72CD1D9C0EE8C47C005F825D /* PBXTargetDependency */,
+ 71D958C51A9455A000C9B286 /* PBXTargetDependency */,
+ );
+ name = All;
+ productName = "network_cmds (Aggregate)";
+ };
+ 72ABD0811083D742008C721C /* All-EmbeddedOther */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 72ABD0A11083D792008C721C /* Build configuration list for PBXAggregateTarget "All-EmbeddedOther" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 72ABD0A41083D818008C721C /* PBXTargetDependency */,
+ 72ABD0881083D750008C721C /* PBXTargetDependency */,
+ 7282BA591AFBDEC2005DE836 /* PBXTargetDependency */,
+ 72946F4E1BBF063F00087E35 /* PBXTargetDependency */,
+ 565825B113392242003E5FA5 /* PBXTargetDependency */,
+ 72311F4F194A34FE00EB4788 /* PBXTargetDependency */,
+ 690D97BA12DE7130004323A7 /* PBXTargetDependency */,
+ 72ABD08C1083D75D008C721C /* PBXTargetDependency */,
+ 72ABD08E1083D75F008C721C /* PBXTargetDependency */,
+ 7250E14B1616643000A11A76 /* PBXTargetDependency */,
+ 7200F3071958A5040033E22C /* PBXTargetDependency */,
+ 72ABD0901083D762008C721C /* PBXTargetDependency */,
+ 72ABD0921083D764008C721C /* PBXTargetDependency */,
+ 72ABD0941083D767008C721C /* PBXTargetDependency */,
+ 72ABD0961083D76A008C721C /* PBXTargetDependency */,
+ 72ABD0981083D76D008C721C /* PBXTargetDependency */,
+ 72ABD09A1083D76F008C721C /* PBXTargetDependency */,
+ 72ABD09C1083D772008C721C /* PBXTargetDependency */,
+ 72ABD09E1083D774008C721C /* PBXTargetDependency */,
+ );
+ name = "All-EmbeddedOther";
+ productName = "All-EmbeddedOther";
+ };
+ 72C77D3A1484199C002D2577 /* network_cmds_libs */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 72C77D671484199C002D2577 /* Build configuration list for PBXAggregateTarget "network_cmds_libs" */;
+ buildPhases = (
+ );
+ dependencies = (
+ );
+ name = network_cmds_libs;
+ productName = "network_cmds (Aggregate)";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 01560DFD241969D3001AA29A /* vsock.c in Sources */ = {isa = PBXBuildFile; fileRef = 01560DFC241969D3001AA29A /* vsock.c */; };
+ 03EB2F9A120A1DDA0007C1A0 /* ip6addrctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4D2B04E41208C12F0004A3F3 /* ip6addrctl.8 */; };
+ 4D2B04F81208C21B0004A3F3 /* ip6addrctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2B04E51208C12F0004A3F3 /* ip6addrctl.c */; };
+ 565825A4133921A3003E5FA5 /* mnc_error.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825961339217B003E5FA5 /* mnc_error.c */; };
+ 565825A5133921A3003E5FA5 /* mnc_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825971339217B003E5FA5 /* mnc_main.c */; };
+ 565825A6133921A3003E5FA5 /* mnc_multicast.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825981339217B003E5FA5 /* mnc_multicast.c */; };
+ 565825A7133921A3003E5FA5 /* mnc_opts.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825991339217B003E5FA5 /* mnc_opts.c */; };
+ 565825A9133921CF003E5FA5 /* mnc.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 565825941339217B003E5FA5 /* mnc.1 */; };
+ 56B6B66816F79A1C00D8A7A9 /* mptcp.c in Sources */ = {isa = PBXBuildFile; fileRef = 56B6B66716F79A1C00D8A7A9 /* mptcp.c */; };
+ 690D97A612DE6F96004323A7 /* mtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 690D979412DE6E6B004323A7 /* mtest.c */; };
+ 690D97AE12DE70AE004323A7 /* mtest.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 690D979512DE6E76004323A7 /* mtest.8 */; };
+ 7200F2FD1958A34D0033E22C /* packet_mangler.c in Sources */ = {isa = PBXBuildFile; fileRef = 7200F2FC1958A34D0033E22C /* packet_mangler.c */; };
+ 721654C31EC52447005B17BA /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 721654C21EC52447005B17BA /* misc.c */; };
+ 7216D24C0EE896F300AE70E4 /* data.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208B0EE86F4800AFED1B /* data.c */; };
+ 7216D24D0EE896F300AE70E4 /* if.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208D0EE86F4800AFED1B /* if.c */; };
+ 7216D24E0EE896F300AE70E4 /* inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208E0EE86F4800AFED1B /* inet.c */; };
+ 7216D24F0EE896F300AE70E4 /* inet6.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208F0EE86F4800AFED1B /* inet6.c */; };
+ 7216D2500EE896F300AE70E4 /* ipsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120900EE86F4800AFED1B /* ipsec.c */; };
+ 7216D2510EE896F300AE70E4 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120910EE86F4800AFED1B /* main.c */; };
+ 7216D2520EE896F300AE70E4 /* mbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120930EE86F4800AFED1B /* mbuf.c */; };
+ 7216D2530EE896F300AE70E4 /* mcast.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120940EE86F4800AFED1B /* mcast.c */; };
+ 7216D2560EE896F300AE70E4 /* route.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120990EE86F4800AFED1B /* route.c */; };
+ 7216D2570EE896F300AE70E4 /* tp_astring.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261209A0EE86F4800AFED1B /* tp_astring.c */; };
+ 7216D2580EE896F300AE70E4 /* unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261209B0EE86F4800AFED1B /* unix.c */; };
+ 7216D2600EE8971500AE70E4 /* netstat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120970EE86F4800AFED1B /* netstat.1 */; };
+ 7216D2800EE8981C00AE70E4 /* ping.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120A10EE86F5000AFED1B /* ping.c */; };
+ 7216D2880EE8982F00AE70E4 /* ping.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120A00EE86F5000AFED1B /* ping.8 */; };
+ 7216D2A00EE898DF00AE70E4 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120A60EE86F5C00AFED1B /* md5.c */; };
+ 7216D2A10EE898DF00AE70E4 /* ping6.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120A90EE86F5C00AFED1B /* ping6.c */; };
+ 7216D2A90EE898F300AE70E4 /* ping6.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120A80EE86F5C00AFED1B /* ping6.8 */; };
+ 7216D2D10EE89B8300AE70E4 /* rarpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120AF0EE86F6700AFED1B /* rarpd.c */; };
+ 7216D2E40EE89C8B00AE70E4 /* rarpd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120AE0EE86F6700AFED1B /* rarpd.8 */; };
+ 7216D2F20EE89CD600AE70E4 /* route.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120B80EE86F7200AFED1B /* route.c */; };
+ 7216D3040EE89D4900AE70E4 /* route.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120B70EE86F7200AFED1B /* route.8 */; };
+ 7216D3190EE89EC100AE70E4 /* advcap.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120BC0EE86F8200AFED1B /* advcap.c */; };
+ 7216D31A0EE89EC100AE70E4 /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120BE0EE86F8200AFED1B /* config.c */; };
+ 7216D31B0EE89EC100AE70E4 /* dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C00EE86F8200AFED1B /* dump.c */; };
+ 7216D31C0EE89EC100AE70E4 /* if.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C20EE86F8200AFED1B /* if.c */; };
+ 7216D31D0EE89EC100AE70E4 /* rrenum.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C60EE86F8200AFED1B /* rrenum.c */; };
+ 7216D31E0EE89EC100AE70E4 /* rtadvd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C90EE86F8200AFED1B /* rtadvd.c */; };
+ 7216D31F0EE89EC100AE70E4 /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120CD0EE86F8200AFED1B /* timer.c */; };
+ 7216D3240EE89F4200AE70E4 /* rtadvd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120C80EE86F8200AFED1B /* rtadvd.8 */; };
+ 7216D3390EE89F8400AE70E4 /* rtadvd.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120CB0EE86F8200AFED1B /* rtadvd.conf.5 */; };
+ 7216D3410EE89FAF00AE70E4 /* rtadvd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120CA0EE86F8200AFED1B /* rtadvd.conf */; };
+ 7216D3670EE8A04700AE70E4 /* dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D20EE86F9100AFED1B /* dump.c */; };
+ 7216D3680EE8A04700AE70E4 /* if.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D30EE86F9100AFED1B /* if.c */; };
+ 7216D3690EE8A04700AE70E4 /* probe.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D50EE86F9100AFED1B /* probe.c */; };
+ 7216D36A0EE8A04700AE70E4 /* rtsock.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D60EE86F9100AFED1B /* rtsock.c */; };
+ 7216D36B0EE8A04700AE70E4 /* rtsol.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D80EE86F9100AFED1B /* rtsol.c */; };
+ 7216D36C0EE8A04700AE70E4 /* rtsold.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D90EE86F9100AFED1B /* rtsold.c */; };
+ 7216D3700EE8A05B00AE70E4 /* rtsol.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120D70EE86F9100AFED1B /* rtsol.8 */; };
+ 7216D3AB0EE8A3C400AE70E4 /* spray.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E00EE86F9D00AFED1B /* spray.c */; };
+ 7216D3AF0EE8A3D800AE70E4 /* spray.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120DF0EE86F9D00AFED1B /* spray.8 */; };
+ 7218B54A191D4202001B7B52 /* systm.c in Sources */ = {isa = PBXBuildFile; fileRef = 7218B549191D4202001B7B52 /* systm.c */; };
+ 72311F54194A354F00EB4788 /* conn_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 72311F50194A354F00EB4788 /* conn_lib.c */; };
+ 72311F55194A354F00EB4788 /* mptcp_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 72311F53194A354F00EB4788 /* mptcp_client.c */; };
+ 72311F56194A76DA00EB4788 /* mptcp_client.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72311F52194A354F00EB4788 /* mptcp_client.1 */; };
+ 724753E7144905E300F6A941 /* dnctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 724753E61448E1EF00F6A941 /* dnctl.8 */; };
+ 724769371CE2B1FF00AAB5F0 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; };
+ 724769381CE2C1E400AAB5F0 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; };
+ 7247B83616165EDC00873B3C /* pktapctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7247B83516165EDC00873B3C /* pktapctl.8 */; };
+ 7247B83C16165F0100873B3C /* pktapctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 7247B83B16165F0100873B3C /* pktapctl.c */; };
+ 724DABA60EE88FED008900D0 /* kdumpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120710EE86F2D00AFED1B /* kdumpd.c */; };
+ 724DABA70EE88FED008900D0 /* kdumpsubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120720EE86F2D00AFED1B /* kdumpsubs.c */; };
+ 724DABAB0EE89006008900D0 /* kdumpd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120700EE86F2D00AFED1B /* kdumpd.8 */; };
+ 724DABBC0EE8908A008900D0 /* com.apple.kdumpd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */; };
+ 724DAC120EE89423008900D0 /* ndp.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120870EE86F4000AFED1B /* ndp.c */; };
+ 724DAC3B0EE89555008900D0 /* ndp.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120860EE86F4000AFED1B /* ndp.8 */; };
+ 726121310EE8711E00AFED1B /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261204E0EE86EF900AFED1B /* arp.c */; };
+ 726121350EE8713800AFED1B /* arp.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7261204D0EE86EF900AFED1B /* arp.8 */; };
+ 7261215A0EE8883900AFED1B /* ifbond.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120550EE86F0900AFED1B /* ifbond.c */; };
+ 7261215B0EE8883900AFED1B /* ifconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120570EE86F0900AFED1B /* ifconfig.c */; };
+ 7261215C0EE8883900AFED1B /* ifmedia.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120590EE86F0900AFED1B /* ifmedia.c */; };
+ 7261215D0EE8883900AFED1B /* ifvlan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261205A0EE86F0900AFED1B /* ifvlan.c */; };
+ 726121610EE8885400AFED1B /* ifconfig.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120560EE86F0900AFED1B /* ifconfig.8 */; };
+ 7263A9630EEE31C800164D5D /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72CD1DB50EE8C619005F825D /* libipsec.dylib */; };
+ 7282BA491AFAD58E005DE836 /* capture.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA351AFAD58E005DE836 /* capture.c */; };
+ 7282BA4B1AFAD58E005DE836 /* ecn_probe.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA391AFAD58E005DE836 /* ecn_probe.c */; };
+ 7282BA4C1AFAD58E005DE836 /* ecn.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3A1AFAD58E005DE836 /* ecn.c */; };
+ 7282BA4D1AFAD58E005DE836 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; };
+ 7282BA4E1AFAD58E005DE836 /* history.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3E1AFAD58E005DE836 /* history.c */; };
+ 7282BA4F1AFAD58E005DE836 /* inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA401AFAD58E005DE836 /* inet.c */; };
+ 7282BA521AFAD58E005DE836 /* session.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA451AFAD58E005DE836 /* session.c */; };
+ 7282BA531AFAD58E005DE836 /* support.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA471AFAD58E005DE836 /* support.c */; };
+ 7282BA551AFBCA66005DE836 /* libpcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7282BA541AFBCA66005DE836 /* libpcap.dylib */; };
+ 72946F501BBF07FF00087E35 /* frame_delay.c in Sources */ = {isa = PBXBuildFile; fileRef = 72946F4F1BBF07FF00087E35 /* frame_delay.c */; };
+ 7294F0DF0EE8BA730052EC88 /* spray.x in Sources */ = {isa = PBXBuildFile; fileRef = 726120E10EE86F9D00AFED1B /* spray.x */; };
+ 7294F1000EE8BB990052EC88 /* as.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E50EE86FA700AFED1B /* as.c */; };
+ 7294F1010EE8BB990052EC88 /* findsaddr-socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E70EE86FA700AFED1B /* findsaddr-socket.c */; };
+ 7294F1020EE8BB990052EC88 /* ifaddrlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120EA0EE86FA700AFED1B /* ifaddrlist.c */; };
+ 7294F1030EE8BB990052EC88 /* traceroute.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120F10EE86FA700AFED1B /* traceroute.c */; };
+ 7294F1040EE8BB990052EC88 /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120F30EE86FA700AFED1B /* version.c */; };
+ 7294F1080EE8BBB10052EC88 /* traceroute.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120F00EE86FA700AFED1B /* traceroute.8 */; };
+ 7294F12E0EE8BD2F0052EC88 /* traceroute6.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120FB0EE86FB500AFED1B /* traceroute6.c */; };
+ 7294F1320EE8BD430052EC88 /* traceroute6.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120FA0EE86FB500AFED1B /* traceroute6.8 */; };
+ 72B732DF1899B0380060E6D4 /* cfilutil.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72B732DE1899B0380060E6D4 /* cfilutil.1 */; };
+ 72B732EF1899B23A0060E6D4 /* cfilutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B732EE1899B23A0060E6D4 /* cfilutil.c */; };
+ 72B732F11899B2430060E6D4 /* cfilstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B732F01899B2430060E6D4 /* cfilstat.c */; };
+ 72B7F36B1BA69352003A9AA2 /* if6lowpan.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B7F36A1BA69281003A9AA2 /* if6lowpan.c */; };
+ 72B894EC0EEDB17C00C218D6 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72CD1DB50EE8C619005F825D /* libipsec.dylib */; };
+ 72D000C4142BB11100151981 /* dnctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72D000C3142BB11100151981 /* dnctl.c */; };
+ 72D33F572271319400EF5B5E /* rtadvd_logging.c in Sources */ = {isa = PBXBuildFile; fileRef = 72D33F562271220100EF5B5E /* rtadvd_logging.c */; };
+ 72E42BA314B7CF3D003AAE28 /* network_cmds.plist in Install OSS Plist */ = {isa = PBXBuildFile; fileRef = 72E42BA214B7CF37003AAE28 /* network_cmds.plist */; };
+ 72E650A7107BF2F000AAF325 /* af_inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A2107BF2F000AAF325 /* af_inet.c */; };
+ 72E650A8107BF2F000AAF325 /* af_inet6.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A3107BF2F000AAF325 /* af_inet6.c */; };
+ 72E650A9107BF2F000AAF325 /* af_link.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A4107BF2F000AAF325 /* af_link.c */; };
+ 72E650AA107BF2F000AAF325 /* ifbridge.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A5107BF2F000AAF325 /* ifbridge.c */; };
+ 72E650AB107BF2F000AAF325 /* ifclone.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A6107BF2F000AAF325 /* ifclone.c */; };
+ E01AB0901368880F008C66FF /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E01AB08F1368880F008C66FF /* libutil.dylib */; };
+ F940359D1E2FF5A900283EB1 /* iffake.c in Sources */ = {isa = PBXBuildFile; fileRef = F940359C1E2FF58500283EB1 /* iffake.c */; };
+ F97F1E041E9C3FC8002355FF /* nexus.c in Sources */ = {isa = PBXBuildFile; fileRef = F97F1E031E9C3FBC002355FF /* nexus.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ 7216D47D0EE8B84900AE70E4 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ filePatterns = "$(PROJECT_DIR)/spray.tproj/spray.x";
+ fileType = pattern.proxy;
+ inputFiles = (
+ );
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE).h",
+ "$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE)_xdr.c",
+ );
+ script = "/usr/bin/rpcgen -h -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}.h ${INPUT_FILE_PATH}\n/usr/bin/rpcgen -c -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}_xdr.c ${INPUT_FILE_PATH}";
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+ 034E4463100BDCA3009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7261212C0EE8710B00AFED1B;
+ remoteInfo = arp;
+ };
+ 034E4468100BDD00009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726121530EE8881700AFED1B;
+ remoteInfo = ifconfig;
+ };
+ 034E4474100BDEC6009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2450EE896C000AE70E4;
+ remoteInfo = netstat;
+ };
+ 034E447A100BDF0D009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D27B0EE8980A00AE70E4;
+ remoteInfo = ping;
+ };
+ 034E447E100BDF54009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2EC0EE89CBC00AE70E4;
+ remoteInfo = route;
+ };
+ 034E4484100BE15F009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F0F80EE8BB460052EC88;
+ remoteInfo = traceroute;
+ };
+ 03B2DBD0100BE626005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DAC0C0EE8940D008900D0;
+ remoteInfo = ndp;
+ };
+ 03B2DBD2100BE645005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2990EE898BD00AE70E4;
+ remoteInfo = ping6;
+ };
+ 03B2DBDA100BE6D2005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3580EE8A02200AE70E4;
+ remoteInfo = rtsol;
+ };
+ 03B2DBDC100BE6D5005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F1290EE8BD280052EC88;
+ remoteInfo = traceroute6;
+ };
+ 18515B84133D1DBF000148A4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3130EE89E9E00AE70E4;
+ remoteInfo = rtadvd;
+ };
+ 4D2B05131208C6BB0004A3F3 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D2B04F21208C2040004A3F3;
+ remoteInfo = ip6addrctl;
+ };
+ 565825AC13392232003E5FA5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5658259E1339218F003E5FA5;
+ remoteInfo = mnc;
+ };
+ 565825AE13392239003E5FA5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5658259E1339218F003E5FA5;
+ remoteInfo = mnc;
+ };
+ 565825B013392242003E5FA5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5658259E1339218F003E5FA5;
+ remoteInfo = mnc;
+ };
+ 690D97B912DE7130004323A7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 690D978012DE6034004323A7;
+ remoteInfo = mtest;
+ };
+ 690D97BB12DE7151004323A7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 690D978012DE6034004323A7;
+ remoteInfo = mtest;
+ };
+ 690D97BD12DE7166004323A7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 690D978012DE6034004323A7;
+ remoteInfo = mtest;
+ };
+ 71D958C41A9455A000C9B286 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 713297671A93C743002359CF;
+ remoteInfo = unbound;
+ };
+ 7200F3021958A4F10033E22C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7200F2F91958A34D0033E22C;
+ remoteInfo = pktmnglr;
+ };
+ 7200F3041958A4FA0033E22C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7200F2F91958A34D0033E22C;
+ remoteInfo = pktmnglr;
+ };
+ 7200F3061958A5040033E22C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7200F2F91958A34D0033E22C;
+ remoteInfo = pktmnglr;
+ };
+ 7216D2660EE8978F00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2450EE896C000AE70E4;
+ remoteInfo = netstat;
+ };
+ 7216D2BF0EE89ADF00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D27B0EE8980A00AE70E4;
+ remoteInfo = ping;
+ };
+ 7216D2C10EE89ADF00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2990EE898BD00AE70E4;
+ remoteInfo = ping6;
+ };
+ 7216D2D90EE89BE900AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2CC0EE89B7900AE70E4;
+ remoteInfo = rarpd;
+ };
+ 7216D3050EE89D9A00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2EC0EE89CBC00AE70E4;
+ remoteInfo = route;
+ };
+ 7216D34C0EE89FEC00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3130EE89E9E00AE70E4;
+ remoteInfo = rtadvd;
+ };
+ 7216D37E0EE8A0B300AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3580EE8A02200AE70E4;
+ remoteInfo = rtsol;
+ };
+ 72179EAD146233390098FB3E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723C7067142BAFEA007C87E9;
+ remoteInfo = dnctl;
+ };
+ 72311F4A194A34EB00EB4788 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72311F41194A349000EB4788;
+ remoteInfo = mptcp_client;
+ };
+ 72311F4C194A34F500EB4788 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72311F41194A349000EB4788;
+ remoteInfo = mptcp_client;
+ };
+ 72311F4E194A34FE00EB4788 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72311F41194A349000EB4788;
+ remoteInfo = mptcp_client;
+ };
+ 723C7073142BB003007C87E9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723C7067142BAFEA007C87E9;
+ remoteInfo = dnctl;
+ };
+ 724DABC20EE890A6008900D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DABA10EE88FE3008900D0;
+ remoteInfo = kdumpd;
+ };
+ 724DAC230EE89525008900D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DAC0C0EE8940D008900D0;
+ remoteInfo = ndp;
+ };
+ 7250E1461616642000A11A76 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7247B83016165EDC00873B3C;
+ remoteInfo = pktapctl;
+ };
+ 7250E1481616642900A11A76 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7247B83016165EDC00873B3C;
+ remoteInfo = pktapctl;
+ };
+ 7250E14A1616643000A11A76 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7247B83016165EDC00873B3C;
+ remoteInfo = pktapctl;
+ };
+ 726121480EE8717B00AFED1B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7261212C0EE8710B00AFED1B;
+ remoteInfo = arp;
+ };
+ 7261217C0EE8896800AFED1B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726121530EE8881700AFED1B;
+ remoteInfo = ifconfig;
+ };
+ 7263724A1BCC709900E4B026 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72946F421BBF055700087E35;
+ remoteInfo = frame_delay;
+ };
+ 7282BA561AFBDEAD005DE836 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836;
+ remoteInfo = ecnprobe;
+ };
+ 7282BA581AFBDEC2005DE836 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836;
+ remoteInfo = ecnprobe;
+ };
+ 7282BA5A1AFBDED3005DE836 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836;
+ remoteInfo = ecnprobe;
+ };
+ 72946F4B1BBF063800087E35 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72946F421BBF055700087E35;
+ remoteInfo = frame_delay;
+ };
+ 72946F4D1BBF063F00087E35 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72946F421BBF055700087E35;
+ remoteInfo = frame_delay;
+ };
+ 7294F0E90EE8BAC80052EC88 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3A60EE8A3BA00AE70E4;
+ remoteInfo = spray;
+ };
+ 7294F1200EE8BCC20052EC88 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F0F80EE8BB460052EC88;
+ remoteInfo = traceroute;
+ };
+ 72ABD0871083D750008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726121530EE8881700AFED1B;
+ remoteInfo = ifconfig;
+ };
+ 72ABD08B1083D75D008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DAC0C0EE8940D008900D0;
+ remoteInfo = ndp;
+ };
+ 72ABD08D1083D75F008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2450EE896C000AE70E4;
+ remoteInfo = netstat;
+ };
+ 72ABD08F1083D762008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D27B0EE8980A00AE70E4;
+ remoteInfo = ping;
+ };
+ 72ABD0911083D764008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2990EE898BD00AE70E4;
+ remoteInfo = ping6;
+ };
+ 72ABD0931083D767008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2CC0EE89B7900AE70E4;
+ remoteInfo = rarpd;
+ };
+ 72ABD0951083D76A008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2EC0EE89CBC00AE70E4;
+ remoteInfo = route;
+ };
+ 72ABD0971083D76D008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3130EE89E9E00AE70E4;
+ remoteInfo = rtadvd;
+ };
+ 72ABD0991083D76F008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3580EE8A02200AE70E4;
+ remoteInfo = rtsol;
+ };
+ 72ABD09B1083D772008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F0F80EE8BB460052EC88;
+ remoteInfo = traceroute;
+ };
+ 72ABD09D1083D774008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F1290EE8BD280052EC88;
+ remoteInfo = traceroute6;
+ };
+ 72ABD0A31083D818008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7261212C0EE8710B00AFED1B;
+ remoteInfo = arp;
+ };
+ 72B732E81899B18F0060E6D4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72B732D91899B0380060E6D4;
+ remoteInfo = cfilutil;
+ };
+ 72B732EA1899B19A0060E6D4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72B732D91899B0380060E6D4;
+ remoteInfo = cfilutil;
+ };
+ 72CD1D9B0EE8C47C005F825D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F1290EE8BD280052EC88;
+ remoteInfo = traceroute6;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 4D2B05221208CB410004A3F3 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 03EB2F9A120A1DDA0007C1A0 /* ip6addrctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 565825AA133921ED003E5FA5 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 565825A9133921CF003E5FA5 /* mnc.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 690D97AD12DE7074004323A7 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 690D97AE12DE70AE004323A7 /* mtest.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 69C10A6312DF7D5300BCDF4C /* Install OSS Plist */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceVersions/;
+ dstSubfolderSpec = 0;
+ files = (
+ 72E42BA314B7CF3D003AAE28 /* network_cmds.plist in Install OSS Plist */,
+ );
+ name = "Install OSS Plist";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 713297661A93C743002359CF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 71D958BB1A9452C200C9B286 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 71D958BE1A9453A500C9B286 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/etc/unbound;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7200F2F81958A34D0033E22C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2750EE8979500AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2600EE8971500AE70E4 /* netstat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2930EE8988200AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2880EE8982F00AE70E4 /* ping.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2AA0EE8991200AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2A90EE898F300AE70E4 /* ping6.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2E20EE89BEA00AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2E40EE89C8B00AE70E4 /* rarpd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2FA0EE89D2600AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3040EE89D4900AE70E4 /* route.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3370EE89F7500AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3240EE89F4200AE70E4 /* rtadvd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3380EE89F7500AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3390EE89F8400AE70E4 /* rtadvd.conf.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3460EE89FD700AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3410EE89FAF00AE70E4 /* rtadvd.conf in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D37B0EE8A06200AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3700EE8A05B00AE70E4 /* rtsol.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3C10EE8A42D00AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3AF0EE8A3D800AE70E4 /* spray.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72311F40194A349000EB4788 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 72311F56194A76DA00EB4788 /* mptcp_client.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723C7066142BAFEA007C87E9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 724753E7144905E300F6A941 /* dnctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7247B82F16165EDC00873B3C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 7247B83616165EDC00873B3C /* pktapctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724DABB70EE89035008900D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 724DABAB0EE89006008900D0 /* kdumpd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724DABC10EE89090008900D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ 724DABBC0EE8908A008900D0 /* com.apple.kdumpd.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724DAC1D0EE894E8008900D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 724DAC3B0EE89555008900D0 /* ndp.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7261213F0EE8713B00AFED1B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 726121350EE8713800AFED1B /* arp.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 726121620EE8887300AFED1B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 726121610EE8885400AFED1B /* ifconfig.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7282BA0A1AFAD4C9005DE836 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72946F411BBF055700087E35 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7294F11A0EE8BC0C0052EC88 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7294F1080EE8BBB10052EC88 /* traceroute.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7294F13E0EE8BDB30052EC88 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7294F1320EE8BD430052EC88 /* traceroute6.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72B732D81899B0380060E6D4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 72B732DF1899B0380060E6D4 /* cfilutil.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 01560DFC241969D3001AA29A /* vsock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vsock.c; sourceTree = "<group>"; };
+ 4D2B04E41208C12F0004A3F3 /* ip6addrctl.8 */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = ip6addrctl.8; sourceTree = "<group>"; };
+ 4D2B04E51208C12F0004A3F3 /* ip6addrctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ip6addrctl.c; sourceTree = "<group>"; };
+ 4D2B04E61208C12F0004A3F3 /* ip6addrctl.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ip6addrctl.conf; sourceTree = "<group>"; };
+ 4D2B04F31208C2040004A3F3 /* ip6addrctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ip6addrctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 565825941339217B003E5FA5 /* mnc.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mnc.1; sourceTree = "<group>"; };
+ 565825951339217B003E5FA5 /* LICENCE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENCE; sourceTree = "<group>"; };
+ 565825961339217B003E5FA5 /* mnc_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_error.c; sourceTree = "<group>"; };
+ 565825971339217B003E5FA5 /* mnc_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_main.c; sourceTree = "<group>"; };
+ 565825981339217B003E5FA5 /* mnc_multicast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_multicast.c; sourceTree = "<group>"; };
+ 565825991339217B003E5FA5 /* mnc_opts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_opts.c; sourceTree = "<group>"; };
+ 5658259A1339217B003E5FA5 /* mnc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mnc.h; sourceTree = "<group>"; };
+ 5658259B1339217B003E5FA5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ 5658259F1339218F003E5FA5 /* mnc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mnc; sourceTree = BUILT_PRODUCTS_DIR; };
+ 56B6B66716F79A1C00D8A7A9 /* mptcp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mptcp.c; sourceTree = "<group>"; };
+ 690D978112DE6034004323A7 /* mtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mtest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 690D979412DE6E6B004323A7 /* mtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mtest.c; sourceTree = "<group>"; };
+ 690D979512DE6E76004323A7 /* mtest.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mtest.8; sourceTree = "<group>"; };
+ 69C10A7912DF80F200BCDF4C /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
+ 713297681A93C743002359CF /* unbound */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unbound; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7200F2FA1958A34D0033E22C /* pktmnglr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pktmnglr; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7200F2FC1958A34D0033E22C /* packet_mangler.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = packet_mangler.c; sourceTree = "<group>"; };
+ 7211D9B2190713A60086EF20 /* network-client-server-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "network-client-server-entitlements.plist"; sourceTree = "<group>"; };
+ 721654C21EC52447005B17BA /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ 7216D2460EE896C000AE70E4 /* netstat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = netstat; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D27C0EE8980A00AE70E4 /* ping */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ping; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D29A0EE898BD00AE70E4 /* ping6 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ping6; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D2CD0EE89B7900AE70E4 /* rarpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rarpd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D2ED0EE89CBC00AE70E4 /* route */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = route; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D3140EE89E9E00AE70E4 /* rtadvd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rtadvd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D3590EE8A02200AE70E4 /* rtsol */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rtsol; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D3A70EE8A3BB00AE70E4 /* spray */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = spray; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7218B549191D4202001B7B52 /* systm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = systm.c; sourceTree = "<group>"; };
+ 72311F42194A349000EB4788 /* mptcp_client */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mptcp_client; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72311F50194A354F00EB4788 /* conn_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = conn_lib.c; sourceTree = "<group>"; };
+ 72311F51194A354F00EB4788 /* conn_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conn_lib.h; sourceTree = "<group>"; };
+ 72311F52194A354F00EB4788 /* mptcp_client.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mptcp_client.1; sourceTree = "<group>"; };
+ 72311F53194A354F00EB4788 /* mptcp_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mptcp_client.c; sourceTree = "<group>"; };
+ 723C7068142BAFEA007C87E9 /* dnctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724753E61448E1EF00F6A941 /* dnctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dnctl.8; sourceTree = "<group>"; };
+ 7247B83116165EDC00873B3C /* pktapctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pktapctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7247B83516165EDC00873B3C /* pktapctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pktapctl.8; sourceTree = "<group>"; };
+ 7247B83B16165F0100873B3C /* pktapctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pktapctl.c; sourceTree = "<group>"; };
+ 724DABA20EE88FE3008900D0 /* kdumpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kdumpd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724DAC0D0EE8940D008900D0 /* ndp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ndp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7255D4301E44036D008F4A32 /* libcrypto.35.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.35.dylib; path = usr/lib/libcrypto.35.dylib; sourceTree = SDKROOT; };
+ 7255D4321E44037F008F4A32 /* libssl.35.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.35.dylib; path = usr/lib/libssl.35.dylib; sourceTree = SDKROOT; };
+ 7261204D0EE86EF900AFED1B /* arp.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = arp.8; sourceTree = "<group>"; };
+ 7261204E0EE86EF900AFED1B /* arp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arp.c; sourceTree = "<group>"; };
+ 7261204F0EE86EF900AFED1B /* arp4.4 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = arp4.4; sourceTree = "<group>"; };
+ 726120550EE86F0900AFED1B /* ifbond.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifbond.c; sourceTree = "<group>"; };
+ 726120560EE86F0900AFED1B /* ifconfig.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ifconfig.8; sourceTree = "<group>"; };
+ 726120570EE86F0900AFED1B /* ifconfig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifconfig.c; sourceTree = "<group>"; };
+ 726120580EE86F0900AFED1B /* ifconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ifconfig.h; sourceTree = "<group>"; };
+ 726120590EE86F0900AFED1B /* ifmedia.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifmedia.c; sourceTree = "<group>"; };
+ 7261205A0EE86F0900AFED1B /* ifvlan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifvlan.c; sourceTree = "<group>"; };
+ 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.kdumpd.plist; sourceTree = "<group>"; };
+ 7261206F0EE86F2D00AFED1B /* kdump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kdump.h; sourceTree = "<group>"; };
+ 726120700EE86F2D00AFED1B /* kdumpd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = kdumpd.8; sourceTree = "<group>"; };
+ 726120710EE86F2D00AFED1B /* kdumpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kdumpd.c; sourceTree = "<group>"; };
+ 726120720EE86F2D00AFED1B /* kdumpsubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kdumpsubs.c; sourceTree = "<group>"; };
+ 726120730EE86F2D00AFED1B /* kdumpsubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kdumpsubs.h; sourceTree = "<group>"; };
+ 726120840EE86F4000AFED1B /* gnuc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gnuc.h; sourceTree = "<group>"; };
+ 726120860EE86F4000AFED1B /* ndp.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ndp.8; sourceTree = "<group>"; };
+ 726120870EE86F4000AFED1B /* ndp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ndp.c; sourceTree = "<group>"; };
+ 7261208B0EE86F4800AFED1B /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = data.c; sourceTree = "<group>"; };
+ 7261208C0EE86F4800AFED1B /* DERIVED_FILES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DERIVED_FILES; sourceTree = "<group>"; };
+ 7261208D0EE86F4800AFED1B /* if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if.c; sourceTree = "<group>"; };
+ 7261208E0EE86F4800AFED1B /* inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet.c; sourceTree = "<group>"; };
+ 7261208F0EE86F4800AFED1B /* inet6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet6.c; sourceTree = "<group>"; };
+ 726120900EE86F4800AFED1B /* ipsec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipsec.c; sourceTree = "<group>"; };
+ 726120910EE86F4800AFED1B /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ 726120930EE86F4800AFED1B /* mbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbuf.c; sourceTree = "<group>"; };
+ 726120940EE86F4800AFED1B /* mcast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcast.c; sourceTree = "<group>"; };
+ 726120970EE86F4800AFED1B /* netstat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = netstat.1; sourceTree = "<group>"; };
+ 726120980EE86F4800AFED1B /* netstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = netstat.h; sourceTree = "<group>"; };
+ 726120990EE86F4800AFED1B /* route.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = route.c; sourceTree = "<group>"; };
+ 7261209A0EE86F4800AFED1B /* tp_astring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tp_astring.c; sourceTree = "<group>"; };
+ 7261209B0EE86F4800AFED1B /* unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unix.c; sourceTree = "<group>"; };
+ 726120A00EE86F5000AFED1B /* ping.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ping.8; sourceTree = "<group>"; };
+ 726120A10EE86F5000AFED1B /* ping.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ping.c; sourceTree = "<group>"; };
+ 726120A60EE86F5C00AFED1B /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = md5.c; sourceTree = "<group>"; };
+ 726120A70EE86F5C00AFED1B /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; };
+ 726120A80EE86F5C00AFED1B /* ping6.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ping6.8; sourceTree = "<group>"; };
+ 726120A90EE86F5C00AFED1B /* ping6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ping6.c; sourceTree = "<group>"; };
+ 726120AE0EE86F6700AFED1B /* rarpd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rarpd.8; sourceTree = "<group>"; };
+ 726120AF0EE86F6700AFED1B /* rarpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rarpd.c; sourceTree = "<group>"; };
+ 726120B30EE86F7200AFED1B /* gen_header.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = gen_header.pl; sourceTree = "<group>"; };
+ 726120B40EE86F7200AFED1B /* keywords */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = keywords; sourceTree = "<group>"; };
+ 726120B50EE86F7200AFED1B /* keywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywords.h; sourceTree = "<group>"; };
+ 726120B70EE86F7200AFED1B /* route.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = route.8; sourceTree = "<group>"; };
+ 726120B80EE86F7200AFED1B /* route.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = route.c; sourceTree = "<group>"; };
+ 726120BC0EE86F8200AFED1B /* advcap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = advcap.c; sourceTree = "<group>"; };
+ 726120BD0EE86F8200AFED1B /* advcap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advcap.h; sourceTree = "<group>"; };
+ 726120BE0EE86F8200AFED1B /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = config.c; sourceTree = "<group>"; };
+ 726120BF0EE86F8200AFED1B /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+ 726120C00EE86F8200AFED1B /* dump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dump.c; sourceTree = "<group>"; };
+ 726120C10EE86F8200AFED1B /* dump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dump.h; sourceTree = "<group>"; };
+ 726120C20EE86F8200AFED1B /* if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if.c; sourceTree = "<group>"; };
+ 726120C30EE86F8200AFED1B /* if.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if.h; sourceTree = "<group>"; };
+ 726120C50EE86F8200AFED1B /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ 726120C60EE86F8200AFED1B /* rrenum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rrenum.c; sourceTree = "<group>"; };
+ 726120C70EE86F8200AFED1B /* rrenum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rrenum.h; sourceTree = "<group>"; };
+ 726120C80EE86F8200AFED1B /* rtadvd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtadvd.8; sourceTree = "<group>"; };
+ 726120C90EE86F8200AFED1B /* rtadvd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtadvd.c; sourceTree = "<group>"; };
+ 726120CA0EE86F8200AFED1B /* rtadvd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtadvd.conf; sourceTree = "<group>"; };
+ 726120CB0EE86F8200AFED1B /* rtadvd.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtadvd.conf.5; sourceTree = "<group>"; };
+ 726120CC0EE86F8200AFED1B /* rtadvd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtadvd.h; sourceTree = "<group>"; };
+ 726120CD0EE86F8200AFED1B /* timer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = timer.c; sourceTree = "<group>"; };
+ 726120CE0EE86F8200AFED1B /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; };
+ 726120D20EE86F9100AFED1B /* dump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dump.c; sourceTree = "<group>"; };
+ 726120D30EE86F9100AFED1B /* if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if.c; sourceTree = "<group>"; };
+ 726120D50EE86F9100AFED1B /* probe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = probe.c; sourceTree = "<group>"; };
+ 726120D60EE86F9100AFED1B /* rtsock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtsock.c; sourceTree = "<group>"; };
+ 726120D70EE86F9100AFED1B /* rtsol.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtsol.8; sourceTree = "<group>"; };
+ 726120D80EE86F9100AFED1B /* rtsol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtsol.c; sourceTree = "<group>"; };
+ 726120D90EE86F9100AFED1B /* rtsold.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtsold.c; sourceTree = "<group>"; };
+ 726120DA0EE86F9100AFED1B /* rtsold.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtsold.h; sourceTree = "<group>"; };
+ 726120DF0EE86F9D00AFED1B /* spray.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = spray.8; sourceTree = "<group>"; };
+ 726120E00EE86F9D00AFED1B /* spray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spray.c; sourceTree = "<group>"; };
+ 726120E10EE86F9D00AFED1B /* spray.x */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = spray.x; sourceTree = "<group>"; };
+ 726120E50EE86FA700AFED1B /* as.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = as.c; sourceTree = "<group>"; };
+ 726120E60EE86FA700AFED1B /* as.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = as.h; sourceTree = "<group>"; };
+ 726120E70EE86FA700AFED1B /* findsaddr-socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "findsaddr-socket.c"; sourceTree = "<group>"; };
+ 726120E80EE86FA700AFED1B /* findsaddr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = findsaddr.h; sourceTree = "<group>"; };
+ 726120E90EE86FA700AFED1B /* gnuc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gnuc.h; sourceTree = "<group>"; };
+ 726120EA0EE86FA700AFED1B /* ifaddrlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifaddrlist.c; sourceTree = "<group>"; };
+ 726120EB0EE86FA700AFED1B /* ifaddrlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ifaddrlist.h; sourceTree = "<group>"; };
+ 726120ED0EE86FA700AFED1B /* mean.awk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mean.awk; sourceTree = "<group>"; };
+ 726120EE0EE86FA700AFED1B /* median.awk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = median.awk; sourceTree = "<group>"; };
+ 726120EF0EE86FA700AFED1B /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ 726120F00EE86FA700AFED1B /* traceroute.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = traceroute.8; sourceTree = "<group>"; };
+ 726120F10EE86FA700AFED1B /* traceroute.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traceroute.c; sourceTree = "<group>"; };
+ 726120F20EE86FA700AFED1B /* traceroute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traceroute.h; sourceTree = "<group>"; };
+ 726120F30EE86FA700AFED1B /* version.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = "<group>"; };
+ 726120FA0EE86FB500AFED1B /* traceroute6.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = traceroute6.8; sourceTree = "<group>"; };
+ 726120FB0EE86FB500AFED1B /* traceroute6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traceroute6.c; sourceTree = "<group>"; };
+ 7261212D0EE8710B00AFED1B /* arp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = arp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 726121540EE8881700AFED1B /* ifconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ifconfig; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7263724C1BCC718B00E4B026 /* frame_delay.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = frame_delay.8; sourceTree = "<group>"; };
+ 7282BA0C1AFAD4C9005DE836 /* ecnprobe */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ecnprobe; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7282BA341AFAD58E005DE836 /* base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base.h; sourceTree = "<group>"; };
+ 7282BA351AFAD58E005DE836 /* capture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = capture.c; sourceTree = "<group>"; };
+ 7282BA361AFAD58E005DE836 /* capture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = capture.h; sourceTree = "<group>"; };
+ 7282BA391AFAD58E005DE836 /* ecn_probe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ecn_probe.c; sourceTree = "<group>"; };
+ 7282BA3A1AFAD58E005DE836 /* ecn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ecn.c; sourceTree = "<group>"; };
+ 7282BA3B1AFAD58E005DE836 /* ecn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecn.h; sourceTree = "<group>"; };
+ 7282BA3C1AFAD58E005DE836 /* gmt2local.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gmt2local.c; sourceTree = "<group>"; };
+ 7282BA3D1AFAD58E005DE836 /* gmt2local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gmt2local.h; sourceTree = "<group>"; };
+ 7282BA3E1AFAD58E005DE836 /* history.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = history.c; sourceTree = "<group>"; };
+ 7282BA3F1AFAD58E005DE836 /* history.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = history.h; sourceTree = "<group>"; };
+ 7282BA401AFAD58E005DE836 /* inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet.c; sourceTree = "<group>"; };
+ 7282BA411AFAD58E005DE836 /* inet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inet.h; sourceTree = "<group>"; };
+ 7282BA451AFAD58E005DE836 /* session.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = session.c; sourceTree = "<group>"; };
+ 7282BA461AFAD58E005DE836 /* session.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = "<group>"; };
+ 7282BA471AFAD58E005DE836 /* support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = support.c; sourceTree = "<group>"; };
+ 7282BA481AFAD58E005DE836 /* support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = support.h; sourceTree = "<group>"; };
+ 7282BA541AFBCA66005DE836 /* libpcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcap.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libpcap.dylib; sourceTree = DEVELOPER_DIR; };
+ 7282BA5C1AFBED07005DE836 /* ecnprobe.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ecnprobe.1; sourceTree = "<group>"; };
+ 72946F431BBF055700087E35 /* frame_delay */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = frame_delay; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72946F4F1BBF07FF00087E35 /* frame_delay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frame_delay.c; sourceTree = "<group>"; };
+ 7294F0F90EE8BB460052EC88 /* traceroute */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = traceroute; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7294F12A0EE8BD280052EC88 /* traceroute6 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = traceroute6; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72B732DA1899B0380060E6D4 /* cfilutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cfilutil; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72B732DE1899B0380060E6D4 /* cfilutil.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cfilutil.1; sourceTree = "<group>"; };
+ 72B732EE1899B23A0060E6D4 /* cfilutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cfilutil.c; sourceTree = "<group>"; };
+ 72B732F01899B2430060E6D4 /* cfilstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cfilstat.c; sourceTree = "<group>"; };
+ 72B7F36A1BA69281003A9AA2 /* if6lowpan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if6lowpan.c; sourceTree = "<group>"; };
+ 72CD1DB50EE8C619005F825D /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = "<absolute>"; };
+ 72D000C3142BB11100151981 /* dnctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnctl.c; sourceTree = "<group>"; };
+ 72D33F552271220100EF5B5E /* rtadvd_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtadvd_logging.h; sourceTree = "<group>"; };
+ 72D33F562271220100EF5B5E /* rtadvd_logging.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtadvd_logging.c; sourceTree = "<group>"; };
+ 72E42BA214B7CF37003AAE28 /* network_cmds.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = network_cmds.plist; sourceTree = "<group>"; };
+ 72E650A2107BF2F000AAF325 /* af_inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = af_inet.c; sourceTree = "<group>"; };
+ 72E650A3107BF2F000AAF325 /* af_inet6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = af_inet6.c; sourceTree = "<group>"; };
+ 72E650A4107BF2F000AAF325 /* af_link.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = af_link.c; sourceTree = "<group>"; };
+ 72E650A5107BF2F000AAF325 /* ifbridge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifbridge.c; sourceTree = "<group>"; };
+ 72E650A6107BF2F000AAF325 /* ifclone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifclone.c; sourceTree = "<group>"; };
+ E01AB08F1368880F008C66FF /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = $SDKROOT/usr/lib/libutil.dylib; sourceTree = "<group>"; };
+ F940359C1E2FF58500283EB1 /* iffake.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iffake.c; sourceTree = "<group>"; };
+ F97F1E031E9C3FBC002355FF /* nexus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nexus.c; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5658259D1339218F003E5FA5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 690D977F12DE6034004323A7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 713297651A93C743002359CF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7200F2F71958A34D0033E22C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2440EE896C000AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D27A0EE8980A00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2980EE898BD00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7263A9630EEE31C800164D5D /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2CB0EE89B7900AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2EB0EE89CBC00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3120EE89E9E00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ E01AB0901368880F008C66FF /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3570EE8A02200AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3A50EE8A3BA00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72311F3F194A349000EB4788 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723C7065142BAFEA007C87E9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7247B82E16165EDC00873B3C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DABA00EE88FE3008900D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DAC0B0EE8940D008900D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7261212B0EE8710B00AFED1B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 726121520EE8881700AFED1B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7282BA091AFAD4C9005DE836 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7282BA551AFBCA66005DE836 /* libpcap.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72946F401BBF055700087E35 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F0F70EE8BB460052EC88 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F1280EE8BD280052EC88 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72B894EC0EEDB17C00C218D6 /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72B732D71899B0380060E6D4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 4D2B04E31208C12F0004A3F3 /* ip6addrctl.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 4D2B04E41208C12F0004A3F3 /* ip6addrctl.8 */,
+ 4D2B04E51208C12F0004A3F3 /* ip6addrctl.c */,
+ 4D2B04E61208C12F0004A3F3 /* ip6addrctl.conf */,
+ );
+ path = ip6addrctl.tproj;
+ sourceTree = "<group>";
+ };
+ 56582591133920B5003E5FA5 /* mnc.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 565825941339217B003E5FA5 /* mnc.1 */,
+ 565825951339217B003E5FA5 /* LICENCE */,
+ 565825961339217B003E5FA5 /* mnc_error.c */,
+ 565825971339217B003E5FA5 /* mnc_main.c */,
+ 565825981339217B003E5FA5 /* mnc_multicast.c */,
+ 565825991339217B003E5FA5 /* mnc_opts.c */,
+ 5658259A1339217B003E5FA5 /* mnc.h */,
+ 5658259B1339217B003E5FA5 /* README */,
+ );
+ path = mnc.tproj;
+ sourceTree = "<group>";
+ };
+ 690D973F12DE5A21004323A7 /* mtest.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 690D979512DE6E76004323A7 /* mtest.8 */,
+ 690D979412DE6E6B004323A7 /* mtest.c */,
+ 69C10A7912DF80F200BCDF4C /* COPYING */,
+ );
+ path = mtest.tproj;
+ sourceTree = "<group>";
+ };
+ 7200F2FB1958A34D0033E22C /* pktmnglr */ = {
+ isa = PBXGroup;
+ children = (
+ 7200F2FC1958A34D0033E22C /* packet_mangler.c */,
+ );
+ path = pktmnglr;
+ sourceTree = "<group>";
+ };
+ 72311F43194A349100EB4788 /* mptcp_client */ = {
+ isa = PBXGroup;
+ children = (
+ 72311F53194A354F00EB4788 /* mptcp_client.c */,
+ 72311F50194A354F00EB4788 /* conn_lib.c */,
+ 72311F51194A354F00EB4788 /* conn_lib.h */,
+ 72311F52194A354F00EB4788 /* mptcp_client.1 */,
+ );
+ path = mptcp_client;
+ sourceTree = "<group>";
+ };
+ 723C706A142BAFEA007C87E9 /* dnctl */ = {
+ isa = PBXGroup;
+ children = (
+ 724753E61448E1EF00F6A941 /* dnctl.8 */,
+ 72D000C3142BB11100151981 /* dnctl.c */,
+ );
+ path = dnctl;
+ sourceTree = "<group>";
+ };
+ 7247B83216165EDC00873B3C /* pktapctl */ = {
+ isa = PBXGroup;
+ children = (
+ 7247B83B16165F0100873B3C /* pktapctl.c */,
+ 7247B83516165EDC00873B3C /* pktapctl.8 */,
+ );
+ path = pktapctl;
+ sourceTree = "<group>";
+ };
+ 7248622F0EE86EB7001D0DE9 = {
+ isa = PBXGroup;
+ children = (
+ 7282BA541AFBCA66005DE836 /* libpcap.dylib */,
+ 72E42BA214B7CF37003AAE28 /* network_cmds.plist */,
+ 7211D9B2190713A60086EF20 /* network-client-server-entitlements.plist */,
+ E01AB08F1368880F008C66FF /* libutil.dylib */,
+ 7261204C0EE86EF900AFED1B /* arp.tproj */,
+ 72B732DB1899B0380060E6D4 /* cfilutil */,
+ 723C706A142BAFEA007C87E9 /* dnctl */,
+ 7282BA0D1AFAD4C9005DE836 /* ecnprobe */,
+ 72946F441BBF055700087E35 /* frame_delay */,
+ 726120540EE86F0900AFED1B /* ifconfig.tproj */,
+ 4D2B04E31208C12F0004A3F3 /* ip6addrctl.tproj */,
+ 7261206D0EE86F2D00AFED1B /* kdumpd.tproj */,
+ 56582591133920B5003E5FA5 /* mnc.tproj */,
+ 72311F43194A349100EB4788 /* mptcp_client */,
+ 690D973F12DE5A21004323A7 /* mtest.tproj */,
+ 726120830EE86F4000AFED1B /* ndp.tproj */,
+ 7261208A0EE86F4800AFED1B /* netstat.tproj */,
+ 7247B83216165EDC00873B3C /* pktapctl */,
+ 7200F2FB1958A34D0033E22C /* pktmnglr */,
+ 7261209E0EE86F5000AFED1B /* ping.tproj */,
+ 726120A40EE86F5C00AFED1B /* ping6.tproj */,
+ 726120AC0EE86F6700AFED1B /* rarpd.tproj */,
+ 726120B20EE86F7200AFED1B /* route.tproj */,
+ 726120BB0EE86F8200AFED1B /* rtadvd.tproj */,
+ 726120D10EE86F9100AFED1B /* rtsol.tproj */,
+ 726120DD0EE86F9D00AFED1B /* spray.tproj */,
+ 726120E40EE86FA700AFED1B /* traceroute.tproj */,
+ 726120F80EE86FB500AFED1B /* traceroute6.tproj */,
+ 72CD1DB50EE8C619005F825D /* libipsec.dylib */,
+ 7261210D0EE8707500AFED1B /* Products */,
+ 7255D42F1E44036D008F4A32 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 7255D42F1E44036D008F4A32 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 7255D4321E44037F008F4A32 /* libssl.35.dylib */,
+ 7255D4301E44036D008F4A32 /* libcrypto.35.dylib */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 7261204C0EE86EF900AFED1B /* arp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 7261204D0EE86EF900AFED1B /* arp.8 */,
+ 7261204E0EE86EF900AFED1B /* arp.c */,
+ 7261204F0EE86EF900AFED1B /* arp4.4 */,
+ );
+ path = arp.tproj;
+ sourceTree = "<group>";
+ };
+ 726120540EE86F0900AFED1B /* ifconfig.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 72B7F36A1BA69281003A9AA2 /* if6lowpan.c */,
+ 72E650A2107BF2F000AAF325 /* af_inet.c */,
+ 72E650A3107BF2F000AAF325 /* af_inet6.c */,
+ 72E650A4107BF2F000AAF325 /* af_link.c */,
+ 72E650A5107BF2F000AAF325 /* ifbridge.c */,
+ 72E650A6107BF2F000AAF325 /* ifclone.c */,
+ 726120550EE86F0900AFED1B /* ifbond.c */,
+ 726120560EE86F0900AFED1B /* ifconfig.8 */,
+ 726120570EE86F0900AFED1B /* ifconfig.c */,
+ 726120580EE86F0900AFED1B /* ifconfig.h */,
+ F940359C1E2FF58500283EB1 /* iffake.c */,
+ 726120590EE86F0900AFED1B /* ifmedia.c */,
+ 7261205A0EE86F0900AFED1B /* ifvlan.c */,
+ F97F1E031E9C3FBC002355FF /* nexus.c */,
+ );
+ path = ifconfig.tproj;
+ sourceTree = "<group>";
+ };
+ 7261206D0EE86F2D00AFED1B /* kdumpd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */,
+ 7261206F0EE86F2D00AFED1B /* kdump.h */,
+ 726120700EE86F2D00AFED1B /* kdumpd.8 */,
+ 726120710EE86F2D00AFED1B /* kdumpd.c */,
+ 726120720EE86F2D00AFED1B /* kdumpsubs.c */,
+ 726120730EE86F2D00AFED1B /* kdumpsubs.h */,
+ );
+ path = kdumpd.tproj;
+ sourceTree = "<group>";
+ };
+ 726120830EE86F4000AFED1B /* ndp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120840EE86F4000AFED1B /* gnuc.h */,
+ 726120860EE86F4000AFED1B /* ndp.8 */,
+ 726120870EE86F4000AFED1B /* ndp.c */,
+ );
+ path = ndp.tproj;
+ sourceTree = "<group>";
+ };
+ 7261208A0EE86F4800AFED1B /* netstat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 7261208B0EE86F4800AFED1B /* data.c */,
+ 7261208C0EE86F4800AFED1B /* DERIVED_FILES */,
+ 7261208D0EE86F4800AFED1B /* if.c */,
+ 7261208E0EE86F4800AFED1B /* inet.c */,
+ 7261208F0EE86F4800AFED1B /* inet6.c */,
+ 726120900EE86F4800AFED1B /* ipsec.c */,
+ 726120910EE86F4800AFED1B /* main.c */,
+ 726120930EE86F4800AFED1B /* mbuf.c */,
+ 726120940EE86F4800AFED1B /* mcast.c */,
+ 56B6B66716F79A1C00D8A7A9 /* mptcp.c */,
+ 726120970EE86F4800AFED1B /* netstat.1 */,
+ 726120980EE86F4800AFED1B /* netstat.h */,
+ 726120990EE86F4800AFED1B /* route.c */,
+ 7261209A0EE86F4800AFED1B /* tp_astring.c */,
+ 7261209B0EE86F4800AFED1B /* unix.c */,
+ 7218B549191D4202001B7B52 /* systm.c */,
+ 721654C21EC52447005B17BA /* misc.c */,
+ 01560DFC241969D3001AA29A /* vsock.c */,
+ );
+ path = netstat.tproj;
+ sourceTree = "<group>";
+ };
+ 7261209E0EE86F5000AFED1B /* ping.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120A00EE86F5000AFED1B /* ping.8 */,
+ 726120A10EE86F5000AFED1B /* ping.c */,
+ );
+ path = ping.tproj;
+ sourceTree = "<group>";
+ };
+ 726120A40EE86F5C00AFED1B /* ping6.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120A60EE86F5C00AFED1B /* md5.c */,
+ 726120A70EE86F5C00AFED1B /* md5.h */,
+ 726120A80EE86F5C00AFED1B /* ping6.8 */,
+ 726120A90EE86F5C00AFED1B /* ping6.c */,
+ );
+ path = ping6.tproj;
+ sourceTree = "<group>";
+ };
+ 726120AC0EE86F6700AFED1B /* rarpd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120AE0EE86F6700AFED1B /* rarpd.8 */,
+ 726120AF0EE86F6700AFED1B /* rarpd.c */,
+ );
+ path = rarpd.tproj;
+ sourceTree = "<group>";
+ };
+ 726120B20EE86F7200AFED1B /* route.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120B30EE86F7200AFED1B /* gen_header.pl */,
+ 726120B40EE86F7200AFED1B /* keywords */,
+ 726120B50EE86F7200AFED1B /* keywords.h */,
+ 726120B70EE86F7200AFED1B /* route.8 */,
+ 726120B80EE86F7200AFED1B /* route.c */,
+ );
+ path = route.tproj;
+ sourceTree = "<group>";
+ };
+ 726120BB0EE86F8200AFED1B /* rtadvd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 72D33F562271220100EF5B5E /* rtadvd_logging.c */,
+ 72D33F552271220100EF5B5E /* rtadvd_logging.h */,
+ 726120BC0EE86F8200AFED1B /* advcap.c */,
+ 726120BD0EE86F8200AFED1B /* advcap.h */,
+ 726120BE0EE86F8200AFED1B /* config.c */,
+ 726120BF0EE86F8200AFED1B /* config.h */,
+ 726120C00EE86F8200AFED1B /* dump.c */,
+ 726120C10EE86F8200AFED1B /* dump.h */,
+ 726120C20EE86F8200AFED1B /* if.c */,
+ 726120C30EE86F8200AFED1B /* if.h */,
+ 726120C50EE86F8200AFED1B /* pathnames.h */,
+ 726120C60EE86F8200AFED1B /* rrenum.c */,
+ 726120C70EE86F8200AFED1B /* rrenum.h */,
+ 726120C80EE86F8200AFED1B /* rtadvd.8 */,
+ 726120C90EE86F8200AFED1B /* rtadvd.c */,
+ 726120CA0EE86F8200AFED1B /* rtadvd.conf */,
+ 726120CB0EE86F8200AFED1B /* rtadvd.conf.5 */,
+ 726120CC0EE86F8200AFED1B /* rtadvd.h */,
+ 726120CD0EE86F8200AFED1B /* timer.c */,
+ 726120CE0EE86F8200AFED1B /* timer.h */,
+ );
+ path = rtadvd.tproj;
+ sourceTree = "<group>";
+ };
+ 726120D10EE86F9100AFED1B /* rtsol.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120D20EE86F9100AFED1B /* dump.c */,
+ 726120D30EE86F9100AFED1B /* if.c */,
+ 726120D50EE86F9100AFED1B /* probe.c */,
+ 726120D60EE86F9100AFED1B /* rtsock.c */,
+ 726120D70EE86F9100AFED1B /* rtsol.8 */,
+ 726120D80EE86F9100AFED1B /* rtsol.c */,
+ 726120D90EE86F9100AFED1B /* rtsold.c */,
+ 726120DA0EE86F9100AFED1B /* rtsold.h */,
+ );
+ path = rtsol.tproj;
+ sourceTree = "<group>";
+ };
+ 726120DD0EE86F9D00AFED1B /* spray.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120DF0EE86F9D00AFED1B /* spray.8 */,
+ 726120E00EE86F9D00AFED1B /* spray.c */,
+ 726120E10EE86F9D00AFED1B /* spray.x */,
+ );
+ path = spray.tproj;
+ sourceTree = "<group>";
+ };
+ 726120E40EE86FA700AFED1B /* traceroute.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120E50EE86FA700AFED1B /* as.c */,
+ 726120E60EE86FA700AFED1B /* as.h */,
+ 726120E70EE86FA700AFED1B /* findsaddr-socket.c */,
+ 726120E80EE86FA700AFED1B /* findsaddr.h */,
+ 726120E90EE86FA700AFED1B /* gnuc.h */,
+ 726120EA0EE86FA700AFED1B /* ifaddrlist.c */,
+ 726120EB0EE86FA700AFED1B /* ifaddrlist.h */,
+ 726120ED0EE86FA700AFED1B /* mean.awk */,
+ 726120EE0EE86FA700AFED1B /* median.awk */,
+ 726120EF0EE86FA700AFED1B /* README */,
+ 726120F00EE86FA700AFED1B /* traceroute.8 */,
+ 726120F10EE86FA700AFED1B /* traceroute.c */,
+ 726120F20EE86FA700AFED1B /* traceroute.h */,
+ 726120F30EE86FA700AFED1B /* version.c */,
+ );
+ path = traceroute.tproj;
+ sourceTree = "<group>";
+ };
+ 726120F80EE86FB500AFED1B /* traceroute6.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120FA0EE86FB500AFED1B /* traceroute6.8 */,
+ 726120FB0EE86FB500AFED1B /* traceroute6.c */,
+ );
+ path = traceroute6.tproj;
+ sourceTree = "<group>";
+ };
+ 7261210D0EE8707500AFED1B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 7261212D0EE8710B00AFED1B /* arp */,
+ 726121540EE8881700AFED1B /* ifconfig */,
+ 724DABA20EE88FE3008900D0 /* kdumpd */,
+ 724DAC0D0EE8940D008900D0 /* ndp */,
+ 7216D2460EE896C000AE70E4 /* netstat */,
+ 7216D27C0EE8980A00AE70E4 /* ping */,
+ 7216D29A0EE898BD00AE70E4 /* ping6 */,
+ 7216D2CD0EE89B7900AE70E4 /* rarpd */,
+ 7216D2ED0EE89CBC00AE70E4 /* route */,
+ 7216D3140EE89E9E00AE70E4 /* rtadvd */,
+ 7216D3590EE8A02200AE70E4 /* rtsol */,
+ 7216D3A70EE8A3BB00AE70E4 /* spray */,
+ 7294F0F90EE8BB460052EC88 /* traceroute */,
+ 7294F12A0EE8BD280052EC88 /* traceroute6 */,
+ 4D2B04F31208C2040004A3F3 /* ip6addrctl */,
+ 690D978112DE6034004323A7 /* mtest */,
+ 5658259F1339218F003E5FA5 /* mnc */,
+ 723C7068142BAFEA007C87E9 /* dnctl */,
+ 7247B83116165EDC00873B3C /* pktapctl */,
+ 72B732DA1899B0380060E6D4 /* cfilutil */,
+ 72311F42194A349000EB4788 /* mptcp_client */,
+ 7200F2FA1958A34D0033E22C /* pktmnglr */,
+ 713297681A93C743002359CF /* unbound */,
+ 7282BA0C1AFAD4C9005DE836 /* ecnprobe */,
+ 72946F431BBF055700087E35 /* frame_delay */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 7282BA0D1AFAD4C9005DE836 /* ecnprobe */ = {
+ isa = PBXGroup;
+ children = (
+ 7282BA341AFAD58E005DE836 /* base.h */,
+ 7282BA351AFAD58E005DE836 /* capture.c */,
+ 7282BA361AFAD58E005DE836 /* capture.h */,
+ 7282BA391AFAD58E005DE836 /* ecn_probe.c */,
+ 7282BA3A1AFAD58E005DE836 /* ecn.c */,
+ 7282BA3B1AFAD58E005DE836 /* ecn.h */,
+ 7282BA3C1AFAD58E005DE836 /* gmt2local.c */,
+ 7282BA3D1AFAD58E005DE836 /* gmt2local.h */,
+ 7282BA3E1AFAD58E005DE836 /* history.c */,
+ 7282BA3F1AFAD58E005DE836 /* history.h */,
+ 7282BA401AFAD58E005DE836 /* inet.c */,
+ 7282BA411AFAD58E005DE836 /* inet.h */,
+ 7282BA451AFAD58E005DE836 /* session.c */,
+ 7282BA461AFAD58E005DE836 /* session.h */,
+ 7282BA471AFAD58E005DE836 /* support.c */,
+ 7282BA481AFAD58E005DE836 /* support.h */,
+ 7282BA5C1AFBED07005DE836 /* ecnprobe.1 */,
+ );
+ path = ecnprobe;
+ sourceTree = "<group>";
+ };
+ 72946F441BBF055700087E35 /* frame_delay */ = {
+ isa = PBXGroup;
+ children = (
+ 72946F4F1BBF07FF00087E35 /* frame_delay.c */,
+ 7263724C1BCC718B00E4B026 /* frame_delay.8 */,
+ );
+ path = frame_delay;
+ sourceTree = "<group>";
+ };
+ 72B732DB1899B0380060E6D4 /* cfilutil */ = {
+ isa = PBXGroup;
+ children = (
+ 72B732EE1899B23A0060E6D4 /* cfilutil.c */,
+ 72B732F01899B2430060E6D4 /* cfilstat.c */,
+ 72B732DE1899B0380060E6D4 /* cfilutil.1 */,
+ );
+ path = cfilutil;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 4D2B04F21208C2040004A3F3 /* ip6addrctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D2B05121208C2300004A3F3 /* Build configuration list for PBXNativeTarget "ip6addrctl" */;
+ buildPhases = (
+ 4D2B04F01208C2040004A3F3 /* Sources */,
+ 4D2B05221208CB410004A3F3 /* CopyFiles */,
+ 039D6A11120A2CF60006B8C8 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ip6addrctl;
+ productName = ip6addrctl;
+ productReference = 4D2B04F31208C2040004A3F3 /* ip6addrctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 5658259E1339218F003E5FA5 /* mnc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 565825AB133921ED003E5FA5 /* Build configuration list for PBXNativeTarget "mnc" */;
+ buildPhases = (
+ 5658259C1339218F003E5FA5 /* Sources */,
+ 5658259D1339218F003E5FA5 /* Frameworks */,
+ 565825AA133921ED003E5FA5 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mnc;
+ productName = mnc;
+ productReference = 5658259F1339218F003E5FA5 /* mnc */;
+ productType = "com.apple.product-type.tool";
+ };
+ 690D978012DE6034004323A7 /* mtest */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 690D978612DE6053004323A7 /* Build configuration list for PBXNativeTarget "mtest" */;
+ buildPhases = (
+ 690D977E12DE6034004323A7 /* Sources */,
+ 690D977F12DE6034004323A7 /* Frameworks */,
+ 690D97AD12DE7074004323A7 /* CopyFiles */,
+ 69C10A6312DF7D5300BCDF4C /* Install OSS Plist */,
+ 69C10A7612DF7EBB00BCDF4C /* Install OSS License */,
+ 690D97C212DE71CF004323A7 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mtest;
+ productName = mtest;
+ productReference = 690D978112DE6034004323A7 /* mtest */;
+ productType = "com.apple.product-type.tool";
+ };
+ 713297671A93C743002359CF /* unbound */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7132976F1A93C743002359CF /* Build configuration list for PBXNativeTarget "unbound" */;
+ buildPhases = (
+ 713297641A93C743002359CF /* Sources */,
+ 713297651A93C743002359CF /* Frameworks */,
+ 713297661A93C743002359CF /* CopyFiles */,
+ 71D958BB1A9452C200C9B286 /* CopyFiles */,
+ 71D958BE1A9453A500C9B286 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = unbound;
+ productName = unbound;
+ productReference = 713297681A93C743002359CF /* unbound */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7200F2F91958A34D0033E22C /* pktmnglr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7200F3011958A34E0033E22C /* Build configuration list for PBXNativeTarget "pktmnglr" */;
+ buildPhases = (
+ 7200F2F61958A34D0033E22C /* Sources */,
+ 7200F2F71958A34D0033E22C /* Frameworks */,
+ 7200F2F81958A34D0033E22C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pktmnglr;
+ productName = pktmnglr;
+ productReference = 7200F2FA1958A34D0033E22C /* pktmnglr */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2450EE896C000AE70E4 /* netstat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D24B0EE896EC00AE70E4 /* Build configuration list for PBXNativeTarget "netstat" */;
+ buildPhases = (
+ 7216D2430EE896C000AE70E4 /* Sources */,
+ 7216D2440EE896C000AE70E4 /* Frameworks */,
+ 7216D2750EE8979500AE70E4 /* CopyFiles */,
+ 7216D2640EE8972E00AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = netstat;
+ productName = netstat;
+ productReference = 7216D2460EE896C000AE70E4 /* netstat */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D27B0EE8980A00AE70E4 /* ping */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2940EE8988200AE70E4 /* Build configuration list for PBXNativeTarget "ping" */;
+ buildPhases = (
+ 7216D2790EE8980A00AE70E4 /* Sources */,
+ 7216D27A0EE8980A00AE70E4 /* Frameworks */,
+ 7216D2930EE8988200AE70E4 /* CopyFiles */,
+ 7216D2870EE8982900AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ping;
+ productName = ping;
+ productReference = 7216D27C0EE8980A00AE70E4 /* ping */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2990EE898BD00AE70E4 /* ping6 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2AB0EE8991200AE70E4 /* Build configuration list for PBXNativeTarget "ping6" */;
+ buildPhases = (
+ 7216D2970EE898BD00AE70E4 /* Sources */,
+ 7216D2980EE898BD00AE70E4 /* Frameworks */,
+ 7216D2AA0EE8991200AE70E4 /* CopyFiles */,
+ 7216D2AF0EE8993100AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ping6;
+ productName = ping6;
+ productReference = 7216D29A0EE898BD00AE70E4 /* ping6 */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2CC0EE89B7900AE70E4 /* rarpd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2E30EE89BEA00AE70E4 /* Build configuration list for PBXNativeTarget "rarpd" */;
+ buildPhases = (
+ 7216D2CA0EE89B7900AE70E4 /* Sources */,
+ 7216D2CB0EE89B7900AE70E4 /* Frameworks */,
+ 7216D2E20EE89BEA00AE70E4 /* CopyFiles */,
+ 7216D2D80EE89B9B00AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rarpd;
+ productName = rarpd;
+ productReference = 7216D2CD0EE89B7900AE70E4 /* rarpd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2EC0EE89CBC00AE70E4 /* route */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2FB0EE89D2600AE70E4 /* Build configuration list for PBXNativeTarget "route" */;
+ buildPhases = (
+ 7216D2EA0EE89CBC00AE70E4 /* Sources */,
+ 7216D2EB0EE89CBC00AE70E4 /* Frameworks */,
+ 7216D2FA0EE89D2600AE70E4 /* CopyFiles */,
+ 7216D3030EE89D4300AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = route;
+ productName = route;
+ productReference = 7216D2ED0EE89CBC00AE70E4 /* route */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D3130EE89E9E00AE70E4 /* rtadvd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D3200EE89EDF00AE70E4 /* Build configuration list for PBXNativeTarget "rtadvd" */;
+ buildPhases = (
+ 7216D3110EE89E9E00AE70E4 /* Sources */,
+ 7216D3120EE89E9E00AE70E4 /* Frameworks */,
+ 7216D3370EE89F7500AE70E4 /* CopyFiles */,
+ 7216D3380EE89F7500AE70E4 /* CopyFiles */,
+ 7216D3460EE89FD700AE70E4 /* CopyFiles */,
+ 7216D3450EE89FB900AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rtadvd;
+ productName = rtadvd;
+ productReference = 7216D3140EE89E9E00AE70E4 /* rtadvd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D3580EE8A02200AE70E4 /* rtsol */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D3660EE8A02B00AE70E4 /* Build configuration list for PBXNativeTarget "rtsol" */;
+ buildPhases = (
+ 7216D3560EE8A02200AE70E4 /* Sources */,
+ 7216D3570EE8A02200AE70E4 /* Frameworks */,
+ 7216D37B0EE8A06200AE70E4 /* CopyFiles */,
+ 7216D3740EE8A06000AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rtsol;
+ productName = rtsol;
+ productReference = 7216D3590EE8A02200AE70E4 /* rtsol */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D3A60EE8A3BA00AE70E4 /* spray */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D3C20EE8A42D00AE70E4 /* Build configuration list for PBXNativeTarget "spray" */;
+ buildPhases = (
+ 7216D3A40EE8A3BA00AE70E4 /* Sources */,
+ 7216D3A50EE8A3BA00AE70E4 /* Frameworks */,
+ 7216D3C10EE8A42D00AE70E4 /* CopyFiles */,
+ 7216D3B30EE8A3E000AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ 7216D47D0EE8B84900AE70E4 /* PBXBuildRule */,
+ );
+ dependencies = (
+ );
+ name = spray;
+ productName = spray;
+ productReference = 7216D3A70EE8A3BB00AE70E4 /* spray */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72311F41194A349000EB4788 /* mptcp_client */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72311F46194A349100EB4788 /* Build configuration list for PBXNativeTarget "mptcp_client" */;
+ buildPhases = (
+ 72311F3E194A349000EB4788 /* Sources */,
+ 72311F3F194A349000EB4788 /* Frameworks */,
+ 72311F40194A349000EB4788 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mptcp_client;
+ productName = mptcp_client;
+ productReference = 72311F42194A349000EB4788 /* mptcp_client */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723C7067142BAFEA007C87E9 /* dnctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723C706F142BAFEA007C87E9 /* Build configuration list for PBXNativeTarget "dnctl" */;
+ buildPhases = (
+ 723C7064142BAFEA007C87E9 /* Sources */,
+ 723C7065142BAFEA007C87E9 /* Frameworks */,
+ 723C7066142BAFEA007C87E9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dnctl;
+ productName = dnctl;
+ productReference = 723C7068142BAFEA007C87E9 /* dnctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7247B83016165EDC00873B3C /* pktapctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7247B83A16165EDC00873B3C /* Build configuration list for PBXNativeTarget "pktapctl" */;
+ buildPhases = (
+ 7247B82D16165EDC00873B3C /* Sources */,
+ 7247B82E16165EDC00873B3C /* Frameworks */,
+ 7247B82F16165EDC00873B3C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pktapctl;
+ productName = pktapctl;
+ productReference = 7247B83116165EDC00873B3C /* pktapctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 724DABA10EE88FE3008900D0 /* kdumpd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724DABB80EE89035008900D0 /* Build configuration list for PBXNativeTarget "kdumpd" */;
+ buildPhases = (
+ 724DAB9F0EE88FE3008900D0 /* Sources */,
+ 724DABA00EE88FE3008900D0 /* Frameworks */,
+ 724DABB70EE89035008900D0 /* CopyFiles */,
+ 724DABC10EE89090008900D0 /* CopyFiles */,
+ 7216D25F0EE8970100AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = kdumpd;
+ productName = kdumpd;
+ productReference = 724DABA20EE88FE3008900D0 /* kdumpd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 724DAC0C0EE8940D008900D0 /* ndp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724DAC1E0EE894E8008900D0 /* Build configuration list for PBXNativeTarget "ndp" */;
+ buildPhases = (
+ 724DAC0A0EE8940D008900D0 /* Sources */,
+ 724DAC0B0EE8940D008900D0 /* Frameworks */,
+ 724DAC1D0EE894E8008900D0 /* CopyFiles */,
+ 724DAC440EE89562008900D0 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ndp;
+ productName = ndp;
+ productReference = 724DAC0D0EE8940D008900D0 /* ndp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7261212C0EE8710B00AFED1B /* arp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 726121400EE8713B00AFED1B /* Build configuration list for PBXNativeTarget "arp" */;
+ buildPhases = (
+ 7261212A0EE8710B00AFED1B /* Sources */,
+ 7261212B0EE8710B00AFED1B /* Frameworks */,
+ 7261213F0EE8713B00AFED1B /* CopyFiles */,
+ 72CD1DA00EE8C4EC005F825D /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = arp;
+ productName = arp;
+ productReference = 7261212D0EE8710B00AFED1B /* arp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 726121530EE8881700AFED1B /* ifconfig */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 726121630EE8887300AFED1B /* Build configuration list for PBXNativeTarget "ifconfig" */;
+ buildPhases = (
+ 726121510EE8881700AFED1B /* Sources */,
+ 726121520EE8881700AFED1B /* Frameworks */,
+ 726121620EE8887300AFED1B /* CopyFiles */,
+ 72CD1DA40EE8C500005F825D /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ifconfig;
+ productName = ifconfig;
+ productReference = 726121540EE8881700AFED1B /* ifconfig */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7282BA0B1AFAD4C9005DE836 /* ecnprobe */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7282BA131AFAD4C9005DE836 /* Build configuration list for PBXNativeTarget "ecnprobe" */;
+ buildPhases = (
+ 7282BA081AFAD4C9005DE836 /* Sources */,
+ 7282BA091AFAD4C9005DE836 /* Frameworks */,
+ 7282BA0A1AFAD4C9005DE836 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ecnprobe;
+ productName = ecnprobe;
+ productReference = 7282BA0C1AFAD4C9005DE836 /* ecnprobe */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72946F421BBF055700087E35 /* frame_delay */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72946F4A1BBF055700087E35 /* Build configuration list for PBXNativeTarget "frame_delay" */;
+ buildPhases = (
+ 72946F3F1BBF055700087E35 /* Sources */,
+ 72946F401BBF055700087E35 /* Frameworks */,
+ 72946F411BBF055700087E35 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = frame_delay;
+ productName = frame_delay;
+ productReference = 72946F431BBF055700087E35 /* frame_delay */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7294F0F80EE8BB460052EC88 /* traceroute */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7294F0FD0EE8BB550052EC88 /* Build configuration list for PBXNativeTarget "traceroute" */;
+ buildPhases = (
+ 7294F0F60EE8BB460052EC88 /* Sources */,
+ 7294F0F70EE8BB460052EC88 /* Frameworks */,
+ 7294F11A0EE8BC0C0052EC88 /* CopyFiles */,
+ 7294F10C0EE8BBB60052EC88 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = traceroute;
+ productName = traceroute;
+ productReference = 7294F0F90EE8BB460052EC88 /* traceroute */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7294F1290EE8BD280052EC88 /* traceroute6 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7294F13F0EE8BDB30052EC88 /* Build configuration list for PBXNativeTarget "traceroute6" */;
+ buildPhases = (
+ 7294F1270EE8BD280052EC88 /* Sources */,
+ 7294F1280EE8BD280052EC88 /* Frameworks */,
+ 7294F13E0EE8BDB30052EC88 /* CopyFiles */,
+ 7294F1360EE8BD4D0052EC88 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = traceroute6;
+ productName = traceroute6;
+ productReference = 7294F12A0EE8BD280052EC88 /* traceroute6 */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72B732D91899B0380060E6D4 /* cfilutil */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72B732E31899B0380060E6D4 /* Build configuration list for PBXNativeTarget "cfilutil" */;
+ buildPhases = (
+ 72B732D61899B0380060E6D4 /* Sources */,
+ 72B732D71899B0380060E6D4 /* Frameworks */,
+ 72B732D81899B0380060E6D4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cfilutil;
+ productName = cfilutil;
+ productReference = 72B732DA1899B0380060E6D4 /* cfilutil */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 724862310EE86EB7001D0DE9 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0800;
+ TargetAttributes = {
+ 713297671A93C743002359CF = {
+ CreatedOnToolsVersion = 6.3;
+ };
+ 7200F2F91958A34D0033E22C = {
+ CreatedOnToolsVersion = 6.0;
+ };
+ 72311F41194A349000EB4788 = {
+ CreatedOnToolsVersion = 6.0;
+ };
+ 7282BA0B1AFAD4C9005DE836 = {
+ CreatedOnToolsVersion = 7.0;
+ };
+ 72946F421BBF055700087E35 = {
+ CreatedOnToolsVersion = 6.3;
+ };
+ };
+ };
+ buildConfigurationList = 724862340EE86EB7001D0DE9 /* Build configuration list for PBXProject "network_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 7248622F0EE86EB7001D0DE9;
+ productRefGroup = 7261210D0EE8707500AFED1B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 726121430EE8717500AFED1B /* All */,
+ 72570DA20EE8EBF3000F4CFB /* All-Embedded */,
+ 72ABD0811083D742008C721C /* All-EmbeddedOther */,
+ 72C77D3A1484199C002D2577 /* network_cmds_libs */,
+ 7261212C0EE8710B00AFED1B /* arp */,
+ 72B732D91899B0380060E6D4 /* cfilutil */,
+ 723C7067142BAFEA007C87E9 /* dnctl */,
+ 7282BA0B1AFAD4C9005DE836 /* ecnprobe */,
+ 72946F421BBF055700087E35 /* frame_delay */,
+ 726121530EE8881700AFED1B /* ifconfig */,
+ 4D2B04F21208C2040004A3F3 /* ip6addrctl */,
+ 724DABA10EE88FE3008900D0 /* kdumpd */,
+ 5658259E1339218F003E5FA5 /* mnc */,
+ 72311F41194A349000EB4788 /* mptcp_client */,
+ 690D978012DE6034004323A7 /* mtest */,
+ 724DAC0C0EE8940D008900D0 /* ndp */,
+ 7216D2450EE896C000AE70E4 /* netstat */,
+ 7247B83016165EDC00873B3C /* pktapctl */,
+ 7200F2F91958A34D0033E22C /* pktmnglr */,
+ 7216D27B0EE8980A00AE70E4 /* ping */,
+ 7216D2990EE898BD00AE70E4 /* ping6 */,
+ 7216D2CC0EE89B7900AE70E4 /* rarpd */,
+ 7216D2EC0EE89CBC00AE70E4 /* route */,
+ 7216D3130EE89E9E00AE70E4 /* rtadvd */,
+ 7216D3580EE8A02200AE70E4 /* rtsol */,
+ 7216D3A60EE8A3BA00AE70E4 /* spray */,
+ 7294F0F80EE8BB460052EC88 /* traceroute */,
+ 7294F1290EE8BD280052EC88 /* traceroute6 */,
+ 713297671A93C743002359CF /* unbound */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 039D6A11120A2CF60006B8C8 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/local/share/man/man8/ip6addrctl.8";
+ };
+ 690D97C212DE71CF004323A7 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/local/share/man/man8/mtest.8";
+ };
+ 69C10A7612DF7EBB00BCDF4C /* Install OSS License */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/mtest.tproj/COPYING",
+ );
+ name = "Install OSS License";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/network_cmds.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "cp \"$SRCROOT/mtest.tproj/COPYING\" \"$DERIVED_FILE_DIR/network_cmds.txt\"\n\nmkdir -p \"$DSTROOT/usr/local/OpenSourceLicenses\"\ncp \"$DERIVED_FILE_DIR/network_cmds.txt\" \"$DSTROOT/usr/local/OpenSourceLicenses/\"\n\n";
+ };
+ 7216D25F0EE8970100AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/kdumpd.8\n/bin/chmod 0644 $DSTROOT/System/Library/LaunchDaemons/com.apple.kdumpd.plist";
+ };
+ 7216D2640EE8972E00AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man1/netstat.1\t";
+ };
+ 7216D2870EE8982900AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ping.8\t";
+ };
+ 7216D2AF0EE8993100AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ping6.8";
+ };
+ 7216D2D80EE89B9B00AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/rarpd.8";
+ };
+ 7216D3030EE89D4300AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/route.8";
+ };
+ 7216D3450EE89FB900AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/rtadvd.8\n/bin/chmod 0444 $DSTROOT/usr/share/man/man5/rtadvd.conf.5\n/bin/chmod 0644 $DSTROOT/private/etc/rtadvd.conf";
+ };
+ 7216D3740EE8A06000AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/rtsol.8\n/bin/ln -f $DSTROOT/usr/share/man/man8/rtsol.8 $DSTROOT/usr/share/man/man8/rtsold.8\n/bin/ln -f $DSTROOT/sbin/rtsol $DSTROOT/usr/sbin/rtsold\n/usr/bin/strip $DSTROOT/usr/sbin/rtsold\n/bin/chmod 0555 $DSTROOT/usr/sbin/rtsold\n";
+ };
+ 7216D3B30EE8A3E000AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/spray.8";
+ };
+ 724DAC440EE89562008900D0 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ndp.8\t";
+ };
+ 7294F10C0EE8BBB60052EC88 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/traceroute.8";
+ };
+ 7294F1360EE8BD4D0052EC88 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/traceroute6.8";
+ };
+ 72CD1DA00EE8C4EC005F825D /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/arp.8";
+ };
+ 72CD1DA40EE8C500005F825D /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ifconfig.8\t";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 4D2B04F01208C2040004A3F3 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D2B04F81208C21B0004A3F3 /* ip6addrctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 5658259C1339218F003E5FA5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 565825A4133921A3003E5FA5 /* mnc_error.c in Sources */,
+ 565825A5133921A3003E5FA5 /* mnc_main.c in Sources */,
+ 565825A6133921A3003E5FA5 /* mnc_multicast.c in Sources */,
+ 565825A7133921A3003E5FA5 /* mnc_opts.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 690D977E12DE6034004323A7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 690D97A612DE6F96004323A7 /* mtest.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 713297641A93C743002359CF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7200F2F61958A34D0033E22C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7200F2FD1958A34D0033E22C /* packet_mangler.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2430EE896C000AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D24C0EE896F300AE70E4 /* data.c in Sources */,
+ 7216D24D0EE896F300AE70E4 /* if.c in Sources */,
+ 7216D24E0EE896F300AE70E4 /* inet.c in Sources */,
+ 7216D24F0EE896F300AE70E4 /* inet6.c in Sources */,
+ 7216D2500EE896F300AE70E4 /* ipsec.c in Sources */,
+ 7216D2510EE896F300AE70E4 /* main.c in Sources */,
+ 01560DFD241969D3001AA29A /* vsock.c in Sources */,
+ 7216D2520EE896F300AE70E4 /* mbuf.c in Sources */,
+ 7216D2530EE896F300AE70E4 /* mcast.c in Sources */,
+ 7218B54A191D4202001B7B52 /* systm.c in Sources */,
+ 7216D2560EE896F300AE70E4 /* route.c in Sources */,
+ 7216D2570EE896F300AE70E4 /* tp_astring.c in Sources */,
+ 56B6B66816F79A1C00D8A7A9 /* mptcp.c in Sources */,
+ 7216D2580EE896F300AE70E4 /* unix.c in Sources */,
+ 721654C31EC52447005B17BA /* misc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2790EE8980A00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724769381CE2C1E400AAB5F0 /* gmt2local.c in Sources */,
+ 7216D2800EE8981C00AE70E4 /* ping.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2970EE898BD00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724769371CE2B1FF00AAB5F0 /* gmt2local.c in Sources */,
+ 7216D2A00EE898DF00AE70E4 /* md5.c in Sources */,
+ 7216D2A10EE898DF00AE70E4 /* ping6.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2CA0EE89B7900AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D2D10EE89B8300AE70E4 /* rarpd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2EA0EE89CBC00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D2F20EE89CD600AE70E4 /* route.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3110EE89E9E00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72D33F572271319400EF5B5E /* rtadvd_logging.c in Sources */,
+ 7216D3190EE89EC100AE70E4 /* advcap.c in Sources */,
+ 7216D31A0EE89EC100AE70E4 /* config.c in Sources */,
+ 7216D31B0EE89EC100AE70E4 /* dump.c in Sources */,
+ 7216D31C0EE89EC100AE70E4 /* if.c in Sources */,
+ 7216D31D0EE89EC100AE70E4 /* rrenum.c in Sources */,
+ 7216D31E0EE89EC100AE70E4 /* rtadvd.c in Sources */,
+ 7216D31F0EE89EC100AE70E4 /* timer.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3560EE8A02200AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D3670EE8A04700AE70E4 /* dump.c in Sources */,
+ 7216D3680EE8A04700AE70E4 /* if.c in Sources */,
+ 7216D3690EE8A04700AE70E4 /* probe.c in Sources */,
+ 7216D36A0EE8A04700AE70E4 /* rtsock.c in Sources */,
+ 7216D36B0EE8A04700AE70E4 /* rtsol.c in Sources */,
+ 7216D36C0EE8A04700AE70E4 /* rtsold.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3A40EE8A3BA00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D3AB0EE8A3C400AE70E4 /* spray.c in Sources */,
+ 7294F0DF0EE8BA730052EC88 /* spray.x in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72311F3E194A349000EB4788 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72311F54194A354F00EB4788 /* conn_lib.c in Sources */,
+ 72311F55194A354F00EB4788 /* mptcp_client.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723C7064142BAFEA007C87E9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72D000C4142BB11100151981 /* dnctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7247B82D16165EDC00873B3C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7247B83C16165F0100873B3C /* pktapctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DAB9F0EE88FE3008900D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724DABA60EE88FED008900D0 /* kdumpd.c in Sources */,
+ 724DABA70EE88FED008900D0 /* kdumpsubs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DAC0A0EE8940D008900D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724DAC120EE89423008900D0 /* ndp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7261212A0EE8710B00AFED1B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 726121310EE8711E00AFED1B /* arp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 726121510EE8881700AFED1B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72B7F36B1BA69352003A9AA2 /* if6lowpan.c in Sources */,
+ 7261215A0EE8883900AFED1B /* ifbond.c in Sources */,
+ 7261215B0EE8883900AFED1B /* ifconfig.c in Sources */,
+ 7261215C0EE8883900AFED1B /* ifmedia.c in Sources */,
+ 7261215D0EE8883900AFED1B /* ifvlan.c in Sources */,
+ 72E650A7107BF2F000AAF325 /* af_inet.c in Sources */,
+ 72E650A8107BF2F000AAF325 /* af_inet6.c in Sources */,
+ 72E650A9107BF2F000AAF325 /* af_link.c in Sources */,
+ 72E650AA107BF2F000AAF325 /* ifbridge.c in Sources */,
+ 72E650AB107BF2F000AAF325 /* ifclone.c in Sources */,
+ F940359D1E2FF5A900283EB1 /* iffake.c in Sources */,
+ F97F1E041E9C3FC8002355FF /* nexus.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7282BA081AFAD4C9005DE836 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7282BA531AFAD58E005DE836 /* support.c in Sources */,
+ 7282BA4D1AFAD58E005DE836 /* gmt2local.c in Sources */,
+ 7282BA4C1AFAD58E005DE836 /* ecn.c in Sources */,
+ 7282BA4B1AFAD58E005DE836 /* ecn_probe.c in Sources */,
+ 7282BA521AFAD58E005DE836 /* session.c in Sources */,
+ 7282BA491AFAD58E005DE836 /* capture.c in Sources */,
+ 7282BA4E1AFAD58E005DE836 /* history.c in Sources */,
+ 7282BA4F1AFAD58E005DE836 /* inet.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72946F3F1BBF055700087E35 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72946F501BBF07FF00087E35 /* frame_delay.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F0F60EE8BB460052EC88 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7294F1000EE8BB990052EC88 /* as.c in Sources */,
+ 7294F1010EE8BB990052EC88 /* findsaddr-socket.c in Sources */,
+ 7294F1020EE8BB990052EC88 /* ifaddrlist.c in Sources */,
+ 7294F1030EE8BB990052EC88 /* traceroute.c in Sources */,
+ 7294F1040EE8BB990052EC88 /* version.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F1270EE8BD280052EC88 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7294F12E0EE8BD2F0052EC88 /* traceroute6.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72B732D61899B0380060E6D4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72B732EF1899B23A0060E6D4 /* cfilutil.c in Sources */,
+ 72B732F11899B2430060E6D4 /* cfilstat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 034E4464100BDCA3009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7261212C0EE8710B00AFED1B /* arp */;
+ targetProxy = 034E4463100BDCA3009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E4469100BDD00009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726121530EE8881700AFED1B /* ifconfig */;
+ targetProxy = 034E4468100BDD00009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E4475100BDEC6009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2450EE896C000AE70E4 /* netstat */;
+ targetProxy = 034E4474100BDEC6009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E447B100BDF0D009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D27B0EE8980A00AE70E4 /* ping */;
+ targetProxy = 034E447A100BDF0D009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E447F100BDF54009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2EC0EE89CBC00AE70E4 /* route */;
+ targetProxy = 034E447E100BDF54009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E4485100BE15F009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F0F80EE8BB460052EC88 /* traceroute */;
+ targetProxy = 034E4484100BE15F009CA3DC /* PBXContainerItemProxy */;
+ };
+ 03B2DBD1100BE626005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DAC0C0EE8940D008900D0 /* ndp */;
+ targetProxy = 03B2DBD0100BE626005349BC /* PBXContainerItemProxy */;
+ };
+ 03B2DBD3100BE645005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2990EE898BD00AE70E4 /* ping6 */;
+ targetProxy = 03B2DBD2100BE645005349BC /* PBXContainerItemProxy */;
+ };
+ 03B2DBDB100BE6D2005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3580EE8A02200AE70E4 /* rtsol */;
+ targetProxy = 03B2DBDA100BE6D2005349BC /* PBXContainerItemProxy */;
+ };
+ 03B2DBDD100BE6D5005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F1290EE8BD280052EC88 /* traceroute6 */;
+ targetProxy = 03B2DBDC100BE6D5005349BC /* PBXContainerItemProxy */;
+ };
+ 18515B85133D1DBF000148A4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3130EE89E9E00AE70E4 /* rtadvd */;
+ targetProxy = 18515B84133D1DBF000148A4 /* PBXContainerItemProxy */;
+ };
+ 4D2B05141208C6BB0004A3F3 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D2B04F21208C2040004A3F3 /* ip6addrctl */;
+ targetProxy = 4D2B05131208C6BB0004A3F3 /* PBXContainerItemProxy */;
+ };
+ 565825AD13392232003E5FA5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5658259E1339218F003E5FA5 /* mnc */;
+ targetProxy = 565825AC13392232003E5FA5 /* PBXContainerItemProxy */;
+ };
+ 565825AF13392239003E5FA5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5658259E1339218F003E5FA5 /* mnc */;
+ targetProxy = 565825AE13392239003E5FA5 /* PBXContainerItemProxy */;
+ };
+ 565825B113392242003E5FA5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5658259E1339218F003E5FA5 /* mnc */;
+ targetProxy = 565825B013392242003E5FA5 /* PBXContainerItemProxy */;
+ };
+ 690D97BA12DE7130004323A7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 690D978012DE6034004323A7 /* mtest */;
+ targetProxy = 690D97B912DE7130004323A7 /* PBXContainerItemProxy */;
+ };
+ 690D97BC12DE7151004323A7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 690D978012DE6034004323A7 /* mtest */;
+ targetProxy = 690D97BB12DE7151004323A7 /* PBXContainerItemProxy */;
+ };
+ 690D97BE12DE7166004323A7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 690D978012DE6034004323A7 /* mtest */;
+ targetProxy = 690D97BD12DE7166004323A7 /* PBXContainerItemProxy */;
+ };
+ 71D958C51A9455A000C9B286 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 713297671A93C743002359CF /* unbound */;
+ targetProxy = 71D958C41A9455A000C9B286 /* PBXContainerItemProxy */;
+ };
+ 7200F3031958A4F10033E22C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7200F2F91958A34D0033E22C /* pktmnglr */;
+ targetProxy = 7200F3021958A4F10033E22C /* PBXContainerItemProxy */;
+ };
+ 7200F3051958A4FA0033E22C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7200F2F91958A34D0033E22C /* pktmnglr */;
+ targetProxy = 7200F3041958A4FA0033E22C /* PBXContainerItemProxy */;
+ };
+ 7200F3071958A5040033E22C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7200F2F91958A34D0033E22C /* pktmnglr */;
+ targetProxy = 7200F3061958A5040033E22C /* PBXContainerItemProxy */;
+ };
+ 7216D2670EE8978F00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2450EE896C000AE70E4 /* netstat */;
+ targetProxy = 7216D2660EE8978F00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D2C00EE89ADF00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D27B0EE8980A00AE70E4 /* ping */;
+ targetProxy = 7216D2BF0EE89ADF00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D2C20EE89ADF00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2990EE898BD00AE70E4 /* ping6 */;
+ targetProxy = 7216D2C10EE89ADF00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D2DA0EE89BE900AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2CC0EE89B7900AE70E4 /* rarpd */;
+ targetProxy = 7216D2D90EE89BE900AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D3060EE89D9A00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2EC0EE89CBC00AE70E4 /* route */;
+ targetProxy = 7216D3050EE89D9A00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D34D0EE89FEC00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3130EE89E9E00AE70E4 /* rtadvd */;
+ targetProxy = 7216D34C0EE89FEC00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D37F0EE8A0B300AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3580EE8A02200AE70E4 /* rtsol */;
+ targetProxy = 7216D37E0EE8A0B300AE70E4 /* PBXContainerItemProxy */;
+ };
+ 72179EAE146233390098FB3E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723C7067142BAFEA007C87E9 /* dnctl */;
+ targetProxy = 72179EAD146233390098FB3E /* PBXContainerItemProxy */;
+ };
+ 72311F4B194A34EB00EB4788 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72311F41194A349000EB4788 /* mptcp_client */;
+ targetProxy = 72311F4A194A34EB00EB4788 /* PBXContainerItemProxy */;
+ };
+ 72311F4D194A34F500EB4788 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72311F41194A349000EB4788 /* mptcp_client */;
+ targetProxy = 72311F4C194A34F500EB4788 /* PBXContainerItemProxy */;
+ };
+ 72311F4F194A34FE00EB4788 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72311F41194A349000EB4788 /* mptcp_client */;
+ targetProxy = 72311F4E194A34FE00EB4788 /* PBXContainerItemProxy */;
+ };
+ 723C7074142BB003007C87E9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723C7067142BAFEA007C87E9 /* dnctl */;
+ targetProxy = 723C7073142BB003007C87E9 /* PBXContainerItemProxy */;
+ };
+ 724DABC30EE890A6008900D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DABA10EE88FE3008900D0 /* kdumpd */;
+ targetProxy = 724DABC20EE890A6008900D0 /* PBXContainerItemProxy */;
+ };
+ 724DAC240EE89525008900D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DAC0C0EE8940D008900D0 /* ndp */;
+ targetProxy = 724DAC230EE89525008900D0 /* PBXContainerItemProxy */;
+ };
+ 7250E1471616642000A11A76 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7247B83016165EDC00873B3C /* pktapctl */;
+ targetProxy = 7250E1461616642000A11A76 /* PBXContainerItemProxy */;
+ };
+ 7250E1491616642900A11A76 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7247B83016165EDC00873B3C /* pktapctl */;
+ targetProxy = 7250E1481616642900A11A76 /* PBXContainerItemProxy */;
+ };
+ 7250E14B1616643000A11A76 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7247B83016165EDC00873B3C /* pktapctl */;
+ targetProxy = 7250E14A1616643000A11A76 /* PBXContainerItemProxy */;
+ };
+ 726121490EE8717B00AFED1B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7261212C0EE8710B00AFED1B /* arp */;
+ targetProxy = 726121480EE8717B00AFED1B /* PBXContainerItemProxy */;
+ };
+ 7261217D0EE8896800AFED1B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726121530EE8881700AFED1B /* ifconfig */;
+ targetProxy = 7261217C0EE8896800AFED1B /* PBXContainerItemProxy */;
+ };
+ 7263724B1BCC709900E4B026 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72946F421BBF055700087E35 /* frame_delay */;
+ targetProxy = 7263724A1BCC709900E4B026 /* PBXContainerItemProxy */;
+ };
+ 7282BA571AFBDEAD005DE836 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */;
+ targetProxy = 7282BA561AFBDEAD005DE836 /* PBXContainerItemProxy */;
+ };
+ 7282BA591AFBDEC2005DE836 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */;
+ targetProxy = 7282BA581AFBDEC2005DE836 /* PBXContainerItemProxy */;
+ };
+ 7282BA5B1AFBDED3005DE836 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */;
+ targetProxy = 7282BA5A1AFBDED3005DE836 /* PBXContainerItemProxy */;
+ };
+ 72946F4C1BBF063800087E35 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72946F421BBF055700087E35 /* frame_delay */;
+ targetProxy = 72946F4B1BBF063800087E35 /* PBXContainerItemProxy */;
+ };
+ 72946F4E1BBF063F00087E35 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72946F421BBF055700087E35 /* frame_delay */;
+ targetProxy = 72946F4D1BBF063F00087E35 /* PBXContainerItemProxy */;
+ };
+ 7294F0EA0EE8BAC80052EC88 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3A60EE8A3BA00AE70E4 /* spray */;
+ targetProxy = 7294F0E90EE8BAC80052EC88 /* PBXContainerItemProxy */;
+ };
+ 7294F1210EE8BCC20052EC88 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F0F80EE8BB460052EC88 /* traceroute */;
+ targetProxy = 7294F1200EE8BCC20052EC88 /* PBXContainerItemProxy */;
+ };
+ 72ABD0881083D750008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726121530EE8881700AFED1B /* ifconfig */;
+ targetProxy = 72ABD0871083D750008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD08C1083D75D008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DAC0C0EE8940D008900D0 /* ndp */;
+ targetProxy = 72ABD08B1083D75D008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD08E1083D75F008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2450EE896C000AE70E4 /* netstat */;
+ targetProxy = 72ABD08D1083D75F008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0901083D762008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D27B0EE8980A00AE70E4 /* ping */;
+ targetProxy = 72ABD08F1083D762008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0921083D764008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2990EE898BD00AE70E4 /* ping6 */;
+ targetProxy = 72ABD0911083D764008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0941083D767008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2CC0EE89B7900AE70E4 /* rarpd */;
+ targetProxy = 72ABD0931083D767008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0961083D76A008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2EC0EE89CBC00AE70E4 /* route */;
+ targetProxy = 72ABD0951083D76A008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0981083D76D008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3130EE89E9E00AE70E4 /* rtadvd */;
+ targetProxy = 72ABD0971083D76D008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD09A1083D76F008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3580EE8A02200AE70E4 /* rtsol */;
+ targetProxy = 72ABD0991083D76F008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD09C1083D772008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F0F80EE8BB460052EC88 /* traceroute */;
+ targetProxy = 72ABD09B1083D772008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD09E1083D774008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F1290EE8BD280052EC88 /* traceroute6 */;
+ targetProxy = 72ABD09D1083D774008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0A41083D818008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7261212C0EE8710B00AFED1B /* arp */;
+ targetProxy = 72ABD0A31083D818008C721C /* PBXContainerItemProxy */;
+ };
+ 72B732E91899B18F0060E6D4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72B732D91899B0380060E6D4 /* cfilutil */;
+ targetProxy = 72B732E81899B18F0060E6D4 /* PBXContainerItemProxy */;
+ };
+ 72B732EB1899B19A0060E6D4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72B732D91899B0380060E6D4 /* cfilutil */;
+ targetProxy = 72B732EA1899B19A0060E6D4 /* PBXContainerItemProxy */;
+ };
+ 72CD1D9C0EE8C47C005F825D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F1290EE8BD280052EC88 /* traceroute6 */;
+ targetProxy = 72CD1D9B0EE8C47C005F825D /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 03B2DBE2100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ "STRIPFLAGS[sdk=iphoneos*]" = "-S";
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE3100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds;
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE4100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = network_cmds;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE6100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = arp;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE7100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ USE_IF_MEDIA,
+ NO_IPX,
+ INET6,
+ );
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_VLANS,
+ USE_BONDS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ifconfig;
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBEB100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = kdumpd;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBED100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC_DEBUG,
+ KAME_SCOPEID,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = ndp;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBEE100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ $inherited,
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = netstat;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBEF100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF0100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping6;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF1100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "TFTP_DIR=\\\"/tftpboot\\\"",
+ );
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rarpd;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF2100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = route;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF3100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rtadvd;
+ USE_HEADERMAP = NO;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ "-Wno-address-of-packed-member",
+ );
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF4100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = rtsol;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ );
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF5100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = spray;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF6100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 04555;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ HAVE_SOCKADDR_SA_LEN,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF7100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute6;
+ };
+ name = "Ignore Me";
+ };
+ 4D2B04F51208C2050004A3F3 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 0555;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = ip6addrctl;
+ };
+ name = Debug;
+ };
+ 4D2B04F61208C2050004A3F3 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = ip6addrctl;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 4D2B04F71208C2050004A3F3 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = ip6addrctl;
+ };
+ name = "Ignore Me";
+ };
+ 565825A11339218F003E5FA5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mnc;
+ };
+ name = Debug;
+ };
+ 565825A21339218F003E5FA5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mnc;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 565825A31339218F003E5FA5 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mnc;
+ };
+ name = "Ignore Me";
+ };
+ 690D978312DE6035004323A7 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mtest;
+ };
+ name = Debug;
+ };
+ 690D978412DE6035004323A7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mtest;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 690D978512DE6035004323A7 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mtest;
+ };
+ name = "Ignore Me";
+ };
+ 7132976C1A93C743002359CF /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ HEADER_SEARCH_PATHS = /usr/local/libressl/include;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ LIBRARY_SEARCH_PATHS = /usr/local/libressl/lib;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ OTHER_LDFLAGS = (
+ "-lssl",
+ "-lcrypto",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = macosx;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/unbound";
+ USE_HEADERMAP = NO;
+ VALID_ARCHS = "x86_64 x86_64h";
+ };
+ name = Debug;
+ };
+ 7132976D1A93C743002359CF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ HEADER_SEARCH_PATHS = /usr/local/libressl/include;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ LIBRARY_SEARCH_PATHS = /usr/local/libressl/lib;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = (
+ "-lssl",
+ "-lcrypto",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = macosx;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/unbound";
+ USE_HEADERMAP = NO;
+ VALID_ARCHS = "x86_64 x86_64h";
+ };
+ name = Release;
+ };
+ 7132976E1A93C743002359CF /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ HEADER_SEARCH_PATHS = /usr/local/libressl/include;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ LIBRARY_SEARCH_PATHS = /usr/local/libressl/lib;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = (
+ "-lssl",
+ "-lcrypto",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = macosx;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/unbound";
+ USE_HEADERMAP = NO;
+ VALID_ARCHS = "x86_64 x86_64h";
+ };
+ name = "Ignore Me";
+ };
+ 7200F2FE1958A34D0033E22C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7200F2FF1958A34D0033E22C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7200F3001958A34D0033E22C /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 7216D2480EE896C100AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ $inherited,
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = netstat;
+ };
+ name = Debug;
+ };
+ 7216D2490EE896C100AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ $inherited,
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = netstat;
+ };
+ name = Release;
+ };
+ 7216D27E0EE8980B00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ "DEBUG=1",
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping;
+ };
+ name = Debug;
+ };
+ 7216D27F0EE8980B00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping;
+ };
+ name = Release;
+ };
+ 7216D29C0EE898BE00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping6;
+ };
+ name = Debug;
+ };
+ 7216D29D0EE898BE00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping6;
+ };
+ name = Release;
+ };
+ 7216D2CF0EE89B7A00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "TFTP_DIR=\\\"/tftpboot\\\"",
+ );
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rarpd;
+ };
+ name = Debug;
+ };
+ 7216D2D00EE89B7A00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "TFTP_DIR=\\\"/tftpboot\\\"",
+ );
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rarpd;
+ };
+ name = Release;
+ };
+ 7216D2EF0EE89CBC00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = route;
+ };
+ name = Debug;
+ };
+ 7216D2F00EE89CBC00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = route;
+ };
+ name = Release;
+ };
+ 7216D3160EE89E9F00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rtadvd;
+ USE_HEADERMAP = NO;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ "-Wno-address-of-packed-member",
+ );
+ };
+ name = Debug;
+ };
+ 7216D3170EE89E9F00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rtadvd;
+ USE_HEADERMAP = NO;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ "-Wno-address-of-packed-member",
+ );
+ };
+ name = Release;
+ };
+ 7216D35B0EE8A02300AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = rtsol;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ );
+ };
+ name = Debug;
+ };
+ 7216D35C0EE8A02300AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = rtsol;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ );
+ };
+ name = Release;
+ };
+ 7216D3A90EE8A3BB00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = spray;
+ };
+ name = Debug;
+ };
+ 7216D3AA0EE8A3BB00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = spray;
+ };
+ name = Release;
+ };
+ 72311F47194A349100EB4788 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72311F48194A349100EB4788 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72311F49194A349100EB4788 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 723C7070142BAFEA007C87E9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 723C7071142BAFEA007C87E9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 723C7072142BAFEA007C87E9 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 7247B83716165EDC00873B3C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7247B83816165EDC00873B3C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7247B83916165EDC00873B3C /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 724862320EE86EB7001D0DE9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPRESSION = lossless;
+ COPY_PHASE_STRIP = NO;
+ DEAD_CODE_STRIPPING = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Debug;
+ };
+ 724862330EE86EB7001D0DE9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPRESSION = "respect-asset-catalog";
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ "STRIPFLAGS[sdk=iphoneos*]" = "-S";
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 724DABA40EE88FE3008900D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = kdumpd;
+ };
+ name = Debug;
+ };
+ 724DABA50EE88FE3008900D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = kdumpd;
+ };
+ name = Release;
+ };
+ 724DAC0F0EE8940E008900D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC_DEBUG,
+ KAME_SCOPEID,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = ndp;
+ };
+ name = Debug;
+ };
+ 724DAC100EE8940E008900D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC_DEBUG,
+ KAME_SCOPEID,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = ndp;
+ };
+ name = Release;
+ };
+ 72570DA30EE8EBF3000F4CFB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = network_cmds;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 72570DA40EE8EBF3000F4CFB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = network_cmds;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ 7261212F0EE8710B00AFED1B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = arp;
+ };
+ name = Debug;
+ };
+ 726121300EE8710B00AFED1B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = arp;
+ };
+ name = Release;
+ };
+ 726121440EE8717500AFED1B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = network_cmds;
+ };
+ name = Debug;
+ };
+ 726121450EE8717500AFED1B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 726121560EE8881800AFED1B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ USE_IF_MEDIA,
+ NO_IPX,
+ INET6,
+ );
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ $inherited,
+ USE_VLANS,
+ USE_BONDS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ifconfig;
+ };
+ name = Debug;
+ };
+ 726121570EE8881800AFED1B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ USE_IF_MEDIA,
+ NO_IPX,
+ INET6,
+ );
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_VLANS,
+ USE_BONDS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ifconfig;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 7282BA101AFAD4C9005DE836 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7282BA111AFAD4C9005DE836 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7282BA121AFAD4C9005DE836 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 72946F471BBF055700087E35 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include,
+ /System/Library/Frameworks/System.framework/PrivateHeaders,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72946F481BBF055700087E35 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include,
+ /System/Library/Frameworks/System.framework/PrivateHeaders,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72946F491BBF055700087E35 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include,
+ /System/Library/Frameworks/System.framework/PrivateHeaders,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 7294F0FB0EE8BB460052EC88 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 04555;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ HAVE_SOCKADDR_SA_LEN,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute;
+ };
+ name = Debug;
+ };
+ 7294F0FC0EE8BB460052EC88 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 04555;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ HAVE_SOCKADDR_SA_LEN,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute;
+ };
+ name = Release;
+ };
+ 7294F12C0EE8BD290052EC88 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute6;
+ };
+ name = Debug;
+ };
+ 7294F12D0EE8BD290052EC88 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute6;
+ };
+ name = Release;
+ };
+ 72ABD0821083D743008C721C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = "All-EmbeddedOther";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 72ABD0831083D743008C721C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = "All-EmbeddedOther";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 72ABD0841083D743008C721C /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "All-EmbeddedOther";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Ignore Me";
+ };
+ 72B732E01899B0380060E6D4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72B732E11899B0380060E6D4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72B732E21899B0380060E6D4 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 72C77D681484199C002D2577 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = network_cmds_libs;
+ };
+ name = Debug;
+ };
+ 72C77D691484199C002D2577 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds_libs;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 72C77D6A1484199C002D2577 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds_libs;
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4D2B05121208C2300004A3F3 /* Build configuration list for PBXNativeTarget "ip6addrctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D2B04F51208C2050004A3F3 /* Debug */,
+ 4D2B04F61208C2050004A3F3 /* Release */,
+ 4D2B04F71208C2050004A3F3 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 565825AB133921ED003E5FA5 /* Build configuration list for PBXNativeTarget "mnc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 565825A11339218F003E5FA5 /* Debug */,
+ 565825A21339218F003E5FA5 /* Release */,
+ 565825A31339218F003E5FA5 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 690D978612DE6053004323A7 /* Build configuration list for PBXNativeTarget "mtest" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 690D978312DE6035004323A7 /* Debug */,
+ 690D978412DE6035004323A7 /* Release */,
+ 690D978512DE6035004323A7 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7132976F1A93C743002359CF /* Build configuration list for PBXNativeTarget "unbound" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7132976C1A93C743002359CF /* Debug */,
+ 7132976D1A93C743002359CF /* Release */,
+ 7132976E1A93C743002359CF /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7200F3011958A34E0033E22C /* Build configuration list for PBXNativeTarget "pktmnglr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7200F2FE1958A34D0033E22C /* Debug */,
+ 7200F2FF1958A34D0033E22C /* Release */,
+ 7200F3001958A34D0033E22C /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D24B0EE896EC00AE70E4 /* Build configuration list for PBXNativeTarget "netstat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D2480EE896C100AE70E4 /* Debug */,
+ 7216D2490EE896C100AE70E4 /* Release */,
+ 03B2DBEE100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2940EE8988200AE70E4 /* Build configuration list for PBXNativeTarget "ping" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D27E0EE8980B00AE70E4 /* Debug */,
+ 7216D27F0EE8980B00AE70E4 /* Release */,
+ 03B2DBEF100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2AB0EE8991200AE70E4 /* Build configuration list for PBXNativeTarget "ping6" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D29C0EE898BE00AE70E4 /* Debug */,
+ 7216D29D0EE898BE00AE70E4 /* Release */,
+ 03B2DBF0100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2E30EE89BEA00AE70E4 /* Build configuration list for PBXNativeTarget "rarpd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D2CF0EE89B7A00AE70E4 /* Debug */,
+ 7216D2D00EE89B7A00AE70E4 /* Release */,
+ 03B2DBF1100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2FB0EE89D2600AE70E4 /* Build configuration list for PBXNativeTarget "route" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D2EF0EE89CBC00AE70E4 /* Debug */,
+ 7216D2F00EE89CBC00AE70E4 /* Release */,
+ 03B2DBF2100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D3200EE89EDF00AE70E4 /* Build configuration list for PBXNativeTarget "rtadvd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D3160EE89E9F00AE70E4 /* Debug */,
+ 7216D3170EE89E9F00AE70E4 /* Release */,
+ 03B2DBF3100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D3660EE8A02B00AE70E4 /* Build configuration list for PBXNativeTarget "rtsol" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D35B0EE8A02300AE70E4 /* Debug */,
+ 7216D35C0EE8A02300AE70E4 /* Release */,
+ 03B2DBF4100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D3C20EE8A42D00AE70E4 /* Build configuration list for PBXNativeTarget "spray" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D3A90EE8A3BB00AE70E4 /* Debug */,
+ 7216D3AA0EE8A3BB00AE70E4 /* Release */,
+ 03B2DBF5100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72311F46194A349100EB4788 /* Build configuration list for PBXNativeTarget "mptcp_client" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72311F47194A349100EB4788 /* Debug */,
+ 72311F48194A349100EB4788 /* Release */,
+ 72311F49194A349100EB4788 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723C706F142BAFEA007C87E9 /* Build configuration list for PBXNativeTarget "dnctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723C7070142BAFEA007C87E9 /* Debug */,
+ 723C7071142BAFEA007C87E9 /* Release */,
+ 723C7072142BAFEA007C87E9 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7247B83A16165EDC00873B3C /* Build configuration list for PBXNativeTarget "pktapctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7247B83716165EDC00873B3C /* Debug */,
+ 7247B83816165EDC00873B3C /* Release */,
+ 7247B83916165EDC00873B3C /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724862340EE86EB7001D0DE9 /* Build configuration list for PBXProject "network_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724862320EE86EB7001D0DE9 /* Debug */,
+ 724862330EE86EB7001D0DE9 /* Release */,
+ 03B2DBE2100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724DABB80EE89035008900D0 /* Build configuration list for PBXNativeTarget "kdumpd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724DABA40EE88FE3008900D0 /* Debug */,
+ 724DABA50EE88FE3008900D0 /* Release */,
+ 03B2DBEB100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724DAC1E0EE894E8008900D0 /* Build configuration list for PBXNativeTarget "ndp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724DAC0F0EE8940E008900D0 /* Debug */,
+ 724DAC100EE8940E008900D0 /* Release */,
+ 03B2DBED100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72570DA60EE8EC0F000F4CFB /* Build configuration list for PBXAggregateTarget "All-Embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72570DA30EE8EBF3000F4CFB /* Debug */,
+ 72570DA40EE8EBF3000F4CFB /* Release */,
+ 03B2DBE4100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 726121400EE8713B00AFED1B /* Build configuration list for PBXNativeTarget "arp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7261212F0EE8710B00AFED1B /* Debug */,
+ 726121300EE8710B00AFED1B /* Release */,
+ 03B2DBE6100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7261214B0EE8717D00AFED1B /* Build configuration list for PBXAggregateTarget "All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 726121440EE8717500AFED1B /* Debug */,
+ 726121450EE8717500AFED1B /* Release */,
+ 03B2DBE3100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 726121630EE8887300AFED1B /* Build configuration list for PBXNativeTarget "ifconfig" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 726121560EE8881800AFED1B /* Debug */,
+ 726121570EE8881800AFED1B /* Release */,
+ 03B2DBE7100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7282BA131AFAD4C9005DE836 /* Build configuration list for PBXNativeTarget "ecnprobe" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7282BA101AFAD4C9005DE836 /* Debug */,
+ 7282BA111AFAD4C9005DE836 /* Release */,
+ 7282BA121AFAD4C9005DE836 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72946F4A1BBF055700087E35 /* Build configuration list for PBXNativeTarget "frame_delay" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72946F471BBF055700087E35 /* Debug */,
+ 72946F481BBF055700087E35 /* Release */,
+ 72946F491BBF055700087E35 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7294F0FD0EE8BB550052EC88 /* Build configuration list for PBXNativeTarget "traceroute" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7294F0FB0EE8BB460052EC88 /* Debug */,
+ 7294F0FC0EE8BB460052EC88 /* Release */,
+ 03B2DBF6100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7294F13F0EE8BDB30052EC88 /* Build configuration list for PBXNativeTarget "traceroute6" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7294F12C0EE8BD290052EC88 /* Debug */,
+ 7294F12D0EE8BD290052EC88 /* Release */,
+ 03B2DBF7100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72ABD0A11083D792008C721C /* Build configuration list for PBXAggregateTarget "All-EmbeddedOther" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72ABD0821083D743008C721C /* Debug */,
+ 72ABD0831083D743008C721C /* Release */,
+ 72ABD0841083D743008C721C /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72B732E31899B0380060E6D4 /* Build configuration list for PBXNativeTarget "cfilutil" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72B732E01899B0380060E6D4 /* Debug */,
+ 72B732E11899B0380060E6D4 /* Release */,
+ 72B732E21899B0380060E6D4 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72C77D671484199C002D2577 /* Build configuration list for PBXAggregateTarget "network_cmds_libs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72C77D681484199C002D2577 /* Debug */,
+ 72C77D691484199C002D2577 /* Release */,
+ 72C77D6A1484199C002D2577 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 724862310EE86EB7001D0DE9 /* Project object */;
+}
diff --git a/network_cmds/ping.tproj/ping.8 b/network_cmds/ping.tproj/ping.8
new file mode 100644
index 0000000..a2955a6
--- /dev/null
+++ b/network_cmds/ping.tproj/ping.8
@@ -0,0 +1,616 @@
+.\" Copyright (c) 1999-2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1985, 1991, 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.
+.\" 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.
+.\"
+.\" @(#)ping.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd March 29, 2013
+.Dt PING 8
+.Os
+.Sh NAME
+.Nm ping
+.Nd send
+.Tn ICMP ECHO_REQUEST
+packets to network hosts
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaCDdfnoQqRrv
+.Op Fl b Ar boundif
+.Op Fl c Ar count
+.Op Fl G Ar sweepmaxsize
+.Op Fl g Ar sweepminsize
+.Op Fl h Ar sweepincrsize
+.Op Fl i Ar wait
+.Op Fl k Ar trafficclass
+.Op Fl K Ar netservicetype
+.Op Fl l Ar preload
+.Op Fl M Cm mask | time
+.Op Fl m Ar ttl
+.Op Fl P Ar policy
+.Op Fl p Ar pattern
+.Op Fl S Ar src_addr
+.Op Fl s Ar packetsize
+.Op Fl t Ar timeout
+.Op Fl W Ar waittime
+.Op Fl z Ar tos
+.Op Fl Fl apple-connect
+.Op Fl Fl apple-time
+.Ar host
+.Nm
+.Op Fl AaDdfLnoQqRrv
+.Op Fl b Ar boundif
+.Op Fl c Ar count
+.Op Fl I Ar iface
+.Op Fl i Ar wait
+.Op Fl k Ar trafficclass
+.Op Fl K Ar netservicetype
+.Op Fl l Ar preload
+.Op Fl M Cm mask | time
+.Op Fl m Ar ttl
+.Op Fl P Ar policy
+.Op Fl p Ar pattern
+.Op Fl S Ar src_addr
+.Op Fl s Ar packetsize
+.Op Fl T Ar ttl
+.Op Fl t Ar timeout
+.Op Fl W Ar waittime
+.Op Fl z Ar tos
+.Op Fl Fl apple-connect
+.Op Fl Fl apple-time
+.Ar mcast-group
+.Sh DESCRIPTION
+The
+.Nm
+utility uses the
+.Tn ICMP
+.No protocol Ap s mandatory
+.Tn ECHO_REQUEST
+datagram to elicit an
+.Tn ICMP ECHO_RESPONSE
+from a host or gateway.
+.Tn ECHO_REQUEST
+datagrams
+.Pq Dq pings
+have an IP and
+.Tn ICMP
+header, followed by a
+.Dq struct timeval
+and then an arbitrary number of
+.Dq pad
+bytes used to fill out the packet.
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Audible.
+Output a bell
+.Tn ( ASCII
+0x07)
+character when no packet is received before the next packet
+is transmitted.
+To cater for round-trip times that are longer than the interval
+between transmissions, further missing packets cause a bell only
+if the maximum number of unreceived packets has increased.
+.It Fl a
+Audible.
+Include a bell
+.Tn ( ASCII
+0x07)
+character in the output when any packet is received.
+This option is ignored
+if other format options are present.
+.It Fl b Ar boundif
+Bind the socket to interface
+.Ar boundif
+for sending.
+This option is an Apple addition.
+.It Fl C
+Prohibit the socket from using the cellular network interface.
+This option is an Apple addition.
+.It Fl c Ar count
+Stop after sending
+(and receiving)
+.Ar count
+.Tn ECHO_RESPONSE
+packets.
+If this option is not specified,
+.Nm
+will operate until interrupted.
+If this option is specified in conjunction with ping sweeps,
+each sweep will consist of
+.Ar count
+packets.
+.It Fl D
+Set the Don't Fragment bit.
+.It Fl d
+Set the
+.Dv SO_DEBUG
+option on the socket being used.
+.It Fl f
+Flood ping.
+Outputs packets as fast as they come back or one hundred times per second,
+whichever is more.
+For every
+.Tn ECHO_REQUEST
+sent a period
+.Dq .\&
+is printed, while for every
+.Tn ECHO_REPLY
+received a backspace is printed.
+This provides a rapid display of how many packets are being dropped.
+Only the super-user may use this option.
+.Bf -emphasis
+This can be very hard on a network and should be used with caution.
+.Ef
+.It Fl G Ar sweepmaxsize
+Specify the maximum size of
+.Tn ICMP
+payload when sending sweeping pings.
+This option is required for ping sweeps.
+.It Fl g Ar sweepminsize
+Specify the size of
+.Tn ICMP
+payload to start with when sending sweeping pings.
+The default value is 0.
+.It Fl h Ar sweepincrsize
+Specify the number of bytes to increment the size of
+.Tn ICMP
+payload after
+each sweep when sending sweeping pings.
+The default value is 1.
+.It Fl I Ar iface
+Source multicast packets with the given interface address.
+This flag only applies if the ping destination is a multicast address.
+.It Fl i Ar wait
+Wait
+.Ar wait
+seconds
+.Em between sending each packet .
+The default is to wait for one second between each packet.
+The wait time may be fractional, but only the super-user may specify
+values less than 0.1 second.
+This option is incompatible with the
+.Fl f
+option.
+.It Fl k Ar trafficclass
+Specifies the traffic class to use for sending ICMP packets.
+The supported traffic classes are
+BK_SYS, BK, BE, RD, OAM, AV, RV, VI, VO and CTL.
+By default
+.Nm
+uses the control traffic class (CTL).
+This option is an Apple addition.
+.It Fl K Ar netservicetype
+Specifies the network service type to use for sending ICMP packets.
+The supported network service type are BK_SYS, BK, BE, RV, AV, RD, OAM, VI, SIG and VO.
+Note this overrides the default traffic class (-k can still be specified after -K to use both).
+This option is an Apple addition.
+.It Fl L
+Suppress loopback of multicast packets.
+This flag only applies if the ping destination is a multicast address.
+.It Fl l Ar preload
+If
+.Ar preload
+is specified,
+.Nm
+sends that many packets as fast as possible before falling into its normal
+mode of behavior.
+Only the super-user may use this option.
+.It Fl M Cm mask | time
+Use
+.Dv ICMP_MASKREQ
+or
+.Dv ICMP_TSTAMP
+instead of
+.Dv ICMP_ECHO .
+For
+.Cm mask ,
+print the netmask of the remote machine.
+Set the
+.Va net.inet.icmp.maskrepl
+MIB variable to enable
+.Dv ICMP_MASKREPLY .
+For
+.Cm time ,
+print the origination, reception and transmission timestamps.
+.It Fl m Ar ttl
+Set the IP Time To Live for outgoing packets.
+If not specified, the kernel uses the value of the
+.Va net.inet.ip.ttl
+MIB variable.
+.It Fl n
+Numeric output only.
+No attempt will be made to lookup symbolic names for host addresses.
+.It Fl o
+Exit successfully after receiving one reply packet.
+.It Fl P Ar policy
+.Ar policy
+specifies IPsec policy for the ping session.
+For details please refer to
+.Xr ipsec 4
+and
+.Xr ipsec_set_policy 3 .
+.It Fl p Ar pattern
+You may specify up to 16
+.Dq pad
+bytes to fill out the packet you send.
+This is useful for diagnosing data-dependent problems in a network.
+For example,
+.Dq Li \-p ff
+will cause the sent packet to be filled with all
+ones.
+.It Fl Q
+Somewhat quiet output.
+.No Don Ap t
+display ICMP error messages that are in response to our query messages.
+Originally, the
+.Fl v
+flag was required to display such errors, but
+.Fl v
+displays all ICMP error messages.
+On a busy machine, this output can be overbearing.
+Without the
+.Fl Q
+flag,
+.Nm
+prints out any ICMP error messages caused by its own ECHO_REQUEST
+messages.
+.It Fl q
+Quiet output.
+Nothing is displayed except the summary lines at startup time and
+when finished.
+.It Fl R
+Record route.
+Includes the
+.Tn RECORD_ROUTE
+option in the
+.Tn ECHO_REQUEST
+packet and displays
+the route buffer on returned packets.
+Note that the IP header is only large enough for nine such routes;
+the
+.Xr traceroute 8
+command is usually better at determining the route packets take to a
+particular destination.
+If more routes come back than should, such as due to an illegal spoofed
+packet, ping will print the route list and then truncate it at the correct
+spot.
+Many hosts ignore or discard the
+.Tn RECORD_ROUTE
+option.
+.It Fl r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network, an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it
+(e.g., after the interface was dropped by
+.Xr routed 8 ) .
+.It Fl S Ar src_addr
+Use the following IP address as the source address in outgoing packets.
+On hosts with more than one IP address, this option can be used to
+force the source address to be something other than the IP address
+of the interface the probe packet is sent on.
+If the IP address
+is not one of this machine's interface addresses, an error is
+returned and nothing is sent.
+.It Fl s Ar packetsize
+Specify the number of data bytes to be sent.
+The default is 56, which translates into 64
+.Tn ICMP
+data bytes when combined
+with the 8 bytes of
+.Tn ICMP
+header data.
+This option cannot be used with ping sweeps.
+.It Fl T Ar ttl
+Set the IP Time To Live for multicasted packets.
+This flag only applies if the ping destination is a multicast address.
+.It Fl t Ar timeout
+Specify a timeout, in seconds, before ping exits regardless of how
+many packets have been received.
+.It Fl v
+Verbose output.
+.Tn ICMP
+packets other than
+.Tn ECHO_RESPONSE
+that are received are listed.
+.It Fl W Ar waittime
+Time in milliseconds to wait for a reply for each packet sent.
+If a reply arrives later, the packet is not printed as replied, but
+considered as replied when calculating statistics.
+.It Fl z Ar tos
+Use the specified type of service.
+.It Fl Fl apple-connect
+Connects the socket to the destination address.
+This option is an Apple addition.
+.It Fl Fl apple-time
+Prints the time a packet was received.
+This option is an Apple addition.
+.El
+.Pp
+When using
+.Nm
+for fault isolation, it should first be run on the local host, to verify
+that the local network interface is up and running.
+Then, hosts and gateways further and further away should be
+.Dq pinged .
+Round-trip times and packet loss statistics are computed.
+If duplicate packets are received, they are not included in the packet
+loss calculation, although the round trip time of these packets is used
+in calculating the round-trip time statistics.
+When the specified number of packets have been sent
+(and received)
+or if the program is terminated with a
+.Dv SIGINT ,
+a brief summary is displayed, showing the number of packets sent and
+received, and the minimum, mean, maximum, and standard deviation of
+the round-trip times.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Cm status
+argument for
+.Xr stty 1 )
+signal, the current number of packets sent and received, and the
+minimum, mean, and maximum of the round-trip times will be written to
+the standard error output.
+.Pp
+This program is intended for use in network testing, measurement and
+management.
+Because of the load it can impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.Sh ICMP PACKET DETAILS
+An IP header without options is 20 bytes.
+An
+.Tn ICMP
+.Tn ECHO_REQUEST
+packet contains an additional 8 bytes worth of
+.Tn ICMP
+header followed by an arbitrary amount of data.
+When a
+.Ar packetsize
+is given, this indicated the size of this extra piece of data
+(the default is 56).
+Thus the amount of data received inside of an IP packet of type
+.Tn ICMP
+.Tn ECHO_REPLY
+will always be 8 bytes more than the requested data space
+(the
+.Tn ICMP
+header).
+.Pp
+If the data space is at least eight bytes large,
+.Nm
+uses the first eight bytes of this space to include a timestamp which
+it uses in the computation of round trip times.
+If less than eight bytes of pad are specified, no round trip times are
+given.
+.Sh DUPLICATE AND DAMAGED PACKETS
+The
+.Nm
+utility will report duplicate and damaged packets.
+Duplicate packets should never occur when pinging a unicast address,
+and seem to be caused by
+inappropriate link-level retransmissions.
+Duplicates may occur in many situations and are rarely
+(if ever)
+a good sign, although the presence of low levels of duplicates may not
+always be cause for alarm.
+Duplicates are expected when pinging a broadcast or multicast address,
+since they are not really duplicates but replies from different hosts
+to the same request.
+.Pp
+Damaged packets are obviously serious cause for alarm and often
+indicate broken hardware somewhere in the
+.Nm
+packet's path (in the network or in the hosts).
+.Sh TRYING DIFFERENT DATA PATTERNS
+The
+(inter)network
+layer should never treat packets differently depending on the data
+contained in the data portion.
+Unfortunately, data-dependent problems have been known to sneak into
+networks and remain undetected for long periods of time.
+In many cases the particular pattern that will have problems is something
+that does not have sufficient
+.Dq transitions ,
+such as all ones or all zeros, or a pattern right at the edge, such as
+almost all zeros.
+It is not
+necessarily enough to specify a data pattern of all zeros (for example)
+on the command line because the pattern that is of interest is
+at the data link level, and the relationship between what you type and
+what the controllers transmit can be complicated.
+.Pp
+This means that if you have a data-dependent problem you will probably
+have to do a lot of testing to find it.
+If you are lucky, you may manage to find a file that either
+cannot
+be sent across your network or that takes much longer to transfer than
+other similar length files.
+You can then examine this file for repeated patterns that you can test
+using the
+.Fl p
+option of
+.Nm .
+.Sh TTL DETAILS
+The
+.Tn TTL
+value of an IP packet represents the maximum number of IP routers
+that the packet can go through before being thrown away.
+In current practice you can expect each router in the Internet to decrement
+the
+.Tn TTL
+field by exactly one.
+.Pp
+The
+.Tn TCP/IP
+specification recommends setting the
+.Tn TTL
+field for
+.Tn IP
+packets to 64, but many systems use smaller values
+.No ( Bx 4.3
+uses 30,
+.Bx 4.2
+used 15).
+.Pp
+The maximum possible value of this field is 255, and most
+.Ux
+systems set
+the
+.Tn TTL
+field of
+.Tn ICMP ECHO_REQUEST
+packets to 255.
+This is why you will find you can
+.Dq ping
+some hosts, but not reach them with
+.Xr telnet 1
+or
+.Xr ftp 1 .
+.Pp
+In normal operation
+.Nm
+prints the ttl value from the packet it receives.
+When a remote system receives a ping packet, it can do one of three things
+with the
+.Tn TTL
+field in its response:
+.Bl -bullet
+.It
+Not change it; this is what
+.Bx
+systems did before the
+.Bx 4.3 tahoe
+release.
+In this case the
+.Tn TTL
+value in the received packet will be 255 minus the
+number of routers in the round-trip path.
+.It
+Set it to 255; this is what current
+.Bx
+systems do.
+In this case the
+.Tn TTL
+value in the received packet will be 255 minus the
+number of routers in the path
+.Em from
+the remote system
+.Em to
+the
+.Nm Ns Em ing
+host.
+.It
+Set it to some other value.
+Some machines use the same value for
+.Tn ICMP
+packets that they use for
+.Tn TCP
+packets, for example either 30 or 60.
+Others may use completely wild values.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent
+.It 0
+At least one response was heard from the specified
+.Ar host .
+.It 2
+The transmission was successful but no responses were received.
+.It any other value
+An error occurred.
+These values are defined in
+.In sysexits.h .
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ifconfig 8 ,
+.Xr routed 8 ,
+.Xr traceroute 8 ,
+.Xr ping6 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 .
+.Sh AUTHORS
+The original
+.Nm
+utility was written by
+.An Mike Muuss
+while at the US Army Ballistics
+Research Laboratory.
+.Sh BUGS
+Many Hosts and Gateways ignore the
+.Tn RECORD_ROUTE
+option.
+.Pp
+The maximum IP header length is too small for options like
+.Tn RECORD_ROUTE
+to be completely useful.
+.No There Ap s
+not much that can be done about this, however.
+.Pp
+Flood pinging is not recommended in general, and flood pinging the
+broadcast address should only be done under very controlled conditions.
+.Pp
+The
+.Fl v
+option is not worth much on busy hosts.
diff --git a/network_cmds/ping.tproj/ping.c b/network_cmds/ping.tproj/ping.c
new file mode 100644
index 0000000..58e7f80
--- /dev/null
+++ b/network_cmds/ping.tproj/ping.c
@@ -0,0 +1,2134 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * 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.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * P I N G . C
+ *
+ * Using the Internet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ *
+ * Status -
+ * Public Domain. Distribution Unlimited.
+ * Bugs -
+ * More statistics could always be gathered.
+ * This program has to run SUID to ROOT to access the ICMP socket.
+ */
+
+#include <sys/param.h> /* NB: we rely on this for <sys/types.h> */
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif /*IPSEC*/
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <getopt.h>
+
+#define INADDR_LEN ((int)sizeof(in_addr_t))
+#define TIMEVAL_LEN ((int)sizeof(struct tv32))
+#define MASK_LEN (ICMP_MASKLEN - ICMP_MINLEN)
+#define TS_LEN (ICMP_TSLEN - ICMP_MINLEN)
+#define DEFDATALEN 56 /* default data length */
+#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */
+ /* runs out of buffer space */
+#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN)
+#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN)
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
+#define MAXTOS 255
+
+#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
+#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
+#define SET(bit) (A(bit) |= B(bit))
+#define CLR(bit) (A(bit) &= (~B(bit)))
+#define TST(bit) (A(bit) & B(bit))
+
+struct tv32 {
+ u_int32_t tv32_sec;
+ u_int32_t tv32_usec;
+};
+
+/* various options */
+int options;
+#define F_FLOOD 0x0001
+#define F_INTERVAL 0x0002
+#define F_NUMERIC 0x0004
+#define F_PINGFILLED 0x0008
+#define F_QUIET 0x0010
+#define F_RROUTE 0x0020
+#define F_SO_DEBUG 0x0040
+#define F_SO_DONTROUTE 0x0080
+#define F_VERBOSE 0x0100
+#define F_QUIET2 0x0200
+#define F_NOLOOP 0x0400
+#define F_MTTL 0x0800
+#define F_MIF 0x1000
+#define F_AUDIBLE 0x2000
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define F_POLICY 0x4000
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+#define F_TTL 0x8000
+#define F_MISSED 0x10000
+#define F_ONCE 0x20000
+#define F_HDRINCL 0x40000
+#define F_MASK 0x80000
+#define F_TIME 0x100000
+#define F_SWEEP 0x200000
+#define F_WAITTIME 0x400000
+#define F_CONNECT 0x800000
+#define F_PRTIME 0x1000000
+
+/*
+ * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
+ * number of received sequence numbers we can keep track of. Change 128
+ * to 8192 for complete accuracy...
+ */
+#define MAX_DUP_CHK (8 * 128)
+int mx_dup_ck = MAX_DUP_CHK;
+char rcvd_tbl[MAX_DUP_CHK / 8];
+
+struct sockaddr_in whereto; /* who to ping */
+int datalen = DEFDATALEN;
+int maxpayload;
+int s; /* socket file descriptor */
+u_char outpackhdr[IP_MAXPACKET], *outpack;
+char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
+char BSPACE = '\b'; /* characters written for flood */
+char DOT = '.';
+char *hostname;
+char *shostname;
+int ident; /* process id to identify our packets */
+int uid; /* cached uid for micro-optimization */
+u_char icmp_type = ICMP_ECHO;
+u_char icmp_type_rsp = ICMP_ECHOREPLY;
+int phdr_len = 0;
+int send_len;
+char *boundif;
+unsigned int ifscope;
+int nocell;
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int traffic_class = SO_TC_CTL; /* use control class, by default */
+int net_service_type = -1;
+int no_dup = 0;
+
+/* counters */
+long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
+long npackets; /* max packets to transmit */
+long nreceived; /* # of packets we got back */
+long nrepeats; /* number of duplicates */
+long ntransmitted; /* sequence # for outbound packets = #sent */
+long snpackets; /* max packets to transmit in one sweep */
+long snreceived; /* # of packets we got back in this sweep */
+long sntransmitted; /* # of packets we sent in this sweep */
+int sweepmax; /* max value of payload in sweep */
+int sweepmin = 0; /* start value of payload in sweep */
+int sweepincr = 1; /* payload increment in sweep */
+int interval = 1000; /* interval between packets, ms */
+int waittime = MAXWAIT; /* timeout for each packet */
+long nrcvtimeout = 0; /* # of packets we got back after waittime */
+int icmp_len = 0; /* length of the ICMP header */
+
+/* timing */
+int timing; /* flag to do timing */
+double tmin = 999999999.0; /* minimum round trip time */
+double tmax = 0.0; /* maximum round trip time */
+double tsum = 0.0; /* sum of all times, for doing average */
+double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+
+volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */
+volatile sig_atomic_t siginfo_p;
+
+static void fill(char *, char *);
+static u_short in_cksum(u_short *, int);
+static void check_status(void);
+static void finish(void) __dead2;
+static void pinger(void);
+static char *pr_addr(struct in_addr);
+static char *pr_ntime(n_time);
+static void pr_icmph(struct icmp *);
+static void pr_iph(struct ip *);
+static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *, int);
+static void pr_retip(struct ip *);
+static void status(int);
+static void stopit(int);
+static void tvsub(struct timeval *, const struct timeval *);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tos(const char *, bool *);
+static void usage(void) __dead2;
+
+int32_t thiszone; /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
+
+static int longopt_flag = 0;
+
+#define LOF_CONNECT 0x01
+#define LOF_PRTIME 0x02
+
+static const struct option longopts[] = {
+ { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT },
+ { "apple-time", no_argument, &longopt_flag, LOF_PRTIME },
+ { NULL, 0, NULL, 0 }
+};
+
+int
+main(int argc, char *const *argv)
+{
+ struct sockaddr_in from, sock_in;
+ struct in_addr ifaddr;
+ struct timeval last, intvl;
+ struct iovec iov;
+ struct ip *ip;
+ struct msghdr msg;
+ struct sigaction si_sa;
+ size_t sz;
+ u_char *datap, packet[IP_MAXPACKET] __attribute__((aligned(4)));
+ char *ep, *source, *target, *payload;
+ struct hostent *hp;
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy_in, *policy_out;
+#endif
+ struct sockaddr_in *to;
+ double t;
+ u_long alarmtimeout, ultmp;
+ int almost_done, ch, df, hold, i, mib[4], preload, sockerrno,
+ tos, ttl;
+ char ctrl[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(int))];
+ char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
+#ifdef IP_OPTIONS
+ char rspace[MAX_IPOPTLEN]; /* record route space */
+#endif
+ unsigned char loop, mttl;
+
+ payload = source = NULL;
+#ifdef IPSEC_POLICY_IPSEC
+ policy_in = policy_out = NULL;
+#endif
+ bool valid;
+
+ /*
+ * Do the stuff that we need root priv's for *first*, and
+ * then drop our setuid bit. Save error reporting for
+ * after arg parsing.
+ */
+ if (getuid())
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ else
+ s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ sockerrno = errno;
+
+ if (setuid(getuid()) != 0)
+ err(EX_NOPERM, "setuid() failed");
+ uid = getuid();
+
+ alarmtimeout = df = preload = tos = 0;
+
+ outpack = outpackhdr + sizeof(struct ip);
+ while ((ch = getopt_long(argc, argv,
+ "AaB:b:Cc:DdfG:g:h:I:i:k:K:Ll:M:m:noP:p:QqRrS:s:T:t:vW:z:",
+ longopts, NULL)) != -1)
+ {
+ switch(ch) {
+ case 'A':
+ options |= F_MISSED;
+ break;
+ case 'a':
+ options |= F_AUDIBLE;
+ break;
+ case 'B':
+ case 'b':
+ boundif = optarg;
+ break;
+ case 'C':
+ nocell++;
+ break;
+ case 'c':
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
+ errx(EX_USAGE,
+ "invalid count of packets to transmit: `%s'",
+ optarg);
+ npackets = ultmp;
+ break;
+ case 'D':
+ options |= F_HDRINCL;
+ df = 1;
+ break;
+ case 'd':
+ options |= F_SO_DEBUG;
+ break;
+ case 'f':
+ if (uid) {
+ errno = EPERM;
+ err(EX_NOPERM, "-f flag");
+ }
+ options |= F_FLOOD;
+ setbuf(stdout, (char *)NULL);
+ break;
+ case 'G': /* Maximum packet size for ping sweep */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "invalid packet size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ options |= F_SWEEP;
+ sweepmax = ultmp;
+ break;
+ case 'g': /* Minimum packet size for ping sweep */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "invalid packet size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ options |= F_SWEEP;
+ sweepmin = ultmp;
+ break;
+ case 'h': /* Packet size increment for ping sweep */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp < 1)
+ errx(EX_USAGE, "invalid increment size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ options |= F_SWEEP;
+ sweepincr = ultmp;
+ break;
+ case 'I': /* multicast interface */
+ if (inet_aton(optarg, &ifaddr) == 0)
+ errx(EX_USAGE,
+ "invalid multicast interface: `%s'",
+ optarg);
+ options |= F_MIF;
+ break;
+ case 'i': /* wait between sending packets */
+ t = strtod(optarg, &ep) * 1000.0;
+ if (*ep || ep == optarg || t > (double)INT_MAX)
+ errx(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_INTERVAL;
+ interval = (int)t;
+ if (uid && interval < 100) {
+ errno = EPERM;
+ err(EX_NOPERM, "-i interval too short");
+ }
+ break;
+ case 'k':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ if (strcasecmp(optarg, "recvmsg") == 0) {
+ use_recvmsg++;
+ break;
+ }
+ traffic_class = str2sotc(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad traffic class: `%s'",
+ optarg);
+ break;
+ case 'K':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ net_service_type = str2netservicetype(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad network service type: `%s'",
+ optarg);
+ /* suppress default traffic class (-k can still be specified after -K) */
+ traffic_class = -1;
+ break;
+ case 'L':
+ options |= F_NOLOOP;
+ loop = 0;
+ break;
+ case 'l':
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > INT_MAX)
+ errx(EX_USAGE,
+ "invalid preload value: `%s'", optarg);
+ if (uid) {
+ errno = EPERM;
+ err(EX_NOPERM, "-l flag");
+ }
+ preload = ultmp;
+ break;
+ case 'M':
+ switch(optarg[0]) {
+ case 'M':
+ case 'm':
+ options |= F_MASK;
+ break;
+ case 'T':
+ case 't':
+ options |= F_TIME;
+ break;
+ default:
+ errx(EX_USAGE, "invalid message: `%c'", optarg[0]);
+ break;
+ }
+ break;
+ case 'm': /* TTL */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTTL)
+ errx(EX_USAGE, "invalid TTL: `%s'", optarg);
+ ttl = ultmp;
+ options |= F_TTL;
+ break;
+ case 'n':
+ options |= F_NUMERIC;
+ break;
+ case 'o':
+ options |= F_ONCE;
+ break;
+ case 'P':
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ options |= F_POLICY;
+ if (!strncmp("in", optarg, 2))
+ policy_in = strdup(optarg);
+ else if (!strncmp("out", optarg, 3))
+ policy_out = strdup(optarg);
+ else
+ errx(1, "invalid security policy");
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+ break;
+ case 'p': /* fill buffer with user pattern */
+ options |= F_PINGFILLED;
+ payload = optarg;
+ break;
+ case 'Q':
+ options |= F_QUIET2;
+ break;
+ case 'q':
+ options |= F_QUIET;
+ break;
+ case 'R':
+ options |= F_RROUTE;
+ break;
+ case 'r':
+ options |= F_SO_DONTROUTE;
+ break;
+ case 'S':
+ source = optarg;
+ break;
+ case 's': /* size of packet to send */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "invalid packet size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ datalen = ultmp;
+ break;
+ case 'T': /* multicast TTL */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTTL)
+ errx(EX_USAGE, "invalid multicast TTL: `%s'",
+ optarg);
+ mttl = ultmp;
+ options |= F_MTTL;
+ break;
+ case 't':
+ alarmtimeout = strtoul(optarg, &ep, 0);
+ if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((unsigned int)alarmtimeout);
+ break;
+ case 'v':
+ options |= F_VERBOSE;
+ break;
+ case 'W': /* wait ms for answer */
+ t = strtod(optarg, &ep);
+ if (*ep || ep == optarg || t > (double)INT_MAX)
+ errx(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_WAITTIME;
+ waittime = (int)t;
+ break;
+ case 'z':
+ options |= F_HDRINCL;
+ tos = str2tos(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "invalid TOS: `%s'", optarg);
+ break;
+ case 0:
+ switch (longopt_flag) {
+ case LOF_CONNECT:
+ options |= F_CONNECT;
+ break;
+ case LOF_PRTIME:
+ options |= F_PRTIME;
+ thiszone = gmt2local(0);
+ break;
+ default:
+ break;
+ }
+ longopt_flag = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "bad interface name");
+
+ if (argc - optind != 1)
+ usage();
+ target = argv[optind];
+
+ switch (options & (F_MASK|F_TIME)) {
+ case 0: break;
+ case F_MASK:
+ icmp_type = ICMP_MASKREQ;
+ icmp_type_rsp = ICMP_MASKREPLY;
+ phdr_len = MASK_LEN;
+ if (!(options & F_QUIET))
+ (void)printf("ICMP_MASKREQ\n");
+ break;
+ case F_TIME:
+ icmp_type = ICMP_TSTAMP;
+ icmp_type_rsp = ICMP_TSTAMPREPLY;
+ phdr_len = TS_LEN;
+ if (!(options & F_QUIET))
+ (void)printf("ICMP_TSTAMP\n");
+ break;
+ default:
+ errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive.");
+ break;
+ }
+ icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len;
+ if (options & F_RROUTE)
+ icmp_len += MAX_IPOPTLEN;
+ maxpayload = IP_MAXPACKET - icmp_len;
+ if (datalen > maxpayload)
+ errx(EX_USAGE, "packet size too large: %d > %d", datalen,
+ maxpayload);
+ send_len = icmp_len + datalen;
+ datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN];
+ if (options & F_PINGFILLED) {
+ fill((char *)datap, payload);
+ }
+ if (source) {
+ bzero((char *)&sock_in, sizeof(sock_in));
+ sock_in.sin_family = AF_INET;
+ if (inet_aton(source, &sock_in.sin_addr) != 0) {
+ shostname = source;
+ } else {
+ hp = gethostbyname2(source, AF_INET);
+ if (!hp)
+ errx(EX_NOHOST, "cannot resolve %s: %s",
+ source, hstrerror(h_errno));
+
+ sock_in.sin_len = sizeof sock_in;
+ if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) ||
+ hp->h_length < 0)
+ errx(1, "gethostbyname2: illegal address");
+ memcpy(&sock_in.sin_addr, hp->h_addr_list[0],
+ sizeof(sock_in.sin_addr));
+ (void)strlcpy(snamebuf, hp->h_name,
+ sizeof(snamebuf));
+ shostname = snamebuf;
+ }
+ if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
+#if (DEBUG || DEVELOPMENT)
+ options |= F_HDRINCL;
+#else
+ err(1, "bind");
+#endif /* DEBUG || DEVELOPMENT */
+ }
+
+ bzero(&whereto, sizeof(whereto));
+ to = &whereto;
+ to->sin_family = AF_INET;
+ to->sin_len = sizeof *to;
+ if (inet_aton(target, &to->sin_addr) != 0) {
+ hostname = target;
+ } else {
+ hp = gethostbyname2(target, AF_INET);
+ if (!hp)
+ errx(EX_NOHOST, "cannot resolve %s: %s",
+ target, hstrerror(h_errno));
+
+ if ((unsigned)hp->h_length > sizeof(to->sin_addr))
+ errx(1, "gethostbyname2 returned an illegal address");
+ memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr);
+ (void)strlcpy(hnamebuf, hp->h_name, sizeof(hnamebuf));
+ hostname = hnamebuf;
+ }
+
+ do {
+ struct ifaddrs *ifa_list, *ifa;
+
+ if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)) || whereto.sin_addr.s_addr == INADDR_BROADCAST) {
+ no_dup = 1;
+ break;
+ }
+
+ if (getifaddrs(&ifa_list) == -1)
+ break;
+ for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ if ((ifa->ifa_flags & IFF_BROADCAST) == 0 || ifa->ifa_broadaddr == NULL)
+ continue;
+ if (whereto.sin_addr.s_addr != ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr)
+ continue;
+ no_dup = 1;
+ break;
+ }
+
+ freeifaddrs(ifa_list);
+ } while (0);
+
+ if (options & F_FLOOD && options & F_INTERVAL)
+ errx(EX_USAGE, "-f and -i: incompatible options");
+
+ if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ errx(EX_USAGE,
+ "-f flag cannot be used with multicast destination");
+ if (options & (F_MIF | F_NOLOOP | F_MTTL)
+ && !IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ errx(EX_USAGE,
+ "-I, -L, -T flags cannot be used with unicast destination");
+
+ if (!(options & F_PINGFILLED))
+ for (i = TIMEVAL_LEN; i < MAX(datalen, sweepmax); ++i)
+ *datap++ = i;
+
+ ident = getpid() & 0xFFFF;
+
+ if (s < 0) {
+ errno = sockerrno;
+ err(EX_OSERR, "socket");
+ }
+ hold = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+ sizeof(hold));
+ if (ifscope != 0) {
+ if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
+ (char *)&ifscope, sizeof (ifscope)) != 0)
+ err(EX_OSERR, "setsockopt(IP_BOUND_IF)");
+ }
+ if (nocell) {
+ if (setsockopt(s, IPPROTO_IP, IP_NO_IFT_CELLULAR,
+ (char *)&nocell, sizeof (nocell)) != 0)
+ err(EX_OSERR, "setsockopt(IP_NO_IFT_CELLULAR)");
+ }
+ if (options & F_SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ sizeof(hold));
+ if (options & F_SO_DONTROUTE)
+ (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
+ sizeof(hold));
+ if (use_sendmsg == 0) {
+ if (net_service_type != -1)
+ if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE,
+ (void *)&net_service_type, sizeof (net_service_type)) != 0)
+ warn("setsockopt(SO_NET_SERVICE_TYPE");
+ if (traffic_class != -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&traffic_class, sizeof (traffic_class)) != 0)
+ warn("setsockopt(SO_TRAFFIC_CLASS");
+
+ }
+ }
+ if (use_recvmsg > 0) {
+ int on = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+ (void *)&on, sizeof (on));
+ }
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (options & F_POLICY) {
+ char *buf;
+ if (policy_in != NULL) {
+ buf = ipsec_set_policy(policy_in, strlen(policy_in));
+ if (buf == NULL)
+ errx(EX_CONFIG, "%s", ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG,
+ "ipsec policy cannot be configured");
+ free(buf);
+ }
+
+ if (policy_out != NULL) {
+ buf = ipsec_set_policy(policy_out, strlen(policy_out));
+ if (buf == NULL)
+ errx(EX_CONFIG, "%s", ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG,
+ "ipsec policy cannot be configured");
+ free(buf);
+ }
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+ if (options & F_HDRINCL) {
+ ip = (struct ip*)outpackhdr;
+ if (!(options & (F_TTL | F_MTTL))) {
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_IP;
+ mib[3] = IPCTL_DEFTTL;
+ sz = sizeof(ttl);
+ if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1)
+ err(1, "sysctl(net.inet.ip.ttl)");
+ }
+ setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_tos = tos;
+ ip->ip_id = 0;
+ ip->ip_off = df ? IP_DF : 0;
+ ip->ip_ttl = ttl;
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
+ ip->ip_dst = to->sin_addr;
+ }
+ /* record route option */
+ if (options & F_RROUTE) {
+#ifdef IP_OPTIONS
+ bzero(rspace, sizeof(rspace));
+ rspace[IPOPT_OPTVAL] = IPOPT_RR;
+ rspace[IPOPT_OLEN] = sizeof(rspace) - 1;
+ rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
+ rspace[sizeof(rspace) - 1] = IPOPT_EOL;
+ if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
+ sizeof(rspace)) < 0)
+ err(EX_OSERR, "setsockopt IP_OPTIONS");
+#else
+ errx(EX_UNAVAILABLE,
+ "record route not available in this implementation");
+#endif /* IP_OPTIONS */
+ }
+
+ if (options & F_TTL) {
+ if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
+ sizeof(ttl)) < 0) {
+ err(EX_OSERR, "setsockopt IP_TTL");
+ }
+ }
+ if (options & F_NOLOOP) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
+ sizeof(loop)) < 0) {
+ err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP");
+ }
+ }
+ if (options & F_MTTL) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
+ sizeof(mttl)) < 0) {
+ err(EX_OSERR, "setsockopt IP_MULTICAST_TTL");
+ }
+ }
+ if (options & F_MIF) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
+ sizeof(ifaddr)) < 0) {
+ err(EX_OSERR, "setsockopt IP_MULTICAST_IF");
+ }
+ }
+#ifdef SO_TIMESTAMP
+ { int on = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
+ err(EX_OSERR, "setsockopt SO_TIMESTAMP");
+ }
+#endif
+
+ if ((options & F_CONNECT)) {
+ if (connect(s, (struct sockaddr *)&whereto, sizeof whereto) == -1)
+ err(EX_OSERR, "connect");
+ }
+
+ if (sweepmax) {
+ if (sweepmin >= sweepmax)
+ errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+
+ if (datalen != DEFDATALEN)
+ errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
+
+ if (npackets > 0) {
+ snpackets = npackets;
+ npackets = 0;
+ } else
+ snpackets = 1;
+ datalen = sweepmin;
+ send_len = icmp_len + sweepmin;
+ }
+ if (options & F_SWEEP && !sweepmax)
+ errx(EX_USAGE, "Maximum sweep size must be specified");
+
+ /*
+ * When pinging the broadcast address, you can get a lot of answers.
+ * Doing something so evil is useful if you are trying to stress the
+ * ethernet, or just want to fill the arp cache to get some stuff for
+ * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast
+ * or multicast pings if they wish.
+ */
+
+ /*
+ * XXX receive buffer needs undetermined space for mbuf overhead
+ * as well.
+ */
+ hold = IP_MAXPACKET + 128;
+ (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
+ sizeof(hold));
+ if (uid == 0)
+ (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
+ sizeof(hold));
+
+ if (to->sin_family == AF_INET) {
+ (void)printf("PING %s (%s)", hostname,
+ inet_ntoa(to->sin_addr));
+ if (source)
+ (void)printf(" from %s", shostname);
+ if (sweepmax)
+ (void)printf(": (%d ... %d) data bytes\n",
+ sweepmin, sweepmax);
+ else
+ (void)printf(": %d data bytes\n", datalen);
+
+ } else {
+ if (sweepmax)
+ (void)printf("PING %s: (%d ... %d) data bytes\n",
+ hostname, sweepmin, sweepmax);
+ else
+ (void)printf("PING %s: %d data bytes\n", hostname, datalen);
+ }
+
+ /*
+ * rdar://25829310
+ *
+ * Clear blocked signals inherited from the parent
+ */
+ sigset_t newset;
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+
+ /*
+ * Use sigaction() instead of signal() to get unambiguous semantics,
+ * in particular with SA_RESTART not set.
+ */
+
+ sigemptyset(&si_sa.sa_mask);
+ si_sa.sa_flags = 0;
+
+ si_sa.sa_handler = stopit;
+ if (sigaction(SIGINT, &si_sa, 0) == -1) {
+ err(EX_OSERR, "sigaction SIGINT");
+ }
+ si_sa.sa_handler = stopit;
+ if (sigaction(SIGQUIT, &si_sa, 0) == -1) {
+ err(EX_OSERR, "sigaction SIGQUIT");
+ }
+
+ si_sa.sa_handler = status;
+ if (sigaction(SIGINFO, &si_sa, 0) == -1) {
+ err(EX_OSERR, "sigaction SIGINFO");
+ }
+
+ if (alarmtimeout > 0) {
+ si_sa.sa_handler = stopit;
+ if (sigaction(SIGALRM, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGALRM");
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (caddr_t)&from;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+#ifdef SO_TIMESTAMP
+ msg.msg_control = (caddr_t)ctrl;
+#endif
+ iov.iov_base = packet;
+ iov.iov_len = IP_MAXPACKET;
+
+ if (preload == 0)
+ pinger(); /* send the first ping */
+ else {
+ if (npackets != 0 && preload > npackets)
+ preload = npackets;
+ while (preload--) /* fire off them quickies */
+ pinger();
+ }
+ (void)gettimeofday(&last, NULL);
+
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else {
+ intvl.tv_sec = interval / 1000;
+ intvl.tv_usec = interval % 1000 * 1000;
+ }
+
+ almost_done = 0;
+ while (!finish_up) {
+ struct timeval now, timeout;
+ fd_set rfds;
+ int cc, n;
+ int tc = -1;
+
+ check_status();
+ if ((unsigned)s >= FD_SETSIZE)
+ errx(EX_OSERR, "descriptor too large");
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ (void)gettimeofday(&now, NULL);
+ timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+ timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+ while (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
+ }
+ while (timeout.tv_usec >= 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_usec = 0;
+ n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ if (n < 0)
+ continue; /* Must be EINTR. */
+ if (n == 1) {
+ struct timeval *tv = NULL;
+#ifdef SO_TIMESTAMP
+ struct cmsghdr *cmsg;
+
+ msg.msg_controllen = sizeof(ctrl);
+#endif
+ msg.msg_namelen = sizeof(from);
+ if ((cc = recvmsg(s, &msg, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ warn("recvmsg");
+ continue;
+ }
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+#ifdef SO_TIMESTAMP
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_TIMESTAMP &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
+ /* Copy to avoid alignment problems: */
+ memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
+ tv = &now;
+ }
+#endif
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SO_TRAFFIC_CLASS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ /* Copy to avoid alignment problems: */
+ memcpy(&tc, CMSG_DATA(cmsg), sizeof(tc));
+ }
+ }
+ if (tv == NULL) {
+ (void)gettimeofday(&now, NULL);
+ tv = &now;
+ }
+ pr_pack((char *)packet, cc, &from, tv, tc);
+ if ((options & F_ONCE && nreceived) ||
+ (npackets && nreceived >= npackets))
+ break;
+ }
+ if (n == 0 || options & F_FLOOD) {
+ if (sweepmax && sntransmitted == snpackets) {
+ datalen += sweepincr;
+ if (datalen > sweepmax)
+ break;
+ send_len = icmp_len + datalen;
+ sntransmitted = 0;
+ }
+ if (!npackets || ntransmitted < npackets)
+ pinger();
+ else {
+ if (almost_done)
+ break;
+ almost_done = 1;
+ intvl.tv_usec = 0;
+ if (nreceived) {
+ intvl.tv_sec = 2 * tmax / 1000;
+ if (!intvl.tv_sec)
+ intvl.tv_sec = 1;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
+ }
+ }
+ (void)gettimeofday(&last, NULL);
+ if (ntransmitted - nreceived - 1 > nmissedmax) {
+ nmissedmax = ntransmitted - nreceived - 1;
+ if (options & F_MISSED)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ if (!(options & F_QUIET)) {
+ printf("Request timeout for icmp_seq %u\n",
+ (uint16_t)(ntransmitted - 2));
+ if (!(options & F_FLOOD))
+ (void)fflush(stdout);
+ }
+ }
+ }
+ }
+ finish();
+ /* NOTREACHED */
+ exit(0); /* Make the compiler happy */
+}
+
+/*
+ * stopit --
+ * Set the global bit that causes the main loop to quit.
+ * Do NOT call finish() from here, since finish() does far too much
+ * to be called from a signal handler.
+ */
+void
+stopit(int sig __unused)
+{
+
+ /*
+ * When doing reverse DNS lookups, the finish_up flag might not
+ * be noticed for a while. Just exit if we get a second SIGINT.
+ */
+ if (!(options & F_NUMERIC) && finish_up)
+ _exit(nreceived ? 0 : 2);
+ finish_up = 1;
+}
+
+/*
+ * pinger --
+ * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
+ * will be added on by the kernel. The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer. The first TIMEVAL_LEN
+ * bytes of the data portion are used to hold a UNIX "timeval" struct in
+ * host byte-order, to compute the round-trip time.
+ */
+static void
+pinger(void)
+{
+ struct timeval now;
+ struct tv32 tv32;
+ struct ip *ip;
+ struct icmp *icp;
+ int cc, i;
+ u_char *packet;
+
+ packet = outpack;
+ icp = (struct icmp *)outpack;
+ icp->icmp_type = icmp_type;
+ icp->icmp_code = 0;
+ icp->icmp_cksum = 0;
+ icp->icmp_seq = htons(ntransmitted);
+ icp->icmp_id = ident; /* ID */
+
+ CLR(ntransmitted % mx_dup_ck);
+
+ if (datalen >= TIMEVAL_LEN) /* can we time transfer */
+ timing = 1;
+ else
+ timing = 0;
+
+ if ((options & F_TIME) || timing) {
+ (void)gettimeofday(&now, NULL);
+
+ tv32.tv32_sec = htonl(now.tv_sec);
+ tv32.tv32_usec = htonl(now.tv_usec);
+ if (options & F_TIME)
+ icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
+ * 1000 + now.tv_usec / 1000);
+ if (timing)
+ bcopy((void *)&tv32,
+ (void *)&outpack[ICMP_MINLEN + phdr_len],
+ sizeof(tv32));
+ }
+
+ cc = ICMP_MINLEN + phdr_len + datalen;
+
+ /* compute ICMP checksum here */
+ icp->icmp_cksum = in_cksum((u_short *)icp, cc);
+
+ if (options & F_HDRINCL) {
+ cc += sizeof(struct ip);
+ ip = (struct ip *)outpackhdr;
+ ip->ip_len = cc;
+ ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
+ packet = outpackhdr;
+ }
+ if (use_sendmsg > 0) {
+ struct msghdr msg;
+ struct iovec iov;
+ char cmbuf[2 * CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cm = (struct cmsghdr *)cmbuf;
+
+ if ((options & F_CONNECT)) {
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ } else {
+ msg.msg_name = &whereto;
+ msg.msg_namelen = sizeof(whereto);
+ }
+ iov.iov_base = packet;
+ iov.iov_len = cc;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ msg.msg_controllen = 0;
+ msg.msg_control = NULL;
+
+ if (traffic_class >= 0) {
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ cm->cmsg_level = SOL_SOCKET;
+ cm->cmsg_type = SO_TRAFFIC_CLASS;
+ *(int *)CMSG_DATA(cm) = traffic_class;
+ msg.msg_controllen += CMSG_SPACE(sizeof(int));
+ cm = (struct cmsghdr *)(((char *)cm) + CMSG_SPACE(sizeof(int)));
+ }
+ if (net_service_type >= 0) {
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ cm->cmsg_level = SOL_SOCKET;
+ cm->cmsg_type = SO_NET_SERVICE_TYPE;
+ msg.msg_controllen += CMSG_SPACE(sizeof(int));
+ *(int *)CMSG_DATA(cm) = net_service_type;
+ }
+ msg.msg_control = cmbuf;
+
+ msg.msg_flags = 0;
+
+ i = sendmsg(s, &msg, 0);
+ } else {
+ if ((options & F_CONNECT)) {
+ i = send(s, (char *)packet, cc, 0);
+ } else {
+ i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
+ sizeof(whereto));
+ }
+ }
+ if (i < 0 || i != cc) {
+ if (i < 0) {
+ if (options & F_FLOOD && errno == ENOBUFS) {
+ usleep(FLOOD_BACKOFF);
+ return;
+ }
+ warn("sendto");
+ } else {
+ warn("%s: partial write: %d of %d bytes",
+ hostname, i, cc);
+ }
+ }
+ ntransmitted++;
+ sntransmitted++;
+ if (!(options & F_QUIET) && options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &DOT, 1);
+}
+
+/*
+ * pr_pack --
+ * Print out the packet, if it came from us. This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair). This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+static void
+pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv,
+ int tc)
+{
+ struct in_addr ina;
+ u_char *cp, *dp;
+ struct icmp *icp;
+ struct ip *ip;
+ const void *tp;
+ double triptime;
+ int dupflag, hlen, i, j, recv_len, seq;
+ static int old_rrlen;
+ static char old_rr[MAX_IPOPTLEN];
+
+ /* Check the IP header */
+ ip = (struct ip *)buf;
+ hlen = ip->ip_hl << 2;
+ recv_len = cc;
+ if (cc < hlen + ICMP_MINLEN) {
+ if (options & F_VERBOSE)
+ warn("packet too short (%d bytes) from %s", cc,
+ inet_ntoa(from->sin_addr));
+ return;
+ }
+
+ /* Now the ICMP part */
+ cc -= hlen;
+ icp = (struct icmp *)(buf + hlen);
+ if (icp->icmp_type == icmp_type_rsp) {
+ if (icp->icmp_id != ident)
+ return; /* 'Twas not our ECHO */
+ ++nreceived;
+ triptime = 0.0;
+ if (timing) {
+ struct timeval tv1;
+ struct tv32 tv32;
+#ifndef icmp_data
+ tp = &icp->icmp_ip;
+#else
+ tp = icp->icmp_data;
+#endif
+ tp = (const char *)tp + phdr_len;
+
+ if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) {
+ /* Copy to avoid alignment problems: */
+ memcpy(&tv32, tp, sizeof(tv32));
+ tv1.tv_sec = ntohl(tv32.tv32_sec);
+ tv1.tv_usec = ntohl(tv32.tv32_usec);
+ tvsub(tv, &tv1);
+ triptime = ((double)tv->tv_sec) * 1000.0 +
+ ((double)tv->tv_usec) / 1000.0;
+ tsum += triptime;
+ tsumsq += triptime * triptime;
+ if (triptime < tmin)
+ tmin = triptime;
+ if (triptime > tmax)
+ tmax = triptime;
+ } else
+ timing = 0;
+ }
+
+ seq = ntohs(icp->icmp_seq);
+
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
+ if (options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &BSPACE, 1);
+ else {
+ int seq_sent_len = send_len;
+ int seq_datalen = datalen;
+
+ if (sweepmax != 0) {
+ /*
+ * When sweeping take in account the length of that
+ * was sent based on the sequence number
+ */
+ seq_datalen = sweepmin + (seq / snpackets) * sweepincr;
+ seq_sent_len = icmp_len + seq_datalen;
+ }
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: icmp_seq=%u", cc,
+ inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
+ seq);
+ (void)printf(" ttl=%d", ip->ip_ttl);
+ if (timing)
+ (void)printf(" time=%.3f ms", triptime);
+ if (tc != -1) {
+ (void)printf(" tc=%d", tc);
+ }
+ if (dupflag && no_dup == 0) {
+ (void)printf(" (DUP!)");
+ }
+ if (options & F_AUDIBLE)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ if (options & F_MASK) {
+ /* Just prentend this cast isn't ugly */
+ (void)printf(" mask=%s",
+ pr_addr(*(struct in_addr *)&(icp->icmp_mask)));
+ }
+ if (options & F_TIME) {
+ (void)printf(" tso=%s", pr_ntime(icp->icmp_otime));
+ (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime));
+ (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime));
+ }
+ if (recv_len != seq_sent_len) {
+ (void)printf(
+ "\nwrong total length %d instead of %d",
+ recv_len, seq_sent_len);
+ }
+ /* check the data */
+ cp = (u_char*)&icp->icmp_data[phdr_len];
+ dp = &outpack[ICMP_MINLEN + phdr_len];
+ cc -= ICMP_MINLEN + phdr_len;
+ i = 0;
+ if (timing) { /* don't check variable timestamp */
+ cp += TIMEVAL_LEN;
+ dp += TIMEVAL_LEN;
+ cc -= TIMEVAL_LEN;
+ i += TIMEVAL_LEN;
+ }
+ for (; i < seq_datalen && cc > 0; ++i, ++cp, ++dp, --cc) {
+ if (*cp != *dp) {
+ (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
+ i, *dp, *cp);
+ (void)printf("\ncp:");
+ cp = (u_char*)&icp->icmp_data[0];
+ for (i = 0; i < seq_datalen; ++i, ++cp) {
+ if ((i % 16) == 0)
+ (void)printf("\n\t");
+ (void)printf("%2x ", *cp);
+ }
+ (void)printf("\ndp:");
+ cp = &outpack[ICMP_MINLEN];
+ for (i = 0; i < seq_datalen; ++i, ++cp) {
+ if ((i % 16) == 0)
+ (void)printf("\n\t");
+ (void)printf("%2x ", *cp);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ /*
+ * We've got something other than an ECHOREPLY.
+ * See if it's a reply to something that we sent.
+ * We can compare IP destination, protocol,
+ * and ICMP type and ID.
+ *
+ * Only print all the error messages if we are running
+ * as root to avoid leaking information not normally
+ * available to those not running as root.
+ */
+#ifndef icmp_data
+ struct ip *oip = &icp->icmp_ip;
+#else
+ struct ip *oip = (struct ip *)icp->icmp_data;
+#endif
+ struct icmp *oicmp = (struct icmp *)(oip + 1);
+
+ if (((options & F_VERBOSE) && uid == 0) ||
+ (!(options & F_QUIET2) &&
+ (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) &&
+ (oip->ip_p == IPPROTO_ICMP) &&
+ (oicmp->icmp_type == ICMP_ECHO) &&
+ (oicmp->icmp_id == ident))) {
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: ", cc,
+ pr_addr(from->sin_addr));
+ pr_icmph(icp);
+ } else
+ return;
+ }
+
+ /* Display any IP options */
+ cp = (u_char *)buf + sizeof(struct ip);
+
+ for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
+ switch (*cp) {
+ case IPOPT_EOL:
+ hlen = 0;
+ break;
+ case IPOPT_LSRR:
+ case IPOPT_SSRR:
+ (void)printf(*cp == IPOPT_LSRR ?
+ "\nLSRR: " : "\nSSRR: ");
+ j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1;
+ hlen -= 2;
+ cp += 2;
+ if (j >= INADDR_LEN &&
+ j <= hlen - (int)sizeof(struct ip)) {
+ for (;;) {
+ bcopy(++cp, &ina.s_addr, INADDR_LEN);
+ if (ina.s_addr == 0)
+ (void)printf("\t0.0.0.0");
+ else
+ (void)printf("\t%s",
+ pr_addr(ina));
+ hlen -= INADDR_LEN;
+ cp += INADDR_LEN - 1;
+ j -= INADDR_LEN;
+ if (j < INADDR_LEN)
+ break;
+ (void)putchar('\n');
+ }
+ } else
+ (void)printf("\t(truncated route)\n");
+ break;
+ case IPOPT_RR:
+ j = cp[IPOPT_OLEN]; /* get length */
+ i = cp[IPOPT_OFFSET]; /* and pointer */
+ hlen -= 2;
+ cp += 2;
+ if (i > j)
+ i = j;
+ i = i - IPOPT_MINOFF + 1;
+ if (i < 0 || i > (hlen - (int)sizeof(struct ip))) {
+ old_rrlen = 0;
+ continue;
+ }
+ if (i == old_rrlen
+ && !bcmp((char *)cp, old_rr, i)
+ && !(options & F_FLOOD)) {
+ (void)printf("\t(same route)");
+ hlen -= i;
+ cp += i;
+ break;
+ }
+ old_rrlen = i;
+ bcopy((char *)cp, old_rr, i);
+ (void)printf("\nRR: ");
+ if (i >= INADDR_LEN &&
+ i <= hlen - (int)sizeof(struct ip)) {
+ for (;;) {
+ bcopy(++cp, &ina.s_addr, INADDR_LEN);
+ if (ina.s_addr == 0)
+ (void)printf("\t0.0.0.0");
+ else
+ (void)printf("\t%s",
+ pr_addr(ina));
+ hlen -= INADDR_LEN;
+ cp += INADDR_LEN - 1;
+ i -= INADDR_LEN;
+ if (i < INADDR_LEN)
+ break;
+ (void)putchar('\n');
+ }
+ } else
+ (void)printf("\t(truncated route)");
+ break;
+ case IPOPT_NOP:
+ (void)printf("\nNOP");
+ break;
+ default:
+ (void)printf("\nunknown option %x", *cp);
+ break;
+ }
+ if (!(options & F_FLOOD)) {
+ (void)putchar('\n');
+ (void)fflush(stdout);
+ }
+}
+
+/*
+ * in_cksum --
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+u_short
+in_cksum(u_short *addr, int len)
+{
+ int nleft, sum;
+ u_short *w;
+ union {
+ u_short us;
+ u_char uc[2];
+ } last;
+ u_short answer;
+
+ nleft = len;
+ sum = 0;
+ w = addr;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+ * sequential 16 bit words to it, and at the end, fold back all the
+ * carry bits from the top 16 bits into the lower 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nleft == 1) {
+ last.uc[0] = *(u_char *)w;
+ last.uc[1] = 0;
+ sum += last.us;
+ }
+
+ /* add back carry outs from top 16 bits to low 16 bits */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return(answer);
+}
+
+/*
+ * tvsub --
+ * Subtract 2 timeval structs: out = out - in. Out is assumed to
+ * be >= in.
+ */
+static void
+tvsub(struct timeval *out, const struct timeval *in)
+{
+
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ --out->tv_sec;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * status --
+ * Print out statistics when SIGINFO is received.
+ */
+
+static void
+status(int sig __unused)
+{
+
+ siginfo_p = 1;
+}
+
+static void
+check_status(void)
+{
+
+ if (siginfo_p) {
+ siginfo_p = 0;
+ (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)",
+ nreceived, ntransmitted,
+ ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0);
+ if (nreceived && timing)
+ (void)fprintf(stderr, " %.3f min / %.3f avg / %.3f max",
+ tmin, tsum / (nreceived + nrepeats), tmax);
+ (void)fprintf(stderr, "\n");
+ }
+}
+
+/*
+ * finish --
+ * Print out statistics, and give up.
+ */
+static void
+finish(void)
+{
+
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)putchar('\n');
+ (void)fflush(stdout);
+ (void)printf("--- %s ping statistics ---\n", hostname);
+ (void)printf("%ld packets transmitted, ", ntransmitted);
+ (void)printf("%ld packets received, ", nreceived);
+ if (nrepeats)
+ (void)printf("+%ld duplicates, ", nrepeats);
+ if (ntransmitted) {
+ if (nreceived > ntransmitted)
+ (void)printf("-- somebody's printing up packets!");
+ else
+ (void)printf("%.1f%% packet loss",
+ ((ntransmitted - nreceived) * 100.0) /
+ ntransmitted);
+ }
+ if (nrcvtimeout)
+ (void)printf(", %ld packets out of wait time", nrcvtimeout);
+ (void)putchar('\n');
+ if (nreceived && timing) {
+ double n = nreceived + nrepeats;
+ double avg = tsum / n;
+ double vari = tsumsq / n - avg * avg;
+ (void)printf(
+ "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n",
+ tmin, avg, tmax, sqrt(vari));
+ }
+
+ if (nreceived)
+ exit(0);
+ else
+ exit(2);
+}
+
+#ifdef notdef
+static char *ttab[] = {
+ "Echo Reply", /* ip + seq + udata */
+ "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
+ "Source Quench", /* IP */
+ "Redirect", /* redirect type, gateway, + IP */
+ "Echo",
+ "Time Exceeded", /* transit, frag reassem + IP */
+ "Parameter Problem", /* pointer + IP */
+ "Timestamp", /* id + seq + three timestamps */
+ "Timestamp Reply", /* " */
+ "Info Request", /* id + sq */
+ "Info Reply" /* " */
+};
+#endif
+
+/*
+ * pr_icmph --
+ * Print a descriptive string about an ICMP header.
+ */
+static void
+pr_icmph(struct icmp *icp)
+{
+
+ switch(icp->icmp_type) {
+ case ICMP_ECHOREPLY:
+ (void)printf("Echo Reply\n");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP_UNREACH:
+ switch(icp->icmp_code) {
+ case ICMP_UNREACH_NET:
+ (void)printf("Destination Net Unreachable\n");
+ break;
+ case ICMP_UNREACH_HOST:
+ (void)printf("Destination Host Unreachable\n");
+ break;
+ case ICMP_UNREACH_PROTOCOL:
+ (void)printf("Destination Protocol Unreachable\n");
+ break;
+ case ICMP_UNREACH_PORT:
+ (void)printf("Destination Port Unreachable\n");
+ break;
+ case ICMP_UNREACH_NEEDFRAG:
+ (void)printf("frag needed and DF set (MTU %d)\n",
+ ntohs(icp->icmp_nextmtu));
+ break;
+ case ICMP_UNREACH_SRCFAIL:
+ (void)printf("Source Route Failed\n");
+ break;
+ case ICMP_UNREACH_FILTER_PROHIB:
+ (void)printf("Communication prohibited by filter\n");
+ break;
+ default:
+ (void)printf("Dest Unreachable, Bad Code: %d\n",
+ icp->icmp_code);
+ break;
+ }
+ /* Print returned IP header information */
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_SOURCEQUENCH:
+ (void)printf("Source Quench\n");
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_REDIRECT:
+ switch(icp->icmp_code) {
+ case ICMP_REDIRECT_NET:
+ (void)printf("Redirect Network");
+ break;
+ case ICMP_REDIRECT_HOST:
+ (void)printf("Redirect Host");
+ break;
+ case ICMP_REDIRECT_TOSNET:
+ (void)printf("Redirect Type of Service and Network");
+ break;
+ case ICMP_REDIRECT_TOSHOST:
+ (void)printf("Redirect Type of Service and Host");
+ break;
+ default:
+ (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
+ break;
+ }
+ (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr));
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_ECHO:
+ (void)printf("Echo Request\n");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP_TIMXCEED:
+ switch(icp->icmp_code) {
+ case ICMP_TIMXCEED_INTRANS:
+ (void)printf("Time to live exceeded\n");
+ break;
+ case ICMP_TIMXCEED_REASS:
+ (void)printf("Frag reassembly time exceeded\n");
+ break;
+ default:
+ (void)printf("Time exceeded, Bad Code: %d\n",
+ icp->icmp_code);
+ break;
+ }
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_PARAMPROB:
+ (void)printf("Parameter problem: pointer = 0x%02x\n",
+ icp->icmp_hun.ih_pptr);
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_TSTAMP:
+ (void)printf("Timestamp\n");
+ /* XXX ID + Seq + 3 timestamps */
+ break;
+ case ICMP_TSTAMPREPLY:
+ (void)printf("Timestamp Reply\n");
+ /* XXX ID + Seq + 3 timestamps */
+ break;
+ case ICMP_IREQ:
+ (void)printf("Information Request\n");
+ /* XXX ID + Seq */
+ break;
+ case ICMP_IREQREPLY:
+ (void)printf("Information Reply\n");
+ /* XXX ID + Seq */
+ break;
+ case ICMP_MASKREQ:
+ (void)printf("Address Mask Request\n");
+ break;
+ case ICMP_MASKREPLY:
+ (void)printf("Address Mask Reply\n");
+ break;
+ case ICMP_ROUTERADVERT:
+ (void)printf("Router Advertisement\n");
+ break;
+ case ICMP_ROUTERSOLICIT:
+ (void)printf("Router Solicitation\n");
+ break;
+ default:
+ (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
+ }
+}
+
+/*
+ * pr_iph --
+ * Print an IP header with options.
+ */
+static void
+pr_iph(struct ip *ip)
+{
+ u_char *cp;
+ int hlen;
+
+ hlen = ip->ip_hl << 2;
+ cp = (u_char *)ip + 20; /* point to options */
+
+ (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n");
+ (void)printf(" %1x %1x %02x %04x %04x",
+ ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len),
+ ntohs(ip->ip_id));
+ (void)printf(" %1lx %04lx",
+ (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13,
+ (u_long) ntohl(ip->ip_off) & 0x1fff);
+ (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p,
+ ntohs(ip->ip_sum));
+ (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
+ (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
+ /* dump any option bytes */
+ while (hlen-- > 20) {
+ (void)printf("%02x", *cp++);
+ }
+ (void)putchar('\n');
+}
+
+/*
+ * pr_addr --
+ * Return an ascii host address as a dotted quad and optionally with
+ * a hostname.
+ */
+static char *
+pr_addr(struct in_addr ina)
+{
+ struct hostent *hp;
+ static char buf[16 + 3 + MAXHOSTNAMELEN];
+
+ if ((options & F_NUMERIC) ||
+ !(hp = gethostbyaddr((char *)&ina, 4, AF_INET)))
+ return inet_ntoa(ina);
+ else
+ (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
+ inet_ntoa(ina));
+ return(buf);
+}
+
+/*
+ * pr_retip --
+ * Dump some info on a returned (via ICMP) IP packet.
+ */
+static void
+pr_retip(struct ip *ip)
+{
+ u_char *cp;
+ int hlen;
+
+ pr_iph(ip);
+ hlen = ip->ip_hl << 2;
+ cp = (u_char *)ip + hlen;
+
+ if (ip->ip_p == 6)
+ (void)printf("TCP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
+ else if (ip->ip_p == 17)
+ (void)printf("UDP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
+}
+
+static char *
+pr_ntime(n_time timestamp)
+{
+ static char buf[10];
+ int hour, min, sec;
+
+ sec = ntohl(timestamp) / 1000;
+ hour = sec / 60 / 60;
+ min = (sec % (60 * 60)) / 60;
+ sec = (sec % (60 * 60)) % 60;
+
+ (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec);
+
+ return (buf);
+}
+
+static void
+fill(char *bp, char *patp)
+{
+ char *cp;
+ int pat[16];
+ u_int ii, jj, kk;
+
+ for (cp = patp; *cp; cp++) {
+ if (!isxdigit(*cp))
+ errx(EX_USAGE,
+ "patterns must be specified as hex digits");
+
+ }
+ ii = sscanf(patp,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
+ &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
+ &pat[13], &pat[14], &pat[15]);
+
+ if (ii > 0)
+ for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii)
+ for (jj = 0; jj < ii; ++jj)
+ bp[jj + kk] = pat[jj];
+ if (!(options & F_QUIET)) {
+ (void)printf("PATTERN: 0x");
+ for (jj = 0; jj < ii; ++jj)
+ (void)printf("%02x", bp[jj] & 0xFF);
+ (void)printf("\n");
+ }
+}
+
+int
+str2sotc(const char *str, bool *valid)
+{
+ int sotc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK_SYS") == 0)
+ return SO_TC_BK_SYS;
+ else if (strcasecmp(str, "BK") == 0)
+ return SO_TC_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return SO_TC_BE;
+ else if (strcasecmp(str, "RD") == 0)
+ return SO_TC_RD;
+ else if (strcasecmp(str, "OAM") == 0)
+ return SO_TC_OAM;
+ else if (strcasecmp(str, "AV") == 0)
+ return SO_TC_AV;
+ else if (strcasecmp(str, "RV") == 0)
+ return SO_TC_RV;
+ else if (strcasecmp(str, "VI") == 0)
+ return SO_TC_VI;
+ else if (strcasecmp(str, "VO") == 0)
+ return SO_TC_VO;
+ else if (strcasecmp(str, "CTL") == 0)
+ return SO_TC_CTL;
+ else {
+ sotc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (sotc);
+}
+
+int
+str2netservicetype(const char *str, bool *valid)
+{
+ int svc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK") == 0)
+ return NET_SERVICE_TYPE_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return NET_SERVICE_TYPE_BE;
+ else if (strcasecmp(str, "VI") == 0)
+ return NET_SERVICE_TYPE_VI;
+ else if (strcasecmp(str, "SIG") == 0)
+ return NET_SERVICE_TYPE_SIG;
+ else if (strcasecmp(str, "VO") == 0)
+ return NET_SERVICE_TYPE_VO;
+ else if (strcasecmp(str, "RV") == 0)
+ return NET_SERVICE_TYPE_RV;
+ else if (strcasecmp(str, "AV") == 0)
+ return NET_SERVICE_TYPE_AV;
+ else if (strcasecmp(str, "OAM") == 0)
+ return NET_SERVICE_TYPE_OAM;
+ else if (strcasecmp(str, "RD") == 0)
+ return NET_SERVICE_TYPE_RD;
+ else {
+ svc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (svc);
+}
+
+u_int8_t
+str2tos(const char *str, bool *valid)
+{
+ u_int8_t dscp = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "DF") == 0)
+ dscp = _DSCP_DF;
+ else if (strcasecmp(str, "EF") == 0)
+ dscp = _DSCP_EF;
+ else if (strcasecmp(str, "VA") == 0)
+ dscp = _DSCP_VA;
+
+ else if (strcasecmp(str, "CS0") == 0)
+ dscp = _DSCP_CS0;
+ else if (strcasecmp(str, "CS1") == 0)
+ dscp = _DSCP_CS1;
+ else if (strcasecmp(str, "CS2") == 0)
+ dscp = _DSCP_CS2;
+ else if (strcasecmp(str, "CS3") == 0)
+ dscp = _DSCP_CS3;
+ else if (strcasecmp(str, "CS4") == 0)
+ dscp = _DSCP_CS4;
+ else if (strcasecmp(str, "CS5") == 0)
+ dscp = _DSCP_CS5;
+ else if (strcasecmp(str, "CS6") == 0)
+ dscp = _DSCP_CS6;
+ else if (strcasecmp(str, "CS7") == 0)
+ dscp = _DSCP_CS7;
+
+ else if (strcasecmp(str, "AF11") == 0)
+ dscp = _DSCP_AF11;
+ else if (strcasecmp(str, "AF12") == 0)
+ dscp = _DSCP_AF12;
+ else if (strcasecmp(str, "AF13") == 0)
+ dscp = _DSCP_AF13;
+ else if (strcasecmp(str, "AF21") == 0)
+ dscp = _DSCP_AF21;
+ else if (strcasecmp(str, "AF22") == 0)
+ dscp = _DSCP_AF22;
+ else if (strcasecmp(str, "AF23") == 0)
+ dscp = _DSCP_AF23;
+ else if (strcasecmp(str, "AF31") == 0)
+ dscp = _DSCP_AF31;
+ else if (strcasecmp(str, "AF32") == 0)
+ dscp = _DSCP_AF32;
+ else if (strcasecmp(str, "AF33") == 0)
+ dscp = _DSCP_AF33;
+ else if (strcasecmp(str, "AF41") == 0)
+ dscp = _DSCP_AF41;
+ else if (strcasecmp(str, "AF42") == 0)
+ dscp = _DSCP_AF42;
+ else if (strcasecmp(str, "AF43") == 0)
+ dscp = _DSCP_AF43;
+
+ else {
+ unsigned long val = strtoul(str, &endptr, 0);
+ if (*endptr != '\0' || val > 255)
+ *valid = false;
+ else
+ return ((u_int8_t)val);
+ }
+ /* DSCP occupies the 6 upper bits of the TOS field */
+ return (dscp << 2);
+}
+
+void
+pr_currenttime(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+#define SECOPT " [-P policy]"
+#else
+#define SECOPT ""
+#endif
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize]",
+" [-g sweepminsize] [-h sweepincrsize] [-i wait]",
+" [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern]",
+" [-S src_addr] [-s packetsize] [-t timeout][-W waittime]",
+" [-z tos] host",
+" ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait]",
+" [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
+" [-s packetsize] [-T ttl] [-t timeout] [-W waittime]",
+" [-z tos] mcast-group");
+ (void)fprintf(stderr, "Apple specific options (to be specified before mcast-group or host like all options)\n");
+ (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n");
+ (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n");
+ (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n");
+ (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n");
+ (void)fprintf(stderr, " -apple-time # display current time\n");
+ exit(EX_USAGE);
+}
diff --git a/network_cmds/ping6.tproj/md5.c b/network_cmds/ping6.tproj/md5.c
new file mode 100644
index 0000000..68a654b
--- /dev/null
+++ b/network_cmds/ping6.tproj/md5.c
@@ -0,0 +1,308 @@
+/* $KAME: md5.c,v 1.3 2000/05/27 07:14:22 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.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+#include <string.h>
+#include "md5.h"
+
+#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
+
+#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
+#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
+#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
+#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
+
+#define ROUND1(a, b, c, d, k, s, i) { \
+ (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define ROUND2(a, b, c, d, k, s, i) { \
+ (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define ROUND3(a, b, c, d, k, s, i) { \
+ (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define ROUND4(a, b, c, d, k, s, i) { \
+ (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define Sa 7
+#define Sb 12
+#define Sc 17
+#define Sd 22
+
+#define Se 5
+#define Sf 9
+#define Sg 14
+#define Sh 20
+
+#define Si 4
+#define Sj 11
+#define Sk 16
+#define Sl 23
+
+#define Sm 6
+#define Sn 10
+#define So 15
+#define Sp 21
+
+#define MD5_A0 0x67452301
+#define MD5_B0 0xefcdab89
+#define MD5_C0 0x98badcfe
+#define MD5_D0 0x10325476
+
+/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
+static const u_int32_t T[65] = {
+ 0,
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+};
+
+static const u_int8_t md5_paddat[MD5_BUFLEN] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static void md5_calc __P((u_int8_t *, md5_ctxt *));
+
+void md5_init(ctxt)
+ md5_ctxt *ctxt;
+{
+ ctxt->md5_n = 0;
+ ctxt->md5_i = 0;
+ ctxt->md5_sta = MD5_A0;
+ ctxt->md5_stb = MD5_B0;
+ ctxt->md5_stc = MD5_C0;
+ ctxt->md5_std = MD5_D0;
+ bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf));
+}
+
+void md5_loop(ctxt, input, len)
+ md5_ctxt *ctxt;
+ u_int8_t *input;
+ u_int len; /* number of bytes */
+{
+ u_int gap, i;
+
+ ctxt->md5_n += len * 8; /* byte to bit */
+ gap = MD5_BUFLEN - ctxt->md5_i;
+
+ if (len >= gap) {
+ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
+ gap);
+ md5_calc(ctxt->md5_buf, ctxt);
+
+ for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
+ md5_calc((u_int8_t *)(input + i), ctxt);
+ }
+
+ ctxt->md5_i = len - i;
+ bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
+ } else {
+ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
+ len);
+ ctxt->md5_i += len;
+ }
+}
+
+void md5_pad(ctxt)
+ md5_ctxt *ctxt;
+{
+ u_int gap;
+
+ /* Don't count up padding. Keep md5_n. */
+ gap = MD5_BUFLEN - ctxt->md5_i;
+ if (gap > 8) {
+ bcopy((void *)md5_paddat,
+ (void *)(ctxt->md5_buf + ctxt->md5_i),
+ gap - sizeof(ctxt->md5_n));
+ } else {
+ /* including gap == 8 */
+ bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
+ gap);
+ md5_calc(ctxt->md5_buf, ctxt);
+ bcopy((void *)(md5_paddat + gap),
+ (void *)ctxt->md5_buf,
+ MD5_BUFLEN - sizeof(ctxt->md5_n));
+ }
+
+ /* 8 byte word */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ ctxt->md5_buf[56] = ctxt->md5_n8[7];
+ ctxt->md5_buf[57] = ctxt->md5_n8[6];
+ ctxt->md5_buf[58] = ctxt->md5_n8[5];
+ ctxt->md5_buf[59] = ctxt->md5_n8[4];
+ ctxt->md5_buf[60] = ctxt->md5_n8[3];
+ ctxt->md5_buf[61] = ctxt->md5_n8[2];
+ ctxt->md5_buf[62] = ctxt->md5_n8[1];
+ ctxt->md5_buf[63] = ctxt->md5_n8[0];
+#endif
+
+ md5_calc(ctxt->md5_buf, ctxt);
+}
+
+void md5_result(digest, ctxt)
+ u_int8_t *digest;
+ md5_ctxt *ctxt;
+{
+ /* 4 byte words */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bcopy(&ctxt->md5_st8[0], digest, 16);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
+ digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
+ digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
+ digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
+ digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
+ digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
+ digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
+ digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
+#endif
+}
+
+#if BYTE_ORDER == BIG_ENDIAN
+u_int32_t X[16];
+#endif
+
+static void md5_calc(b64, ctxt)
+ u_int8_t *b64;
+ md5_ctxt *ctxt;
+{
+ u_int32_t A = ctxt->md5_sta;
+ u_int32_t B = ctxt->md5_stb;
+ u_int32_t C = ctxt->md5_stc;
+ u_int32_t D = ctxt->md5_std;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int32_t *X = (u_int32_t *)b64;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ /* 4 byte words */
+ /* what a brute force but fast! */
+ u_int8_t *y = (u_int8_t *)X;
+ y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
+ y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
+ y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
+ y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
+ y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
+ y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
+ y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
+ y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
+ y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
+ y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
+ y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
+ y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
+ y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
+ y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
+ y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
+ y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
+#endif
+
+ ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2);
+ ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4);
+ ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6);
+ ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8);
+ ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10);
+ ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
+ ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
+ ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);
+
+ ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18);
+ ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20);
+ ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
+ ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24);
+ ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
+ ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28);
+ ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30);
+ ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);
+
+ ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34);
+ ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
+ ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38);
+ ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
+ ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42);
+ ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44);
+ ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
+ ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48);
+
+ ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50);
+ ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52);
+ ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54);
+ ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56);
+ ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
+ ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
+ ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
+ ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64);
+
+ ctxt->md5_sta += A;
+ ctxt->md5_stb += B;
+ ctxt->md5_stc += C;
+ ctxt->md5_std += D;
+}
diff --git a/network_cmds/ping6.tproj/md5.h b/network_cmds/ping6.tproj/md5.h
new file mode 100644
index 0000000..b0752af
--- /dev/null
+++ b/network_cmds/ping6.tproj/md5.h
@@ -0,0 +1,75 @@
+/* $KAME: md5.h,v 1.1 2000/05/27 06:18:21 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.
+ */
+
+#ifndef _NETINET6_MD5_H_
+#define _NETINET6_MD5_H_
+
+#define MD5_BUFLEN 64
+
+typedef struct {
+ union {
+ u_int32_t md5_state32[4];
+ u_int8_t md5_state8[16];
+ } md5_st;
+
+#define md5_sta md5_st.md5_state32[0]
+#define md5_stb md5_st.md5_state32[1]
+#define md5_stc md5_st.md5_state32[2]
+#define md5_std md5_st.md5_state32[3]
+#define md5_st8 md5_st.md5_state8
+
+ union {
+ u_int64_t md5_count64;
+ u_int8_t md5_count8[8];
+ } md5_count;
+#define md5_n md5_count.md5_count64
+#define md5_n8 md5_count.md5_count8
+
+ u_int md5_i;
+ u_int8_t md5_buf[MD5_BUFLEN];
+} md5_ctxt;
+
+extern void md5_init __P((md5_ctxt *));
+extern void md5_loop __P((md5_ctxt *, u_int8_t *, u_int));
+extern void md5_pad __P((md5_ctxt *));
+extern void md5_result __P((u_int8_t *, md5_ctxt *));
+
+/* compatibility */
+#define MD5_CTX md5_ctxt
+#define MD5Init(x) md5_init((x))
+#define MD5Update(x, y, z) md5_loop((x), (y), (z))
+#define MD5Final(x, y) \
+do { \
+ md5_pad((y)); \
+ md5_result((x), (y)); \
+} while (0)
+
+#endif /* ! _NETINET6_MD5_H_*/
diff --git a/network_cmds/ping6.tproj/ping6.8 b/network_cmds/ping6.tproj/ping6.8
new file mode 100644
index 0000000..7ec0b70
--- /dev/null
+++ b/network_cmds/ping6.tproj/ping6.8
@@ -0,0 +1,625 @@
+.\" Copyright (c) 2002-2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" 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.
+.\"
+.\"
+.Dd March 29, 2013
+.Dt PING6 8
+.Os
+.Sh NAME
+.Nm ping6
+.Nd send
+.Tn ICMPv6 ECHO_REQUEST
+packets to network hosts
+.Sh SYNOPSIS
+.Nm
+.\" without ipsec, or new ipsec
+.Op Fl CDdfHmnNoqtvwW
+.\" old ipsec
+.\" .Op Fl ADdEfmnNqRtvwW
+.Bk -words
+.Op Fl a Ar addrtype
+.Ek
+.Bk -words
+.Op Fl b Ar bufsiz
+.Ek
+.Bk -words
+.Op Fl B Ar boundif
+.Ek
+.Bk -words
+.Op Fl c Ar count
+.Ek
+.Bk -words
+.Op Fl G Ar sweepmaxsize[,sweepminsize[,sweepincrsize]]
+.Ek
+.Bk -words
+.Op Fl g Ar gateway
+.Ek
+.Bk -words
+.Op Fl G Ar sweep
+.Ek
+.Bk -words
+.Op Fl h Ar hoplimit
+.Ek
+.Bk -words
+.Op Fl I Ar interface
+.Ek
+.Bk -words
+.Op Fl i Ar wait
+.Ek
+.Bk -words
+.Op Fl k Ar trafficclass
+.Ek
+.Bk -words
+.Op Fl K Ar netservicetype
+.Ek
+.Bk -words
+.Op Fl l Ar preload
+.Ek
+.Bk -words
+.\" new ipsec
+.Op Fl P Ar policy
+.Ek
+.Bk -words
+.Op Fl p Ar pattern
+.Ek
+.Bk -words
+.Op Fl S Ar sourceaddr
+.Ek
+.Bk -words
+.Op Fl s Ar packetsize
+.Ek
+.Bk -words
+.Op Fl z Ar tclass
+.Ek
+.Bk -words
+.Op Fl Fl apple-connect
+.Ek
+.Bk -words
+.Op Fl Fl apple-time
+.Ek
+.Bk -words
+.Op Ar hops ...
+.Ek
+.Bk -words
+.Ar host
+.Ek
+.Sh DESCRIPTION
+The
+.Nm
+utility uses the
+.Tn ICMPv6
+protocol's mandatory
+.Tn ICMP6_ECHO_REQUEST
+datagram to elicit an
+.Tn ICMP6_ECHO_REPLY
+from a host or gateway.
+.Tn ICMP6_ECHO_REQUEST
+datagrams (``pings'') have an IPv6 header,
+and
+.Tn ICMPv6
+header formatted as documented in RFC2463.
+The options are as follows:
+.Bl -tag -width Ds
+.\" old ipsec
+.\" .It Fl A
+.\" Enables transport-mode IPsec authentication header
+.\" (experimental).
+.It Fl a Ar addrtype
+Generate ICMPv6 Node Information Node Addresses query, rather than echo-request.
+.Ar addrtype
+must be a string constructed of the following characters.
+.Bl -tag -width Ds -compact
+.It Ic a
+requests unicast addresses from all of the responder's interfaces.
+If the character is omitted,
+only those addresses which belong to the interface which has the
+responder's address are requests.
+.It Ic c
+requests responder's IPv4-compatible and IPv4-mapped addresses.
+.It Ic g
+requests responder's global-scope addresses.
+.It Ic s
+requests responder's site-local addresses.
+.It Ic l
+requests responder's link-local addresses.
+.It Ic A
+requests responder's anycast addresses.
+Without this character, the responder will return unicast addresses only.
+With this character, the responder will return anycast addresses only.
+Note that the specification does not specify how to get responder's
+anycast addresses.
+This is an experimental option.
+.El
+.It Fl b Ar bufsiz
+Set socket buffer size.
+.It Fl B Ar boundif
+Bind the socket to interface
+This option is an Apple addition.
+.Ar boundif
+for sending.
+.It Fl C
+Prohibit the socket from using the cellular network interface.
+.It Fl c Ar count
+Stop after sending
+(and receiving)
+.Ar count
+.Tn ECHO_RESPONSE
+packets.
+If this option is specified in conjunction with ping sweeps,
+each sweep will consist of
+.Ar count
+packets.
+.It Fl D
+Disable IPv6 fragmentation.
+.It Fl d
+Set the
+.Dv SO_DEBUG
+option on the socket being used.
+.\" .It Fl E
+.\" Enables transport-mode IPsec encapsulated security payload
+.\" (experimental).
+.It Fl f
+Flood ping.
+Outputs packets as fast as they come back or one hundred times per second,
+whichever is more.
+For every
+.Tn ECHO_REQUEST
+sent a period
+.Dq \&.
+is printed, while for every
+.Tn ECHO_REPLY
+received a backspace is printed.
+This provides a rapid display of how many packets are being dropped.
+Only the super-user may use this option.
+.Bf -emphasis
+This can be very hard on a network and should be used with caution.
+.Ef
+.It Fl G Ar sweepmaxsize[,sweepminsize[,sweepincrsize]]
+.Ar sweepmaxsize
+specifies the maximum size of the payload when sending sweeping
+pings and is required for sweeps.
+.Ar sweepminsize
+specifies the size of the payload to start with when sending
+sweeping pings -- the default value is 0.
+.Ar sweepincrsize
+specifies the number of bytes to increment the size of the payload
+after each sweep when sending sweeping pings -- the default value
+is 1.
+This option is an Apple addition.
+.It Fl g Ar gateway
+Specifies to use
+.Ar gateway
+as the next hop to the destination.
+The gateway must be a neighbor of the sending node.
+.It Fl H
+Specifies to try reverse-lookup of IPv6 addresses.
+The
+.Nm
+utility does not try reverse-lookup unless the option is specified.
+.It Fl h Ar hoplimit
+Set the IPv6 hoplimit.
+.It Fl I Ar interface
+Source packets with the given interface address.
+This flag applies if the ping destination is a multicast address,
+or link-local/site-local unicast address.
+.It Fl i Ar wait
+Wait
+.Ar wait
+seconds
+.Em between sending each packet .
+The default is to wait for one second between each packet.
+The wait time may be fractional, but only the super-user may specify
+values less than 0.1 second.
+This option is incompatible with the
+.Fl f
+option.
+.It Fl k Ar trafficclass
+Specifies the traffic class to use for sending ICMPv6 packets.
+The supported traffic classes are
+BK_SYS, BK, BE, RD, OAM, AV, RV, VI, VO and CTL.
+By default
+.Nm
+uses the control traffic class (CTL).
+This option is an Apple addition.
+.It Fl K Ar netservicetype
+Specifies the network service type to use for sending ICMPv6 packets.
+The supported network service type are BK_SYS, BK, BE, RV, AV, RD, OAM, VI, SIG and VO.
+Note this overrides the default traffic class (-k can still be specified after -K to use both).
+This option is an Apple addition.
+.It Fl l Ar preload
+If
+.Ar preload
+is specified,
+.Nm
+sends that many packets as fast as possible before falling into its normal
+mode of behavior.
+Only the super-user may use this option.
+.It Fl m
+By default,
+.Nm
+asks the kernel to fragment packets to fit into the minimum IPv6 MTU.
+The
+.Fl m
+option
+will suppress the behavior in the following two levels:
+when the option is specified once, the behavior will be disabled for
+unicast packets.
+When the option is more than once, it will be disabled for both
+unicast and multicast packets.
+.It Fl n
+Numeric output only.
+No attempt will be made to lookup symbolic names from addresses in the reply.
+.It Fl N
+Probe node information multicast group
+.Pq Li ff02::2:xxxx:xxxx .
+.Ar host
+must be string hostname of the target
+(must not be a numeric IPv6 address).
+Node information multicast group will be computed based on given
+.Ar host ,
+and will be used as the final destination.
+Since node information multicast group is a link-local multicast group,
+outgoing interface needs to be specified by
+.Fl I
+option.
+.It Fl o
+Exit successfully after receiving one reply packet.
+.It Fl p Ar pattern
+You may specify up to 16
+.Dq pad
+bytes to fill out the packet you send.
+This is useful for diagnosing data-dependent problems in a network.
+For example,
+.Dq Li \-p ff
+will cause the sent packet to be filled with all
+ones.
+.\" new ipsec
+.It Fl P Ar policy
+.Ar policy
+specifies IPsec policy to be used for the probe.
+.It Fl q
+Quiet output.
+Nothing is displayed except the summary lines at startup time and
+when finished.
+.It Fl r
+Audible.
+Include a bell
+.Tn ( ASCII
+0x07)
+character in the output when any packet is received.
+.It Fl R
+Audible.
+Output a bell
+.Tn ( ASCII
+0x07)
+character when no packet is received before the next packet
+is transmitted.
+To cater for round-trip times that are longer than the interval
+between transmissions, further missing packets cause a bell only
+if the maximum number of unreceived packets has increased.
+.It Fl S Ar sourceaddr
+Specifies the source address of request packets.
+The source address must be one of the unicast addresses of the sending node,
+and must be numeric.
+.It Fl s Ar packetsize
+Specifies the number of data bytes to be sent.
+The default is 56, which translates into 64
+.Tn ICMP
+data bytes when combined
+with the 8 bytes of
+.Tn ICMP
+header data.
+You may need to specify
+.Fl b
+as well to extend socket buffer size.
+.It Fl t
+Generate ICMPv6 Node Information supported query types query,
+rather than echo-request.
+.Fl s
+has no effect if
+.Fl t
+is specified.
+.It Fl v
+Verbose output.
+.Tn ICMP
+packets other than
+.Tn ECHO_RESPONSE
+that are received are listed.
+.It Fl w
+Generate ICMPv6 Node Information DNS Name query, rather than echo-request.
+.Fl s
+has no effect if
+.Fl w
+is specified.
+.It Fl W
+Same as
+.Fl w ,
+but with old packet format based on 03 draft.
+This option is present for backward compatibility.
+.Fl s
+has no effect if
+.Fl w
+is specified.
+.It Fl z Ar tclass
+Use the specified traffic class.
+.It Fl Fl apple-connect
+Connects the socket to the destination address.
+This option is an Apple addition.
+.It Fl Fl apple-time
+Prints the time a packet was received.
+This option is an Apple addition.
+.It Ar hops
+IPv6 addresses for intermediate nodes,
+which will be put into type 0 routing header.
+.It Ar host
+IPv6 address of the final destination node.
+.El
+.Pp
+When using
+.Nm
+for fault isolation, it should first be run on the local host, to verify
+that the local network interface is up and running.
+Then, hosts and gateways further and further away should be
+.Dq pinged .
+Round-trip times and packet loss statistics are computed.
+If duplicate packets are received, they are not included in the packet
+loss calculation, although the round trip time of these packets is used
+in calculating the round-trip time statistics.
+When the specified number of packets have been sent
+(and received)
+or if the program is terminated with a
+.Dv SIGINT ,
+a brief summary is displayed, showing the number of packets sent and
+received, and the minimum, mean, maximum, and standard deviation of
+the round-trip times.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Cm status
+argument for
+.Xr stty 1 )
+signal, the current number of packets sent and received, and the
+minimum, mean, maximum, and standard deviation of the round-trip times
+will be written to the standard output in the same format as the
+standard completion message.
+.Pp
+This program is intended for use in network testing, measurement and
+management.
+Because of the load it can impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.\" .Sh ICMP PACKET DETAILS
+.\" An IP header without options is 20 bytes.
+.\" An
+.\" .Tn ICMP
+.\" .Tn ECHO_REQUEST
+.\" packet contains an additional 8 bytes worth of
+.\" .Tn ICMP
+.\" header followed by an arbitrary amount of data.
+.\" When a
+.\" .Ar packetsize
+.\" is given, this indicated the size of this extra piece of data
+.\" (the default is 56).
+.\" Thus the amount of data received inside of an IP packet of type
+.\" .Tn ICMP
+.\" .Tn ECHO_REPLY
+.\" will always be 8 bytes more than the requested data space
+.\" (the
+.\" .Tn ICMP
+.\" header).
+.\" .Pp
+.\" If the data space is at least eight bytes large,
+.\" .Nm
+.\" uses the first eight bytes of this space to include a timestamp which
+.\" it uses in the computation of round trip times.
+.\" If less than eight bytes of pad are specified, no round trip times are
+.\" given.
+.Sh DUPLICATE AND DAMAGED PACKETS
+The
+.Nm
+utility will report duplicate and damaged packets.
+Duplicate packets should never occur when pinging a unicast address,
+and seem to be caused by
+inappropriate link-level retransmissions.
+Duplicates may occur in many situations and are rarely
+(if ever)
+a good sign, although the presence of low levels of duplicates may not
+always be cause for alarm.
+Duplicates are expected when pinging a broadcast or multicast address,
+since they are not really duplicates but replies from different hosts
+to the same request.
+.Pp
+Damaged packets are obviously serious cause for alarm and often
+indicate broken hardware somewhere in the
+.Nm
+packet's path
+(in the network or in the hosts).
+.Sh TRYING DIFFERENT DATA PATTERNS
+The
+(inter)network
+layer should never treat packets differently depending on the data
+contained in the data portion.
+Unfortunately, data-dependent problems have been known to sneak into
+networks and remain undetected for long periods of time.
+In many cases the particular pattern that will have problems is something
+that does not have sufficient
+.Dq transitions ,
+such as all ones or all zeros, or a pattern right at the edge, such as
+almost all zeros.
+It is not
+necessarily enough to specify a data pattern of all zeros (for example)
+on the command line because the pattern that is of interest is
+at the data link level, and the relationship between what you type and
+what the controllers transmit can be complicated.
+.Pp
+This means that if you have a data-dependent problem you will probably
+have to do a lot of testing to find it.
+If you are lucky, you may manage to find a file that either
+cannot
+be sent across your network or that takes much longer to transfer than
+other similar length files.
+You can then examine this file for repeated patterns that you can test
+using the
+.Fl p
+option of
+.Nm .
+.Sh EXIT STATUS
+The
+.Nm
+utility returns 0 on success (the host is alive),
+2 if the transmission was successful but no responses were received,
+any other non-zero value if the arguments are incorrect or
+another error has occurred.
+.Sh EXAMPLES
+Normally,
+.Nm
+works just like
+.Xr ping 8
+would work; the following will send ICMPv6 echo request to
+.Li dst.foo.com .
+.Bd -literal -offset indent
+ping6 -n dst.foo.com
+.Ed
+.Pp
+The following will probe hostnames for all nodes on the network link attached to
+.Li wi0
+interface.
+The address
+.Li ff02::1
+is named the link-local all-node multicast address, and the packet would
+reach every node on the network link.
+.Bd -literal -offset indent
+ping6 -w ff02::1%wi0
+.Ed
+.Pp
+The following will probe addresses assigned to the destination node,
+.Li dst.foo.com .
+.Bd -literal -offset indent
+ping6 -a agl dst.foo.com
+.Ed
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr icmp6 4 ,
+.Xr inet6 4 ,
+.Xr ip6 4 ,
+.Xr ifconfig 8 ,
+.Xr ping 8 ,
+.Xr routed 8 ,
+.Xr traceroute 8 ,
+.Xr traceroute6 8
+.Rs
+.%A A. Conta
+.%A S. Deering
+.%T "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification"
+.%N RFC2463
+.%D December 1998
+.Re
+.Rs
+.%A Matt Crawford
+.%T "IPv6 Node Information Queries"
+.%N draft-ietf-ipngwg-icmp-name-lookups-09.txt
+.%D May 2002
+.%O work in progress material
+.Re
+.Sh HISTORY
+The
+.Xr ping 8
+utility appeared in
+.Bx 4.3 .
+The
+.Nm
+utility with IPv6 support first appeared in the WIDE Hydrangea IPv6
+protocol stack kit.
+.Pp
+IPv6 and IPsec support based on the KAME Project
+.Pq Pa http://www.kame.net/
+stack was initially integrated into
+.Fx 4.0 .
+.Sh BUGS
+The
+.Nm
+utility
+is intentionally separate from
+.Xr ping 8 .
+.Pp
+There have been many discussions on why we separate
+.Nm
+and
+.Xr ping 8 .
+Some people argued that it would be more convenient to uniform the
+ping command for both IPv4 and IPv6.
+The followings are an answer to the request.
+.Pp
+From a developer's point of view:
+since the underling raw sockets API is totally different between IPv4
+and IPv6, we would end up having two types of code base.
+There would actually be less benefit to uniform the two commands
+into a single command from the developer's standpoint.
+.Pp
+From an operator's point of view: unlike ordinary network applications
+like remote login tools, we are usually aware of address family when using
+network management tools.
+We do not just want to know the reachability to the host, but want to know the
+reachability to the host via a particular network protocol such as
+IPv6.
+Thus, even if we had a unified
+.Xr ping 8
+command for both IPv4 and IPv6, we would usually type a
+.Fl 6
+or
+.Fl 4
+option (or something like those) to specify the particular address family.
+This essentially means that we have two different commands.
diff --git a/network_cmds/ping6.tproj/ping6.c b/network_cmds/ping6.tproj/ping6.c
new file mode 100644
index 0000000..7890e66
--- /dev/null
+++ b/network_cmds/ping6.tproj/ping6.c
@@ -0,0 +1,3340 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * 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) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ *
+ * Status -
+ * Public Domain. Distribution Unlimited.
+ * Bugs -
+ * More statistics could always be gathered.
+ * This program has to run SUID to ROOT to access the ICMP socket.
+ */
+/*
+ * NOTE:
+ * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics
+ * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link*
+ * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of
+ * network attached to 1 or more interfaces)
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <getopt.h>
+
+#ifdef IPSEC
+#include <netinet6/ah.h>
+#include <netinet6/ipsec.h>
+#endif
+
+#include "md5.h"
+
+struct tv32 {
+ u_int32_t tv32_sec;
+ u_int32_t tv32_usec;
+};
+
+#define MAXPACKETLEN 131072
+#define IP6LEN 40
+#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */
+#define ICMP6ECHOTMLEN sizeof(struct tv32)
+#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8)
+# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */
+/* FQDN case, 64 bits of nonce + 32 bits ttl */
+#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12)
+#define EXTRA 256 /* for AH and various other headers. weird. */
+#define DEFDATALEN ICMP6ECHOTMLEN
+#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
+#define NROUTES 9 /* number of record route slots */
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
+
+#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
+#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
+#define SET(bit) (A(bit) |= B(bit))
+#define CLR(bit) (A(bit) &= (~B(bit)))
+#define TST(bit) (A(bit) & B(bit))
+
+#define F_FLOOD 0x0001
+#define F_INTERVAL 0x0002
+#define F_PINGFILLED 0x0008
+#define F_QUIET 0x0010
+#define F_RROUTE 0x0020
+#define F_SO_DEBUG 0x0040
+#define F_PRTIME 0x0080
+#define F_VERBOSE 0x0100
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define F_POLICY 0x0400
+#else
+#define F_AUTHHDR 0x0200
+#define F_ENCRYPT 0x0400
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+#define F_NODEADDR 0x0800
+#define F_FQDN 0x1000
+#define F_INTERFACE 0x2000
+#define F_SRCADDR 0x4000
+#define F_HOSTNAME 0x10000
+#define F_FQDNOLD 0x20000
+#define F_NIGROUP 0x40000
+#define F_SUPTYPES 0x80000
+#define F_NOMINMTU 0x100000
+#define F_ONCE 0x200000
+#define F_AUDIBLE 0x400000
+#define F_MISSED 0x800000
+#define F_DONTFRAG 0x1000000
+#define F_SWEEP 0x2000000
+#define F_CONNECT 0x4000000
+#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
+#define F_WAITTIME 0x8000000
+u_int options;
+
+static int longopt_flag = 0;
+
+#define LOF_CONNECT 0x01
+#define LOF_PRTIME 0x02
+
+static const struct option longopts[] = {
+ { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT },
+ { "apple-time", no_argument, &longopt_flag, LOF_PRTIME },
+ { NULL, 0, NULL, 0 }
+};
+
+#define IN6LEN sizeof(struct in6_addr)
+#define SA6LEN sizeof(struct sockaddr_in6)
+#define DUMMY_PORT 10101
+
+#define SIN6(s) ((struct sockaddr_in6 *)(s))
+
+#define MAXTOS 255
+/*
+ * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
+ * number of received sequence numbers we can keep track of. Change 128
+ * to 8192 for complete accuracy...
+ */
+#define MAX_DUP_CHK (8 * 8192)
+int mx_dup_ck = MAX_DUP_CHK;
+char rcvd_tbl[MAX_DUP_CHK / 8];
+
+struct addrinfo *res;
+struct sockaddr_in6 dst; /* who to ping6 */
+struct sockaddr_in6 src; /* src addr of this packet */
+socklen_t srclen;
+int datalen = DEFDATALEN;
+int s; /* socket file descriptor */
+u_char outpack[MAXPACKETLEN];
+char BSPACE = '\b'; /* characters written for flood */
+char BBELL = '\a'; /* characters written for AUDIBLE */
+char DOT = '.';
+char *hostname;
+int ident; /* process id to identify our packets */
+u_int8_t nonce[8]; /* nonce field for node information */
+int hoplimit = -1; /* hoplimit */
+int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */
+u_char *packet = NULL;
+struct cmsghdr *cm = NULL;
+char *boundif;
+unsigned int ifscope;
+int nocell;
+
+/* counters */
+long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
+long npackets; /* max packets to transmit */
+long nreceived; /* # of packets we got back */
+long nrepeats; /* number of duplicates */
+long ntransmitted; /* sequence # for outbound packets = #sent */
+static int interval = 1000; /* interval between packets in ms */
+static int waittime = MAXWAIT; /* timeout for each packet */
+static long nrcvtimeout = 0; /* # of packets we got back after waittime */
+
+long snpackets = 0; /* max packets to transmit in one sweep */
+long sntransmitted = 0; /* # of packets we sent in this sweep */
+int sweepmax = 0; /* max value of payload in sweep */
+int sweepmin = 0; /* start value of payload in sweep */
+int sweepincr = 1; /* payload increment in sweep */
+
+/* timing */
+int timing; /* flag to do timing */
+double tmin = 999999999.0; /* minimum round trip time */
+double tmax = 0.0; /* maximum round trip time */
+double tsum = 0.0; /* sum of all times, for doing average */
+double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+
+/* for node addresses */
+u_short naflags;
+
+/* for ancillary data(advanced API) */
+struct msghdr smsghdr;
+struct iovec smsgiov[2];
+char *scmsg = NULL;
+
+volatile sig_atomic_t seenalrm;
+volatile sig_atomic_t seenint;
+#ifdef SIGINFO
+volatile sig_atomic_t seeninfo;
+#endif
+
+int rcvtclass = 0;
+
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int so_traffic_class = SO_TC_CTL; /* use control class, by default */
+int net_service_type = -1;
+
+int32_t thiszone; /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
+
+int main(int, char *[]);
+void fill(char *, char *);
+int get_hoplim(struct msghdr *);
+int get_pathmtu(struct msghdr *);
+int get_tclass(struct msghdr *);
+int get_so_traffic_class(struct msghdr *);
+struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
+void onsignal(int);
+void onint(int);
+size_t pingerlen(void);
+int pinger(void);
+const char *pr_addr(struct sockaddr *, int);
+void pr_icmph(struct icmp6_hdr *, u_char *);
+void pr_iph(struct ip6_hdr *);
+void pr_suptypes(struct icmp6_nodeinfo *, size_t);
+void pr_nodeaddr(struct icmp6_nodeinfo *, int);
+int myechoreply(const struct icmp6_hdr *);
+int mynireply(const struct icmp6_nodeinfo *);
+char *dnsdecode(const u_char **, const u_char *, const u_char *,
+ char *, size_t);
+void pr_pack(u_char *, int, struct msghdr *);
+void pr_exthdrs(struct msghdr *);
+void pr_ip6opt(void *, size_t);
+void pr_rthdr(void *, size_t);
+int pr_bitrange(u_int32_t, int, int);
+void pr_retip(struct ip6_hdr *, u_char *);
+void summary(void);
+void tvsub(struct timeval *, struct timeval *);
+int setpolicy(int, char *);
+char *nigroup(char *, int);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tclass(const char *, bool *);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct timeval last, intvl;
+ struct sockaddr_in6 from;
+ struct addrinfo hints;
+ int cc, i;
+ int almost_done, ch, hold, packlen, preload, optval, ret_ga;
+ int nig_oldmcprefix = -1;
+ u_char *datap;
+ char *e, *target, *ifname = NULL, *gateway = NULL;
+ int ip6optlen = 0;
+ struct cmsghdr *scmsgp = NULL;
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ u_long lsockbufsize;
+ int sockbufsize = 0;
+#endif
+ int usepktinfo = 0;
+ struct in6_pktinfo *pktinfo = NULL;
+#ifdef USE_RFC2292BIS
+ struct ip6_rthdr *rthdr = NULL;
+#endif
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy_in = NULL;
+ char *policy_out = NULL;
+#endif
+ double t;
+ u_long alarmtimeout;
+ size_t rthlen;
+#ifdef IPV6_USE_MIN_MTU
+ int mflag = 0;
+#endif
+ /* T_CLASS value -1 means default, so -2 means do not bother */
+ int tclass = -2;
+ bool valid;
+
+ /* just to be sure */
+ memset(&smsghdr, 0, sizeof(smsghdr));
+ memset(&smsgiov, 0, sizeof(smsgiov));
+
+ preload = 0;
+ datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
+#ifndef IPSEC
+#define ADDOPTS
+#else
+#ifdef IPSEC_POLICY_IPSEC
+#define ADDOPTS "P:"
+#else
+#define ADDOPTS "AE"
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif
+ while ((ch = getopt_long(argc, argv,
+ "a:b:B:Cc:DdfHG:g:h:I:i:k:K:l:mnNop:qrRS:s:tvwWz:" ADDOPTS,
+ longopts, NULL)) != -1) {
+#undef ADDOPTS
+ switch (ch) {
+ case 'a':
+ {
+ char *cp;
+
+ options &= ~F_NOUSERDATA;
+ options |= F_NODEADDR;
+ for (cp = optarg; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case 'a':
+ naflags |= NI_NODEADDR_FLAG_ALL;
+ break;
+ case 'c':
+ case 'C':
+ naflags |= NI_NODEADDR_FLAG_COMPAT;
+ break;
+ case 'l':
+ case 'L':
+ naflags |= NI_NODEADDR_FLAG_LINKLOCAL;
+ break;
+ case 's':
+ case 'S':
+ naflags |= NI_NODEADDR_FLAG_SITELOCAL;
+ break;
+ case 'g':
+ case 'G':
+ naflags |= NI_NODEADDR_FLAG_GLOBAL;
+ break;
+ case 'A': /* experimental. not in the spec */
+#ifdef NI_NODEADDR_FLAG_ANYCAST
+ naflags |= NI_NODEADDR_FLAG_ANYCAST;
+ break;
+#else
+ errx(1, "-a A is not supported on "
+ "the platform");
+ /*NOTREACHED*/
+#endif
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ break;
+ }
+ case 'b':
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ errno = 0;
+ e = NULL;
+ lsockbufsize = strtoul(optarg, &e, 10);
+ sockbufsize = lsockbufsize;
+ if (errno || !*optarg || *e ||
+ sockbufsize != lsockbufsize)
+ errx(1, "invalid socket buffer size");
+#else
+ errx(1, "-b option ignored: SO_SNDBUF/SO_RCVBUF "
+ "socket options not supported");
+#endif
+ break;
+ case 'B':
+ boundif = optarg;
+ break;
+ case 'C':
+ nocell++;
+ break;
+ case 'c':
+ npackets = strtol(optarg, &e, 10);
+ if (npackets <= 0 || *optarg == '\0' || *e != '\0')
+ errx(1,
+ "illegal number of packets -- %s", optarg);
+ break;
+ case 'D':
+ options |= F_DONTFRAG;
+ break;
+ case 'd':
+ options |= F_SO_DEBUG;
+ break;
+ case 'f':
+ if (getuid()) {
+ errno = EPERM;
+ errx(1, "Must be superuser to flood ping");
+ }
+ options |= F_FLOOD;
+ setbuf(stdout, (char *)NULL);
+ break;
+ case 'g':
+ gateway = optarg;
+ break;
+ case 'G': {
+ char *ptr ;
+ char *tofree;
+ unsigned long ultmp;
+
+ tofree = strdup(optarg);
+ if (tofree == NULL)
+ errx(1, "### strdup() failed");
+ ptr = tofree;
+ do {
+ char *str;
+ char *ep;
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ errx(1, "-G requires maximum packet size");
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid maximum packet size: `%s'",
+ str);
+ options |= F_SWEEP;
+ sweepmax = ultmp;
+ if (sweepmax < 1 || sweepmax > MAXDATALEN) {
+ errx(1,
+ "-G invalid maximum packet size, needs to be between 1 and %d",
+ MAXDATALEN);
+ }
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ break;
+ if (*str != 0) {
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid minimum packet size: `%s'",
+ str);
+ sweepmin = ultmp;
+ if (sweepmin < 0 || sweepmin > MAXDATALEN) {
+ errx(1,
+ "-G invalid minimum packet size, needs to be between 0 and %d",
+ MAXDATALEN);
+ }
+ }
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ break;
+ if (*str == 0)
+ break;
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid sweep increment size: `%s'",
+ str);
+ sweepincr = ultmp;
+ if (sweepincr < 1 || sweepincr > MAXDATALEN) {
+ errx(1,
+ "-G invalid sweep increment size, needs to be between 1 and %d",
+ MAXDATALEN);
+ }
+ } while (0);
+ free(tofree);
+ break;
+ }
+ case 'H':
+ options |= F_HOSTNAME;
+ break;
+ case 'h': /* hoplimit */
+ hoplimit = strtol(optarg, &e, 10);
+ if (*optarg == '\0' || *e != '\0')
+ errx(1, "illegal hoplimit %s", optarg);
+ if (255 < hoplimit || hoplimit < -1)
+ errx(1,
+ "illegal hoplimit -- %s", optarg);
+ break;
+ case 'I':
+ ifname = optarg;
+ options |= F_INTERFACE;
+#ifndef USE_SIN6_SCOPE_ID
+ usepktinfo++;
+#endif
+ break;
+ case 'i': /* wait between sending packets */
+ t = strtod(optarg, &e);
+ if (*optarg == '\0' || *e != '\0')
+ errx(1, "illegal timing interval %s", optarg);
+ if (t < 0.1 && getuid()) {
+ errx(1, "%s: only root may use interval < 1s",
+ strerror(EPERM));
+ }
+ intvl.tv_sec = (long)t;
+ intvl.tv_usec =
+ (long)((t - intvl.tv_sec) * 1000000);
+ if (intvl.tv_sec < 0)
+ errx(1, "illegal timing interval %s", optarg);
+ /* less than 1/hz does not make sense */
+ if (intvl.tv_sec == 0 && intvl.tv_usec < 1) {
+ warnx("too small interval, raised to .000001");
+ intvl.tv_usec = 1;
+ }
+ options |= F_INTERVAL;
+ break;
+ case 'k':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ if (strcasecmp(optarg, "recvmsg") == 0) {
+ use_recvmsg++;
+ break;
+ }
+ so_traffic_class = str2sotc(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad traffic class: `%s'",
+ optarg);
+ break;
+ case 'K':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ net_service_type = str2netservicetype(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad network service type: `%s'",
+ optarg);
+ /* suppress default traffic class (-k can still be specified after -K) */
+ so_traffic_class = -1;
+ break;
+ case 'l':
+ if (getuid()) {
+ errno = EPERM;
+ errx(1, "Must be superuser to preload");
+ }
+ preload = strtol(optarg, &e, 10);
+ if (preload < 0 || *optarg == '\0' || *e != '\0')
+ errx(1, "illegal preload value -- %s", optarg);
+ break;
+ case 'm':
+#ifdef IPV6_USE_MIN_MTU
+ mflag++;
+ break;
+#else
+ errx(1, "-%c is not supported on this platform", ch);
+ /*NOTREACHED*/
+#endif
+ case 'n':
+ options &= ~F_HOSTNAME;
+ break;
+ case 'N':
+ options |= F_NIGROUP;
+ nig_oldmcprefix++;
+ break;
+ case 'o':
+ options |= F_ONCE;
+ break;
+ case 'p': /* fill buffer with user pattern */
+ options |= F_PINGFILLED;
+ fill((char *)datap, optarg);
+ break;
+ case 'q':
+ options |= F_QUIET;
+ break;
+ case 'r':
+ options |= F_AUDIBLE;
+ break;
+ case 'R':
+ options |= F_MISSED;
+ break;
+ case 'S':
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
+
+ ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
+ if (ret_ga) {
+ errx(1, "invalid source address: %s",
+ gai_strerror(ret_ga));
+ }
+ /*
+ * res->ai_family must be AF_INET6 and res->ai_addrlen
+ * must be sizeof(src).
+ */
+ memcpy(&src, res->ai_addr, res->ai_addrlen);
+ srclen = res->ai_addrlen;
+ freeaddrinfo(res);
+ res = NULL;
+ options |= F_SRCADDR;
+ break;
+ case 's': /* size of packet to send */
+ datalen = strtol(optarg, &e, 10);
+ if (datalen <= 0 || *optarg == '\0' || *e != '\0')
+ errx(1, "illegal datalen value -- %s", optarg);
+ if (datalen > MAXDATALEN) {
+ errx(1,
+ "datalen value too large, maximum is %d",
+ MAXDATALEN);
+ }
+ break;
+ case 't':
+ options &= ~F_NOUSERDATA;
+ options |= F_SUPTYPES;
+ break;
+ case 'v':
+ options |= F_VERBOSE;
+ break;
+ case 'w':
+ options &= ~F_NOUSERDATA;
+ options |= F_FQDN;
+ break;
+ case 'W':
+ options &= ~F_NOUSERDATA;
+ options |= F_FQDNOLD;
+ break;
+ case 'z':
+ tclass = str2tclass(optarg, &valid);
+ if (valid == false)
+ errx(1, "illegal TOS value -- %s", optarg);
+ rcvtclass = 1;
+ break;
+ case 'X':
+ alarmtimeout = strtoul(optarg, &e, 0);
+ if (alarmtimeout < 1 || alarmtimeout == ULONG_MAX)
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((int)alarmtimeout);
+ break;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ case 'P':
+ options |= F_POLICY;
+ if (!strncmp("in", optarg, 2)) {
+ if ((policy_in = strdup(optarg)) == NULL)
+ errx(1, "strdup");
+ } else if (!strncmp("out", optarg, 3)) {
+ if ((policy_out = strdup(optarg)) == NULL)
+ errx(1, "strdup");
+ } else
+ errx(1, "invalid security policy");
+ break;
+#else
+ case 'A':
+ options |= F_AUTHHDR;
+ break;
+ case 'E':
+ options |= F_ENCRYPT;
+ break;
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+ case 0:
+ switch (longopt_flag) {
+ case LOF_CONNECT:
+ options |= F_CONNECT;
+ break;
+ case LOF_PRTIME:
+ options |= F_PRTIME;
+ thiszone = gmt2local(0);
+ break;
+ default:
+ break;
+ }
+ longopt_flag = 0;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "bad interface name");
+
+ if ((options & F_SWEEP) && !sweepmax)
+ errx(EX_USAGE, "Maximum sweep size must be specified");
+
+ if ((options & F_SWEEP) && (options & F_NOUSERDATA))
+ errx(EX_USAGE, "Option -G incompatible with -t, -w and -W");
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (argc > 1) {
+#ifdef IPV6_RECVRTHDR /* 2292bis */
+ rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0,
+ argc - 1));
+#else /* RFC2292 */
+ rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1);
+#endif
+ if (rthlen == 0) {
+ errx(1, "too many intermediate hops");
+ /*NOTREACHED*/
+ }
+ ip6optlen += rthlen;
+ }
+
+ if (options & F_NIGROUP) {
+ target = nigroup(argv[argc - 1], nig_oldmcprefix);
+ if (target == NULL) {
+ usage();
+ /*NOTREACHED*/
+ }
+ } else
+ target = argv[argc - 1];
+
+ /* getaddrinfo */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
+
+ ret_ga = getaddrinfo(target, NULL, &hints, &res);
+ if (ret_ga)
+ errx(1, "getaddrinfo -- %s", gai_strerror(ret_ga));
+ if (res->ai_canonname)
+ hostname = strdup(res->ai_canonname);
+ else
+ hostname = target;
+
+ if (!res->ai_addr)
+ errx(1, "getaddrinfo failed");
+
+ (void)memcpy(&dst, res->ai_addr, res->ai_addrlen);
+
+ res->ai_socktype = getuid() ? SOCK_DGRAM : SOCK_RAW;
+ res->ai_protocol = IPPROTO_ICMPV6;
+
+ if ((s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol)) < 0)
+ err(1, "socket");
+
+ if (ifscope != 0) {
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
+ (char *)&ifscope, sizeof (ifscope)) != 0)
+ err(1, "setsockopt(IPV6_BOUND_IF)");
+ }
+
+ if (nocell != 0) {
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_NO_IFT_CELLULAR,
+ (char *)&nocell, sizeof (nocell)) != 0)
+ err(1, "setsockopt(IPV6_NO_IFT_CELLULAR)");
+ }
+
+ /* set the source address if specified. */
+ if ((options & F_SRCADDR) &&
+ bind(s, (struct sockaddr *)&src, srclen) != 0) {
+ err(1, "bind");
+ }
+
+ /* set the gateway (next hop) if specified */
+ if (gateway) {
+ struct addrinfo ghints, *gres;
+ int error;
+
+ memset(&ghints, 0, sizeof(ghints));
+ ghints.ai_family = AF_INET6;
+ ghints.ai_socktype = SOCK_RAW;
+ ghints.ai_protocol = IPPROTO_ICMPV6;
+
+ error = getaddrinfo(gateway, NULL, &hints, &gres);
+ if (error) {
+ errx(1, "getaddrinfo for the gateway %s: %s",
+ gateway, gai_strerror(error));
+ }
+ if (gres->ai_next && (options & F_VERBOSE))
+ warnx("gateway resolves to multiple addresses");
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
+ gres->ai_addr, gres->ai_addrlen)) {
+ err(1, "setsockopt(IPV6_NEXTHOP)");
+ }
+
+ freeaddrinfo(gres);
+ }
+
+ /*
+ * let the kerel pass extension headers of incoming packets,
+ * for privileged socket options
+ */
+ if ((options & F_VERBOSE) != 0) {
+ int opton = 1;
+
+#ifdef IPV6_RECVHOPOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVHOPOPTS)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_HOPOPTS)");
+#endif
+#ifdef IPV6_RECVDSTOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVDSTOPTS)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_DSTOPTS)");
+#endif
+#ifdef IPV6_RECVRTHDRDSTOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)");
+#endif
+ }
+
+ /* revoke root privilege */
+ if (seteuid(getuid()) != 0)
+ err(1, "seteuid() failed");
+ if (setuid(getuid()) != 0)
+ err(1, "setuid() failed");
+
+ if ((options & F_FLOOD) && (options & F_INTERVAL))
+ errx(1, "-f and -i incompatible options");
+
+ if ((options & F_CONNECT)) {
+ if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -1)
+ err(EX_OSERR, "connect");
+ }
+
+ if (sweepmax) {
+ if (sweepmin >= sweepmax)
+ errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+
+ if (datalen != DEFDATALEN)
+ errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
+
+ if (npackets > 0) {
+ snpackets = npackets;
+ npackets = 0;
+ } else
+ snpackets = 1;
+ datalen = sweepmin;
+ }
+
+ if ((options & F_NOUSERDATA) == 0) {
+ if (datalen >= sizeof(struct tv32)) {
+ /* we can time transfer */
+ timing = 1;
+ } else
+ timing = 0;
+ /* in F_VERBOSE case, we may get non-echoreply packets*/
+ if (options & F_VERBOSE)
+ packlen = MAX(2048, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ else
+ packlen = MAX(datalen, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ } else {
+ /* suppress timing for node information query */
+ timing = 0;
+ datalen = 2048;
+ packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ }
+
+ if (!(packet = (u_char *)malloc(packlen)))
+ err(1, "Unable to allocate packet");
+ if (!(options & F_PINGFILLED))
+ for (i = ICMP6ECHOLEN; i < MAX(datalen, sweepmax); ++i)
+ *datap++ = i;
+
+ ident = getpid() & 0xFFFF;
+ arc4random_buf(nonce, sizeof(nonce));
+ optval = 1;
+ if (options & F_DONTFRAG)
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_DONTFRAG");
+ hold = 1;
+
+ if (options & F_SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ sizeof(hold));
+
+ hold = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+ sizeof(hold));
+
+ optval = IPV6_DEFHLIM;
+ if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_MULTICAST_HOPS");
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1) {
+ optval = mflag > 1 ? 0 : 1;
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_USE_MIN_MTU)");
+ }
+#ifdef IPV6_RECVPATHMTU
+ else {
+ optval = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_RECVPATHMTU)");
+ }
+#endif /* IPV6_RECVPATHMTU */
+#endif /* IPV6_USE_MIN_MTU */
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (options & F_POLICY) {
+ if (setpolicy(s, policy_in) < 0)
+ errx(1, "%s", ipsec_strerror());
+ if (setpolicy(s, policy_out) < 0)
+ errx(1, "%s", ipsec_strerror());
+ }
+#else
+ if (options & F_AUTHHDR) {
+ optval = IPSEC_LEVEL_REQUIRE;
+#ifdef IPV6_AUTH_TRANS_LEVEL
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)");
+#else /* old def */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_AUTH_LEVEL)");
+#endif
+ }
+ if (options & F_ENCRYPT) {
+ optval = IPSEC_LEVEL_REQUIRE;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)");
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif
+
+#ifdef ICMP6_FILTER
+ {
+ struct icmp6_filter filt;
+ if (!(options & F_VERBOSE)) {
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ if ((options & F_FQDN) || (options & F_FQDNOLD) ||
+ (options & F_NODEADDR) || (options & F_SUPTYPES))
+ ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
+ else
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
+ } else {
+ ICMP6_FILTER_SETPASSALL(&filt);
+ }
+ if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0)
+ err(1, "setsockopt(ICMP6_FILTER)");
+ }
+#endif /*ICMP6_FILTER*/
+
+ /* let the kerel pass extension headers of incoming packets */
+ if ((options & F_VERBOSE) != 0) {
+ int opton = 1;
+
+#ifdef IPV6_RECVRTHDR
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVRTHDR)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RTHDR)");
+#endif
+ }
+
+ if (tclass != -2) {
+ int on = 1;
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on,
+ sizeof(on)))
+ err(1, "setsockopt(IPV6_RECVTCLASS)");
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
+ sizeof(tclass)))
+ err(1, "setsockopt(IPV6_TCLASS)");
+ }
+
+/*
+ optval = 1;
+ if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_MULTICAST_LOOP");
+*/
+
+ /* Specify the outgoing interface and/or the source address */
+ if (usepktinfo)
+ ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+ if (hoplimit != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+#endif /* IPV6_USE_MIN_MTU */
+
+ if (tclass != -2)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+
+ if (use_sendmsg == 0) {
+ if (net_service_type != -1)
+ if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE,
+ (void *)&net_service_type, sizeof (net_service_type)) != 0)
+ warn("setsockopt(SO_NET_SERVICE_TYPE");
+ if (so_traffic_class != -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&so_traffic_class, sizeof (so_traffic_class)) != 0)
+ warn("setsockopt(SO_TRAFFIC_CLASS");
+
+ }
+ } else {
+ if (net_service_type != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+ if (so_traffic_class != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+ }
+ if (use_recvmsg > 0) {
+ int on = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+ (void *)&on, sizeof (on)) != 0)
+ warn("setsockopt(SO_RECV_TRAFFIC_CLASS");
+ }
+
+ /* set IP6 packet options */
+ if (ip6optlen) {
+ if ((scmsg = (char *)malloc(ip6optlen)) == 0)
+ errx(1, "can't allocate enough memory");
+ smsghdr.msg_control = (caddr_t)scmsg;
+ smsghdr.msg_controllen = ip6optlen;
+ scmsgp = (struct cmsghdr *)scmsg;
+ }
+ if (usepktinfo) {
+ pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
+ memset(pktinfo, 0, sizeof(*pktinfo));
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_PKTINFO;
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+
+ /* set the outgoing interface */
+ if (ifname) {
+#ifndef USE_SIN6_SCOPE_ID
+ /* pktinfo must have already been allocated */
+ if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0)
+ errx(1, "%s: invalid interface name", ifname);
+#else
+ if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0)
+ errx(1, "%s: invalid interface name", ifname);
+#endif
+ }
+ if (hoplimit != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_HOPLIMIT;
+ *(int *)(CMSG_DATA(scmsgp)) = hoplimit;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1) {
+ optval = mflag > 1 ? 0 : 1;
+
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_USE_MIN_MTU;
+ *(int *)(CMSG_DATA(scmsgp)) = optval;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+#endif /* IPV6_USE_MIN_MTU */
+
+ if (argc > 1) { /* some intermediate addrs are specified */
+ int hops, error;
+#ifdef USE_RFC2292BIS
+ int rthdrlen;
+#endif
+
+#ifdef USE_RFC2292BIS
+ rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1);
+ scmsgp->cmsg_len = CMSG_LEN(rthdrlen);
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_RTHDR;
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp);
+ rthdr = inet6_rth_init((void *)rthdr, rthdrlen,
+ IPV6_RTHDR_TYPE_0, argc - 1);
+ if (rthdr == NULL)
+ errx(1, "can't initialize rthdr");
+#else /* old advanced API */
+ if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp,
+ IPV6_RTHDR_TYPE_0)) == 0)
+ errx(1, "can't initialize rthdr");
+#endif /* USE_RFC2292BIS */
+
+ for (hops = 0; hops < argc - 1; hops++) {
+ struct addrinfo *iaip;
+
+ if ((error = getaddrinfo(argv[hops], NULL, &hints,
+ &iaip)))
+ errx(1, "%s", gai_strerror(error));
+ if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
+ errx(1,
+ "bad addr family of an intermediate addr");
+
+#ifdef USE_RFC2292BIS
+ if (inet6_rth_add(rthdr,
+ &(SIN6(iaip->ai_addr))->sin6_addr))
+ errx(1, "can't add an intermediate node");
+#else /* old advanced API */
+ if (inet6_rthdr_add(scmsgp,
+ &(SIN6(iaip->ai_addr))->sin6_addr,
+ IPV6_RTHDR_LOOSE))
+ errx(1, "can't add an intermediate node");
+#endif /* USE_RFC2292BIS */
+ freeaddrinfo(iaip);
+ }
+
+#ifndef USE_RFC2292BIS
+ if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE))
+ errx(1, "can't set the last flag");
+#endif
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+
+ if (tclass != -2) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_TCLASS;
+ *(int *)(CMSG_DATA(scmsgp)) = tclass;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+ if (use_sendmsg != 0) {
+ if (so_traffic_class != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = SOL_SOCKET;
+ scmsgp->cmsg_type = SO_TRAFFIC_CLASS;
+ *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+ if (net_service_type != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = SOL_SOCKET;
+ scmsgp->cmsg_type = SO_NET_SERVICE_TYPE;
+ *(int *)(CMSG_DATA(scmsgp)) = net_service_type;
+ }
+ }
+ if (!(options & F_SRCADDR)) {
+ /*
+ * get the source address. XXX since we revoked the root
+ * privilege, we cannot use a raw socket for this.
+ */
+ int dummy;
+ socklen_t len = sizeof(src);
+
+ if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "UDP socket");
+
+ if (ifscope != 0) {
+ if (setsockopt(dummy, IPPROTO_IPV6, IPV6_BOUND_IF,
+ (char *)&ifscope, sizeof (ifscope)) != 0)
+ err(1, "setsockopt(IPV6_BOUND_IF)");
+ }
+
+ if (nocell != 0) {
+ if (setsockopt(dummy, IPPROTO_IPV6, IPV6_NO_IFT_CELLULAR,
+ (char *)&nocell, sizeof (nocell)) != 0)
+ err(1, "setsockopt(IPV6_NO_IFT_CELLULAR)");
+ }
+
+ src.sin6_family = AF_INET6;
+ src.sin6_addr = dst.sin6_addr;
+ src.sin6_port = ntohs(DUMMY_PORT);
+ src.sin6_scope_id = dst.sin6_scope_id;
+
+#ifdef USE_RFC2292BIS
+ if (pktinfo &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void *)pktinfo, sizeof(*pktinfo)))
+ err(1, "UDP setsockopt(IPV6_PKTINFO)");
+
+ if (hoplimit != -1 &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ (void *)&hoplimit, sizeof(hoplimit)))
+ err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");
+
+ if (hoplimit != -1 &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ (void *)&hoplimit, sizeof(hoplimit)))
+ err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");
+
+ if (rthdr &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR,
+ (void *)rthdr, (rthdr->ip6r_len + 1) << 3))
+ err(1, "UDP setsockopt(IPV6_RTHDR)");
+#else /* old advanced API */
+ if (smsghdr.msg_control &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS,
+ (void *)smsghdr.msg_control, smsghdr.msg_controllen))
+ err(1, "UDP setsockopt(IPV6_PKTOPTIONS)");
+#endif
+
+ if (connect(dummy, (struct sockaddr *)&src, len) < 0)
+ err(1, "UDP connect");
+
+ if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0)
+ err(1, "getsockname");
+
+ close(dummy);
+ }
+
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ if (sockbufsize) {
+ if (MAX(datalen, sweepmax) > sockbufsize)
+ warnx("you need -b to increase socket buffer size");
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
+ sizeof(sockbufsize)) < 0)
+ err(1, "setsockopt(SO_SNDBUF)");
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
+ sizeof(sockbufsize)) < 0)
+ err(1, "setsockopt(SO_RCVBUF)");
+ }
+ else {
+ if (MAX(datalen, sweepmax) > 8 * 1024) /*XXX*/
+ warnx("you need -b to increase socket buffer size");
+ /*
+ * When pinging the broadcast address, you can get a lot of
+ * answers. Doing something so evil is useful if you are trying
+ * to stress the ethernet, or just want to fill the arp cache
+ * to get some stuff for /etc/ethers.
+ */
+ hold = 48 * 1024;
+ setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
+ sizeof(hold));
+ }
+#endif
+
+ optval = 1;
+#ifndef USE_SIN6_SCOPE_ID
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */
+#endif
+#endif /* USE_SIN6_SCOPE_ID */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_HOPLIMIT, %d, %lu)",
+ optval, sizeof(optval)); /* XXX err? */
+#endif
+
+ if (sweepmax)
+ printf("PING6(40+8+[%lu...%lu] bytes) ",
+ (unsigned long)(sweepmin),
+ (unsigned long)(sweepmax));
+ else
+ printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
+ (unsigned long)(pingerlen() - 8));
+ printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
+ printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
+
+ if (preload == 0)
+ pinger();
+ else {
+ if (npackets != 0 && preload > npackets)
+ preload = npackets;
+ while (preload--)
+ pinger();
+ }
+ gettimeofday(&last, NULL);
+
+ /*
+ * rdar://25829310
+ *
+ * Clear blocked signals inherited from the parent
+ */
+ sigset_t newset;
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+
+ seenalrm = seenint = 0;
+#ifdef SIGINFO
+ seeninfo = 0;
+#endif
+
+ (void)signal(SIGINT, onsignal);
+#ifdef SIGINFO
+ (void)signal(SIGINFO, onsignal);
+#endif
+ if (alarmtimeout > 0) {
+ (void)signal(SIGALRM, onsignal);
+ }
+
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else if ((options & F_INTERVAL) == 0) {
+ intvl.tv_sec = interval / 1000;
+ intvl.tv_usec = interval % 1000 * 1000;
+ }
+
+ /* For control (ancillary) data received from recvmsg() */
+ cm = (struct cmsghdr *)malloc(CONTROLLEN);
+ if (cm == NULL)
+ err(1, "malloc");
+
+ almost_done = 0;
+ while (seenint == 0) {
+ struct timeval now, timeout;
+ struct msghdr m;
+ struct iovec iov[2];
+ fd_set rfds;
+ int n;
+
+ /* signal handling */
+ if (seenint)
+ onint(SIGINT);
+#ifdef SIGINFO
+ if (seeninfo) {
+ summary();
+ seeninfo = 0;
+ continue;
+ }
+#endif
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+ timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+ while (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
+ }
+ while (timeout.tv_usec > 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ if (n < 0)
+ continue; /* EINTR */
+ if (n == 1) {
+ m.msg_name = (caddr_t)&from;
+ m.msg_namelen = sizeof(from);
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = (caddr_t)packet;
+ iov[0].iov_len = packlen;
+ m.msg_iov = iov;
+ m.msg_iovlen = 1;
+ memset(cm, 0, CONTROLLEN);
+ m.msg_control = (void *)cm;
+ m.msg_controllen = CONTROLLEN;
+ m.msg_flags = 0;
+
+ cc = recvmsg(s, &m, 0);
+ if (cc < 0) {
+ if (errno != EINTR) {
+ warn("recvmsg");
+ sleep(1);
+ }
+ continue;
+ } else if (cc == 0) {
+ int mtu;
+
+ /*
+ * receive control messages only. Process the
+ * exceptions (currently the only possibility is
+ * a path MTU notification.)
+ */
+ if ((mtu = get_pathmtu(&m)) > 0) {
+ if ((options & F_VERBOSE) != 0) {
+ printf("new path MTU (%d) is "
+ "notified\n", mtu);
+ }
+ }
+ continue;
+ } else {
+ /*
+ * an ICMPv6 message (probably an echoreply)
+ * arrived.
+ */
+ pr_pack(packet, cc, &m);
+ }
+ if (((options & F_ONCE) != 0 && nreceived > 0) ||
+ (npackets > 0 && nreceived >= npackets) ||
+ (sweepmax && datalen > sweepmax))
+ break;
+ }
+ if (n == 0 || (options & F_FLOOD)) {
+ if (npackets == 0 || ntransmitted < npackets)
+ pinger();
+ else {
+ if (almost_done)
+ break;
+ almost_done = 1;
+ /*
+ * If we're not transmitting any more packets,
+ * change the timer to wait two round-trip times
+ * if we've received any packets or (waittime)
+ * milliseconds if we haven't.
+ */
+ intvl.tv_usec = 0;
+ if (nreceived) {
+ intvl.tv_sec = 2 * tmax / 1000;
+ if (intvl.tv_sec == 0)
+ intvl.tv_sec = 1;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
+ }
+ }
+ gettimeofday(&last, NULL);
+ if (ntransmitted - nreceived - 1 > nmissedmax) {
+ nmissedmax = ntransmitted - nreceived - 1;
+ if (options & F_MISSED)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ }
+ }
+ }
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+ summary();
+
+ if (packet != NULL)
+ free(packet);
+
+ exit(nreceived == 0 ? 2 : 0);
+}
+
+void
+onsignal(int sig)
+{
+ fflush(stdout);
+
+ switch (sig) {
+ case SIGINT:
+ case SIGALRM:
+ seenint++;
+ break;
+#ifdef SIGINFO
+ case SIGINFO:
+ seeninfo++;
+ break;
+#endif
+ }
+}
+
+/*
+ * pinger --
+ * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
+ * will be added on by the kernel. The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer. The first 8 bytes
+ * of the data portion are used to hold a UNIX "timeval" struct in VAX
+ * byte-order, to compute the round-trip time.
+ */
+size_t
+pingerlen(void)
+{
+ size_t l;
+
+ if (options & F_FQDN)
+ l = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ else if (options & F_FQDNOLD)
+ l = ICMP6_NIQLEN;
+ else if (options & F_NODEADDR)
+ l = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ else if (options & F_SUPTYPES)
+ l = ICMP6_NIQLEN;
+ else
+ l = ICMP6ECHOLEN + datalen;
+
+ return l;
+}
+
+int
+pinger(void)
+{
+ struct icmp6_hdr *icp;
+ int i, cc;
+ struct icmp6_nodeinfo *nip;
+ int seq;
+
+ if (npackets && ntransmitted >= npackets)
+ return(-1); /* no more transmission */
+
+ if (sweepmax && sntransmitted == snpackets) {
+ datalen += sweepincr;
+ if (datalen > sweepmax)
+ return(-1); /* no more transmission */
+ sntransmitted = 0;
+ }
+
+ icp = (struct icmp6_hdr *)outpack;
+ nip = (struct icmp6_nodeinfo *)outpack;
+ memset(icp, 0, sizeof(*icp));
+ icp->icmp6_cksum = 0;
+ seq = ntransmitted++;
+ CLR(seq % mx_dup_ck);
+
+ if (options & F_FQDN) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
+ nip->ni_qtype = htons(NI_QTYPE_FQDN);
+ nip->ni_flags = htons(0);
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
+ memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
+ sizeof(dst.sin6_addr));
+ cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ datalen = 0;
+ } else if (options & F_FQDNOLD) {
+ /* packet format in 03 draft - no Subject data on queries */
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = 0; /* code field is always 0 */
+ nip->ni_qtype = htons(NI_QTYPE_FQDN);
+ nip->ni_flags = htons(0);
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
+ cc = ICMP6_NIQLEN;
+ datalen = 0;
+ } else if (options & F_NODEADDR) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
+ nip->ni_qtype = htons(NI_QTYPE_NODEADDR);
+ nip->ni_flags = naflags;
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
+ memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
+ sizeof(dst.sin6_addr));
+ cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ datalen = 0;
+ } else if (options & F_SUPTYPES) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/
+ nip->ni_qtype = htons(NI_QTYPE_SUPTYPES);
+ /* we support compressed bitmap */
+ nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS;
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+ cc = ICMP6_NIQLEN;
+ datalen = 0;
+ } else {
+ icp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icp->icmp6_code = 0;
+ icp->icmp6_id = htons(ident);
+ icp->icmp6_seq = ntohs(seq);
+ if (timing) {
+ struct timeval tv;
+ struct tv32 *tv32;
+ (void)gettimeofday(&tv, NULL);
+ tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN];
+ tv32->tv32_sec = htonl(tv.tv_sec);
+ tv32->tv32_usec = htonl(tv.tv_usec);
+ }
+ cc = ICMP6ECHOLEN + datalen;
+ }
+
+#ifdef DIAGNOSTIC
+ if (pingerlen() != cc)
+ errx(1, "internal error; length mismatch");
+#endif
+
+ if ((options & F_CONNECT)) {
+ smsghdr.msg_name = NULL;
+ smsghdr.msg_namelen = 0;
+ } else {
+ smsghdr.msg_name = (caddr_t)&dst;
+ smsghdr.msg_namelen = sizeof(dst);
+ }
+ memset(&smsgiov, 0, sizeof(smsgiov));
+ smsgiov[0].iov_base = (caddr_t)outpack;
+ smsgiov[0].iov_len = cc;
+ smsghdr.msg_iov = smsgiov;
+ smsghdr.msg_iovlen = 1;
+
+ i = sendmsg(s, &smsghdr, 0);
+
+ if (i < 0 || i != cc) {
+ if (i < 0)
+ warn("sendmsg");
+ (void)printf("ping6: wrote %s %d chars, ret=%d\n",
+ hostname, cc, i);
+ }
+ sntransmitted++;
+ if (!(options & F_QUIET) && options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &DOT, 1);
+
+ return(0);
+}
+
+int
+myechoreply(const struct icmp6_hdr *icp)
+{
+ if (ntohs(icp->icmp6_id) == ident)
+ return 1;
+ else
+ return 0;
+}
+
+int
+mynireply(const struct icmp6_nodeinfo *nip)
+{
+ if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
+ nonce + sizeof(u_int16_t),
+ sizeof(nonce) - sizeof(u_int16_t)) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+char *
+dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
+ size_t bufsiz)
+ /*base for compressed name*/
+{
+ int i = 0;
+ const u_char *cp;
+ char cresult[NS_MAXDNAME + 1];
+ const u_char *comp;
+ int l;
+
+ cp = *sp;
+ *buf = '\0';
+
+ if (cp >= ep)
+ return NULL;
+ while (cp < ep) {
+ i = *cp;
+ if (i == 0 || cp != *sp) {
+ if (strlcat((char *)buf, ".", bufsiz) >= bufsiz)
+ return NULL; /*result overrun*/
+ }
+ if (i == 0)
+ break;
+ cp++;
+
+ if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) {
+ /* DNS compression */
+ if (!base)
+ return NULL;
+
+ comp = base + (i & 0x3f);
+ if (dnsdecode(&comp, cp, base, cresult,
+ sizeof(cresult)) == NULL)
+ return NULL;
+ if (strlcat(buf, cresult, bufsiz) >= bufsiz)
+ return NULL; /*result overrun*/
+ break;
+ } else if ((i & 0x3f) == i) {
+ if (i > ep - cp)
+ return NULL; /*source overrun*/
+ while (i-- > 0 && cp < ep) {
+ l = snprintf(cresult, sizeof(cresult),
+ isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
+ if (l >= sizeof(cresult) || l < 0)
+ return NULL;
+ if (strlcat(buf, cresult, bufsiz) >= bufsiz)
+ return NULL; /*result overrun*/
+ cp++;
+ }
+ } else
+ return NULL; /*invalid label*/
+ }
+ if (i != 0)
+ return NULL; /*not terminated*/
+ cp++;
+ *sp = cp;
+ return buf;
+}
+
+/*
+ * pr_pack --
+ * Print out the packet, if it came from us. This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair). This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+void
+pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
+{
+#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
+ struct icmp6_hdr *icp;
+ struct icmp6_nodeinfo *ni;
+ int i;
+ int hoplim;
+ struct sockaddr *from;
+ int fromlen;
+ u_char *cp = NULL, *dp, *end = buf + cc;
+ struct in6_pktinfo *pktinfo = NULL;
+ struct timeval tv, tp;
+ struct tv32 *tpp;
+ double triptime = 0;
+ int dupflag;
+ size_t off;
+ int oldfqdn;
+ u_int16_t seq;
+ char dnsname[NS_MAXDNAME + 1];
+ int tclass = 0;
+ int sotc = -1;
+
+ (void)gettimeofday(&tv, NULL);
+
+ if (!mhdr || !mhdr->msg_name ||
+ mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||
+ ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) {
+ if (options & F_VERBOSE)
+ warnx("invalid peername");
+ return;
+ }
+ from = (struct sockaddr *)mhdr->msg_name;
+ fromlen = mhdr->msg_namelen;
+ if (cc < sizeof(struct icmp6_hdr)) {
+ if (options & F_VERBOSE)
+ warnx("packet too short (%d bytes) from %s", cc,
+ pr_addr(from, fromlen));
+ return;
+ }
+ if (((mhdr->msg_flags & MSG_CTRUNC) != 0) &&
+ (options & F_VERBOSE) != 0)
+ warnx("some control data discarded, insufficient buffer size");
+ icp = (struct icmp6_hdr *)buf;
+ ni = (struct icmp6_nodeinfo *)buf;
+ off = 0;
+
+ if ((hoplim = get_hoplim(mhdr)) == -1) {
+ warnx("failed to get receiving hop limit");
+ return;
+ }
+ if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) {
+ warnx("failed to get receiving packet information");
+ return;
+ }
+ if (rcvtclass && (tclass = get_tclass(mhdr)) == -1) {
+ warnx("failed to get receiving traffic class");
+ return;
+ }
+
+ if (use_recvmsg > 0)
+ sotc = get_so_traffic_class(mhdr);
+
+ if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) {
+ seq = ntohs(icp->icmp6_seq);
+ ++nreceived;
+ if (timing) {
+ tpp = (struct tv32 *)(icp + 1);
+ tp.tv_sec = ntohl(tpp->tv32_sec);
+ tp.tv_usec = ntohl(tpp->tv32_usec);
+ tvsub(&tv, &tp);
+ triptime = ((double)tv.tv_sec) * 1000.0 +
+ ((double)tv.tv_usec) / 1000.0;
+ tsum += triptime;
+ tsumsq += triptime * triptime;
+ if (triptime < tmin)
+ tmin = triptime;
+ if (triptime > tmax)
+ tmax = triptime;
+ }
+
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
+ if (options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &BSPACE, 1);
+ else {
+ if (options & F_AUDIBLE)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s, icmp_seq=%u", cc,
+ pr_addr(from, fromlen), seq);
+ (void)printf(" hlim=%d", hoplim);
+ if ((options & F_VERBOSE) != 0) {
+ struct sockaddr_in6 dstsa;
+
+ memset(&dstsa, 0, sizeof(dstsa));
+ dstsa.sin6_family = AF_INET6;
+ dstsa.sin6_len = sizeof(dstsa);
+ dstsa.sin6_scope_id = pktinfo->ipi6_ifindex;
+ dstsa.sin6_addr = pktinfo->ipi6_addr;
+ (void)printf(" dst=%s",
+ pr_addr((struct sockaddr *)&dstsa,
+ sizeof(dstsa)));
+ }
+ if (timing)
+ (void)printf(" time=%.3f ms", triptime);
+ if (dupflag) {
+ if (!IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
+ (void)printf("(DUP!)");
+ }
+ if (rcvtclass)
+ (void)printf(" tclass=%d", tclass);
+ if (sotc != -1)
+ (void)printf(" sotc=%d", sotc);
+ /* check the data */
+ cp = buf + off + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
+ dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
+ for (i = 8; cp < end; ++i, ++cp, ++dp) {
+ if (*cp != *dp) {
+ (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp);
+ break;
+ }
+ }
+ }
+ } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) {
+ seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce);
+ ++nreceived;
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
+
+ switch (ntohs(ni->ni_code)) {
+ case ICMP6_NI_SUCCESS:
+ break;
+ case ICMP6_NI_REFUSED:
+ printf("refused, type 0x%x", ntohs(ni->ni_type));
+ goto fqdnend;
+ case ICMP6_NI_UNKNOWN:
+ printf("unknown, type 0x%x", ntohs(ni->ni_type));
+ goto fqdnend;
+ default:
+ printf("unknown code 0x%x, type 0x%x",
+ ntohs(ni->ni_code), ntohs(ni->ni_type));
+ goto fqdnend;
+ }
+
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ printf("NodeInfo NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ pr_suptypes(ni, end - (u_char *)ni);
+ break;
+ case NI_QTYPE_NODEADDR:
+ pr_nodeaddr(ni, end - (u_char *)ni);
+ break;
+ case NI_QTYPE_FQDN:
+ default: /* XXX: for backward compatibility */
+ cp = (u_char *)ni + ICMP6_NIRLEN;
+ if (buf[off + ICMP6_NIRLEN] ==
+ cc - off - ICMP6_NIRLEN - 1)
+ oldfqdn = 1;
+ else
+ oldfqdn = 0;
+ if (oldfqdn) {
+ cp++; /* skip length */
+ while (cp < end) {
+ safeputc(*cp & 0xff);
+ cp++;
+ }
+ } else {
+ i = 0;
+ while (cp < end) {
+ if (dnsdecode((const u_char **)&cp, end,
+ (const u_char *)(ni + 1), dnsname,
+ sizeof(dnsname)) == NULL) {
+ printf("???");
+ break;
+ }
+ /*
+ * name-lookup special handling for
+ * truncated name
+ */
+ if (cp + 1 <= end && !*cp &&
+ strlen(dnsname) > 0) {
+ dnsname[strlen(dnsname) - 1] = '\0';
+ cp++;
+ }
+ printf("%s%s", i > 0 ? "," : "",
+ dnsname);
+ }
+ }
+ if (options & F_VERBOSE) {
+ int32_t ttl;
+ int comma = 0;
+
+ (void)printf(" ("); /*)*/
+
+ switch (ni->ni_code) {
+ case ICMP6_NI_REFUSED:
+ (void)printf("refused");
+ comma++;
+ break;
+ case ICMP6_NI_UNKNOWN:
+ (void)printf("unknown qtype");
+ comma++;
+ break;
+ }
+
+ if ((end - (u_char *)ni) < ICMP6_NIRLEN) {
+ /* case of refusion, unknown */
+ /*(*/
+ putchar(')');
+ goto fqdnend;
+ }
+ ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]);
+ if (comma)
+ printf(",");
+ if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) {
+ (void)printf("TTL=%d:meaningless",
+ (int)ttl);
+ } else {
+ if (ttl < 0) {
+ (void)printf("TTL=%d:invalid",
+ ttl);
+ } else
+ (void)printf("TTL=%d", ttl);
+ }
+ comma++;
+
+ if (oldfqdn) {
+ if (comma)
+ printf(",");
+ printf("03 draft");
+ comma++;
+ } else {
+ cp = (u_char *)ni + ICMP6_NIRLEN;
+ if (cp == end) {
+ if (comma)
+ printf(",");
+ printf("no name");
+ comma++;
+ }
+ }
+
+ if (buf[off + ICMP6_NIRLEN] !=
+ cc - off - ICMP6_NIRLEN - 1 && oldfqdn) {
+ if (comma)
+ printf(",");
+ (void)printf("invalid namelen:%d/%lu",
+ buf[off + ICMP6_NIRLEN],
+ (u_long)cc - off - ICMP6_NIRLEN - 1);
+ comma++;
+ }
+ /*(*/
+ putchar(')');
+ }
+ fqdnend:
+ ;
+ }
+ } else {
+ /* We've got something other than an ECHOREPLY */
+ if (!(options & F_VERBOSE))
+ return;
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
+ pr_icmph(icp, end);
+ }
+
+ if (!(options & F_FLOOD)) {
+ (void)putchar('\n');
+ if (options & F_VERBOSE)
+ pr_exthdrs(mhdr);
+ (void)fflush(stdout);
+ }
+#undef safeputc
+}
+
+void
+pr_exthdrs(struct msghdr *mhdr)
+{
+ ssize_t bufsize;
+ void *bufp;
+ struct cmsghdr *cm;
+
+ bufsize = 0;
+ bufp = mhdr->msg_control;
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level != IPPROTO_IPV6)
+ continue;
+
+ bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp);
+ if (bufsize <= 0)
+ continue;
+ switch (cm->cmsg_type) {
+ case IPV6_HOPOPTS:
+ printf(" HbH Options: ");
+ pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize);
+ break;
+ case IPV6_DSTOPTS:
+#ifdef IPV6_RTHDRDSTOPTS
+ case IPV6_RTHDRDSTOPTS:
+#endif
+ printf(" Dst Options: ");
+ pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize);
+ break;
+ case IPV6_RTHDR:
+ printf(" Routing: ");
+ pr_rthdr(CMSG_DATA(cm), (size_t)bufsize);
+ break;
+ }
+ }
+}
+
+#ifdef USE_RFC2292BIS
+void
+pr_ip6opt(void *extbuf, size_t bufsize)
+{
+ struct ip6_hbh *ext;
+ int currentlen;
+ u_int8_t type;
+ socklen_t extlen, len;
+ void *databuf;
+ size_t offset;
+ u_int16_t value2;
+ u_int32_t value4;
+
+ ext = (struct ip6_hbh *)extbuf;
+ extlen = (ext->ip6h_len + 1) * 8;
+ printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt,
+ (unsigned int)ext->ip6h_len, (unsigned long)extlen);
+
+ /*
+ * Bounds checking on the ancillary data buffer:
+ * subtract the size of a cmsg structure from the buffer size.
+ */
+ if (bufsize < (extlen + CMSG_SPACE(0))) {
+ extlen = bufsize - CMSG_SPACE(0);
+ warnx("options truncated, showing only %u (total=%u)",
+ (unsigned int)(extlen / 8 - 1),
+ (unsigned int)(ext->ip6h_len));
+ }
+
+ currentlen = 0;
+ while (1) {
+ currentlen = inet6_opt_next(extbuf, extlen, currentlen,
+ &type, &len, &databuf);
+ if (currentlen == -1)
+ break;
+ switch (type) {
+ /*
+ * Note that inet6_opt_next automatically skips any padding
+ * optins.
+ */
+ case IP6OPT_JUMBO:
+ offset = 0;
+ (void) inet6_opt_get_val(databuf, offset,
+ &value4, sizeof(value4));
+ printf(" Jumbo Payload Opt: Length %u\n",
+ (u_int32_t)ntohl(value4));
+ break;
+ case IP6OPT_ROUTER_ALERT:
+ offset = 0;
+ (void)inet6_opt_get_val(databuf, offset,
+ &value2, sizeof(value2));
+ printf(" Router Alert Opt: Type %u\n",
+ ntohs(value2));
+ break;
+ default:
+ printf(" Received Opt %u len %lu\n",
+ type, (unsigned long)len);
+ break;
+ }
+ }
+ return;
+}
+#else /* !USE_RFC2292BIS */
+/* ARGSUSED */
+void
+pr_ip6opt(void *extbuf, size_t bufsize __unused)
+{
+ putchar('\n');
+ return;
+}
+#endif /* USE_RFC2292BIS */
+
+#ifdef USE_RFC2292BIS
+void
+pr_rthdr(void *extbuf, size_t bufsize)
+{
+ struct in6_addr *in6;
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;
+ int i, segments, origsegs, rthsize, size0, size1;
+
+ /* print fixed part of the header */
+ printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
+ rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
+ if ((segments = inet6_rth_segments(extbuf)) >= 0) {
+ printf("%d segments, ", segments);
+ printf("%d left\n", rh->ip6r_segleft);
+ } else {
+ printf("segments unknown, ");
+ printf("%d left\n", rh->ip6r_segleft);
+ return;
+ }
+
+ /*
+ * Bounds checking on the ancillary data buffer. When calculating
+ * the number of items to show keep in mind:
+ * - The size of the cmsg structure
+ * - The size of one segment (the size of a Type 0 routing header)
+ * - When dividing add a fudge factor of one in case the
+ * dividend is not evenly divisible by the divisor
+ */
+ rthsize = (rh->ip6r_len + 1) * 8;
+ if (bufsize < (rthsize + CMSG_SPACE(0))) {
+ origsegs = segments;
+ size0 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0);
+ size1 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 1);
+ segments -= (rthsize - (bufsize - CMSG_SPACE(0))) /
+ (size1 - size0) + 1;
+ warnx("segments truncated, showing only %d (total=%d)",
+ segments, origsegs);
+ }
+
+ for (i = 0; i < segments; i++) {
+ in6 = inet6_rth_getaddr(extbuf, i);
+ if (in6 == NULL)
+ printf(" [%d]<NULL>\n", i);
+ else {
+ if (!inet_ntop(AF_INET6, in6, ntopbuf,
+ sizeof(ntopbuf)))
+ strlcpy(ntopbuf, "?", sizeof(ntopbuf));
+ printf(" [%d]%s\n", i, ntopbuf);
+ }
+ }
+
+ return;
+
+}
+
+#else /* !USE_RFC2292BIS */
+/* ARGSUSED */
+void
+pr_rthdr(void *extbuf, size_t bufsize __unused)
+{
+ putchar('\n');
+ return;
+}
+#endif /* USE_RFC2292BIS */
+
+int
+pr_bitrange(u_int32_t v, int soff, int ii)
+{
+ int off;
+ int i;
+
+ off = 0;
+ while (off < 32) {
+ /* shift till we have 0x01 */
+ if ((v & 0x01) == 0) {
+ if (ii > 1)
+ printf("-%u", soff + off - 1);
+ ii = 0;
+ switch (v & 0x0f) {
+ case 0x00:
+ v >>= 4;
+ off += 4;
+ continue;
+ case 0x08:
+ v >>= 3;
+ off += 3;
+ continue;
+ case 0x04: case 0x0c:
+ v >>= 2;
+ off += 2;
+ continue;
+ default:
+ v >>= 1;
+ off += 1;
+ continue;
+ }
+ }
+
+ /* we have 0x01 with us */
+ for (i = 0; i < 32 - off; i++) {
+ if ((v & (0x01 << i)) == 0)
+ break;
+ }
+ if (!ii)
+ printf(" %u", soff + off);
+ ii += i;
+ v >>= i; off += i;
+ }
+ return ii;
+}
+
+void
+pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
+ /* ni->qtype must be SUPTYPES */
+{
+ size_t clen;
+ u_int32_t v;
+ const u_char *cp, *end;
+ u_int16_t cur;
+ struct cbit {
+ u_int16_t words; /*32bit count*/
+ u_int16_t skip;
+ } cbit = { 0, 0 };
+#define MAXQTYPES (1 << 16)
+ size_t off;
+ int b;
+
+ cp = (u_char *)(ni + 1);
+ end = ((u_char *)ni) + nilen;
+ cur = 0;
+ b = 0;
+
+ printf("NodeInfo Supported Qtypes");
+ if (options & F_VERBOSE) {
+ if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS)
+ printf(", compressed bitmap");
+ else
+ printf(", raw bitmap");
+ }
+
+ while (cp < end) {
+ clen = (size_t)(end - cp);
+ if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) {
+ if (clen == 0 || clen > MAXQTYPES / 8 ||
+ clen % sizeof(v)) {
+ printf("???");
+ return;
+ }
+ } else {
+ if (clen < sizeof(cbit) || clen % sizeof(v))
+ return;
+ memcpy(&cbit, cp, sizeof(cbit));
+ if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) >
+ clen)
+ return;
+ cp += sizeof(cbit);
+ clen = ntohs(cbit.words) * sizeof(v);
+ if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 >
+ MAXQTYPES)
+ return;
+ }
+
+ for (off = 0; off < clen; off += sizeof(v)) {
+ memcpy(&v, cp + off, sizeof(v));
+ v = (u_int32_t)ntohl(v);
+ b = pr_bitrange(v, (int)(cur + off * 8), b);
+ }
+ /* flush the remaining bits */
+ b = pr_bitrange(0, (int)(cur + off * 8), b);
+
+ cp += clen;
+ cur += clen * 8;
+ if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0)
+ cur += ntohs(cbit.skip) * 32;
+ }
+}
+
+void
+pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
+ /* ni->qtype must be NODEADDR */
+{
+ u_char *cp = (u_char *)(ni + 1);
+ char ntop_buf[INET6_ADDRSTRLEN];
+ int withttl = 0;
+
+ nilen -= sizeof(struct icmp6_nodeinfo);
+
+ if (options & F_VERBOSE) {
+ switch (ni->ni_code) {
+ case ICMP6_NI_REFUSED:
+ (void)printf("refused");
+ break;
+ case ICMP6_NI_UNKNOWN:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE)
+ (void)printf(" truncated");
+ }
+ putchar('\n');
+ if (nilen <= 0)
+ printf(" no address\n");
+
+ /*
+ * In icmp-name-lookups 05 and later, TTL of each returned address
+ * is contained in the resposne. We try to detect the version
+ * by the length of the data, but note that the detection algorithm
+ * is incomplete. We assume the latest draft by default.
+ */
+ if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0)
+ withttl = 1;
+ while (nilen > 0) {
+ u_int32_t ttl = 0;
+
+ if (withttl) {
+ /* XXX: alignment? */
+ ttl = (u_int32_t)ntohl(*(u_int32_t *)cp);
+ cp += sizeof(u_int32_t);
+ nilen -= sizeof(u_int32_t);
+ }
+
+ if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) ==
+ NULL)
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ printf(" %s", ntop_buf);
+ if (withttl) {
+ if (ttl == 0xffffffff) {
+ /*
+ * XXX: can this convention be applied to all
+ * type of TTL (i.e. non-ND TTL)?
+ */
+ printf("(TTL=infty)");
+ }
+ else
+ printf("(TTL=%u)", ttl);
+ }
+ putchar('\n');
+
+ nilen -= sizeof(struct in6_addr);
+ cp += sizeof(struct in6_addr);
+ }
+}
+
+int
+get_hoplim(struct msghdr *mhdr)
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(-1);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+struct in6_pktinfo *
+get_rcvpktinfo(struct msghdr *mhdr)
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(NULL);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
+ return((struct in6_pktinfo *)CMSG_DATA(cm));
+ }
+
+ return(NULL);
+}
+
+int
+get_pathmtu(struct msghdr *mhdr)
+{
+#ifdef IPV6_RECVPATHMTU
+ struct cmsghdr *cm;
+ struct ip6_mtuinfo *mtuctl = NULL;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(0);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PATHMTU &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) {
+ mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm);
+
+ /*
+ * If the notified destination is different from
+ * the one we are pinging, just ignore the info.
+ * We check the scope ID only when both notified value
+ * and our own value have non-0 values, because we may
+ * have used the default scope zone ID for sending,
+ * in which case the scope ID value is 0.
+ */
+ if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr,
+ &dst.sin6_addr) ||
+ (mtuctl->ip6m_addr.sin6_scope_id &&
+ dst.sin6_scope_id &&
+ mtuctl->ip6m_addr.sin6_scope_id !=
+ dst.sin6_scope_id)) {
+ if ((options & F_VERBOSE) != 0) {
+ printf("path MTU for %s is notified. "
+ "(ignored)\n",
+ pr_addr((struct sockaddr *)&mtuctl->ip6m_addr,
+ sizeof(mtuctl->ip6m_addr)));
+ }
+ return(0);
+ }
+
+ /*
+ * Ignore an invalid MTU. XXX: can we just believe
+ * the kernel check?
+ */
+ if (mtuctl->ip6m_mtu < IPV6_MMTU)
+ return(0);
+
+ /* notification for our destination. return the MTU. */
+ return((int)mtuctl->ip6m_mtu);
+ }
+ }
+#endif
+ return(0);
+}
+
+int
+get_tclass(mhdr)
+ struct msghdr *mhdr;
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(-1);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_TCLASS &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+int
+get_so_traffic_class(struct msghdr *mhdr)
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(-1);
+
+ if (cm->cmsg_level == SOL_SOCKET &&
+ cm->cmsg_type == SO_TRAFFIC_CLASS &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+/*
+ * tvsub --
+ * Subtract 2 timeval structs: out = out - in. Out is assumed to
+ * be >= in.
+ */
+void
+tvsub(struct timeval *out, struct timeval *in)
+{
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ --out->tv_sec;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * onint --
+ * SIGINT handler.
+ */
+/* ARGSUSED */
+void
+onint(int notused __unused)
+{
+ /*
+ * When doing reverse DNS lookups, the seenint flag might not
+ * be noticed for a while. Just exit if we get a second SIGINT.
+ */
+ if ((options & F_HOSTNAME) && seenint != 0)
+ _exit(nreceived ? 0 : 2);
+}
+
+/*
+ * summary --
+ * Print out statistics.
+ */
+void
+summary(void)
+{
+ (void)printf("\n--- %s ping6 statistics ---\n", hostname);
+ (void)printf("%ld packets transmitted, ", ntransmitted);
+ (void)printf("%ld packets received, ", nreceived);
+ if (nrepeats)
+ (void)printf("+%ld duplicates, ", nrepeats);
+ if (ntransmitted) {
+ if (nreceived > ntransmitted)
+ (void)printf("-- somebody's duplicating packets!");
+ else
+ (void)printf("%.1f%% packet loss",
+ ((((double)ntransmitted - nreceived) * 100.0) /
+ ntransmitted));
+ }
+ if (nrcvtimeout)
+ printf(", %ld packets out of wait time", nrcvtimeout);
+ (void)putchar('\n');
+ if (nreceived && timing) {
+ /* Only display average to microseconds */
+ double num = nreceived + nrepeats;
+ double avg = tsum / num;
+ double dev = sqrt(tsumsq / num - avg * avg);
+ (void)printf(
+ "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
+ tmin, avg, tmax, dev);
+ (void)fflush(stdout);
+ }
+ (void)fflush(stdout);
+}
+
+/*subject type*/
+static const char *niqcode[] = {
+ "IPv6 address",
+ "DNS label", /*or empty*/
+ "IPv4 address",
+};
+
+/*result code*/
+static const char *nircode[] = {
+ "Success", "Refused", "Unknown",
+};
+
+/*
+ * pr_icmph --
+ * Print a descriptive string about an ICMP header.
+ */
+void
+pr_icmph(struct icmp6_hdr *icp, u_char *end)
+{
+ char ntop_buf[INET6_ADDRSTRLEN];
+ struct nd_redirect *red;
+ struct icmp6_nodeinfo *ni;
+ char dnsname[NS_MAXDNAME + 1];
+ const u_char *cp;
+ size_t l;
+
+ switch (icp->icmp6_type) {
+ case ICMP6_DST_UNREACH:
+ switch (icp->icmp6_code) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ (void)printf("No Route to Destination\n");
+ break;
+ case ICMP6_DST_UNREACH_ADMIN:
+ (void)printf("Destination Administratively "
+ "Unreachable\n");
+ break;
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ (void)printf("Destination Unreachable Beyond Scope\n");
+ break;
+ case ICMP6_DST_UNREACH_ADDR:
+ (void)printf("Destination Host Unreachable\n");
+ break;
+ case ICMP6_DST_UNREACH_NOPORT:
+ (void)printf("Destination Port Unreachable\n");
+ break;
+ default:
+ (void)printf("Destination Unreachable, Bad Code: %d\n",
+ icp->icmp6_code);
+ break;
+ }
+ /* Print returned IP header information */
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ (void)printf("Packet too big mtu = %d\n",
+ (int)ntohl(icp->icmp6_mtu));
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ switch (icp->icmp6_code) {
+ case ICMP6_TIME_EXCEED_TRANSIT:
+ (void)printf("Time to live exceeded\n");
+ break;
+ case ICMP6_TIME_EXCEED_REASSEMBLY:
+ (void)printf("Frag reassembly time exceeded\n");
+ break;
+ default:
+ (void)printf("Time exceeded, Bad Code: %d\n",
+ icp->icmp6_code);
+ break;
+ }
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_PARAM_PROB:
+ (void)printf("Parameter problem: ");
+ switch (icp->icmp6_code) {
+ case ICMP6_PARAMPROB_HEADER:
+ (void)printf("Erroneous Header ");
+ break;
+ case ICMP6_PARAMPROB_NEXTHEADER:
+ (void)printf("Unknown Nextheader ");
+ break;
+ case ICMP6_PARAMPROB_OPTION:
+ (void)printf("Unrecognized Option ");
+ break;
+ default:
+ (void)printf("Bad code(%d) ", icp->icmp6_code);
+ break;
+ }
+ (void)printf("pointer = 0x%02x\n",
+ (u_int32_t)ntohl(icp->icmp6_pptr));
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_ECHO_REQUEST:
+ (void)printf("Echo Request");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP6_ECHO_REPLY:
+ (void)printf("Echo Reply");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP6_MEMBERSHIP_QUERY:
+ (void)printf("Listener Query");
+ break;
+ case ICMP6_MEMBERSHIP_REPORT:
+ (void)printf("Listener Report");
+ break;
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ (void)printf("Listener Done");
+ break;
+ case ND_ROUTER_SOLICIT:
+ (void)printf("Router Solicitation");
+ break;
+ case ND_ROUTER_ADVERT:
+ (void)printf("Router Advertisement");
+ break;
+ case ND_NEIGHBOR_SOLICIT:
+ (void)printf("Neighbor Solicitation");
+ break;
+ case ND_NEIGHBOR_ADVERT:
+ (void)printf("Neighbor Advertisement");
+ break;
+ case ND_REDIRECT:
+ red = (struct nd_redirect *)icp;
+ (void)printf("Redirect\n");
+ if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,
+ sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ (void)printf("Destination: %s", ntop_buf);
+ if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,
+ sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ (void)printf(" New Target: %s", ntop_buf);
+ break;
+ case ICMP6_NI_QUERY:
+ (void)printf("Node Information Query");
+ /* XXX ID + Seq + Data */
+ ni = (struct icmp6_nodeinfo *)icp;
+ l = end - (u_char *)(ni + 1);
+ printf(", ");
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ (void)printf("NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ (void)printf("Supported qtypes");
+ break;
+ case NI_QTYPE_FQDN:
+ (void)printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ (void)printf("nodeaddr");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ (void)printf("IPv4 nodeaddr");
+ break;
+ default:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (options & F_VERBOSE) {
+ switch (ni->ni_code) {
+ case ICMP6_NI_SUBJ_IPV6:
+ if (l == sizeof(struct in6_addr) &&
+ inet_ntop(AF_INET6, ni + 1, ntop_buf,
+ sizeof(ntop_buf)) != NULL) {
+ (void)printf(", subject=%s(%s)",
+ niqcode[ni->ni_code], ntop_buf);
+ } else {
+#if 1
+ /* backward compat to -W */
+ (void)printf(", oldfqdn");
+#else
+ (void)printf(", invalid");
+#endif
+ }
+ break;
+ case ICMP6_NI_SUBJ_FQDN:
+ if (end == (u_char *)(ni + 1)) {
+ (void)printf(", no subject");
+ break;
+ }
+ printf(", subject=%s", niqcode[ni->ni_code]);
+ cp = (const u_char *)(ni + 1);
+ if (dnsdecode(&cp, end, NULL, dnsname,
+ sizeof(dnsname)) != NULL)
+ printf("(%s)", dnsname);
+ else
+ printf("(invalid)");
+ break;
+ case ICMP6_NI_SUBJ_IPV4:
+ if (l == sizeof(struct in_addr) &&
+ inet_ntop(AF_INET, ni + 1, ntop_buf,
+ sizeof(ntop_buf)) != NULL) {
+ (void)printf(", subject=%s(%s)",
+ niqcode[ni->ni_code], ntop_buf);
+ } else
+ (void)printf(", invalid");
+ break;
+ default:
+ (void)printf(", invalid");
+ break;
+ }
+ }
+ break;
+ case ICMP6_NI_REPLY:
+ (void)printf("Node Information Reply");
+ /* XXX ID + Seq + Data */
+ ni = (struct icmp6_nodeinfo *)icp;
+ printf(", ");
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ (void)printf("NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ (void)printf("Supported qtypes");
+ break;
+ case NI_QTYPE_FQDN:
+ (void)printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ (void)printf("nodeaddr");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ (void)printf("IPv4 nodeaddr");
+ break;
+ default:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (options & F_VERBOSE) {
+ if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0]))
+ printf(", invalid");
+ else
+ printf(", %s", nircode[ni->ni_code]);
+ }
+ break;
+ default:
+ (void)printf("Bad ICMP type: %d", icp->icmp6_type);
+ }
+}
+
+/*
+ * pr_iph --
+ * Print an IP6 header.
+ */
+void
+pr_iph(struct ip6_hdr *ip6)
+{
+ u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
+ u_int8_t tc;
+ char ntop_buf[INET6_ADDRSTRLEN];
+
+ tc = *(&ip6->ip6_vfc + 1); /* XXX */
+ tc = (tc >> 4) & 0x0f;
+ tc |= (ip6->ip6_vfc << 4);
+
+ printf("Vr TC Flow Plen Nxt Hlim\n");
+ printf(" %1x %02x %05x %04x %02x %02x\n",
+ (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),
+ ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);
+ if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ printf("%s->", ntop_buf);
+ if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ printf("%s\n", ntop_buf);
+}
+
+/*
+ * pr_addr --
+ * Return an ascii host address as a dotted quad and optionally with
+ * a hostname.
+ */
+const char *
+pr_addr(struct sockaddr *addr, int addrlen)
+{
+ static char buf[NI_MAXHOST];
+ int flag = 0;
+
+ if ((options & F_HOSTNAME) == 0)
+ flag |= NI_NUMERICHOST;
+
+ if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)
+ return (buf);
+ else
+ return "?";
+}
+
+/*
+ * pr_retip --
+ * Dump some info on a returned (via ICMPv6) IPv6 packet.
+ */
+void
+pr_retip(struct ip6_hdr *ip6, u_char *end)
+{
+ u_char *cp = (u_char *)ip6, nh;
+ int hlen;
+
+ if (end - (u_char *)ip6 < sizeof(*ip6)) {
+ printf("IP6");
+ goto trunc;
+ }
+ pr_iph(ip6);
+ hlen = sizeof(*ip6);
+
+ nh = ip6->ip6_nxt;
+ cp += hlen;
+ while (end - cp >= 8) {
+ switch (nh) {
+ case IPPROTO_HOPOPTS:
+ printf("HBH ");
+ hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
+ nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
+ break;
+ case IPPROTO_DSTOPTS:
+ printf("DSTOPT ");
+ hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
+ nh = ((struct ip6_dest *)cp)->ip6d_nxt;
+ break;
+ case IPPROTO_FRAGMENT:
+ printf("FRAG ");
+ hlen = sizeof(struct ip6_frag);
+ nh = ((struct ip6_frag *)cp)->ip6f_nxt;
+ break;
+ case IPPROTO_ROUTING:
+ printf("RTHDR ");
+ hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
+ nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
+ break;
+#ifdef IPSEC
+ case IPPROTO_AH:
+ printf("AH ");
+ hlen = (((struct ah *)cp)->ah_len+2) << 2;
+ nh = ((struct ah *)cp)->ah_nxt;
+ break;
+#endif
+ case IPPROTO_ICMPV6:
+ printf("ICMP6: type = %d, code = %d\n",
+ *cp, *(cp + 1));
+ return;
+ case IPPROTO_ESP:
+ printf("ESP\n");
+ return;
+ case IPPROTO_TCP:
+ printf("TCP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)),
+ (*(cp + 2) * 256 + *(cp + 3)));
+ return;
+ case IPPROTO_UDP:
+ printf("UDP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)),
+ (*(cp + 2) * 256 + *(cp + 3)));
+ return;
+ default:
+ printf("Unknown Header(%d)\n", nh);
+ return;
+ }
+
+ if ((cp += hlen) >= end)
+ goto trunc;
+ }
+ if (end - cp < 8)
+ goto trunc;
+
+ putchar('\n');
+ return;
+
+ trunc:
+ printf("...\n");
+ return;
+}
+
+void
+fill(char *bp, char *patp)
+{
+ int ii, jj, kk;
+ int pat[16];
+ char *cp;
+
+ for (cp = patp; *cp; cp++)
+ if (!isxdigit(*cp))
+ errx(1, "patterns must be specified as hex digits");
+ ii = sscanf(patp,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
+ &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
+ &pat[13], &pat[14], &pat[15]);
+
+/* xxx */
+ if (ii > 0)
+ for (kk = 0;
+ kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
+ kk += ii)
+ for (jj = 0; jj < ii; ++jj)
+ bp[jj + kk] = pat[jj];
+ if (!(options & F_QUIET)) {
+ (void)printf("PATTERN: 0x");
+ for (jj = 0; jj < ii; ++jj)
+ (void)printf("%02x", bp[jj] & 0xFF);
+ (void)printf("\n");
+ }
+}
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+int
+setpolicy(int so __unused, char *policy)
+{
+ char *buf;
+
+ if (policy == NULL)
+ return 0; /* ignore */
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL)
+ errx(1, "%s", ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf,
+ ipsec_get_policylen(buf)) < 0)
+ warnx("Unable to set IPsec policy");
+ free(buf);
+
+ return 0;
+}
+#endif
+#endif
+
+char *
+nigroup(char *name, int nig_oldmcprefix)
+{
+ char *p;
+ char *q;
+ MD5_CTX ctxt;
+ u_int8_t digest[16];
+ u_int8_t c;
+ size_t l;
+ char hbuf[NI_MAXHOST];
+ struct in6_addr in6;
+ int valid;
+
+ p = strchr(name, '.');
+ if (!p)
+ p = name + strlen(name);
+ l = p - name;
+ if (l > 63 || l > sizeof(hbuf) - 1)
+ return NULL; /*label too long*/
+ strlcpy(hbuf, name, l);
+ hbuf[(int)l] = '\0';
+
+ for (q = name; *q; q++) {
+ if (isupper(*(unsigned char *)q))
+ *q = tolower(*(unsigned char *)q);
+ }
+
+ /* generate 16 bytes of pseudo-random value. */
+ memset(&ctxt, 0, sizeof(ctxt));
+ MD5Init(&ctxt);
+ c = l & 0xff;
+ MD5Update(&ctxt, &c, sizeof(c));
+ MD5Update(&ctxt, (unsigned char *)name, l);
+ MD5Final(digest, &ctxt);
+
+ if (nig_oldmcprefix) {
+ /* draft-ietf-ipngwg-icmp-name-lookup */
+ valid = inet_pton(AF_INET6, "ff02::2:0000:0000", &in6);
+ } else {
+ /* RFC 4620 */
+ valid = inet_pton(AF_INET6, "ff02::2:ff00:0000", &in6);
+ }
+ if (valid != 1)
+ return NULL; /*XXX*/
+
+ if (nig_oldmcprefix) {
+ /* draft-ietf-ipngwg-icmp-name-lookup */
+ bcopy(digest, &in6.s6_addr[12], 4);
+ } else {
+ /* RFC 4620 */
+ bcopy(digest, &in6.s6_addr[13], 3);
+ }
+
+ if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL)
+ return NULL;
+
+ return strdup(hbuf);
+}
+
+int
+str2sotc(const char *str, bool *valid)
+{
+ int sotc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK_SYS") == 0)
+ return SO_TC_BK_SYS;
+ else if (strcasecmp(str, "BK") == 0)
+ return SO_TC_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return SO_TC_BE;
+ else if (strcasecmp(str, "RD") == 0)
+ return SO_TC_RD;
+ else if (strcasecmp(str, "OAM") == 0)
+ return SO_TC_OAM;
+ else if (strcasecmp(str, "AV") == 0)
+ return SO_TC_AV;
+ else if (strcasecmp(str, "RV") == 0)
+ return SO_TC_RV;
+ else if (strcasecmp(str, "VI") == 0)
+ return SO_TC_VI;
+ else if (strcasecmp(str, "VO") == 0)
+ return SO_TC_VO;
+ else if (strcasecmp(str, "CTL") == 0)
+ return SO_TC_CTL;
+ else {
+ sotc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (sotc);
+}
+
+int
+str2netservicetype(const char *str, bool *valid)
+{
+ int svc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK") == 0)
+ return NET_SERVICE_TYPE_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return NET_SERVICE_TYPE_BE;
+ else if (strcasecmp(str, "VI") == 0)
+ return NET_SERVICE_TYPE_VI;
+ else if (strcasecmp(str, "SIG") == 0)
+ return NET_SERVICE_TYPE_SIG;
+ else if (strcasecmp(str, "VO") == 0)
+ return NET_SERVICE_TYPE_VO;
+ else if (strcasecmp(str, "RV") == 0)
+ return NET_SERVICE_TYPE_RV;
+ else if (strcasecmp(str, "AV") == 0)
+ return NET_SERVICE_TYPE_AV;
+ else if (strcasecmp(str, "OAM") == 0)
+ return NET_SERVICE_TYPE_OAM;
+ else if (strcasecmp(str, "RD") == 0)
+ return NET_SERVICE_TYPE_RD;
+ else {
+ svc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (svc);
+}
+
+u_int8_t
+str2tclass(const char *str, bool *valid)
+{
+ u_int8_t dscp = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "DF") == 0)
+ dscp = _DSCP_DF;
+ else if (strcasecmp(str, "EF") == 0)
+ dscp = _DSCP_EF;
+ else if (strcasecmp(str, "VA") == 0)
+ dscp = _DSCP_VA;
+
+ else if (strcasecmp(str, "CS0") == 0)
+ dscp = _DSCP_CS0;
+ else if (strcasecmp(str, "CS1") == 0)
+ dscp = _DSCP_CS1;
+ else if (strcasecmp(str, "CS2") == 0)
+ dscp = _DSCP_CS2;
+ else if (strcasecmp(str, "CS3") == 0)
+ dscp = _DSCP_CS3;
+ else if (strcasecmp(str, "CS4") == 0)
+ dscp = _DSCP_CS4;
+ else if (strcasecmp(str, "CS5") == 0)
+ dscp = _DSCP_CS5;
+ else if (strcasecmp(str, "CS6") == 0)
+ dscp = _DSCP_CS6;
+ else if (strcasecmp(str, "CS7") == 0)
+ dscp = _DSCP_CS7;
+
+ else if (strcasecmp(str, "AF11") == 0)
+ dscp = _DSCP_AF11;
+ else if (strcasecmp(str, "AF12") == 0)
+ dscp = _DSCP_AF12;
+ else if (strcasecmp(str, "AF13") == 0)
+ dscp = _DSCP_AF13;
+ else if (strcasecmp(str, "AF21") == 0)
+ dscp = _DSCP_AF21;
+ else if (strcasecmp(str, "AF22") == 0)
+ dscp = _DSCP_AF22;
+ else if (strcasecmp(str, "AF23") == 0)
+ dscp = _DSCP_AF23;
+ else if (strcasecmp(str, "AF31") == 0)
+ dscp = _DSCP_AF31;
+ else if (strcasecmp(str, "AF32") == 0)
+ dscp = _DSCP_AF32;
+ else if (strcasecmp(str, "AF33") == 0)
+ dscp = _DSCP_AF33;
+ else if (strcasecmp(str, "AF41") == 0)
+ dscp = _DSCP_AF41;
+ else if (strcasecmp(str, "AF42") == 0)
+ dscp = _DSCP_AF42;
+ else if (strcasecmp(str, "AF43") == 0)
+ dscp = _DSCP_AF43;
+
+ else {
+ unsigned long val = strtoul(str, &endptr, 0);
+ if (*endptr != '\0' || val > 255)
+ *valid = false;
+ else
+ return ((u_int8_t)val);
+ }
+ /* DSCP occupies the 6 upper bits of the traffic class field */
+ return (dscp << 2);
+}
+
+void
+pr_currenttime(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
+ "A"
+#endif
+ "usage: ping6 [-"
+ "Dd"
+#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
+ "E"
+#endif
+ "fH"
+#ifdef IPV6_USE_MIN_MTU
+ "m"
+#endif
+ "nNoqrRtvwW] "
+ "[-a addrtype] [-b bufsiz] [-c count]\n"
+ " [-g gateway] [-h hoplimit] [-I interface] [-i wait] [-l preload]"
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ " [-P policy]"
+#endif
+ "\n"
+ " [-p pattern] [-S sourceaddr] [-s packetsize] [-z tclass] "
+ "[-k traffic_class] [-K net_service_type] "
+ "[hops ...] host\n");
+ (void)fprintf(stderr, "Apple specific options (to be specified before hops or host like all options)\n");
+ (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n");
+ (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n");
+ (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n");
+ (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n");
+ (void)fprintf(stderr, " -apple-time # display current time\n");
+ (void)fprintf(stderr, " -apple-progress # show progress for debugging\n");
+ exit(1);
+}
diff --git a/network_cmds/pktapctl/pktapctl.8 b/network_cmds/pktapctl/pktapctl.8
new file mode 100644
index 0000000..5f11615
--- /dev/null
+++ b/network_cmds/pktapctl/pktapctl.8
@@ -0,0 +1,41 @@
+.Dd 9/28/12
+.Dt pktapctl 8
+.Os Darwin
+.Sh NAME
+.Nm pktapctl
+.Sh SYNOPSIS
+.Nm
+.Op Fl g
+.Op Fl h
+.Op Fl i Ar interface
+.Op Fl p Ar rule
+.Op Fl s Ar rule
+.Sh DESCRIPTION
+.Nm
+let you configure a pktap virtual interface.
+.Pp
+This is an experimental command whose syntax and functionalities may change in
+future releases.
+.Pp
+The options have the following meaning:
+.Bl -tag -width -indent
+.It Fl g
+Get the list of filter rules for the given
+.Ar interface.
+.It Fl h
+Display a quick help and exit.
+.It Fl p
+To add a pass interface filter rule.
+.It Fl s
+To add a skip interface filter rule.
+.El
+.Pp
+Here is the syntax of the interface filter rules:
+.Bl -tag -indent
+.It type number
+An interface type number or 0 for any interface type.
+.It name string
+To specify interface with name matching the given string.
+.El
+.Sh SEE ALSO
+.Xr tcpdump 1
diff --git a/network_cmds/pktapctl/pktapctl.c b/network_cmds/pktapctl/pktapctl.c
new file mode 100644
index 0000000..9bbe0ed
--- /dev/null
+++ b/network_cmds/pktapctl/pktapctl.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+#include <net/pktap.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *ifname = NULL;
+unsigned int ifindex = 0;
+int do_get = 0;
+int num_filter_entries = 0;
+struct pktap_filter set_filter[PKTAP_MAX_FILTERS];
+
+static const char *parameters_format = " %-24s %s\n";
+
+static void
+usage(const char *s)
+{
+ printf("# usage: %s -i <ifname> -g -p <filter_rule> -s <filter_rule> -h\n", s);
+ printf(" Get or set filtering rules on a pktap interface\n");
+ printf(" Options:\n");
+ printf(parameters_format, "-h", "display this help");
+ printf(parameters_format, "-i <ifname>", "name pktap interface");
+ printf(parameters_format, "-g", "get filter rules");
+ printf(parameters_format, "-p <filter_rule> param", "add a pass rule");
+ printf(parameters_format, "-s <filter_rule> param", "add a skip rule");
+ printf(" Format of <filter_rule> parameter:\n");
+ printf(parameters_format, "type <iftype>", "interfaces of given type");
+ printf(parameters_format, "", "use 0 for any interface type");
+ printf(parameters_format, "name <ifname>", "interface of given name");
+}
+
+static void
+print_filter_entry(struct pktap_filter *filter)
+{
+ printf("filter_op: %u filter_param %u ", filter->filter_op, filter->filter_param);
+ if (filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE)
+ printf("%u", filter->filter_param_if_type);
+ else if (filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME)
+ printf("%s", filter->filter_param_if_name);
+}
+
+int main(int argc, char * const argv[])
+{
+ int ch;
+ struct ifdrv ifdr;
+ int fd = -1;
+ int i;
+
+ //printf("sizeof(struct pktap_filter) %lu\n", sizeof(struct pktap_filter));
+ //printf("sizeof(pktap_filter) %lu\n", sizeof(set_filter));
+
+ while ((ch = getopt(argc, argv, "ghi:p:s:")) != -1) {
+ switch (ch) {
+ case 'g':
+ do_get++;
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ /* NOT REACHED */
+
+ case 'i':
+ ifname = optarg;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ err(1, "if_nametoindex(%s) failed", ifname);
+
+ break;
+
+ case 'p':
+ case 's': {
+ /* -p (type|name) <value> */
+ struct pktap_filter entry;
+
+ if (num_filter_entries >= PKTAP_MAX_FILTERS)
+ errx(1, "Too many filter entries, max is %u", PKTAP_MAX_FILTERS);
+ if (optind + 1 > argc)
+ errx(1, "-%c needs two arguments optind %d argc %d", ch, optind, argc);
+ if (ch == 'p')
+ entry.filter_op = PKTAP_FILTER_OP_PASS;
+ else
+ entry.filter_op = PKTAP_FILTER_OP_SKIP;
+ if (strcmp(optarg, "type") == 0) {
+ entry.filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
+ entry.filter_param_if_type = (uint32_t)strtoul(argv[optind], NULL, 0);
+ } else if (strcmp(optarg, "name") == 0) {
+ entry.filter_param = PKTAP_FILTER_PARAM_IF_NAME;
+ snprintf(entry.filter_param_if_name, sizeof(entry.filter_param_if_name), "%s", argv[optind]);
+ } else
+ errx(1, "syntax error -p %s", optarg);
+ printf("Addin entry: ");
+ print_filter_entry(&entry);
+ printf("\n");
+ set_filter[num_filter_entries] = entry;
+
+ num_filter_entries++;
+ optind++;
+ break;
+ }
+
+ case '?':
+ default:
+ err(1, "syntax error");
+ exit(0);
+ /* NOT REACHED */
+ }
+ }
+ if (ifname == NULL)
+ errx(1, "missing interface");
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd == -1)
+ err(1, "socket(PF_INET, SOCK_DGRAM, 0)");
+
+ if (num_filter_entries > 0) {
+ for (i = num_filter_entries; i < PKTAP_MAX_FILTERS; i++) {
+ struct pktap_filter *filter = set_filter + i;
+ filter->filter_op = PKTAP_FILTER_OP_NONE;
+ filter->filter_param = PKTAP_FILTER_PARAM_NONE;
+ }
+
+ snprintf(ifdr.ifd_name, sizeof(ifdr.ifd_name), "%s", ifname);
+ ifdr.ifd_cmd = PKTP_CMD_FILTER_SET;
+ ifdr.ifd_len = sizeof(set_filter);
+ ifdr.ifd_data = &set_filter[0];
+
+ if (ioctl(fd, SIOCSDRVSPEC, &ifdr) == -1)
+ err(1, "ioctl(SIOCSDRVSPEC)");
+
+ }
+
+ if (do_get) {
+ struct pktap_filter get_filter[PKTAP_MAX_FILTERS];
+
+ snprintf(ifdr.ifd_name, sizeof(ifdr.ifd_name), "%s", ifname);
+ ifdr.ifd_cmd = PKTP_CMD_FILTER_GET;
+ ifdr.ifd_len = sizeof(get_filter);
+ ifdr.ifd_data = &get_filter[0];
+
+ if (ioctl(fd, SIOCGDRVSPEC, &ifdr) == -1)
+ err(1, "ioctl(SIOCGDRVSPEC)");
+
+ for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
+ struct pktap_filter *filter = get_filter + i;
+
+ printf("[%d] ", i);
+ print_filter_entry(filter);
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
diff --git a/network_cmds/pktmnglr/packet_mangler.c b/network_cmds/pktmnglr/packet_mangler.c
new file mode 100644
index 0000000..cf94cd4
--- /dev/null
+++ b/network_cmds/pktmnglr/packet_mangler.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+//
+// Created by Prabhakar Lakhera on 06/23/14.
+//
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/errno.h>
+#include <sys/sys_domain.h>
+#include <sys/ioctl.h>
+#include <sys/kern_control.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sysexits.h>
+#include <net/packet_mangler.h>
+
+
+#define BUF_MAX 1000
+int doit();
+
+Pkt_Mnglr_Flow dir = INOUT;
+struct addrinfo * p_localaddr = NULL;
+struct addrinfo * p_remoteaddr = NULL;
+struct sockaddr_storage l_saddr = {0};
+struct sockaddr_storage r_saddr = {0};
+
+int sf = -1;
+uint32_t duration = 0;
+uint32_t protocol = 0;
+uint32_t proto_act_mask = 0;
+uint32_t ip_act_mask = 0;
+uint16_t local_port = 0;
+uint16_t remote_port = 0;
+uint8_t activate = 1;
+
+static const char *
+basename(const char * str)
+{
+ const char *last_slash = strrchr(str, '/');
+
+ if (last_slash == NULL)
+ return (str);
+ else
+ return (last_slash + 1);
+}
+
+struct option_desc {
+ const char *option;
+ const char *description;
+ int required;
+};
+
+struct option_desc option_desc_list[] = {
+ { "-h ", "Help", 0 },
+ { "-f flow", "flow direction to apply mangler on. Values can be: in/out/inout. default is inout", 0 },
+ { "-l IP address ", "Local IP we are interested in ", 0 },
+ { "-r IP address ", "Remote IP we are interested in", 0 },
+ { "-m IP action mask ", "IP action mask", 0 },
+ { "-t time", "Run duration for which packet mangler will run. A value of 0 means forever (till program is killed).", 0 },
+ { "-p IP Protocol ", "IP protocol i.e. one of tcp, udp, icmp, icmpv6", 0 },
+ { "-L Local port ", "Local port", 0 },
+ { "-R Remote port ", "Remote port", 0 },
+ { "-M Protocol action mask ", "Protocol action mask", 0 },
+ { NULL, NULL, 0 } /* Mark end of list */
+};
+
+
+static void
+usage(const char *cmd)
+{
+ struct option_desc *option_desc;
+ char * usage_str = (char *)malloc(BUF_MAX);
+ size_t usage_len;
+
+ if (usage_str == NULL)
+ err(1, "%s: malloc(%d)", __func__, BUF_MAX);
+
+ usage_len = snprintf(usage_str, BUF_MAX, "# usage: %s ", basename(cmd));
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ int len;
+
+ if (option_desc->required)
+ len = snprintf(usage_str + usage_len, BUF_MAX - usage_len, "%s ", option_desc->option);
+ else
+ len = snprintf(usage_str + usage_len, BUF_MAX - usage_len, "[%s] ", option_desc->option);
+ if (len < 0)
+ err(1, "%s: snprintf(", __func__);
+
+ usage_len += len;
+ if (usage_len > BUF_MAX)
+ break;
+ }
+ printf("%s\n", usage_str);
+ printf("options:\n");
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ printf(" %-20s # %s\n", option_desc->option, option_desc->description);
+ }
+
+}
+
+int
+main(int argc, char * const argv[]) {
+ int ch;
+ int error;
+
+ if (argc == 1) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ while ((ch = getopt(argc, argv, "hf:l:r:t:p:m:M:L:R:")) != -1) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'f': {
+ if (strcasecmp(optarg, "in") == 0) {
+ dir = IN;
+ } else if (strcasecmp(optarg, "out") == 0) {
+ dir = OUT;
+ } else if (strcasecmp(optarg, "inout") == 0) {
+ dir = INOUT;
+ } else {
+ usage(argv[0]);
+ errx(1, "syntax error");
+ }
+ }
+ break;
+ case 'l':
+ if ((error = getaddrinfo(optarg, NULL, NULL, &p_localaddr)))
+ errx(1, "getaddrinfo returned error: %s", gai_strerror(error));
+
+ break;
+ case 'r':
+ if ((error = getaddrinfo(optarg, NULL, NULL, &p_remoteaddr)))
+ errx(1, "getaddrinfo returned error: %s", gai_strerror(error));
+
+ break;
+ case 'm':
+ ip_act_mask = (uint32_t)atoi(optarg);
+ break;
+ case 't':
+ duration = (uint32_t)atoi(optarg);
+ break;
+ case 'p':
+ /* Only support tcp for now */
+ if (strcasecmp(optarg, "tcp") == 0) {
+ protocol = IPPROTO_TCP;
+ } else if (strcasecmp(optarg, "udp") == 0) {
+ protocol = IPPROTO_UDP;
+ errx(1, "Protocol not supported.");
+ } else if (strcasecmp(optarg, "icmp") == 0) {
+ protocol = IPPROTO_ICMP;
+ errx(1, "Protocol not supported.");
+ } else if (strcasecmp(optarg, "icmpv6") == 0) {
+ protocol = IPPROTO_ICMPV6;
+ errx(1, "Protocol not supported.");
+ } else {
+ errx(1, "Protocol not supported.");
+ }
+ break;
+
+ case 'L':
+ local_port = htons((uint16_t)atoi(optarg));
+ break;
+ case 'R':
+ remote_port = htons((uint16_t)atoi(optarg));
+ break;
+ case 'M':
+ proto_act_mask = (uint32_t)atoi(optarg);
+ break;
+
+ default:
+ warnx("# syntax error, unknow option '%d'", ch);
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ if (p_localaddr && p_remoteaddr) {
+ if (p_localaddr->ai_family!=p_remoteaddr->ai_family) {
+ errx(1, "The address families for local and remote address"
+ " when both present, must be equal");
+ }
+ }
+
+
+ doit();
+
+ return (0);
+}
+
+
+int
+doit()
+{
+ struct sockaddr_ctl addr;
+
+ sf = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (sf == -1) {
+ err(1, "socket()");
+ }
+
+ /* Connect the socket */
+ bzero(&addr, sizeof(addr));
+ addr.sc_len = sizeof(addr);
+ addr.sc_family = AF_SYSTEM;
+ addr.ss_sysaddr = AF_SYS_CONTROL;
+
+ {
+ struct ctl_info info;
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.ctl_name, PACKET_MANGLER_CONTROL_NAME, sizeof(info.ctl_name));
+ if (ioctl(sf, CTLIOCGINFO, &info)) {
+ perror("Could not get ID for kernel control.\n");
+ exit(-1);
+ }
+ addr.sc_id = info.ctl_id;
+ addr.sc_unit = 1;
+ }
+
+ if (connect(sf, (struct sockaddr *)&addr, sizeof(struct sockaddr_ctl)) == -1) {
+ err(1, "connect()");
+ }
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_DIRECTION,
+ &dir, sizeof(uint32_t)) == -1) {
+ err(1, "setsockopt could not set direction.");
+ }
+
+ /* Set the IP addresses for the flow */
+ if (p_localaddr) {
+ l_saddr = *((struct sockaddr_storage *)(p_localaddr->ai_addr));
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_LOCAL_IP,
+ &l_saddr, sizeof(struct sockaddr_storage)) == -1) {
+ err(1, "setsockopt could not set local address.");
+ }
+ freeaddrinfo(p_localaddr);
+ p_localaddr = NULL;
+ }
+
+ if (p_remoteaddr) {
+ r_saddr = *((struct sockaddr_storage *)(p_remoteaddr->ai_addr));
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_REMOTE_IP,
+ &r_saddr, sizeof(struct sockaddr_storage)) == -1) {
+ err(1, "setsockopt could not set remote address.");
+ }
+ freeaddrinfo(p_remoteaddr);
+ p_remoteaddr = NULL;
+ }
+
+ /* Set ports for the flow */
+ if (local_port && (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_LOCAL_PORT,
+ &local_port, sizeof(uint16_t)) == -1)) {
+ err(1, "setsockopt could not set local port.");
+
+ }
+
+ if (remote_port && (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_REMOTE_PORT,
+ &remote_port, sizeof(uint16_t)) == -1)) {
+ err(1, "setsockopt could not set remote port.");
+
+ }
+
+ if (protocol && setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_PROTOCOL,
+ &protocol, sizeof(uint32_t)) == -1) {
+ err(1, "setsockopt could not set protocol.");
+ }
+
+ if (proto_act_mask &&
+ (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_PROTO_ACT_MASK,
+ &proto_act_mask, sizeof(uint32_t))==-1)) {
+ err(1, "setsockopt could not set protocol action mask.");
+ }
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_ACTIVATE,
+ &activate, sizeof(uint8_t))== -1) {
+ err(1, "setsockopt could not activate packet mangler.");
+ }
+
+ if (!duration) {
+ pause();
+ } else {
+ sleep(duration);
+ }
+
+ close(sf);
+ return 0;
+}
diff --git a/network_cmds/rarpd.tproj/rarpd.8 b/network_cmds/rarpd.tproj/rarpd.8
new file mode 100644
index 0000000..39ecff6
--- /dev/null
+++ b/network_cmds/rarpd.tproj/rarpd.8
@@ -0,0 +1,92 @@
+.\"
+.\" Copyright (c) 1988-1990 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: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\" @(#) $Id: rarpd.8,v 1.1 1999/05/02 03:57:59 wsanchez Exp $
+.\"
+.Dd October 26, 1990
+.Dt RARPD 8
+.Sh NAME
+.Nm rarpd
+.Nd Reverse ARP Daemon
+.Sh SYNOPSIS
+.Nm rarpd
+.Op Fl adf
+.Op Ar interface
+.Sh DESCRIPTION
+.Nm Rarpd
+services Reverse ARP requests on the Ethernet connected to
+.Ar interface.
+Upon receiving a request,
+.Nm rarpd
+maps the target hardware address to an IP address via its name, which
+must be present in both the
+.Xr ethers 5
+and
+.Xr hosts 5
+databases.
+If a host does not exist in both databases, the translation cannot
+proceed and a reply will not be sent.
+.Pp
+Additionally, a request is honored only if the server
+(i.e., the host that rarpd is running on)
+can "boot" the target; that is, if the directory
+.Pa /tftpboot/ Ns Em ipaddr
+exists, where
+.Rm ipaddr
+is the target IP address.
+.Pp
+In normal operation,
+.Nm rarpd
+forks a copy of itself and runs in
+the background. Anomalies and errors are reported via
+.Xr syslog 3 .
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl a
+Listen on all the Ethernets attached to the system.
+If
+.Sq Fl a
+is omitted, an interface must be specified.
+.It Fl d
+Run in debug mode, with all the output to stderr.
+This option implies the
+.Fl f
+option.
+.It Fl f
+Run in the foreground.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/ethers
+.It Pa /etc/hosts
+.It Pa /tftpboot
+.El
+.Sh SEE ALSO
+.Xr bpf 4 ,
+.Rs
+.%R A Reverse Address Resolution Protocol
+.%N RFC 903
+.%A Finlayson, R.
+.%A Mann, T.
+.%A Mogul, J.C.
+.%A Theimer, M.
+.Re
+.Sh AUTHORS
+Craig Leres (leres@ee.lbl.gov) and Steven McCanne (mccanne@ee.lbl.gov).
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
diff --git a/network_cmds/rarpd.tproj/rarpd.c b/network_cmds/rarpd.tproj/rarpd.c
new file mode 100644
index 0000000..1a3ae51
--- /dev/null
+++ b/network_cmds/rarpd.tproj/rarpd.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 1999-2009 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1990 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * rarpd - Reverse ARP Daemon
+ *
+ * Usage: rarpd -a [ -d -f ]
+ * rarpd [ -d -f ] interface
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+
+#define FATAL 1 /* fatal error occurred */
+#define NONFATAL 0 /* non fatal error occurred */
+
+/*
+ * The structure for each interface.
+ */
+struct if_info {
+ int ii_fd; /* BPF file descriptor */
+ u_char ii_eaddr[6]; /* Ethernet address of this interface */
+ in_addr_t ii_ipaddr; /* IP address of this interface */
+ in_addr_t ii_netmask; /* subnet or net mask */
+ struct if_info *ii_next;
+};
+/*
+ * The list of all interfaces that are being listened to. rarp_loop()
+ * "selects" on the descriptors in this list.
+ */
+struct if_info *iflist;
+
+int rarp_open __P((char *));
+int rarp_bootable __P((in_addr_t));
+void init_one __P((char *));
+void init_all __P((void));
+void rarp_loop __P((void));
+void lookup_eaddr __P((char *, u_char *));
+void lookup_ipaddr __P((char *, in_addr_t *, in_addr_t *));
+void usage __P((void));
+void rarp_process __P((struct if_info *, u_char *));
+void rarp_reply __P((struct if_info *, struct ether_header *, in_addr_t));
+void update_arptab __P((u_char *, in_addr_t));
+void err __P((int, const char *,...));
+void debug __P((const char *,...));
+in_addr_t ipaddrtonetmask __P((in_addr_t));
+
+int aflag = 0; /* listen on "all" interfaces */
+int dflag = 0; /* print debugging messages */
+int fflag = 0; /* don't fork */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int op, pid, devnull, f;
+ char *ifname, *hostname, *name;
+
+ extern int optind, opterr;
+
+ if ((name = strrchr(argv[0], '/')) != NULL)
+ ++name;
+ else
+ name = argv[0];
+ if (*name == '-')
+ ++name;
+
+ /* All error reporting is done through syslogs. */
+ openlog(name, LOG_PID | LOG_CONS, LOG_DAEMON);
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "adf")) != EOF) {
+ switch (op) {
+ case 'a':
+ ++aflag;
+ break;
+
+ case 'd':
+ ++dflag;
+ break;
+
+ case 'f':
+ ++fflag;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ ifname = argv[optind++];
+ hostname = ifname ? argv[optind] : 0;
+ if ((aflag && ifname) || (!aflag && ifname == 0))
+ usage();
+
+ if (aflag)
+ init_all();
+ else
+ init_one(ifname);
+
+ if ((!fflag) && (!dflag)) {
+ pid = fork();
+ if (pid > 0)
+ /* Parent exits, leaving child in background. */
+ exit(0);
+ else
+ if (pid == -1) {
+ err(FATAL, "cannot fork");
+ /* NOTREACHED */
+ }
+ /* Fade into the background */
+ f = open("/dev/tty", O_RDWR);
+ if (f >= 0) {
+ if (ioctl(f, TIOCNOTTY, 0) < 0) {
+ err(FATAL, "TIOCNOTTY: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) close(f);
+ }
+ (void) chdir("/");
+ (void) setpgid(0, getpid());
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull >= 0) {
+ (void) dup2(devnull, 0);
+ (void) dup2(devnull, 1);
+ (void) dup2(devnull, 2);
+ if (devnull > 2)
+ (void) close(devnull);
+ }
+ }
+ rarp_loop();
+ /* NOTREACHED */
+ return 0;
+}
+/*
+ * Add 'ifname' to the interface list. Lookup its IP address and network
+ * mask and Ethernet address, and open a BPF file for it.
+ */
+void
+init_one(ifname)
+ char *ifname;
+{
+ struct if_info *p;
+
+ p = (struct if_info *)malloc(sizeof(*p));
+ if (p == 0) {
+ err(FATAL, "malloc: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ p->ii_next = iflist;
+ iflist = p;
+
+ p->ii_fd = rarp_open(ifname);
+ lookup_eaddr(ifname, p->ii_eaddr);
+ lookup_ipaddr(ifname, &p->ii_ipaddr, &p->ii_netmask);
+}
+/*
+ * Initialize all "candidate" interfaces that are in the system
+ * configuration list. A "candidate" is up, not loopback and not
+ * point to point.
+ */
+void
+init_all()
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int fd;
+ int i, len;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ err(FATAL, "init_all: SIOCGIFCONF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0; i < ifc.ifc_len;
+ i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
+ err(FATAL, "init_all: SIOCGIFFLAGS: %s",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ if ((ifr->ifr_flags &
+ (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP)
+ continue;
+ init_one(ifr->ifr_name);
+ }
+ (void) close(fd);
+}
+
+void
+usage()
+{
+ (void) fprintf(stderr, "usage: rarpd -a [ -d -f ]\n");
+ (void) fprintf(stderr, " rarpd [ -d -f ] interface\n");
+ exit(1);
+}
+
+static int
+bpf_open()
+{
+ int fd;
+ int n = 0;
+ char device[sizeof "/dev/bpf000"];
+
+ /* Go through all the minors and find one that isn't in use. */
+ do {
+ (void) snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+ fd = open(device, O_RDWR);
+ } while (fd < 0 && errno == EBUSY);
+
+ if (fd < 0) {
+ err(FATAL, "%s: %s", device, strerror(errno));
+ /* NOTREACHED */
+ }
+ return fd;
+}
+/*
+ * Open a BPF file and attach it to the interface named 'device'.
+ * Set immediate mode, and set a filter that accepts only RARP requests.
+ */
+int
+rarp_open(device)
+ char *device;
+{
+ int fd;
+ struct ifreq ifr;
+ u_int dlt;
+ int immediate;
+
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_REVARP, 0, 3),
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ARPOP_REVREQUEST, 0, 1),
+ BPF_STMT(BPF_RET | BPF_K, sizeof(struct ether_arp) +
+ sizeof(struct ether_header)),
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ };
+ static struct bpf_program filter = {
+ sizeof insns / sizeof(insns[0]),
+ insns
+ };
+
+ fd = bpf_open();
+
+ /* Set immediate mode so packets are processed as they arrive. */
+ immediate = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
+ err(FATAL, "BIOCIMMEDIATE: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
+ if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) {
+ err(FATAL, "BIOCSETIF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /* Check that the data link layer is an Ethernet; this code won't work
+ * with anything else. */
+ if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) {
+ err(FATAL, "BIOCGDLT: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ if (dlt != DLT_EN10MB) {
+ err(FATAL, "%s is not an ethernet", device);
+ /* NOTREACHED */
+ }
+ /* Set filter program. */
+ if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) {
+ err(FATAL, "BIOCSETF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ return fd;
+}
+/*
+ * Perform various sanity checks on the RARP request packet. Return
+ * false on failure and log the reason.
+ */
+static int
+rarp_check(p, len)
+ u_char *p;
+ int len;
+{
+ struct ether_header *ep = (struct ether_header *) p;
+ struct ether_arp *ap = (struct ether_arp *) (p + sizeof(*ep));
+
+ (void) debug("got a packet");
+
+ if (len < sizeof(*ep) + sizeof(*ap)) {
+ err(NONFATAL, "truncated request");
+ return 0;
+ }
+ /* XXX This test might be better off broken out... */
+ if (ntohs (ep->ether_type) != ETHERTYPE_REVARP ||
+ ntohs (ap->arp_hrd) != ARPHRD_ETHER ||
+ ntohs (ap->arp_op) != ARPOP_REVREQUEST ||
+ ntohs (ap->arp_pro) != ETHERTYPE_IP ||
+ ap->arp_hln != 6 || ap->arp_pln != 4) {
+ err(NONFATAL, "request fails sanity check");
+ return 0;
+ }
+ if (bcmp((char *) &ep->ether_shost, (char *) &ap->arp_sha, 6) != 0) {
+ err(NONFATAL, "ether/arp sender address mismatch");
+ return 0;
+ }
+ if (bcmp((char *) &ap->arp_sha, (char *) &ap->arp_tha, 6) != 0) {
+ err(NONFATAL, "ether/arp target address mismatch");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Loop indefinitely listening for RARP requests on the
+ * interfaces in 'iflist'.
+ */
+void
+rarp_loop()
+{
+ u_char *buf, *bp, *ep;
+ int cc, fd;
+ fd_set fds, listeners;
+ int bufsize, maxfd = 0;
+ struct if_info *ii;
+
+ if (iflist == 0) {
+ err(FATAL, "no interfaces");
+ /* NOTREACHED */
+ }
+ if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t) & bufsize) < 0) {
+ err(FATAL, "BIOCGBLEN: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ buf = (u_char *) malloc((unsigned) bufsize);
+ if (buf == 0) {
+ err(FATAL, "malloc: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /*
+ * Find the highest numbered file descriptor for select().
+ * Initialize the set of descriptors to listen to.
+ */
+ FD_ZERO(&fds);
+ for (ii = iflist; ii; ii = ii->ii_next) {
+ FD_SET(ii->ii_fd, &fds);
+ if (ii->ii_fd > maxfd)
+ maxfd = ii->ii_fd;
+ }
+ while (1) {
+ listeners = fds;
+ if (select(maxfd + 1, &listeners, (struct fd_set *) 0,
+ (struct fd_set *) 0, (struct timeval *) 0) < 0) {
+ err(FATAL, "select: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ for (ii = iflist; ii; ii = ii->ii_next) {
+ fd = ii->ii_fd;
+ if (!FD_ISSET(fd, &listeners))
+ continue;
+ again:
+ cc = read(fd, (char *) buf, bufsize);
+ /* Don't choke when we get ptraced */
+ if (cc < 0 && errno == EINTR)
+ goto again;
+ /* Due to a SunOS bug, after 2^31 bytes, the file
+ * offset overflows and read fails with EINVAL. The
+ * lseek() to 0 will fix things. */
+ if (cc < 0) {
+ if (errno == EINVAL &&
+ (lseek(fd, 0, SEEK_CUR) + bufsize) < 0) {
+ (void) lseek(fd, 0, 0);
+ goto again;
+ }
+ err(FATAL, "read: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /* Loop through the packet(s) */
+#define bhp ((struct bpf_hdr *)bp)
+ bp = buf;
+ ep = bp + cc;
+ while (bp < ep) {
+ register int caplen, hdrlen;
+
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+ if (rarp_check(bp + hdrlen, caplen))
+ rarp_process(ii, bp + hdrlen);
+ bp += BPF_WORDALIGN(hdrlen + caplen);
+ }
+ }
+ }
+}
+#ifndef TFTP_DIR
+#define TFTP_DIR "/tftpboot"
+#endif
+
+/*
+ * True if this server can boot the host whose IP address is 'addr'.
+ * This check is made by looking in the tftp directory for the
+ * configuration file.
+ */
+int
+rarp_bootable(addr)
+ in_addr_t addr;
+{
+ register struct dirent *dent;
+ register DIR *d;
+ char ipname[9];
+ static DIR *dd = 0;
+
+ (void) snprintf(ipname, sizeof(ipname), "%08X", addr);
+ /* If directory is already open, rewind it. Otherwise, open it. */
+ if ((d = dd) != NULL)
+ rewinddir(d);
+ else {
+ if (chdir(TFTP_DIR) == -1) {
+ err(FATAL, "chdir: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ d = opendir(".");
+ if (d == 0) {
+ err(FATAL, "opendir: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ dd = d;
+ }
+ while ((dent = readdir(d)) != NULL)
+ if (strncmp(dent->d_name, ipname, 8) == 0)
+ return 1;
+ return 0;
+}
+/*
+ * Given a list of IP addresses, 'alist', return the first address that
+ * is on network 'net'; 'netmask' is a mask indicating the network portion
+ * of the address.
+ */
+in_addr_t
+choose_ipaddr(alist, net, netmask)
+ in_addr_t **alist;
+ in_addr_t net;
+ in_addr_t netmask;
+{
+ for (; *alist; ++alist) {
+ if ((**alist & netmask) == net)
+ return **alist;
+ }
+ return 0;
+}
+/*
+ * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has
+ * already been checked for validity. The reply is overlaid on the request.
+ */
+void
+rarp_process(ii, pkt)
+ struct if_info *ii;
+ u_char *pkt;
+{
+ struct ether_header *ep;
+ struct hostent *hp;
+ in_addr_t target_ipaddr;
+ char ename[256];
+ struct in_addr in;
+
+ ep = (struct ether_header *) pkt;
+
+ if (ether_ntohost(ename, (struct ether_addr *)&ep->ether_shost) != 0 ||
+ (hp = gethostbyname(ename)) == 0)
+ return;
+
+ /* Choose correct address from list. */
+ if (hp->h_addrtype != AF_INET) {
+ err(FATAL, "cannot handle non IP addresses");
+ /* NOTREACHED */
+ }
+ target_ipaddr = choose_ipaddr((in_addr_t **) hp->h_addr_list,
+ ii->ii_ipaddr & ii->ii_netmask, ii->ii_netmask);
+
+ if (target_ipaddr == 0) {
+ in.s_addr = ii->ii_ipaddr & ii->ii_netmask;
+ err(NONFATAL, "cannot find %s on net %s\n",
+ ename, inet_ntoa(in));
+ return;
+ }
+ if (rarp_bootable(htonl(target_ipaddr)))
+ rarp_reply(ii, ep, target_ipaddr);
+}
+/*
+ * Lookup the ethernet address of the interface attached to the BPF
+ * file descriptor 'fd'; return it in 'eaddr'.
+ */
+void
+lookup_eaddr(ifname, eaddr)
+ char *ifname;
+ u_char *eaddr;
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct sockaddr_dl *sdl;
+ int fd;
+ int i, len;
+
+ /* We cannot use SIOCGIFADDR on the BPF descriptor.
+ We must instead get all the interfaces with SIOCGIFCONF
+ and find the right one. */
+
+ /* Use datagram socket to get Ethernet address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ err(FATAL, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0; i < ifc.ifc_len;
+ i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
+ if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
+ sdl->sdl_alen != 6)
+ continue;
+ if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) {
+ bcopy((caddr_t)LLADDR(sdl), (caddr_t)eaddr, 6);
+ if (dflag)
+ fprintf(stderr, "%s: %x:%x:%x:%x:%x:%x\n",
+ ifr->ifr_name, eaddr[0], eaddr[1],
+ eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
+ return;
+ }
+ }
+
+ err(FATAL, "lookup_eaddr: Never saw interface `%s'!", ifname);
+}
+/*
+ * Lookup the IP address and network mask of the interface named 'ifname'.
+ */
+void
+lookup_ipaddr(ifname, addrp, netmaskp)
+ char *ifname;
+ in_addr_t *addrp;
+ in_addr_t *netmaskp;
+{
+ int fd;
+ struct ifreq ifr;
+
+ /* Use datagram socket to get IP address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
+ if (ioctl(fd, SIOCGIFADDR, (char *) &ifr) < 0) {
+ err(FATAL, "SIOCGIFADDR: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ *addrp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
+ if (ioctl(fd, SIOCGIFNETMASK, (char *) &ifr) < 0) {
+ perror("SIOCGIFNETMASK");
+ exit(1);
+ }
+ *netmaskp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
+ /* If SIOCGIFNETMASK didn't work, figure out a mask from the IP
+ * address class. */
+ if (*netmaskp == 0)
+ *netmaskp = ipaddrtonetmask(*addrp);
+
+ (void) close(fd);
+}
+/*
+ * Poke the kernel arp tables with the ethernet/ip address combinataion
+ * given. When processing a reply, we must do this so that the booting
+ * host (i.e. the guy running rarpd), won't try to ARP for the hardware
+ * address of the guy being booted (he cannot answer the ARP).
+ */
+void
+update_arptab(ep, ipaddr)
+ u_char *ep;
+ in_addr_t ipaddr;
+{
+ //int s;
+ struct arpreq request;
+ struct sockaddr_in *sin;
+
+ request.arp_flags = 0;
+ sin = (struct sockaddr_in *) & request.arp_pa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ipaddr;
+ request.arp_ha.sa_family = AF_UNSPEC;
+ /* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN,
+ because AF_UNSPEC is zero and the kernel assumes that a zero
+ sa_family means that the real sa_family value is in sa_len. */
+ request.arp_ha.sa_len = 16; /* XXX */
+ bcopy((char *) ep, (char *) request.arp_ha.sa_data, 6);
+
+#if 0
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ioctl(s, SIOCSARP, (caddr_t) & request) < 0) {
+ err(NONFATAL, "SIOCSARP: %s", strerror(errno));
+ }
+ (void) close(s);
+#endif
+}
+/*
+ * Build a reverse ARP packet and sent it out on the interface.
+ * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built
+ * on top of the request, then written to the network.
+ *
+ * RFC 903 defines the ether_arp fields as follows. The following comments
+ * are taken (more or less) straight from this document.
+ *
+ * ARPOP_REVREQUEST
+ *
+ * arp_sha is the hardware address of the sender of the packet.
+ * arp_spa is undefined.
+ * arp_tha is the 'target' hardware address.
+ * In the case where the sender wishes to determine his own
+ * protocol address, this, like arp_sha, will be the hardware
+ * address of the sender.
+ * arp_tpa is undefined.
+ *
+ * ARPOP_REVREPLY
+ *
+ * arp_sha is the hardware address of the responder (the sender of the
+ * reply packet).
+ * arp_spa is the protocol address of the responder (see the note below).
+ * arp_tha is the hardware address of the target, and should be the same as
+ * that which was given in the request.
+ * arp_tpa is the protocol address of the target, that is, the desired address.
+ *
+ * Note that the requirement that arp_spa be filled in with the responder's
+ * protocol is purely for convenience. For instance, if a system were to use
+ * both ARP and RARP, then the inclusion of the valid protocol-hardware
+ * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
+ * ARP request.
+ */
+void
+rarp_reply(ii, ep, ipaddr)
+ struct if_info *ii;
+ struct ether_header *ep;
+ in_addr_t ipaddr;
+{
+ int n;
+ struct ether_arp *ap = (struct ether_arp *) (ep + 1);
+ int len;
+
+ update_arptab((u_char *) & ap->arp_sha, ipaddr);
+
+ /* Build the rarp reply by modifying the rarp request in place. */
+ ep->ether_type = htons(ETHERTYPE_REVARP);
+ ap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+ ap->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+ ap->arp_op = htons(ARPOP_REVREPLY);
+
+ bcopy((char *) &ap->arp_sha, (char *) &ep->ether_dhost, 6);
+ bcopy((char *) ii->ii_eaddr, (char *) &ep->ether_shost, 6);
+ bcopy((char *) ii->ii_eaddr, (char *) &ap->arp_sha, 6);
+
+ bcopy((char *) &ipaddr, (char *) ap->arp_tpa, 4);
+ /* Target hardware is unchanged. */
+ bcopy((char *) &ii->ii_ipaddr, (char *) ap->arp_spa, 4);
+
+ len = sizeof(*ep) + sizeof(*ap);
+ n = write(ii->ii_fd, (char *) ep, len);
+ if (n != len) {
+ err(NONFATAL, "write: only %d of %d bytes written", n, len);
+ }
+}
+/*
+ * Get the netmask of an IP address. This routine is used if
+ * SIOCGIFNETMASK doesn't work.
+ */
+in_addr_t
+ipaddrtonetmask(addr)
+ in_addr_t addr;
+{
+ if (IN_CLASSA(addr))
+ return IN_CLASSA_NET;
+ if (IN_CLASSB(addr))
+ return IN_CLASSB_NET;
+ if (IN_CLASSC(addr))
+ return IN_CLASSC_NET;
+ err(FATAL, "unknown IP address class: %08X", addr);
+ /* NOTREACHED */
+ return 0;
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(int fatal, const char *fmt,...)
+#else
+err(fmt, va_alist)
+ int fatal;
+ char *fmt;
+va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ if (dflag) {
+ if (fatal)
+ (void) fprintf(stderr, "rarpd: error: ");
+ else
+ (void) fprintf(stderr, "rarpd: warning: ");
+ (void) vfprintf(stderr, fmt, ap);
+ (void) fprintf(stderr, "\n");
+ }
+ vsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
+ if (fatal)
+ exit(1);
+ /* NOTREACHED */
+}
+
+void
+#if __STDC__
+debug(const char *fmt,...)
+#else
+debug(fmt, va_alist)
+ char *fmt;
+va_dcl
+#endif
+{
+ va_list ap;
+
+ if (dflag) {
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) fprintf(stderr, "rarpd: ");
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+ }
+}
diff --git a/network_cmds/route.tproj/gen_header.pl b/network_cmds/route.tproj/gen_header.pl
new file mode 100755
index 0000000..dfd9963
--- /dev/null
+++ b/network_cmds/route.tproj/gen_header.pl
@@ -0,0 +1,15 @@
+#!/usr/local/bin/perl -n
+#
+# Too run convert the keywords run the following command
+# gen_header.pl keywords > keywords.h
+
+next if m/^#/;
+next if m/^$/;
+$line_no++;
+chop;
+$keyword = $_;
+$upper = $keyword;
+$upper =~ tr/a-z/A-Z/;
+
+printf "#define\tK_%s\t%d\n\t{\"%s\", K_%s},\n",
+ $upper, $line_no, $keyword, $upper;
diff --git a/network_cmds/route.tproj/keywords b/network_cmds/route.tproj/keywords
new file mode 100644
index 0000000..8e740e3
--- /dev/null
+++ b/network_cmds/route.tproj/keywords
@@ -0,0 +1,49 @@
+# @(#)keywords 8.2 (Berkeley) 3/19/94
+
+add
+atalk
+blackhole
+change
+cloning
+delete
+dst
+expire
+flush
+gateway
+genmask
+get
+host
+hopcount
+iface
+ifscope
+interface
+ifa
+ifp
+inet
+inet6
+iso
+link
+llinfo
+lock
+lockrest
+mask
+monitor
+mtu
+net
+netmask
+nostatic
+osi
+prefixlen
+proto1
+proto2
+recvpipe
+reject
+rtt
+rttvar
+sa
+sendpipe
+ssthresh
+static
+x25
+xns
+xresolve
diff --git a/network_cmds/route.tproj/keywords.h b/network_cmds/route.tproj/keywords.h
new file mode 100644
index 0000000..b9edd54
--- /dev/null
+++ b/network_cmds/route.tproj/keywords.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#define K_ADD 1
+ {"add", K_ADD},
+#define K_BLACKHOLE 2
+ {"blackhole", K_BLACKHOLE},
+#define K_CHANGE 3
+ {"change", K_CHANGE},
+#define K_CLONING 4
+ {"cloning", K_CLONING},
+#define K_DELETE 5
+ {"delete", K_DELETE},
+#define K_DST 6
+ {"dst", K_DST},
+#define K_EXPIRE 7
+ {"expire", K_EXPIRE},
+#define K_FLUSH 8
+ {"flush", K_FLUSH},
+#define K_GATEWAY 9
+ {"gateway", K_GATEWAY},
+#define K_GENMASK 10
+ {"genmask", K_GENMASK},
+#define K_GET 11
+ {"get", K_GET},
+#define K_HOST 12
+ {"host", K_HOST},
+#define K_HOPCOUNT 13
+ {"hopcount", K_HOPCOUNT},
+#define K_IFACE 14
+ {"iface", K_IFACE},
+#define K_INTERFACE 15
+ {"interface", K_INTERFACE},
+#define K_IFA 16
+ {"ifa", K_IFA},
+#define K_IFP 17
+ {"ifp", K_IFP},
+#define K_INET 18
+ {"inet", K_INET},
+#define K_INET6 19
+ {"inet6", K_INET6},
+#define K_ISO 20
+ {"iso", K_ISO},
+#define K_LINK 21
+ {"link", K_LINK},
+#define K_LLINFO 22
+ {"llinfo", K_LLINFO},
+#define K_LOCK 23
+ {"lock", K_LOCK},
+#define K_LOCKREST 24
+ {"lockrest", K_LOCKREST},
+#define K_MASK 25
+ {"mask", K_MASK},
+#define K_MONITOR 26
+ {"monitor", K_MONITOR},
+#define K_MTU 27
+ {"mtu", K_MTU},
+#define K_NET 28
+ {"net", K_NET},
+#define K_NETMASK 29
+ {"netmask", K_NETMASK},
+#define K_NOSTATIC 30
+ {"nostatic", K_NOSTATIC},
+#define K_OSI 31
+ {"osi", K_OSI},
+#define K_PREFIXLEN 32
+ {"prefixlen", K_PREFIXLEN},
+#define K_PROTO1 33
+ {"proto1", K_PROTO1},
+#define K_PROTO2 34
+ {"proto2", K_PROTO2},
+#define K_RECVPIPE 35
+ {"recvpipe", K_RECVPIPE},
+#define K_REJECT 36
+ {"reject", K_REJECT},
+#define K_RTT 37
+ {"rtt", K_RTT},
+#define K_RTTVAR 38
+ {"rttvar", K_RTTVAR},
+#define K_SA 39
+ {"sa", K_SA},
+#define K_SENDPIPE 40
+ {"sendpipe", K_SENDPIPE},
+#define K_SSTHRESH 41
+ {"ssthresh", K_SSTHRESH},
+#define K_STATIC 42
+ {"static", K_STATIC},
+#define K_X25 43
+ {"x25", K_X25},
+#define K_XNS 44
+ {"xns", K_XNS},
+#define K_XRESOLVE 45
+ {"xresolve", K_XRESOLVE},
+#define K_IFSCOPE 46
+ {"ifscope", K_IFSCOPE},
diff --git a/network_cmds/route.tproj/route.8 b/network_cmds/route.tproj/route.8
new file mode 100644
index 0000000..74609c9
--- /dev/null
+++ b/network_cmds/route.tproj/route.8
@@ -0,0 +1,405 @@
+.\" Copyright (c) 1983, 1991, 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.
+.\"
+.\" @(#)route.8 8.3 (Berkeley) 3/19/94
+.\" $FreeBSD: src/sbin/route/route.8,v 1.17.2.7 2001/10/02 10:04:01 ru Exp $
+.\"
+.Dd June 8, 2001
+.Dt ROUTE 8
+.Os BSD 4.4
+.Sh NAME
+.Nm route
+.Nd manually manipulate the routing tables
+.Sh SYNOPSIS
+.Nm
+.Op Fl dnqtv
+.Ar command
+.Oo
+.Op Ar modifiers
+.Ar args
+.Oc
+.Sh DESCRIPTION
+.Nm Route
+is a utility used to manually manipulate the network
+routing tables. It normally is not needed, as a
+system routing table management daemon such as
+.Xr routed 8 ,
+should tend to this task.
+.Pp
+The
+.Nm
+utility supports a limited number of general options,
+but a rich command language, enabling the user to specify
+any arbitrary request that could be delivered via the
+programmatic interface discussed in
+.Xr route 4 .
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl d
+Run in debug-only mode, i.e., do not actually modify the routing table.
+.It Fl n
+Bypass attempts to print host and network names symbolically
+when reporting actions. (The process of translating between symbolic
+names and numerical equivalents can be quite time consuming, and
+may require correct operation of the network; thus it may be expedient
+to forget this, especially when attempting to repair networking operations).
+.It Fl t
+Run in test-only mode.
+.Pa /dev/null
+is used instead of a socket.
+.It Fl v
+(verbose) Print additional details.
+.It Fl q
+Suppress all output.
+.El
+.Pp
+The
+.Nm
+utility provides six commands:
+.Pp
+.Bl -tag -width Fl -compact
+.It Cm add
+Add a route.
+.It Cm flush
+Remove all routes.
+.It Cm delete
+Delete a specific route.
+.It Cm change
+Change aspects of a route (such as its gateway).
+.It Cm get
+Lookup and display the route for a destination.
+.It Cm monitor
+Continuously report any changes to the routing information base,
+routing lookup misses, or suspected network partitionings.
+.El
+.Pp
+The monitor command has the syntax:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Op Fl n
+.Cm monitor
+.Ed
+.Pp
+The flush command has the syntax:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Op Fl n
+.Cm flush
+.Op Ar family
+.Ed
+.Pp
+If the
+.Cm flush
+command is specified,
+.Nm
+will ``flush'' the routing tables of all gateway entries.
+When the address family may is specified by any of the
+.Fl osi ,
+.Fl xns ,
+.Fl atalk ,
+.Fl inet6 ,
+or
+.Fl inet
+modifiers, only routes having destinations with addresses in the
+delineated family will be deleted.
+.Pp
+The other commands have the following syntax:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Op Fl n
+.Ar command
+.Op Fl net No \&| Fl host
+.Oo Fl ifscope
+.Ar boundif
+.Oc
+.Ar destination gateway
+.Op Ar netmask
+.Ed
+.Pp
+where
+.Ar destination
+is the destination host or network,
+.Ar gateway
+is the next-hop intermediary via which packets should be routed.
+Routes to a particular host may be distinguished from those to
+a network by interpreting the Internet address specified as the
+.Ar destination
+argument.
+The optional modifiers
+.Fl net
+and
+.Fl host
+force the destination to be interpreted as a network or a host, respectively.
+Otherwise, if the
+.Ar destination
+has a
+.Dq local address part
+of
+INADDR_ANY
+.Pq Li 0.0.0.0 ,
+or if the
+.Ar destination
+is the symbolic name of a network, then the route is
+assumed to be to a network; otherwise, it is presumed to be a
+route to a host.
+Optionally, the
+.Ar destination
+could also be specified in the
+.Ar net Ns / Ns Ar bits
+format.
+.Pp
+For example,
+.Li 128.32
+is interpreted as
+.Fl host Li 128.0.0.32 ;
+.Li 128.32.130
+is interpreted as
+.Fl host Li 128.32.0.130 ;
+.Fl net Li 128.32
+is interpreted as
+.Li 128.32.0.0;
+.Fl net Li 128.32.130
+is interpreted as
+.Li 128.32.130.0;
+and
+.Li 192.168.64/20
+is interpreted as
+.Fl net Li 192.168.64 Fl netmask Li 255.255.240.0 .
+.Pp
+A
+.Ar destination
+of
+.Ar default
+is a synonym for
+.Fl net Li 0.0.0.0 ,
+which is the default route.
+.Pp
+If the destination is directly reachable
+via an interface requiring
+no intermediary system to act as a gateway, the
+.Fl interface
+modifier should be specified;
+the gateway given is the address of this host on the common network,
+indicating the interface to be used for transmission.
+Alternately, if the interface is point to point the name of the interface
+itself may be given, in which case the route remains valid even
+if the local or remote addresses change.
+.Pp
+For AF_INET and AF_INET6, the
+.Fl ifscope
+modifier specifies the additional property of the route related to
+the interface scope derived from interface
+.Ar boundif .
+Such property allows for the presence of multiple route entries with
+the same destination, where each route is associated with a unique
+interface. This modifier is required in order to manipulate route
+entries marked with the RTF_IFSCOPE flag.
+.Pp
+The optional modifier
+.Fl link
+specify that all subsequent addresses
+are specified as link-level addresses,
+and the names must be numeric specifications rather than
+symbolic names.
+.Pp
+The optional
+.Fl netmask
+modifier is intended
+to achieve the effect of an
+.Tn OSI
+.Tn ESIS
+redirect with the netmask option,
+or to manually add subnet routes with
+netmasks different from that of the implied network interface
+(as would otherwise be communicated using the OSPF or ISIS routing protocols).
+One specifies an additional ensuing address parameter
+(to be interpreted as a network mask).
+The implicit network mask generated in the AF_INET case
+can be overridden by making sure this option follows the destination parameter.
+.Pp
+For
+.Dv AF_INET6 ,
+the
+.Fl prefixlen
+qualifier
+is available instead of the
+.Fl mask
+qualifier because non-continuous masks are not allowed in IPv6.
+For example,
+.Fl prefixlen Li 32
+specifies network mask of
+.Li ffff:ffff:0000:0000:0000:0000:0000:0000
+to be used.
+The default value of prefixlen is 64 to get along with
+the aggregatable address.
+But 0 is assumed if
+.Cm default
+is specified.
+Note that the qualifier works only for
+.Dv AF_INET6
+address family.
+.Pp
+Routes have associated flags which influence operation of the protocols
+when sending to destinations matched by the routes.
+These flags may be set (or sometimes cleared)
+by indicating the following corresponding modifiers:
+.Bd -literal
+-cloning RTF_CLONING - generates a new route on use
+-xresolve RTF_XRESOLVE - emit mesg on use (for external lookup)
+-iface ~RTF_GATEWAY - destination is directly reachable
+-static RTF_STATIC - manually added route
+-nostatic ~RTF_STATIC - pretend route added by kernel or daemon
+-reject RTF_REJECT - emit an ICMP unreachable when matched
+-blackhole RTF_BLACKHOLE - silently discard pkts (during updates)
+-proto1 RTF_PROTO1 - set protocol specific routing flag #1
+-proto2 RTF_PROTO2 - set protocol specific routing flag #2
+-llinfo RTF_LLINFO - validly translates proto addr to link addr
+.Ed
+.Pp
+The optional modifiers
+.Fl rtt ,
+.Fl rttvar ,
+.Fl sendpipe ,
+.Fl recvpipe ,
+.Fl mtu ,
+.Fl hopcount ,
+.Fl expire ,
+and
+.Fl ssthresh
+provide initial values to quantities maintained in the routing entry
+by transport level protocols, such as TCP or TP4.
+These may be individually locked by preceding each such modifier to
+be locked by
+the
+.Fl lock
+meta-modifier, or one can
+specify that all ensuing metrics may be locked by the
+.Fl lockrest
+meta-modifier.
+.Pp
+In a
+.Cm change
+or
+.Cm add
+command where the destination and gateway are not sufficient to specify
+the route (as in the
+.Tn ISO
+case where several interfaces may have the
+same address), the
+.Fl ifp
+or
+.Fl ifa
+modifiers may be used to determine the interface or interface address.
+.Pp
+The optional
+.Fl proxy
+modifier specifies that the
+.Dv RTF_LLINFO
+routing table entry is the
+.Dq published (proxy-only)
+.Tn ARP
+entry, as reported by
+.Xr arp 8 .
+.Pp
+All symbolic names specified for a
+.Ar destination
+or
+.Ar gateway
+are looked up first as a host name using
+.Xr gethostbyname 3 .
+If this lookup fails,
+.Xr getnetbyname 3
+is then used to interpret the name as that of a network.
+.Pp
+.Nm Route
+uses a routing socket and the new message types
+.Dv RTM_ADD , RTM_DELETE , RTM_GET ,
+and
+.Dv RTM_CHANGE .
+As such, only the super-user may modify
+the routing tables.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "add [host \&| network ] %s: gateway %s flags %x"
+The specified route is being added to the tables. The
+values printed are from the routing table entry supplied
+in the
+.Xr ioctl 2
+call.
+If the gateway address used was not the primary address of the gateway
+(the first one returned by
+.Xr gethostbyname 3 ) ,
+the gateway address is printed numerically as well as symbolically.
+.It "delete [ host \&| network ] %s: gateway %s flags %x"
+As above, but when deleting an entry.
+.It "%s %s done"
+When the
+.Cm flush
+command is specified, each routing table entry deleted
+is indicated with a message of this form.
+.It "Network is unreachable"
+An attempt to add a route failed because the gateway listed was not
+on a directly-connected network.
+The next-hop gateway must be given.
+.It "not in table"
+A delete operation was attempted for an entry which
+wasn't present in the tables.
+.It "routing table overflow"
+An add operation was attempted, but the system was
+low on resources and was unable to allocate memory
+to create the new entry.
+.It "gateway uses the same route"
+A
+.Cm change
+operation resulted in a route whose gateway uses the
+same route as the one being changed.
+The next-hop gateway should be reachable through a different route.
+.El
+.Pp
+.Ex -std
+.Sh SEE ALSO
+.Xr netintro 4 ,
+.Xr route 4 ,
+.Xr arp 8 ,
+.Xr routed 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Sh BUGS
+The first paragraph may have slightly exaggerated
+.Xr routed 8 Ns 's
+abilities.
diff --git a/network_cmds/route.tproj/route.c b/network_cmds/route.tproj/route.c
new file mode 100644
index 0000000..9f7f4bd
--- /dev/null
+++ b/network_cmds/route.tproj/route.c
@@ -0,0 +1,1571 @@
+/*
+ * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1989, 1991, 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+struct keytab {
+ char *kt_cp;
+ int kt_i;
+} keywords[] = {
+#include "keywords.h"
+ {0, 0}
+};
+
+union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_dl sdl;
+ struct sockaddr_storage ss; /* added to avoid memory overrun */
+} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
+
+typedef union sockunion *sup;
+int pid, rtm_addrs, uid;
+int s;
+int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
+int iflag, verbose, aflen = sizeof (struct sockaddr_in);
+int locking, lockrest, debugonly;
+struct rt_metrics rt_metrics;
+u_long rtm_inits;
+unsigned int ifscope;
+
+static const char *route_strerror(int);
+const char *routename(), *netname();
+void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
+void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
+int getaddr(), rtmsg(), x25_makemask();
+int prefixlen();
+extern char *iso_ntoa();
+
+static void
+inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin,
+ struct sockaddr_in *sin_mask, in_addr_t bits);
+
+void usage __P((const char *)) __dead2;
+
+void
+usage(cp)
+ const char *cp;
+{
+ if (cp)
+ warnx("bad keyword: %s", cp);
+ (void) fprintf(stderr,
+ "usage: route [-dnqtv] command [[modifiers] args]\n");
+ exit(EX_USAGE);
+ /* NOTREACHED */
+}
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch;
+
+ if (argc < 2)
+ usage((char *)NULL);
+
+ while ((ch = getopt(argc, argv, "nqdtv")) != -1)
+ switch(ch) {
+ case 'n':
+ nflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'd':
+ debugonly = 1;
+ break;
+ case '?':
+ default:
+ usage((char *)NULL);
+ }
+ argc -= optind;
+ argv += optind;
+
+ pid = getpid();
+ uid = geteuid();
+ if (tflag)
+ s = open(_PATH_DEVNULL, O_WRONLY, 0);
+ else
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ err(EX_OSERR, "socket");
+ setuid(uid);
+ if (*argv)
+ switch (keyword(*argv)) {
+ case K_GET:
+ uid = 0;
+ /* FALLTHROUGH */
+
+ case K_CHANGE:
+ case K_ADD:
+ case K_DELETE:
+ newroute(argc, argv);
+ exit(0);
+ /* NOTREACHED */
+
+ case K_MONITOR:
+ monitor();
+ /* NOTREACHED */
+
+ case K_FLUSH:
+ flushroutes(argc, argv);
+ exit(0);
+ /* NOTREACHED */
+ }
+ usage(*argv);
+ /* NOTREACHED */
+}
+
+/*
+ * Purge all entries in the routing tables not
+ * associated with network interfaces.
+ */
+void
+flushroutes(argc, argv)
+ int argc;
+ char *argv[];
+{
+ size_t needed;
+ int mib[6], rlen, seqno;
+ char *buf, *next, *lim;
+ register struct rt_msghdr *rtm;
+
+ if (uid) {
+ errx(EX_NOPERM, "must be root to alter routing table");
+ }
+ shutdown(s, 0); /* Don't want to read back our messages */
+ if (argc > 1) {
+ argv++;
+ if (argc == 2 && **argv == '-')
+ switch (keyword(*argv + 1)) {
+ case K_INET:
+ af = AF_INET;
+ break;
+#ifdef INET6
+ case K_INET6:
+ af = AF_INET6;
+ break;
+#endif
+ case K_LINK:
+ af = AF_LINK;
+ break;
+ default:
+ goto bad;
+ } else
+bad: usage(*argv);
+ }
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ errx(EX_OSERR, "malloc failed");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "route-sysctl-get");
+ lim = buf + needed;
+ if (verbose)
+ (void) printf("Examining routing table from sysctl\n");
+ seqno = 0; /* ??? */
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (verbose)
+ print_rtmsg(rtm, rtm->rtm_msglen);
+ if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
+ continue;
+ if (af) {
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+
+ if (sa->sa_family != af)
+ continue;
+ }
+ if (debugonly)
+ continue;
+ rtm->rtm_type = RTM_DELETE;
+ rtm->rtm_seq = seqno;
+ rlen = write(s, next, rtm->rtm_msglen);
+ if (rlen < (int)rtm->rtm_msglen) {
+ warn("write to routing socket");
+ (void) printf("got only %d for rlen\n", rlen);
+ break;
+ }
+ seqno++;
+ if (qflag)
+ continue;
+ if (verbose)
+ print_rtmsg(rtm, rlen);
+ else {
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+ (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
+ routename(sa) : netname(sa));
+ sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
+ (void) printf("%-20.20s ", routename(sa));
+ (void) printf("done\n");
+ }
+ }
+}
+
+const char *
+routename(sa)
+ struct sockaddr *sa;
+{
+ register char *cp;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.'))) {
+ domain[MAXHOSTNAMELEN] = '\0';
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ } else
+ domain[0] = 0;
+ }
+
+ if (sa->sa_len == 0)
+ strlcpy(line, "default", sizeof(line));
+ else switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ cp = 0;
+ if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
+ cp = "default";
+ if (cp == 0 && !nflag) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+ /* XXX - why not inet_ntoa()? */
+#define C(x) (unsigned)((x) & 0xff)
+ in.s_addr = ntohl(in.s_addr);
+ (void) snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ }
+ break;
+ }
+
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 sin6; /* use static var for safety */
+ int niflags = 0;
+#ifdef NI_WITHSCOPEID
+ niflags = NI_WITHSCOPEID;
+#endif
+
+ memset(&sin6, 0, sizeof(sin6));
+ memcpy(&sin6, sa, sa->sa_len);
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+ if (sa->sa_len == sizeof(struct sockaddr_in6) &&
+ (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+ sin6.sin6_scope_id == 0) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ if (nflag)
+ niflags |= NI_NUMERICHOST;
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ line, sizeof(line), NULL, 0, niflags) != 0)
+ strlcpy(line, "invalid", sizeof(line));
+
+ return(line);
+ }
+#endif
+
+ case AF_LINK:
+ return (link_ntoa((struct sockaddr_dl *)sa));
+
+ default:
+ { u_short *s = (u_short *)sa;
+ u_short *slim = s + ((sa->sa_len + 1) >> 1);
+ char *cp = line + snprintf(line, sizeof(line), "(%d)", sa->sa_family);
+ char *cpe = line + sizeof(line);
+
+ while (++s < slim && cp < cpe) /* start with sa->sa_data */
+ cp += snprintf(cp, cpe - cp, " %x", *s);
+ break;
+ }
+ }
+ return (line);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net, not a host.
+ */
+const char *
+netname(sa)
+ struct sockaddr *sa;
+{
+ char *cp = NULL;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct netent *np = NULL;
+ register in_addr_t i;
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ i = in.s_addr = ntohl(in.s_addr);
+ if (in.s_addr == 0)
+ cp = "default";
+ else if (!nflag) {
+ np = getnetbyaddr(i, AF_INET);
+ if (np != NULL)
+ cp = np->n_name;
+ }
+#define C(x) (unsigned)((x) & 0xff)
+ if (cp != NULL)
+ strlcpy(line, cp, sizeof(line));
+ else if ((in.s_addr & 0xffffff) == 0)
+ (void) sprintf(line, "%u", C(in.s_addr >> 24));
+ else if ((in.s_addr & 0xffff) == 0)
+ (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16));
+ else if ((in.s_addr & 0xff) == 0)
+ (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8));
+ else
+ (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8),
+ C(in.s_addr));
+#undef C
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 sin6; /* use static var for safety */
+ int niflags = 0;
+#ifdef NI_WITHSCOPEID
+ niflags = NI_WITHSCOPEID;
+#endif
+
+ memset(&sin6, 0, sizeof(sin6));
+ memcpy(&sin6, sa, sa->sa_len);
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+ if (sa->sa_len == sizeof(struct sockaddr_in6) &&
+ (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+ sin6.sin6_scope_id == 0) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ if (nflag)
+ niflags |= NI_NUMERICHOST;
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ line, sizeof(line), NULL, 0, niflags) != 0)
+ strlcpy(line, "invalid", sizeof(line));
+
+ return(line);
+ }
+#endif
+
+ case AF_LINK:
+ return (link_ntoa((struct sockaddr_dl *)sa));
+
+
+ default:
+ { u_short *s = (u_short *)sa->sa_data;
+ u_short *slim = s + ((sa->sa_len + 1)>>1);
+ char *cp = line + snprintf(line, sizeof(line), "af %d:", sa->sa_family);
+ char *cpe = line + sizeof(line);
+
+ while (s < slim && cp < cpe)
+ cp += snprintf(cp, cpe - cp, " %x", *s++);
+ break;
+ }
+ }
+ return (line);
+}
+
+static const char *
+route_strerror(int error)
+{
+
+ switch (error) {
+ case ESRCH:
+ return "not in table";
+ case EBUSY:
+ return "entry in use";
+ case ENOBUFS:
+ return "routing table overflow";
+ default:
+ return (strerror(error));
+ }
+}
+
+void
+set_metric(value, key)
+ char *value;
+ int key;
+{
+ int flag = 0;
+ u_int noval, *valp = &noval;
+
+ switch (key) {
+#define caseof(x, y, z) case x: valp = (u_int *)&rt_metrics.z; flag = y; break
+ caseof(K_MTU, RTV_MTU, rmx_mtu);
+ caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
+ caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
+ caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
+ caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
+ caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
+ caseof(K_RTT, RTV_RTT, rmx_rtt);
+ caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
+ }
+ rtm_inits |= flag;
+ if (lockrest || locking)
+ rt_metrics.rmx_locks |= flag;
+ if (locking)
+ locking = 0;
+ *valp = atoi(value);
+}
+
+void
+newroute(argc, argv)
+ int argc;
+ register char **argv;
+{
+ char *cmd, *dest = "", *gateway = "";
+ int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
+ int key;
+ struct hostent *hp = 0;
+
+ if (uid) {
+ errx(EX_NOPERM, "must be root to alter routing table");
+ }
+ cmd = argv[0];
+ if (*cmd != 'g')
+ shutdown(s, 0); /* Don't want to read back our messages */
+ while (--argc > 0) {
+ if (**(++argv)== '-') {
+ switch (key = keyword(1 + *argv)) {
+ case K_LINK:
+ af = AF_LINK;
+ aflen = sizeof(struct sockaddr_dl);
+ break;
+ case K_INET:
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
+ break;
+#ifdef INET6
+ case K_INET6:
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case K_SA:
+ af = PF_ROUTE;
+ aflen = sizeof(union sockunion);
+ break;
+ case K_IFACE:
+ case K_INTERFACE:
+ iflag++;
+ break;
+ case K_NOSTATIC:
+ flags &= ~RTF_STATIC;
+ break;
+ case K_LLINFO:
+ flags |= RTF_LLINFO;
+ break;
+ case K_LOCK:
+ locking = 1;
+ break;
+ case K_LOCKREST:
+ lockrest = 1;
+ break;
+ case K_HOST:
+ forcehost++;
+ break;
+ case K_REJECT:
+ flags |= RTF_REJECT;
+ break;
+ case K_BLACKHOLE:
+ flags |= RTF_BLACKHOLE;
+ break;
+ case K_PROTO1:
+ flags |= RTF_PROTO1;
+ break;
+ case K_PROTO2:
+ flags |= RTF_PROTO2;
+ break;
+ case K_CLONING:
+ flags |= RTF_CLONING;
+ break;
+ case K_XRESOLVE:
+ flags |= RTF_XRESOLVE;
+ break;
+ case K_STATIC:
+ flags |= RTF_STATIC;
+ break;
+ case K_IFA:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_IFA, *++argv, 0);
+ break;
+ case K_IFP:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_IFP, *++argv, 0);
+ break;
+ case K_GENMASK:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_GENMASK, *++argv, 0);
+ break;
+ case K_GATEWAY:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_GATEWAY, *++argv, 0);
+ break;
+ case K_DST:
+ if (!--argc)
+ usage((char *)NULL);
+ ishost = getaddr(RTA_DST, *++argv, &hp);
+ dest = *argv;
+ break;
+ case K_NETMASK:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_NETMASK, *++argv, 0);
+ /* FALLTHROUGH */
+ case K_NET:
+ forcenet++;
+ break;
+ case K_PREFIXLEN:
+ if (!--argc)
+ usage((char *)NULL);
+ if (prefixlen(*++argv) == -1) {
+ forcenet = 0;
+ ishost = 1;
+ } else {
+ forcenet = 1;
+ ishost = 0;
+ }
+ break;
+ case K_MTU:
+ case K_HOPCOUNT:
+ case K_EXPIRE:
+ case K_RECVPIPE:
+ case K_SENDPIPE:
+ case K_SSTHRESH:
+ case K_RTT:
+ case K_RTTVAR:
+ if (!--argc)
+ usage((char *)NULL);
+ set_metric(*++argv, key);
+ break;
+ case K_IFSCOPE:
+ if (!--argc)
+ usage((char *)NULL);
+ if ((ifscope = if_nametoindex(*++argv)) != 0)
+ flags |= RTF_IFSCOPE;
+ else
+ errx(1, "bad interface name");
+ break;
+ default:
+ usage(1+*argv);
+ }
+ } else {
+ if ((rtm_addrs & RTA_DST) == 0) {
+ dest = *argv;
+ ishost = getaddr(RTA_DST, *argv, &hp);
+ } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
+ gateway = *argv;
+ (void) getaddr(RTA_GATEWAY, *argv, &hp);
+ } else {
+ (void) getaddr(RTA_NETMASK, *argv, 0);
+ }
+ }
+ }
+ if (forcehost) {
+ ishost = 1;
+#ifdef INET6
+ if (af == AF_INET6) {
+ rtm_addrs &= ~RTA_NETMASK;
+ memset((void *)&so_mask, 0, sizeof(so_mask));
+ }
+#endif
+ }
+ if (forcenet)
+ ishost = 0;
+ flags |= RTF_UP;
+ if (ishost)
+ flags |= RTF_HOST;
+ if (iflag == 0)
+ flags |= RTF_GATEWAY;
+ if (so_mask.sin.sin_family == AF_INET) {
+ // make sure the mask is contiguous
+ long i;
+ for (i = 0; i < 32; i++)
+ if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) != 0)
+ break;
+ for (; i < 32; i++)
+ if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) == 0)
+ errx(EX_NOHOST, "invalid mask: %s", inet_ntoa(so_mask.sin.sin_addr));
+ }
+ for (attempts = 1; ; attempts++) {
+ errno = 0;
+ if ((ret = rtmsg(*cmd, flags)) == 0)
+ break;
+ if (errno != ENETUNREACH && errno != ESRCH)
+ break;
+ if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
+ hp->h_addr_list++;
+ bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
+ MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
+ } else
+ break;
+ }
+ if (*cmd == 'g')
+ exit(0);
+ oerrno = errno;
+ (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
+ if (*gateway) {
+ (void) printf(": gateway %s", gateway);
+ if (attempts > 1 && ret == 0 && af == AF_INET)
+ (void) printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
+ }
+ if (ret == 0)
+ (void) printf("\n");
+ else {
+ (void)printf(": %s\n", route_strerror(oerrno));
+ }
+}
+
+static void
+inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin,
+ struct sockaddr_in *sin_mask, in_addr_t bits)
+{
+ in_addr_t mask = 0;
+
+ rtm_addrs |= RTA_NETMASK;
+ /*
+ * MSB of net should be meaningful. 0/0 is exception.
+ */
+ if (net > 0)
+ while ((net & 0xff000000) == 0)
+ net <<= 8;
+
+ /*
+ * If no /xx was specified we must calculate the
+ * CIDR address.
+ */
+ if ((bits == 0) && (net != 0)) {
+ u_long i, j;
+
+ for(i = 0, j = 0xff; i < 4; i++) {
+ if (net & j) {
+ break;
+ }
+ j <<= 8;
+ }
+ /* i holds the first non zero bit */
+ bits = 32 - (i*8);
+ }
+ if (bits != 0)
+ mask = 0xffffffff << (32 - bits);
+
+ sin->sin_addr.s_addr = htonl(net);
+ sin_mask->sin_addr.s_addr = htonl(mask);
+ sin_mask->sin_len = sizeof(struct sockaddr_in);
+ sin_mask->sin_family = AF_INET;
+}
+
+#ifdef INET6
+/*
+ * XXX the function may need more improvement...
+ */
+static int
+inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
+{
+ struct in6_addr in6;
+
+ if (plen == NULL) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+ sin6->sin6_scope_id == 0) {
+ plen = "0";
+ } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
+ /* aggregatable global unicast - RFC2374 */
+ memset(&in6, 0, sizeof(in6));
+ if (!memcmp(&sin6->sin6_addr.s6_addr[8],
+ &in6.s6_addr[8], 8))
+ plen = "64";
+ }
+ }
+
+ if (plen == NULL || strcmp(plen, "128") == 0)
+ return (1);
+ rtm_addrs |= RTA_NETMASK;
+ prefixlen(plen);
+ return (0);
+}
+#endif
+
+/*
+ * Interpret an argument as a network address of some kind,
+ * returning 1 if a host address, 0 if a network address.
+ */
+int
+getaddr(which, s, hpp)
+ int which;
+ char *s;
+ struct hostent **hpp;
+{
+ register sup su = NULL;
+ struct hostent *hp;
+ struct netent *np;
+ in_addr_t val;
+ char *q;
+ int afamily; /* local copy of af so we can change it */
+
+ if (af == 0) {
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
+ }
+ afamily = af;
+ rtm_addrs |= which;
+ switch (which) {
+ case RTA_DST:
+ su = &so_dst;
+ break;
+ case RTA_GATEWAY:
+ su = &so_gate;
+ if (iflag) {
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl *sdl = NULL;
+
+ if (getifaddrs(&ifap))
+ err(1, "getifaddrs");
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ if (strcmp(s, ifa->ifa_name))
+ continue;
+
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ }
+ /* If we found it, then use it */
+ if (sdl) {
+ /*
+ * Copy is safe since we have a
+ * sockaddr_storage member in sockunion{}.
+ * Note that we need to copy before calling
+ * freeifaddrs().
+ */
+ memcpy(&su->sdl, sdl, sdl->sdl_len);
+ }
+ freeifaddrs(ifap);
+ if (sdl)
+ return(1);
+ }
+ break;
+ case RTA_NETMASK:
+ su = &so_mask;
+ break;
+ case RTA_GENMASK:
+ su = &so_genmask;
+ break;
+ case RTA_IFP:
+ su = &so_ifp;
+ afamily = AF_LINK;
+ break;
+ case RTA_IFA:
+ su = &so_ifa;
+ break;
+ default:
+ usage("internal error");
+ /*NOTREACHED*/
+ }
+ su->sa.sa_len = aflen;
+ su->sa.sa_family = afamily; /* cases that don't want it have left already */
+ if (strcmp(s, "default") == 0) {
+ /*
+ * Default is net 0.0.0.0/0
+ */
+ switch (which) {
+ case RTA_DST:
+ forcenet++;
+ /* bzero(su, sizeof(*su)); *//* for readability */
+ (void) getaddr(RTA_NETMASK, s, 0);
+ break;
+ case RTA_NETMASK:
+ case RTA_GENMASK:
+ /* bzero(su, sizeof(*su)); *//* for readability */
+ su->sa.sa_len = 0;
+ break;
+ }
+ return (0);
+ }
+ switch (afamily) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct addrinfo hints, *res;
+ int ecode;
+
+ q = NULL;
+ if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
+ *q = '\0';
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = afamily; /*AF_INET6*/
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ ecode = getaddrinfo(s, NULL, &hints, &res);
+ if (ecode != 0 || res->ai_family != AF_INET6 ||
+ res->ai_addrlen != sizeof(su->sin6)) {
+ (void) fprintf(stderr, "%s: %s\n", s,
+ gai_strerror(ecode));
+ exit(1);
+ }
+ memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
+#ifdef __KAME__
+ if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
+ su->sin6.sin6_scope_id) {
+ *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
+ htons(su->sin6.sin6_scope_id);
+ su->sin6.sin6_scope_id = 0;
+ }
+#endif
+ freeaddrinfo(res);
+ if (hints.ai_flags == AI_NUMERICHOST) {
+ if (q != NULL)
+ *q++ = '/';
+ if (which == RTA_DST)
+ return (inet6_makenetandmask(&su->sin6, q));
+ return (0);
+ } else {
+ return (1);
+ }
+ }
+#endif /* INET6 */
+
+ case AF_LINK:
+ link_addr(s, &su->sdl);
+ return (1);
+
+
+ case PF_ROUTE:
+ su->sa.sa_len = sizeof(*su);
+ sockaddr(s, &su->sa);
+ return (1);
+
+ case AF_INET:
+ default:
+ break;
+ }
+
+ if (hpp == NULL)
+ hpp = &hp;
+ *hpp = NULL;
+
+ q = strchr(s,'/');
+ if (q && which == RTA_DST) {
+ *q = '\0';
+ if ((val = inet_network(s)) != INADDR_NONE) {
+ inet_makenetandmask(
+ val, &su->sin, (struct sockaddr_in *)&so_mask,
+ strtoul(q+1, 0, 0));
+ return (0);
+ }
+ *q = '/';
+ }
+ if ((which != RTA_DST || forcenet == 0) &&
+ inet_aton(s, &su->sin.sin_addr)) {
+ val = su->sin.sin_addr.s_addr;
+ if (which != RTA_DST || forcehost ||
+ inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
+ return (1);
+ else {
+ val = ntohl(val);
+ goto netdone;
+ }
+ }
+ if (which == RTA_DST && forcehost == 0 &&
+ ((val = inet_network(s)) != INADDR_NONE ||
+ ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
+netdone:
+ inet_makenetandmask(val, &su->sin, (struct sockaddr_in *)&so_mask, 0);
+ return (0);
+ }
+ hp = gethostbyname(s);
+ if (hp) {
+ *hpp = hp;
+ su->sin.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, (char *)&su->sin.sin_addr,
+ MIN(hp->h_length, sizeof(su->sin.sin_addr)));
+ return (1);
+ }
+ errx(EX_NOHOST, "bad address: %s", s);
+}
+
+int
+prefixlen(s)
+ char *s;
+{
+ int len = atoi(s), q, r;
+ int max;
+ char *p;
+
+ rtm_addrs |= RTA_NETMASK;
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ max = 128;
+ p = (char *)&so_mask.sin6.sin6_addr;
+ break;
+#endif
+ case AF_INET:
+ max = 32;
+ p = (char *)&so_mask.sin.sin_addr;
+ break;
+ default:
+ (void) fprintf(stderr, "prefixlen not supported in this af\n");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (len < 0 || max < len) {
+ (void) fprintf(stderr, "%s: bad value\n", s);
+ exit(1);
+ }
+
+ q = len >> 3;
+ r = len & 7;
+ so_mask.sa.sa_family = af;
+ so_mask.sa.sa_len = aflen;
+ memset((void *)p, 0, max / 8);
+ if (q > 0)
+ memset((void *)p, 0xff, q);
+ if (r > 0)
+ *((u_char *)p + q) = (0xff00 >> r) & 0xff;
+ if (len == max)
+ return -1;
+ else
+ return len;
+}
+
+void
+interfaces()
+{
+ size_t needed;
+ int mib[6];
+ char *buf, *lim, *next;
+ register struct rt_msghdr *rtm;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ errx(EX_OSERR, "malloc failed");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "actual retrieval of interface table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ print_rtmsg(rtm, rtm->rtm_msglen);
+ }
+}
+
+void
+monitor()
+{
+ int n;
+ char msg[2048];
+
+ verbose = 1;
+ if (debugonly) {
+ interfaces();
+ exit(0);
+ }
+ for(;;) {
+ time_t now;
+ n = read(s, msg, 2048);
+ now = time(NULL);
+ (void) printf("\ngot message of size %d on %s", n, ctime(&now));
+ print_rtmsg((struct rt_msghdr *)msg, n);
+ }
+}
+
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+int
+rtmsg(cmd, flags)
+ int cmd, flags;
+{
+ static int seq;
+ int rlen;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) {\
+ l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
+ if (verbose) sodump(&(u),"u");\
+ }
+
+ errno = 0;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ if (cmd == 'a')
+ cmd = RTM_ADD;
+ else if (cmd == 'c')
+ cmd = RTM_CHANGE;
+ else if (cmd == 'g') {
+ cmd = RTM_GET;
+ if (so_ifp.sa.sa_family == 0) {
+ so_ifp.sa.sa_family = AF_LINK;
+ so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
+ rtm_addrs |= RTA_IFP;
+ }
+ } else
+ cmd = RTM_DELETE;
+#define rtm m_rtmsg.m_rtm
+ rtm.rtm_type = cmd;
+ rtm.rtm_flags = flags;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = ++seq;
+ rtm.rtm_addrs = rtm_addrs;
+ rtm.rtm_rmx = rt_metrics;
+ rtm.rtm_inits = rtm_inits;
+ rtm.rtm_index = ifscope;
+
+ if (rtm_addrs & RTA_NETMASK)
+ mask_addr();
+ NEXTADDR(RTA_DST, so_dst);
+ NEXTADDR(RTA_GATEWAY, so_gate);
+ NEXTADDR(RTA_NETMASK, so_mask);
+ NEXTADDR(RTA_GENMASK, so_genmask);
+ NEXTADDR(RTA_IFP, so_ifp);
+ NEXTADDR(RTA_IFA, so_ifa);
+ rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+ if (verbose)
+ print_rtmsg(&rtm, l);
+ if (debugonly)
+ return (0);
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ warnx("writing to routing socket: %s", route_strerror(errno));
+ return (-1);
+ }
+ if (cmd == RTM_GET) {
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+ if (l < 0)
+ warn("read from routing socket");
+ else
+ print_getmsg(&rtm, l);
+ }
+#undef rtm
+ return (0);
+}
+
+void
+mask_addr()
+{
+ int olen = so_mask.sa.sa_len;
+ register char *cp1 = olen + (char *)&so_mask, *cp2;
+
+ for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
+ if (*--cp1 != 0) {
+ so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
+ break;
+ }
+ if ((rtm_addrs & RTA_DST) == 0)
+ return;
+ switch (so_dst.sa.sa_family) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ case AF_APPLETALK:
+ case 0:
+ return;
+ }
+ cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
+ cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
+ while (cp2 > cp1)
+ *--cp2 = 0;
+ cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
+ while (cp1 > so_dst.sa.sa_data)
+ *--cp1 &= *--cp2;
+}
+
+char *msgtypes[] = {
+ "",
+ "RTM_ADD: Add Route",
+ "RTM_DELETE: Delete Route",
+ "RTM_CHANGE: Change Metrics or flags",
+ "RTM_GET: Report Metrics",
+ "RTM_LOSING: Kernel Suspects Partitioning",
+ "RTM_REDIRECT: Told to use different route",
+ "RTM_MISS: Lookup failed on this address",
+ "RTM_LOCK: fix specified metrics",
+ "RTM_OLDADD: caused by SIOCADDRT",
+ "RTM_OLDDEL: caused by SIOCDELRT",
+ "RTM_RESOLVE: Route created by cloning",
+ "RTM_NEWADDR: address being added to iface",
+ "RTM_DELADDR: address being removed from iface",
+ "RTM_IFINFO: iface status change",
+ "RTM_NEWMADDR: new multicast group membership on iface",
+ "RTM_DELMADDR: multicast group membership removed from iface",
+ 0,
+};
+
+char metricnames[] =
+"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
+"\1mtu";
+char routeflags[] =
+"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010DELCLONE"
+"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
+"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024b024"
+"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\031IFSCOPE\032CONDEMNED"
+"\033IFREF\034PROXY\035ROUTER";
+char ifnetflags[] =
+"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
+"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
+"\017LINK2\020MULTICAST";
+char addrnames[] =
+"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+
+void
+print_rtmsg(rtm, msglen)
+ register struct rt_msghdr *rtm;
+ int msglen;
+{
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+#ifdef RTM_NEWMADDR
+ struct ifma_msghdr *ifmam;
+#endif
+
+ if (verbose == 0)
+ return;
+ if (rtm->rtm_version != RTM_VERSION) {
+ (void) printf("routing message version %d not understood\n",
+ rtm->rtm_version);
+ return;
+ }
+ (void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ (void) printf("if# %d, flags:", ifm->ifm_index);
+ bprintf(stdout, ifm->ifm_flags, ifnetflags);
+ pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ (void) printf("metric %d, flags:", ifam->ifam_metric);
+ bprintf(stdout, ifam->ifam_flags, routeflags);
+ pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
+ break;
+#ifdef RTM_NEWMADDR
+ case RTM_NEWMADDR:
+ case RTM_DELMADDR:
+ ifmam = (struct ifma_msghdr *)rtm;
+ pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
+ break;
+#endif
+ default:
+ (void) printf("pid: %ld, seq %d, errno %d, ",
+ (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
+ if (rtm->rtm_flags & RTF_IFSCOPE)
+ (void) printf("ifscope %d, ", rtm->rtm_index);
+ if (rtm->rtm_flags & RTF_IFREF)
+ (void) printf("ifref, ");
+ (void) printf("flags:");
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+ pmsg_common(rtm);
+ }
+}
+
+void
+print_getmsg(rtm, msglen)
+ register struct rt_msghdr *rtm;
+ int msglen;
+{
+ struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ register struct sockaddr *sa;
+ register char *cp;
+ register int i;
+
+ (void) printf(" route to: %s\n", routename(&so_dst.sa));
+ if (rtm->rtm_version != RTM_VERSION) {
+ warnx("routing message version %d not understood",
+ rtm->rtm_version);
+ return;
+ }
+ if (rtm->rtm_msglen > msglen) {
+ warnx("message length mismatch, in packet %d, returned %d",
+ rtm->rtm_msglen, msglen);
+ }
+ if (rtm->rtm_errno) {
+ errno = rtm->rtm_errno;
+ warn("message indicates error %d", errno);
+ return;
+ }
+ cp = ((char *)(rtm + 1));
+ if (rtm->rtm_addrs)
+ for (i = 1; i; i <<= 1)
+ if (i & rtm->rtm_addrs) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+ case RTA_DST:
+ dst = sa;
+ break;
+ case RTA_GATEWAY:
+ gate = sa;
+ break;
+ case RTA_NETMASK:
+ mask = sa;
+ break;
+ case RTA_IFP:
+ if (sa->sa_family == AF_LINK &&
+ ((struct sockaddr_dl *)sa)->sdl_nlen)
+ ifp = (struct sockaddr_dl *)sa;
+ break;
+ }
+ ADVANCE(cp, sa);
+ }
+ if (dst && mask)
+ mask->sa_family = dst->sa_family; /* XXX */
+ if (dst)
+ (void)printf("destination: %s\n", routename(dst));
+ if (mask) {
+ int savenflag = nflag;
+
+ nflag = 1;
+ (void)printf(" mask: %s\n", routename(mask));
+ nflag = savenflag;
+ }
+ if (gate && rtm->rtm_flags & RTF_GATEWAY)
+ (void)printf(" gateway: %s\n", routename(gate));
+ if (ifp)
+ (void)printf(" interface: %.*s\n",
+ ifp->sdl_nlen, ifp->sdl_data);
+ (void)printf(" flags: ");
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+
+#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
+#define msec(u) (((u) + 500) / 1000) /* usec to msec */
+
+ (void) printf("\n%s\n", "\
+ recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
+ printf("%8u%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
+ printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
+ printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
+ if (rtm->rtm_rmx.rmx_expire)
+ rtm->rtm_rmx.rmx_expire -= time(0);
+ printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
+#undef lock
+#undef msec
+#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
+ if (verbose)
+ pmsg_common(rtm);
+ else if (rtm->rtm_addrs &~ RTA_IGN) {
+ (void) printf("sockaddrs: ");
+ bprintf(stdout, rtm->rtm_addrs, addrnames);
+ putchar('\n');
+ }
+#undef RTA_IGN
+}
+
+void
+pmsg_common(rtm)
+ register struct rt_msghdr *rtm;
+{
+ (void) printf("\nlocks: ");
+ bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
+ (void) printf(" inits: ");
+ bprintf(stdout, rtm->rtm_inits, metricnames);
+ pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
+}
+
+void
+pmsg_addrs(cp, addrs)
+ char *cp;
+ int addrs;
+{
+ register struct sockaddr *sa;
+ int i;
+
+ if (addrs == 0) {
+ (void) putchar('\n');
+ return;
+ }
+ (void) printf("\nsockaddrs: ");
+ bprintf(stdout, addrs, addrnames);
+ (void) putchar('\n');
+ for (i = 1; i; i <<= 1)
+ if (i & addrs) {
+ sa = (struct sockaddr *)cp;
+ (void) printf(" %s", routename(sa));
+ ADVANCE(cp, sa);
+ }
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+void
+bprintf(fp, b, s)
+ register FILE *fp;
+ register int b;
+ register u_char *s;
+{
+ register int i;
+ int gotsome = 0;
+
+ if (b == 0)
+ return;
+ while ((i = *s++) != 0) {
+ if (b & (1 << (i-1))) {
+ if (gotsome == 0)
+ i = '<';
+ else
+ i = ',';
+ (void) putc(i, fp);
+ gotsome = 1;
+ for (; (i = *s) > 32; s++)
+ (void) putc(i, fp);
+ } else
+ while (*s > 32)
+ s++;
+ }
+ if (gotsome)
+ (void) putc('>', fp);
+}
+
+int
+keyword(cp)
+ char *cp;
+{
+ register struct keytab *kt = keywords;
+
+ while (kt->kt_cp && strcmp(kt->kt_cp, cp))
+ kt++;
+ return kt->kt_i;
+}
+
+void
+sodump(su, which)
+ register sup su;
+ char *which;
+{
+ switch (su->sa.sa_family) {
+ case AF_LINK:
+ (void) printf("%s: link %s; ",
+ which, link_ntoa(&su->sdl));
+ break;
+ case AF_INET:
+ (void) printf("%s: inet %s; ",
+ which, inet_ntoa(su->sin.sin_addr));
+ break;
+ }
+ (void) fflush(stdout);
+}
+
+/* States*/
+#define VIRGIN 0
+#define GOTONE 1
+#define GOTTWO 2
+/* Inputs */
+#define DIGIT (4*0)
+#define END (4*1)
+#define DELIM (4*2)
+
+void
+sockaddr(addr, sa)
+ register char *addr;
+ register struct sockaddr *sa;
+{
+ register char *cp = (char *)sa;
+ int size = sa->sa_len;
+ char *cplim = cp + size;
+ register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
+
+ bzero(cp, size);
+ cp++;
+ do {
+ if ((*addr >= '0') && (*addr <= '9')) {
+ new = *addr - '0';
+ } else if ((*addr >= 'a') && (*addr <= 'f')) {
+ new = *addr - 'a' + 10;
+ } else if ((*addr >= 'A') && (*addr <= 'F')) {
+ new = *addr - 'A' + 10;
+ } else if (*addr == 0)
+ state |= END;
+ else
+ state |= DELIM;
+ addr++;
+ switch (state /* | INPUT */) {
+ case GOTTWO | DIGIT:
+ *cp++ = byte; /*FALLTHROUGH*/
+ case VIRGIN | DIGIT:
+ state = GOTONE; byte = new; continue;
+ case GOTONE | DIGIT:
+ state = GOTTWO; byte = new + (byte << 4); continue;
+ default: /* | DELIM */
+ state = VIRGIN; *cp++ = byte; byte = 0; continue;
+ case GOTONE | END:
+ case GOTTWO | END:
+ *cp++ = byte; /* FALLTHROUGH */
+ case VIRGIN | END:
+ break;
+ }
+ break;
+ } while (cp < cplim);
+ sa->sa_len = cp - (char *)sa;
+}
diff --git a/network_cmds/rtadvd.tproj/advcap.c b/network_cmds/rtadvd.tproj/advcap.c
new file mode 100644
index 0000000..33b6fae
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/advcap.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: advcap.c,v 1.11 2003/05/19 09:46:50 keiichi Exp $ */
+
+/*
+ * Copyright (c) 1983 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.
+ */
+
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "pathnames.h"
+#include "rtadvd_logging.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+#define tgetent agetent
+#define tnchktc anchktc
+#define tnamatch anamatch
+#define tgetnum agetnum
+#define tgetflag agetflag
+#define tgetstr agetstr
+
+#if 0
+#define V_TERMCAP "REMOTE"
+#define V_TERM "HOST"
+#endif
+
+char *RM;
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+
+static char *remotefile;
+
+extern char *conffile;
+
+int tgetent(char *, char *);
+int getent(char *, char *, char *);
+int tnchktc(void);
+int tnamatch(char *);
+static char *tskip(char *);
+int64_t tgetnum(char *);
+int tgetflag(char *);
+char *tgetstr(char *, char **);
+static char *tdecode(char *, char **);
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+int
+tgetent(bp, name)
+ char *bp, *name;
+{
+ char *cp;
+
+ remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
+ return (getent(bp, name, cp));
+}
+
+int
+getent(bp, name, cp)
+ char *bp, *name, *cp;
+{
+ int c;
+ int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ tf = open(RM = cp, O_RDONLY);
+ }
+ if (tf < 0) {
+ infolog("<%s> open: %s", __func__, strerror(errno));
+ return (-2);
+ }
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\') {
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp + BUFSIZ - 1) {
+ write(STDERR_FILENO, "Remcap entry too long\n",
+ 22);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return (tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+int
+tnchktc()
+{
+ char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p < tbuf) {
+ write(STDERR_FILENO, "Bad remcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return (1);
+ strlcpy(tcname, p + 3, sizeof tcname);
+ q = tcname;
+ while (*q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(STDERR_FILENO, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (getent(tcbuf, tcname, remotefile) != 1) {
+ return (0);
+ }
+ for (q = tcbuf; *q++ != ':'; )
+ ;
+ l = p - holdtbuf + strlen(q);
+
+ /* check length before copying string below */
+ if (l > BUFSIZ) {
+ write(STDERR_FILENO, "Remcap entry too long\n", 23);
+ q[BUFSIZ - (p-holdtbuf)] = 0;
+ }
+ strlcpy(p, q, p-tbuf);
+ tbuf = holdtbuf;
+ return (1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+int
+tnamatch(np)
+ char *np;
+{
+ char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return (0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ char *bp;
+{
+ int dquote;
+
+ dquote = 0;
+ while (*bp) {
+ switch (*bp) {
+ case ':':
+ if (!dquote)
+ goto breakbreak;
+ else
+ bp++;
+ break;
+ case '\\':
+ bp++;
+ if (isdigit(*bp)) {
+ while (isdigit(*bp++))
+ ;
+ } else
+ bp++;
+ case '"':
+ dquote = (dquote ? 1 : 0);
+ bp++;
+ break;
+ default:
+ bp++;
+ break;
+ }
+ }
+breakbreak:
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+int64_t
+tgetnum(id)
+ char *id;
+{
+ int64_t i;
+ int base;
+ char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (strncmp(bp, id, strlen(id)) != 0)
+ continue;
+ bp += strlen(id);
+ if (*bp == '@')
+ return (-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+int
+tgetflag(id)
+ char *id;
+{
+ char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (strncmp(bp, id, strlen(id)) == 0) {
+ bp += strlen(id);
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return (0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (strncmp(bp, id, strlen(id)) != 0)
+ continue;
+ bp += strlen(id);
+ if (*bp == '@')
+ return (0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ char *str;
+ char **area;
+{
+ char *cp;
+ int c;
+ char *dp;
+ int i;
+ char term;
+
+ term = ':';
+ cp = *area;
+again:
+ if (*str == '"') {
+ term = '"';
+ str++;
+ }
+ while ((c = *str++) && c != term) {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\"";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ if (c == term && term != ':') {
+ term = ':';
+ goto again;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
diff --git a/network_cmds/rtadvd.tproj/advcap.h b/network_cmds/rtadvd.tproj/advcap.h
new file mode 100644
index 0000000..1b42b40
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/advcap.h
@@ -0,0 +1,45 @@
+/* $KAME: advcap.h,v 1.5 2003/06/09 05:40:54 t-momose Exp $ */
+
+/*
+ * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/* Based on Id: termcap.h,v 1.8 1996/09/10 12:42:10 peter Exp */
+
+#ifndef _ADVCAP_H_
+#define _ADVCAP_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int agetent(char *, const char *);
+extern int agetflag(const char *);
+extern int64_t agetnum(const char *);
+extern char *agetstr(const char *, char **);
+
+__END_DECLS
+
+#endif /* _ADVCAP_H_ */
diff --git a/network_cmds/rtadvd.tproj/config.c b/network_cmds/rtadvd.tproj/config.c
new file mode 100644
index 0000000..3d6388d
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/config.c
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2009-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <search.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <stddef.h>
+
+#include "rtadvd.h"
+#include "advcap.h"
+#include "timer.h"
+#include "if.h"
+#include "config.h"
+
+static time_t prefix_timo = (60 * 120); /* 2 hours.
+ * XXX: should be configurable. */
+extern struct rainfo *ralist;
+
+static struct rtadvd_timer *prefix_timeout(void *);
+static void makeentry(char *, size_t, int, char *);
+static int getinet6sysctl(int);
+static int encode_domain(char *, u_char *);
+
+void
+getconfig(intface)
+ char *intface;
+{
+ int stat, i;
+ int rdnss_length;
+ int dnssl_length;
+ char tbuf[BUFSIZ];
+ struct rainfo *rai;
+ long val;
+ int64_t val64;
+ char buf[BUFSIZ];
+ char *bp = buf;
+ char *addr, *flagstr;
+ char *capport;
+ static int forwarding = -1;
+
+#define MUSTHAVE(var, cap) \
+ do { \
+ int64_t t; \
+ if ((t = agetnum(cap)) < 0) { \
+ fprintf(stderr, "rtadvd: need %s for interface %s\n", \
+ cap, intface); \
+ exit(1); \
+ } \
+ var = t; \
+ } while (0)
+#define MAYHAVE(var, cap, def) \
+ do { \
+ if ((var = agetnum(cap)) < 0) \
+ var = def; \
+ } while (0)
+
+ if ((stat = agetent(tbuf, intface)) <= 0) {
+ memset(tbuf, 0, sizeof(tbuf));
+ errorlog("<%s> %s isn't defined in the configuration file"
+ " or the configuration file doesn't exist."
+ " Treat it as default",
+ __func__, intface);
+ }
+
+ ELM_MALLOC(rai, exit(1));
+ rai->prefix.next = rai->prefix.prev = &rai->prefix;
+#ifdef ROUTEINFO
+ rai->route.next = rai->route.prev = &rai->route;
+#endif
+ rai->rdnss_list.next = rai->rdnss_list.prev = &rai->rdnss_list;
+ rai->dnssl_list.next = rai->dnssl_list.prev = &rai->dnssl_list;
+
+ /* check if we are allowed to forward packets (if not determined) */
+ if (forwarding < 0) {
+ if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
+ exit(1);
+ }
+
+ /* get interface information */
+ if (agetflag("nolladdr"))
+ rai->advlinkopt = 0;
+ else
+ rai->advlinkopt = 1;
+ if (rai->advlinkopt) {
+ if ((rai->sdl = if_nametosdl(intface)) == NULL) {
+ errorlog("<%s> can't get information of %s",
+ __func__, intface);
+ exit(1);
+ }
+ rai->ifindex = rai->sdl->sdl_index;
+ } else
+ rai->ifindex = if_nametoindex(intface);
+ strlcpy(rai->ifname, intface, sizeof(rai->ifname));
+ if ((rai->phymtu = if_getmtu(intface)) == 0) {
+ rai->phymtu = IPV6_MMTU;
+ errorlog("<%s> can't get interface mtu of %s. Treat as %d",
+ __func__, intface, IPV6_MMTU);
+ }
+
+ /*
+ * set router configuration variables.
+ */
+ MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
+ if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
+ errorlog("<%s> maxinterval (%ld) on %s is invalid "
+ "(must be between %u and %u)", __func__, val,
+ intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
+ exit(1);
+ }
+ rai->maxinterval = (u_int)val;
+ MAYHAVE(val, "mininterval", rai->maxinterval/3);
+ if (val < MIN_MININTERVAL || val > (rai->maxinterval * 3) / 4) {
+ errorlog("<%s> mininterval (%ld) on %s is invalid "
+ "(must be between %d and %d)",
+ __func__, val, intface, MIN_MININTERVAL,
+ (rai->maxinterval * 3) / 4);
+ exit(1);
+ }
+ rai->mininterval = (u_int)val;
+
+ MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
+ rai->hoplimit = val & 0xff;
+
+ if ((flagstr = (char *)agetstr("raflags", &bp))) {
+ val = 0;
+ if (strchr(flagstr, 'm'))
+ val |= ND_RA_FLAG_MANAGED;
+ if (strchr(flagstr, 'o'))
+ val |= ND_RA_FLAG_OTHER;
+ if (strchr(flagstr, 'h'))
+ val |= ND_RA_FLAG_RTPREF_HIGH;
+ if (strchr(flagstr, 'l')) {
+ if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
+ errorlog("<%s> the \'h\' and \'l\'"
+ " router flags are exclusive", __func__);
+ exit(1);
+ }
+ val |= ND_RA_FLAG_RTPREF_LOW;
+ }
+ } else {
+ MAYHAVE(val, "raflags", 0);
+ }
+ rai->managedflg = val & ND_RA_FLAG_MANAGED;
+ rai->otherflg = val & ND_RA_FLAG_OTHER;
+#ifndef ND_RA_FLAG_RTPREF_MASK
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
+#endif
+ rai->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+ if (rai->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+ errorlog("<%s> invalid router preference (%02x) on %s",
+ __func__, rai->rtpref, intface);
+ exit(1);
+ }
+
+ MAYHAVE(val, "rltime", rai->maxinterval * 3);
+ if (val && (val < rai->maxinterval || val > MAXROUTERLIFETIME)) {
+ errorlog("<%s> router lifetime (%ld) on %s is invalid "
+ "(must be 0 or between %d and %d)",
+ __func__, val, intface,
+ rai->maxinterval,
+ MAXROUTERLIFETIME);
+ exit(1);
+ }
+ /*
+ * Basically, hosts MUST NOT send Router Advertisement messages at any
+ * time (RFC 2461, Section 6.2.3). However, it would sometimes be
+ * useful to allow hosts to advertise some parameters such as prefix
+ * information and link MTU. Thus, we allow hosts to invoke rtadvd
+ * only when router lifetime (on every advertising interface) is
+ * explicitly set zero. (see also the above section)
+ */
+ if (val && forwarding == 0) {
+ errorlog("<%s> non zero router lifetime is specified for %s, "
+ "which must not be allowed for hosts. you must "
+ "change router lifetime or enable IPv6 forwarding.",
+ __func__, intface);
+ exit(1);
+ }
+ rai->lifetime = val & 0xffff;
+
+ MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
+ if (val < 0 || val > MAXREACHABLETIME) {
+ errorlog("<%s> reachable time (%ld) on %s is invalid "
+ "(must be no greater than %d)",
+ __func__, val, intface, MAXREACHABLETIME);
+ exit(1);
+ }
+ rai->reachabletime = (u_int32_t)val;
+
+ MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog("<%s> retrans time (%lld) on %s out of range",
+ __func__, (long long)val64, intface);
+ exit(1);
+ }
+ rai->retranstimer = (u_int32_t)val64;
+
+ if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
+ errorlog("<%s> mobile-ip6 configuration not supported",
+ __func__);
+ exit(1);
+ }
+ /* prefix information */
+
+ /*
+ * This is an implementation specific parameter to consider
+ * link propagation delays and poorly synchronized clocks when
+ * checking consistency of advertised lifetimes.
+ */
+ MAYHAVE(val, "clockskew", 0);
+ rai->clockskew = val;
+
+ rai->pfxs = 0;
+ for (i = -1; i < MAXPREFIX; i++) {
+ struct prefix *pfx;
+ char entbuf[256];
+
+ makeentry(entbuf, sizeof(entbuf), i, "addr");
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL)
+ continue;
+
+ /* allocate memory to store prefix information */
+ ELM_MALLOC(pfx, exit(1));
+
+ pfx->rainfo = rai;
+ pfx->origin = PREFIX_FROM_CONFIG;
+
+ if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) {
+ errorlog("<%s> inet_pton failed for %s",
+ __func__, addr);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
+ errorlog("<%s> multicast prefix (%s) must "
+ "not be advertised on %s",
+ __func__, addr, intface);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
+ noticelog("<%s> link-local prefix (%s) will be"
+ " advertised on %s",
+ __func__, addr, intface);
+
+ makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
+ MAYHAVE(val, entbuf, 64);
+ if (val < 0 || val > 128) {
+ errorlog("<%s> prefixlen (%ld) for %s "
+ "on %s out of range",
+ __func__, val, addr, intface);
+ exit(1);
+ }
+ pfx->prefixlen = (int)val;
+
+ makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
+ if ((flagstr = (char *)agetstr(entbuf, &bp))) {
+ val = 0;
+ if (strchr(flagstr, 'l'))
+ val |= ND_OPT_PI_FLAG_ONLINK;
+ if (strchr(flagstr, 'a'))
+ val |= ND_OPT_PI_FLAG_AUTO;
+ } else {
+ MAYHAVE(val, entbuf,
+ (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
+ }
+ pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
+ pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
+
+ makeentry(entbuf, sizeof(entbuf), i, "vltime");
+ MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog("<%s> vltime (%lld) for "
+ "%s/%d on %s is out of range",
+ __func__, (long long)val64,
+ addr, pfx->prefixlen, intface);
+ exit(1);
+ }
+ pfx->validlifetime = (u_int32_t)val64;
+
+ makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
+ if (agetflag(entbuf)) {
+ struct timeval now;
+ gettimeofday(&now, 0);
+ pfx->vltimeexpire =
+ now.tv_sec + pfx->validlifetime;
+ }
+
+ makeentry(entbuf, sizeof(entbuf), i, "pltime");
+ MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog("<%s> pltime (%lld) for %s/%d on %s "
+ "is out of range",
+ __func__, (long long)val64,
+ addr, pfx->prefixlen, intface);
+ exit(1);
+ }
+ pfx->preflifetime = (u_int32_t)val64;
+
+ makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
+ if (agetflag(entbuf)) {
+ struct timeval now;
+ gettimeofday(&now, 0);
+ pfx->pltimeexpire =
+ now.tv_sec + pfx->preflifetime;
+ }
+ /* link into chain */
+ insque(pfx, &rai->prefix);
+ rai->pfxs++;
+ }
+ if (rai->pfxs == 0)
+ get_prefix(rai);
+
+ MAYHAVE(val, "mtu", 0);
+ if (val < 0 || val > 0xffffffff) {
+ errorlog("<%s> mtu (%ld) on %s out of range",
+ __func__, val, intface);
+ exit(1);
+ }
+ rai->linkmtu = (u_int32_t)val;
+ if (rai->linkmtu == 0) {
+ char *mtustr;
+
+ if ((mtustr = (char *)agetstr("mtu", &bp)) &&
+ strcmp(mtustr, "auto") == 0)
+ rai->linkmtu = rai->phymtu;
+ }
+ else if (rai->linkmtu < IPV6_MMTU || rai->linkmtu > rai->phymtu) {
+ errorlog("<%s> advertised link mtu (%lu) on %s is invalid (must "
+ "be between least MTU (%d) and physical link MTU (%d)",
+ __func__, (unsigned long)rai->linkmtu, intface,
+ IPV6_MMTU, rai->phymtu);
+ exit(1);
+ }
+
+#ifdef SIOCSIFINFO_IN6
+ {
+ struct in6_ndireq ndi;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+ memset(&ndi, 0, sizeof(ndi));
+ strlcpy(ndi.ifname, intface, sizeof(ndi.ifname));
+ if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) {
+ infolog("<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
+ __func__, intface, strerror(errno));
+ }
+
+ /* reflect the RA info to the host variables in kernel */
+ ndi.ndi.chlim = rai->hoplimit;
+ ndi.ndi.retrans = rai->retranstimer;
+ ndi.ndi.basereachable = rai->reachabletime;
+ if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) {
+ infolog("<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
+ __func__, intface, strerror(errno));
+ }
+ close(s);
+ }
+#endif
+
+ /* route information */
+#ifdef ROUTEINFO
+ rai->routes = 0;
+ for (i = -1; i < MAXROUTE; i++) {
+ struct rtinfo *rti;
+ char entbuf[256], oentbuf[256];
+
+ makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
+ addr = (char *)agetstr(oentbuf, &bp);
+ if (addr) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ }
+ }
+ if (addr == NULL)
+ continue;
+
+ /* allocate memory to store prefix information */
+ ELM_MALLOC(rti, exit(1));
+
+ /* link into chain */
+ insque(rti, &rai->route);
+ rai->routes++;
+
+ if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
+ errorlog( "<%s> inet_pton failed for %s",
+ __func__, addr);
+ exit(1);
+ }
+#if 0
+ /*
+ * XXX: currently there's no restriction in route information
+ * prefix according to
+ * draft-ietf-ipngwg-router-selection-00.txt.
+ * However, I think the similar restriction be necessary.
+ */
+ MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
+ if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
+ errorlog("<%s> multicast route (%s) must "
+ "not be advertised on %s",
+ __func__, addr, intface);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
+ noticelog("<%s> link-local route (%s) will "
+ "be advertised on %s",
+ __func__, addr, intface);
+ exit(1);
+ }
+#endif
+
+ makeentry(entbuf, sizeof(entbuf), i, "rtplen");
+ /* XXX: 256 is a magic number for compatibility check. */
+ MAYHAVE(val, entbuf, 256);
+ if (val == 256) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
+ MAYHAVE(val, oentbuf, 256);
+ if (val != 256) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ } else
+ val = 64;
+ }
+ if (val < 0 || val > 128) {
+ errorlog("<%s> prefixlen (%ld) for %s on %s "
+ "out of range",
+ __func__, val, addr, intface);
+ exit(1);
+ }
+ rti->prefixlen = (int)val;
+
+ makeentry(entbuf, sizeof(entbuf), i, "rtflags");
+ if ((flagstr = (char *)agetstr(entbuf, &bp))) {
+ val = 0;
+ if (strchr(flagstr, 'h'))
+ val |= ND_RA_FLAG_RTPREF_HIGH;
+ if (strchr(flagstr, 'l')) {
+ if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
+ errorlog(
+ "<%s> the \'h\' and \'l\' route"
+ " preferences are exclusive",
+ __func__);
+ exit(1);
+ }
+ val |= ND_RA_FLAG_RTPREF_LOW;
+ }
+ } else
+ MAYHAVE(val, entbuf, 256); /* XXX */
+ if (val == 256) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags");
+ MAYHAVE(val, oentbuf, 256);
+ if (val != 256) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ } else
+ val = 0;
+ }
+ rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+ if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+ errorlog("<%s> invalid route preference (%02x) "
+ "for %s/%d on %s",
+ __func__, rti->rtpref, addr,
+ rti->prefixlen, intface);
+ exit(1);
+ }
+
+ /*
+ * Since the spec does not a default value, we should make
+ * this entry mandatory. However, FreeBSD 4.4 has shipped
+ * with this field being optional, we use the router lifetime
+ * as an ad-hoc default value with a warning message.
+ */
+ makeentry(entbuf, sizeof(entbuf), i, "rtltime");
+ MAYHAVE(val64, entbuf, -1);
+ if (val64 == -1) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
+ MAYHAVE(val64, oentbuf, -1);
+ if (val64 != -1) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ } else {
+ fprintf(stderr, "%s should be specified "
+ "for interface %s.\n",
+ entbuf, intface);
+ val64 = rai->lifetime;
+ }
+ }
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog( "<%s> route lifetime (%lld) for "
+ "%s/%d on %s out of range", __func__,
+ (long long)val64, addr, rti->prefixlen, intface);
+ exit(1);
+ }
+ rti->ltime = (u_int32_t)val64;
+ }
+#endif
+
+ /* RDNSS option (RFC5006) */
+ MAYHAVE(val, "rdnsslifetime", 2 * rai->maxinterval);
+ if (val < rai->maxinterval || val > (2 * rai->maxinterval)) {
+ noticelog("<%s> rdnsslifetime (%lu) on %s SHOULD "
+ "be between %u and %u", __func__, val,
+ intface, rai->maxinterval, 2 * rai->maxinterval);
+ }
+ rai->rdnss_lifetime = val;
+ if ((rdnss_length = agetnum("rdnssaddrs")) < 0) {
+ rai->rdnss_length = 0;
+ }
+ else {
+ rai->rdnss_length = rdnss_length;
+
+ /* traverse in reverse order so that the queue has correct order */
+ for (i = (rdnss_length - 1); i >= 0; i--) {
+ struct rdnss *rdnss;
+ char entbuf[256];
+
+ /* allocate memory to store server address information */
+ ELM_MALLOC(rdnss, exit(1));
+ /* link into chain */
+ insque(rdnss, &rai->rdnss_list);
+
+ makeentry(entbuf, sizeof(entbuf), i, "rdnssaddr");
+ addr = (char *)agetstr(entbuf, &bp);
+
+ if (addr == NULL && rdnss_length == 1) {
+ makeentry(entbuf, sizeof(entbuf), -1, "rdnssaddr");
+ addr = agetstr(entbuf, &bp);
+ }
+
+ if (addr == NULL) {
+ errorlog("<%s> need %s as a DNS server address for "
+ "interface %s",
+ __func__, entbuf, intface);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, addr, &rdnss->addr) != 1) {
+ errorlog("<%s> inet_pton failed for %s",
+ __func__, addr);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_MULTICAST(&rdnss->addr)) {
+ errorlog("<%s> multicast address (%s) must "
+ "not be advertised as recursive DNS server",
+ __func__, addr);
+ exit(1);
+ }
+ }
+ }
+
+ /* DNSSL option (RFC6106) */
+
+ /* Parse the DNSSL lifetime from the config */
+ MAYHAVE(val, "dnssllifetime", 2 * rai->maxinterval);
+ if (val < rai->maxinterval || val > (2 * rai->maxinterval)) {
+ noticelog("<%s> dnssllifetime (%lu) on %s SHOULD "
+ "be between %u and %u", __func__, val,
+ intface, rai->maxinterval, 2 * rai->maxinterval);
+ }
+ rai->dnssl_lifetime = val;
+ rai->dnssl_option_length = 8; /* 8 bytes for the option header */
+
+ /* Parse the DNSSL domain list from the config */
+ if ((dnssl_length = agetnum("dnssldomains")) < 0) {
+ rai->dnssl_length = 0;
+ } else {
+ rai->dnssl_length = dnssl_length;
+
+ for (i = (rai->dnssl_length - 1); i >= 0; i--) {
+ unsigned char *dnssl_buf;
+ struct dnssl *dnssl;
+ int dnssl_len;
+ char entbuf[sizeof("dnssldomain") + 20];
+ char *domain;
+ int domain_len;
+
+ makeentry(entbuf, sizeof(entbuf), i, "dnssldomain");
+ domain = agetstr(entbuf, &bp);
+
+ if (domain == NULL && rai->dnssl_length == 1) {
+ makeentry(entbuf, sizeof(entbuf), -1, "dnssldomain");
+ domain = agetstr(entbuf, &bp);
+ }
+
+ if (domain == NULL) {
+ errorlog("<%s> need %s as a DNS search domain for "
+ "interface %s",
+ __func__, entbuf, intface);
+ exit(1);
+ }
+
+ domain_len = strlen(domain);
+
+ /* Trim off leading dots */
+ while (domain_len > 0 && domain[0] == '.') {
+ domain++;
+ domain_len--;
+ }
+
+ /* Trim off trailing dots */
+ while (domain_len > 0 && domain[domain_len-1] == '.') {
+ domain_len--;
+ }
+
+ if (domain_len > 0) {
+ dnssl_len = sizeof(struct dnssl) + domain_len + 1;
+ dnssl_buf = (unsigned char *)malloc(dnssl_len);
+
+ memset(dnssl_buf, 0, dnssl_len);
+
+ dnssl = (struct dnssl *)dnssl_buf;
+ insque(dnssl, &rai->dnssl_list);
+
+ /* Copy the domain name in at the end of the dnssl struct */
+ memcpy(dnssl_buf + offsetof(struct dnssl, domain), domain,
+ domain_len);
+
+ /* Add 2 for leading length byte and the trailing 0 byte */
+ rai->dnssl_option_length += domain_len + 2;
+ }
+ }
+
+ /* Round up to the next multiple of 8 */
+ rai->dnssl_option_length += (8 - (rai->dnssl_option_length & 0x7));
+ }
+
+ /* captive portal */
+ capport = agetstr("capport", &bp);
+ if (capport != NULL) {
+ rai->capport = strdup(capport);
+ rai->capport_length = strlen(capport);
+ rai->capport_option_length
+ = sizeof(struct nd_opt_hdr) + rai->capport_length;
+ rai->capport_option_length
+ += (8 - (rai->capport_option_length & 0x7));
+ }
+
+ /* okey */
+ rai->next = ralist;
+ ralist = rai;
+
+ /* construct the sending packet */
+ make_packet(rai);
+
+ /* set timer */
+ rai->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
+ rai, rai);
+ ra_timer_update((void *)rai, &rai->timer->tm);
+ rtadvd_set_timer(&rai->timer->tm, rai->timer);
+}
+
+void
+get_prefix(struct rainfo *rai)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct prefix *pfx;
+ struct in6_addr *a;
+ u_char *p, *ep, *m, *lim;
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ if (getifaddrs(&ifap) < 0) {
+ errorlog(
+ "<%s> can't get interface addresses",
+ __func__);
+ exit(1);
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ int plen;
+
+ if (strcmp(ifa->ifa_name, rai->ifname) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ if (IN6_IS_ADDR_LINKLOCAL(a))
+ continue;
+ /* get prefix length */
+ m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
+ lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
+ plen = prefixlen(m, lim);
+ if (plen <= 0 || plen > 128) {
+ errorlog( "<%s> failed to get prefixlen "
+ "or prefix is invalid",
+ __func__);
+ exit(1);
+ }
+ if (plen == 128) /* XXX */
+ continue;
+ if (find_prefix(rai, a, plen)) {
+ /* ignore a duplicated prefix. */
+ continue;
+ }
+
+ /* allocate memory to store prefix info. */
+ ELM_MALLOC(pfx, exit(1));
+ /* set prefix, sweep bits outside of prefixlen */
+ pfx->prefixlen = plen;
+ memcpy(&pfx->prefix, a, sizeof(*a));
+ p = (u_char *)&pfx->prefix;
+ ep = (u_char *)(&pfx->prefix + 1);
+ while (m < lim && p < ep)
+ *p++ &= *m++;
+ while (p < ep)
+ *p++ = 0x00;
+ if (!inet_ntop(AF_INET6, &pfx->prefix, ntopbuf,
+ sizeof(ntopbuf))) {
+ errorlog("<%s> inet_ntop failed", __func__);
+ exit(1);
+ }
+ debuglog("<%s> add %s/%d to prefix list on %s",
+ __func__, ntopbuf, pfx->prefixlen, rai->ifname);
+
+ /* set other fields with protocol defaults */
+ pfx->validlifetime = DEF_ADVVALIDLIFETIME;
+ pfx->preflifetime = DEF_ADVPREFERREDLIFETIME;
+ pfx->onlinkflg = 1;
+ pfx->autoconfflg = 1;
+ pfx->origin = PREFIX_FROM_KERNEL;
+ pfx->rainfo = rai;
+
+ /* link into chain */
+ insque(pfx, &rai->prefix);
+
+ /* counter increment */
+ rai->pfxs++;
+ }
+
+ freeifaddrs(ifap);
+}
+
+static void
+makeentry(buf, len, id, string)
+ char *buf;
+ size_t len;
+ int id;
+ char *string;
+{
+
+ if (id < 0)
+ strlcpy(buf, string, len);
+ else
+ snprintf(buf, len, "%s%d", string, id);
+}
+
+/*
+ * Add a prefix to the list of specified interface and reconstruct
+ * the outgoing packet.
+ * The prefix must not be in the list.
+ * XXX: other parameters of the prefix (e.g. lifetime) should be
+ * able to be specified.
+ */
+static void
+add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
+{
+ struct prefix *prefix;
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ ELM_MALLOC(prefix, exit(1));
+ prefix->prefix = ipr->ipr_prefix.sin6_addr;
+ prefix->prefixlen = ipr->ipr_plen;
+ prefix->validlifetime = ipr->ipr_vltime;
+ prefix->preflifetime = ipr->ipr_pltime;
+ prefix->onlinkflg = ipr->ipr_raf_onlink;
+ prefix->autoconfflg = ipr->ipr_raf_auto;
+ prefix->origin = PREFIX_FROM_DYNAMIC;
+ prefix->rainfo = rai;
+
+ insque(prefix, &rai->prefix);
+
+ debuglog("<%s> new prefix %s/%d was added on %s",
+ __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ ipr->ipr_plen, rai->ifname);
+
+ /* free the previous packet */
+ free(rai->ra_data);
+ rai->ra_data = NULL;
+
+ /* reconstruct the packet */
+ rai->pfxs++;
+ make_packet(rai);
+}
+
+/*
+ * Delete a prefix to the list of specified interface and reconstruct
+ * the outgoing packet.
+ * The prefix must be in the list.
+ */
+void
+delete_prefix(struct prefix *prefix)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct rainfo *rai = prefix->rainfo;
+
+ remque(prefix);
+ debuglog("<%s> prefix %s/%d was deleted on %s",
+ __func__, inet_ntop(AF_INET6, &prefix->prefix,
+ ntopbuf, INET6_ADDRSTRLEN),
+ prefix->prefixlen, rai->ifname);
+ if (prefix->timer)
+ rtadvd_remove_timer(&prefix->timer);
+ free(prefix);
+ rai->pfxs--;
+}
+
+void
+invalidate_prefix(struct prefix *prefix)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct timeval timo;
+ struct rainfo *rai = prefix->rainfo;
+
+ if (prefix->timer) { /* sanity check */
+ errorlog("<%s> assumption failure: timer already exists",
+ __func__);
+ exit(1);
+ }
+
+ debuglog("<%s> prefix %s/%d was invalidated on %s, "
+ "will expire in %ld seconds", __func__,
+ inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
+ prefix->prefixlen, rai->ifname, (long)prefix_timo);
+
+ /* set the expiration timer */
+ prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL);
+ if (prefix->timer == NULL) {
+ errorlog("<%s> failed to add a timer for a prefix. "
+ "remove the prefix", __func__);
+ delete_prefix(prefix);
+ return;
+ }
+ timo.tv_sec = prefix_timo;
+ timo.tv_usec = 0;
+ rtadvd_set_timer(&timo, prefix->timer);
+}
+
+static struct rtadvd_timer *
+prefix_timeout(void *arg)
+{
+ struct prefix *prefix = (struct prefix *)arg;
+
+ delete_prefix(prefix);
+
+ return(NULL);
+}
+
+void
+update_prefix(struct prefix * prefix)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct rainfo *rai = prefix->rainfo;
+
+ if (prefix->timer == NULL) { /* sanity check */
+ errorlog("<%s> assumption failure: timer does not exist",
+ __func__);
+ exit(1);
+ }
+
+ debuglog("<%s> prefix %s/%d was re-enabled on %s",
+ __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf,
+ INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname);
+
+ /* stop the expiration timer */
+ rtadvd_remove_timer(&prefix->timer);
+}
+
+/*
+ * Try to get an in6_prefixreq contents for a prefix which matches
+ * ipr->ipr_prefix and ipr->ipr_plen and belongs to
+ * the interface whose name is ipr->ipr_name[].
+ */
+static int
+init_prefix(struct in6_prefixreq *ipr)
+{
+#if 0
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+
+ if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
+ infolog("<%s> ioctl:SIOCGIFPREFIX %s", __func__,
+ strerror(errno));
+
+ ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
+ ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
+ ipr->ipr_raf_onlink = 1;
+ ipr->ipr_raf_auto = 1;
+ /* omit other field initialization */
+ }
+ else if (ipr->ipr_origin < PR_ORIG_RR) {
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ noticelog("<%s> Added prefix(%s)'s origin %d is"
+ "lower than PR_ORIG_RR(router renumbering)."
+ "This should not happen if I am router", __func__,
+ inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), ipr->ipr_origin);
+ close(s);
+ return 1;
+ }
+
+ close(s);
+ return 0;
+#else
+ ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
+ ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
+ ipr->ipr_raf_onlink = 1;
+ ipr->ipr_raf_auto = 1;
+ return 0;
+#endif
+}
+
+void
+make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
+{
+ struct in6_prefixreq ipr;
+
+ memset(&ipr, 0, sizeof(ipr));
+ if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
+ errorlog("<%s> Prefix added interface No.%d doesn't"
+ "exist. This should not happen! %s", __func__,
+ ifindex, strerror(errno));
+ exit(1);
+ }
+ ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
+ ipr.ipr_prefix.sin6_family = AF_INET6;
+ ipr.ipr_prefix.sin6_addr = *addr;
+ ipr.ipr_plen = plen;
+
+ if (init_prefix(&ipr))
+ return; /* init failed by some error */
+ add_prefix(rai, &ipr);
+}
+
+void
+make_packet(struct rainfo *rainfo)
+{
+ size_t packlen, lladdroptlen = 0;
+ u_char *buf;
+ struct nd_router_advert *ra;
+ struct nd_opt_prefix_info *ndopt_pi;
+ struct nd_opt_mtu *ndopt_mtu;
+#ifdef ROUTEINFO
+ struct nd_opt_route_info *ndopt_rti;
+ struct rtinfo *rti;
+#endif
+ struct prefix *pfx;
+
+ /* calculate total length */
+ packlen = sizeof(struct nd_router_advert);
+ if (rainfo->advlinkopt) {
+ if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
+ infolog("<%s> link-layer address option has"
+ " null length on %s. Treat as not included.",
+ __func__, rainfo->ifname);
+ rainfo->advlinkopt = 0;
+ }
+ packlen += lladdroptlen;
+ }
+ if (rainfo->pfxs)
+ packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
+ if (rainfo->linkmtu)
+ packlen += sizeof(struct nd_opt_mtu);
+#ifdef ROUTEINFO
+ for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next)
+ packlen += sizeof(struct nd_opt_route_info) +
+ ((rti->prefixlen + 0x3f) >> 6) * 8;
+#endif
+ if (rainfo->rdnss_length > 0)
+ packlen += 8 + sizeof(struct in6_addr) * rainfo->rdnss_length;
+
+ if (rainfo->dnssl_length > 0) {
+ packlen += rainfo->dnssl_option_length;
+ }
+ if (rainfo->capport_option_length != 0) {
+ packlen += rainfo->capport_option_length;
+ }
+
+ /* allocate memory for the packet */
+ if ((buf = malloc(packlen)) == NULL) {
+ errorlog("<%s> can't get enough memory for an RA packet",
+ __func__);
+ exit(1);
+ }
+ if (rainfo->ra_data) {
+ /* free the previous packet */
+ free(rainfo->ra_data);
+ rainfo->ra_data = NULL;
+ }
+ rainfo->ra_data = buf;
+ /* XXX: what if packlen > 576? */
+ rainfo->ra_datalen = packlen;
+
+ /*
+ * construct the packet
+ */
+ ra = (struct nd_router_advert *)buf;
+ ra->nd_ra_type = ND_ROUTER_ADVERT;
+ ra->nd_ra_code = 0;
+ ra->nd_ra_cksum = 0;
+ ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
+ ra->nd_ra_flags_reserved = 0; /* just in case */
+ /*
+ * XXX: the router preference field, which is a 2-bit field, should be
+ * initialized before other fields.
+ */
+ ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
+ ra->nd_ra_flags_reserved |=
+ rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
+ ra->nd_ra_flags_reserved |=
+ rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
+ ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
+ ra->nd_ra_reachable = htonl(rainfo->reachabletime);
+ ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
+ buf += sizeof(*ra);
+
+ if (rainfo->advlinkopt) {
+ lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
+ buf += lladdroptlen;
+ }
+
+ if (rainfo->linkmtu) {
+ ndopt_mtu = (struct nd_opt_mtu *)buf;
+ ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
+ ndopt_mtu->nd_opt_mtu_len = 1;
+ ndopt_mtu->nd_opt_mtu_reserved = 0;
+ ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
+ buf += sizeof(struct nd_opt_mtu);
+ }
+
+ for (pfx = rainfo->prefix.next;
+ pfx != &rainfo->prefix; pfx = pfx->next) {
+ u_int32_t vltime, pltime;
+ struct timeval now;
+
+ ndopt_pi = (struct nd_opt_prefix_info *)buf;
+ ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+ ndopt_pi->nd_opt_pi_len = 4;
+ ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
+ ndopt_pi->nd_opt_pi_flags_reserved = 0;
+ if (pfx->onlinkflg)
+ ndopt_pi->nd_opt_pi_flags_reserved |=
+ ND_OPT_PI_FLAG_ONLINK;
+ if (pfx->autoconfflg)
+ ndopt_pi->nd_opt_pi_flags_reserved |=
+ ND_OPT_PI_FLAG_AUTO;
+ if (pfx->timer)
+ vltime = 0;
+ else {
+ if (pfx->vltimeexpire || pfx->pltimeexpire)
+ gettimeofday(&now, NULL);
+ if (pfx->vltimeexpire == 0)
+ vltime = pfx->validlifetime;
+ else
+ vltime = (pfx->vltimeexpire > now.tv_sec) ?
+ pfx->vltimeexpire - now.tv_sec : 0;
+ }
+ if (pfx->timer)
+ pltime = 0;
+ else {
+ if (pfx->pltimeexpire == 0)
+ pltime = pfx->preflifetime;
+ else
+ pltime = (pfx->pltimeexpire > now.tv_sec) ?
+ pfx->pltimeexpire - now.tv_sec : 0;
+ }
+ if (vltime < pltime) {
+ /*
+ * this can happen if vltime is decrement but pltime
+ * is not.
+ */
+ pltime = vltime;
+ }
+ ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
+ ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
+ ndopt_pi->nd_opt_pi_reserved2 = 0;
+ ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
+
+ buf += sizeof(struct nd_opt_prefix_info);
+ }
+
+#ifdef ROUTEINFO
+ for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
+ u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
+
+ ndopt_rti = (struct nd_opt_route_info *)buf;
+ ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
+ ndopt_rti->nd_opt_rti_len = 1 + psize;
+ ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
+ ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
+ ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime);
+ memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
+ buf += sizeof(struct nd_opt_route_info) + psize * 8;
+ }
+#endif
+
+ if (rainfo->rdnss_length > 0) {
+ struct nd_opt_rdnss * ndopt_rdnss;
+ struct rdnss * rdnss;
+
+ ndopt_rdnss = (struct nd_opt_rdnss*) buf;
+ ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ ndopt_rdnss->nd_opt_rdnss_len = 1 + (rainfo->rdnss_length * 2);
+ ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+ ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rainfo->rdnss_lifetime);
+ buf += 8;
+
+ for (rdnss = rainfo->rdnss_list.next;
+ rdnss != &rainfo->rdnss_list;
+ rdnss = rdnss->next)
+ {
+ struct in6_addr* addr6 = (struct in6_addr*) buf;
+ *addr6 = rdnss->addr;
+ buf += sizeof *addr6;
+ }
+ }
+
+ if (rainfo->dnssl_length > 0) {
+ struct nd_opt_dnssl * dnssl_opt;
+ struct dnssl * dnssl;
+ int domains_length = 0;
+ u_char * cursor = buf;
+
+ memset(cursor, 0, rainfo->dnssl_option_length);
+
+ dnssl_opt = (struct nd_opt_dnssl *)cursor;
+ dnssl_opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ /*
+ * Length is in units of 8 octets. Divide total byte length
+ * of the option by 8.
+ */
+ dnssl_opt->nd_opt_dnssl_len = rainfo->dnssl_option_length >> 3;
+ dnssl_opt->nd_opt_dnssl_reserved = 0;
+ dnssl_opt->nd_opt_dnssl_lifetime =
+ htonl(rainfo->dnssl_lifetime);
+
+ cursor += offsetof(struct nd_opt_dnssl, nd_opt_dnssl_domains);
+
+ for (dnssl = rainfo->dnssl_list.next;
+ dnssl != &rainfo->dnssl_list;
+ dnssl = dnssl->next)
+ {
+ int encodeLen = encode_domain(dnssl->domain, cursor);
+ cursor += encodeLen;
+ domains_length += encodeLen;
+ }
+
+ buf += rainfo->dnssl_option_length;
+ }
+ if (rainfo->capport != NULL) {
+ struct nd_opt_hdr * capport_opt;
+ u_int32_t zero_space;
+
+ capport_opt = (struct nd_opt_hdr *)buf;
+#ifndef ND_OPT_CAPTIVE_PORTAL
+#define ND_OPT_CAPTIVE_PORTAL 37 /* RFC 7710 */
+#endif /* ND_OPT_CAPTIVE_PORTAL */
+ capport_opt->nd_opt_type = ND_OPT_CAPTIVE_PORTAL;
+ capport_opt->nd_opt_len = rainfo->capport_option_length >> 3;
+ buf += sizeof(*capport_opt);
+ bcopy(rainfo->capport, buf, rainfo->capport_length);
+ buf += rainfo->capport_length;
+ zero_space = rainfo->capport_option_length
+ - rainfo->capport_length;
+ if (zero_space > 0) {
+ bzero(buf, zero_space);
+ buf += zero_space;
+ }
+ }
+ return;
+}
+
+static int
+getinet6sysctl(int code)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+ int value;
+ size_t size;
+
+ mib[3] = code;
+ size = sizeof(value);
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
+ < 0) {
+ errorlog( "<%s>: failed to get ip6 sysctl(%d): %s",
+ __func__, code,
+ strerror(errno));
+ return(-1);
+ }
+ else
+ return(value);
+}
+
+/*
+ * Encode a domain name into a buffer according to the rules in RFC 1035 section
+ * 3.1. Do not use the compression techniques outlined in section 4.1.4.
+ */
+int
+encode_domain(char *domain, u_char *dst)
+{
+ char *domainCopy = strdup(domain);
+ char *input = domainCopy;
+ char *label;
+ u_char *cursor = dst;
+
+ while ((label = strsep(&input, ".")) != NULL) {
+ int label_len = strlen(label) & 0x3f; /* Max length is 63 */
+ if (label_len > 0) {
+ *cursor = (u_char)label_len;
+ cursor++;
+ memcpy(cursor, label, label_len);
+ cursor += label_len;
+ }
+ }
+ *cursor = 0;
+ cursor++;
+
+ free(domainCopy);
+
+ return (cursor - dst);
+}
diff --git a/network_cmds/rtadvd.tproj/config.h b/network_cmds/rtadvd.tproj/config.h
new file mode 100644
index 0000000..f1f0387
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/config.h
@@ -0,0 +1,46 @@
+/* $KAME: config.h,v 1.8 2003/06/17 08:26:22 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+extern void getconfig(char *);
+extern void delete_prefix(struct prefix *);
+extern void invalidate_prefix(struct prefix *);
+extern void update_prefix(struct prefix *);
+extern void make_prefix(struct rainfo *, int, struct in6_addr *, int);
+extern void make_packet(struct rainfo *);
+extern void get_prefix(struct rainfo *);
+
+
+/*
+ * it is highly unlikely to have 100 prefix information options,
+ * so it should be okay to limit it
+ */
+#define MAXPREFIX 100
+#define MAXROUTE 100
diff --git a/network_cmds/rtadvd.tproj/dump.c b/network_cmds/rtadvd.tproj/dump.c
new file mode 100644
index 0000000..ea5dcd9
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/dump.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: dump.c,v 1.32 2003/05/19 09:46:50 keiichi Exp $ */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+
+/* XXX: the following two are non-standard include files */
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "rtadvd.h"
+#include "timer.h"
+#include "if.h"
+#include "dump.h"
+
+static FILE *fp;
+
+extern struct rainfo *ralist;
+
+static char *ether_str(struct sockaddr_dl *);
+static void if_dump(void);
+
+static char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+};
+
+static char *
+ether_str(sdl)
+ struct sockaddr_dl *sdl;
+{
+ static char hbuf[32];
+ u_char *cp;
+
+ if (sdl->sdl_alen && sdl->sdl_alen > 5) {
+ cp = (u_char *)LLADDR(sdl);
+ snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ } else
+ snprintf(hbuf, sizeof(hbuf), "NONE");
+
+ return(hbuf);
+}
+
+static void
+if_dump()
+{
+ struct rainfo *rai;
+ struct prefix *pfx;
+#ifdef ROUTEINFO
+ struct rtinfo *rti;
+#endif
+ char prefixbuf[INET6_ADDRSTRLEN];
+ int first;
+ struct timeval now;
+
+ gettimeofday(&now, NULL); /* XXX: unused in most cases */
+ for (rai = ralist; rai; rai = rai->next) {
+ fprintf(fp, "%s:\n", rai->ifname);
+ struct if_msghdr *ifm = get_interface_entry(rai->ifindex);
+ if (ifm == NULL) {
+ debuglog("Skippingg RA entry for interface %s"
+ "as we couldn't find interface entry for it.", rai->ifname);
+ continue;
+ }
+ fprintf(fp, " Status: %s\n",
+ (ifm->ifm_flags & IFF_UP) ? "UP" :
+ "DOWN");
+
+ /* control information */
+ if (rai->lastsent.tv_sec) {
+ /* note that ctime() appends CR by itself */
+ fprintf(fp, " Last RA sent: %s",
+ ctime((time_t *)&rai->lastsent.tv_sec));
+ }
+ if (rai->timer) {
+ fprintf(fp, " Next RA will be sent: %s",
+ ctime((time_t *)&rai->timer->tm.tv_sec));
+ }
+ else
+ fprintf(fp, " RA timer is stopped");
+ fprintf(fp, " waits: %d, initcount: %d\n",
+ rai->waiting, rai->initcounter);
+
+ /* statistics */
+ fprintf(fp, " statistics: RA(out/in/inconsistent): "
+ "%llu/%llu/%llu, ",
+ (unsigned long long)rai->raoutput,
+ (unsigned long long)rai->rainput,
+ (unsigned long long)rai->rainconsistent);
+ fprintf(fp, "RS(input): %llu\n",
+ (unsigned long long)rai->rsinput);
+
+ /* interface information */
+ if (rai->advlinkopt)
+ fprintf(fp, " Link-layer address: %s\n",
+ ether_str(rai->sdl));
+ fprintf(fp, " MTU: %d\n", rai->phymtu);
+
+ /* Router configuration variables */
+ fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, "
+ "MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval,
+ rai->mininterval);
+ fprintf(fp, " Flags: %s%s%s, ",
+ rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", "");
+ fprintf(fp, "Preference: %s, ",
+ rtpref_str[(rai->rtpref >> 3) & 0xff]);
+ fprintf(fp, "MTU: %d\n", rai->linkmtu);
+ fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
+ "CurHopLimit: %d\n", rai->reachabletime,
+ rai->retranstimer, rai->hoplimit);
+ if (rai->clockskew)
+ fprintf(fp, " Clock skew: %ldsec\n",
+ rai->clockskew);
+ for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix;
+ pfx = pfx->next) {
+ if (first) {
+ fprintf(fp, " Prefixes:\n");
+ first = 0;
+ }
+ fprintf(fp, " %s/%d(",
+ inet_ntop(AF_INET6, &pfx->prefix, prefixbuf,
+ sizeof(prefixbuf)), pfx->prefixlen);
+ switch (pfx->origin) {
+ case PREFIX_FROM_KERNEL:
+ fprintf(fp, "KERNEL, ");
+ break;
+ case PREFIX_FROM_CONFIG:
+ fprintf(fp, "CONFIG, ");
+ break;
+ case PREFIX_FROM_DYNAMIC:
+ fprintf(fp, "DYNAMIC, ");
+ break;
+ }
+ if (pfx->validlifetime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "vltime: infinity");
+ else
+ fprintf(fp, "vltime: %ld",
+ (long)pfx->validlifetime);
+ if (pfx->vltimeexpire != 0)
+ fprintf(fp, "(decr,expire %ld), ", (long)
+ pfx->vltimeexpire > now.tv_sec ?
+ pfx->vltimeexpire - now.tv_sec : 0);
+ else
+ fprintf(fp, ", ");
+ if (pfx->preflifetime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "pltime: infinity");
+ else
+ fprintf(fp, "pltime: %ld",
+ (long)pfx->preflifetime);
+ if (pfx->pltimeexpire != 0)
+ fprintf(fp, "(decr,expire %ld), ", (long)
+ pfx->pltimeexpire > now.tv_sec ?
+ pfx->pltimeexpire - now.tv_sec : 0);
+ else
+ fprintf(fp, ", ");
+ fprintf(fp, "flags: %s%s%s",
+ pfx->onlinkflg ? "L" : "",
+ pfx->autoconfflg ? "A" : "",
+ "");
+ if (pfx->timer) {
+ struct timeval *rest;
+
+ rest = rtadvd_timer_rest(pfx->timer);
+ if (rest) { /* XXX: what if not? */
+ fprintf(fp, ", expire in: %ld",
+ (long)rest->tv_sec);
+ }
+ }
+ fprintf(fp, ")\n");
+ }
+#ifdef ROUTEINFO
+ for (first = 1, rti = rai->route.next; rti != &rai->route;
+ rti = rti->next) {
+ if (first) {
+ fprintf(fp, " Route Information:\n");
+ first = 0;
+ }
+ fprintf(fp, " %s/%d (",
+ inet_ntop(AF_INET6, &rti->prefix,
+ prefixbuf, sizeof(prefixbuf)),
+ rti->prefixlen);
+ fprintf(fp, "preference: %s, ",
+ rtpref_str[0xff & (rti->rtpref >> 3)]);
+ if (rti->ltime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "lifetime: infinity");
+ else
+ fprintf(fp, "lifetime: %ld", (long)rti->ltime);
+ fprintf(fp, ")\n");
+ }
+#endif
+ }
+}
+
+void
+rtadvd_dump_file(dumpfile)
+ char *dumpfile;
+{
+ debuglog("<%s> dump current status to %s", __func__,
+ dumpfile);
+
+ if ((fp = fopen(dumpfile, "w")) == NULL) {
+ errorlog("<%s> open a dump file(%s)",
+ __func__, dumpfile);
+ return;
+ }
+
+ if_dump();
+
+ fclose(fp);
+}
diff --git a/network_cmds/rtadvd.tproj/dump.h b/network_cmds/rtadvd.tproj/dump.h
new file mode 100644
index 0000000..4e10b4a
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/dump.h
@@ -0,0 +1,32 @@
+/* $KAME: dump.h,v 1.1 2000/05/23 11:31:26 itojun Exp $ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+extern void rtadvd_dump_file(char *);
diff --git a/network_cmds/rtadvd.tproj/if.c b/network_cmds/rtadvd.tproj/if.c
new file mode 100644
index 0000000..9862af2
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/if.c
@@ -0,0 +1,604 @@
+/* $KAME: if.c,v 1.17 2001/01/21 15:27:30 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.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <ifaddrs.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rtadvd.h"
+#include "if.h"
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
+ sizeof(uint32_t)) :\
+ sizeof(uint32_t)))
+
+/* Interface list */
+TAILQ_HEAD(ifilist_head_t, ifinfo);
+struct ifilist_head_t ifilist = TAILQ_HEAD_INITIALIZER(ifilist);
+size_t ifblock_size;
+char *ifblock;
+
+static void get_iflist(char **buf, size_t *size);
+static void parse_iflist(char *buf, size_t bufsize);
+static void purge_iflist();
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ NEXT_SA(sa);
+ }
+ else
+ rti_info[i] = NULL;
+ }
+}
+
+struct sockaddr_dl *
+if_nametosdl(char *name)
+{
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
+ char *buf, *next, *lim;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ struct sockaddr_dl *sdl = NULL, *ret_sdl = NULL;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(NULL);
+ if ((buf = malloc(len)) == NULL)
+ return(NULL);
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return(NULL);
+ }
+
+ lim = buf + len;
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sa = (struct sockaddr *)(ifm + 1);
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
+ if ((sa = rti_info[RTAX_IFP]) != NULL) {
+ if (sa->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)sa;
+ if (strlen(name) != sdl->sdl_nlen)
+ continue; /* not same len */
+ if (strncmp(&sdl->sdl_data[0],
+ name,
+ sdl->sdl_nlen) == 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (next == lim) {
+ /* search failed */
+ free(buf);
+ return(NULL);
+ }
+
+ if (sdl == NULL || (ret_sdl = malloc(sdl->sdl_len)) == NULL)
+ goto end;
+ memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
+
+end:
+ free(buf);
+ return(ret_sdl);
+}
+
+int
+if_getmtu(char *name)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct if_data *ifd;
+ int mtu = 0;
+
+ if (getifaddrs(&ifap) < 0)
+ return(0);
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (strcmp(ifa->ifa_name, name) == 0) {
+ ifd = ifa->ifa_data;
+ if (ifd)
+ mtu = ifd->ifi_mtu;
+ break;
+ }
+ }
+ freeifaddrs(ifap);
+
+#ifdef SIOCGIFMTU /* XXX: this ifdef may not be necessary */
+ if (mtu == 0) {
+ struct ifreq ifr;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ return(0);
+
+ ifr.ifr_addr.sa_family = AF_INET6;
+ strlcpy(ifr.ifr_name, name,
+ sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
+ close(s);
+ return(0);
+ }
+ close(s);
+
+ mtu = ifr.ifr_mtu;
+ }
+#endif
+
+ return(mtu);
+}
+
+/* give interface index and its old flags, then new flags returned */
+int
+if_getflags(int ifindex, int oifflags)
+{
+ struct ifreq ifr;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ return (oifflags & ~IFF_UP);
+ }
+
+ if_indextoname(ifindex, ifr.ifr_name);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ errorlog("<%s> ioctl:SIOCGIFFLAGS: failed for %s",
+ __func__, ifr.ifr_name);
+ close(s);
+ return (oifflags & ~IFF_UP);
+ }
+ close(s);
+ return (ifr.ifr_flags);
+}
+
+#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
+int
+lladdropt_length(struct sockaddr_dl *sdl)
+{
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ default:
+ return(0);
+ }
+}
+
+void
+lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
+{
+ char *addr;
+
+ ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
+
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
+ addr = (char *)(ndopt + 1);
+ memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ default:
+ errorlog("<%s> unsupported link type(%d)",
+ __func__, sdl->sdl_type);
+ exit(1);
+ }
+
+ return;
+}
+
+int
+rtbuf_len()
+{
+ size_t len;
+
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(-1);
+
+ return(len);
+}
+
+#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
+#define SIN6(s) ((struct sockaddr_in6 *)(s))
+#define SDL(s) ((struct sockaddr_dl *)(s))
+char *
+get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
+{
+ struct rt_msghdr *rtm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
+
+ *lenp = 0;
+ for (rtm = (struct rt_msghdr *)buf;
+ rtm < (struct rt_msghdr *)lim;
+ rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
+ /* just for safety */
+ if (!rtm->rtm_msglen) {
+ errorlog("<%s> rtm_msglen is 0 "
+ "(buf=%p lim=%p rtm=%p)", __func__,
+ buf, lim, rtm);
+ break;
+ }
+ if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
+ continue;
+ }
+
+ switch (rtm->rtm_type) {
+ case RTM_GET:
+ case RTM_ADD:
+ case RTM_DELETE:
+ /* address related checks */
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ if ((dst = rti_info[RTAX_DST]) == NULL ||
+ dst->sa_family != AF_INET6)
+ continue;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
+ continue;
+
+ if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
+ gw->sa_family != AF_LINK)
+ continue;
+ if (ifindex && SDL(gw)->sdl_index != ifindex)
+ continue;
+
+ if (rti_info[RTAX_NETMASK] == NULL)
+ continue;
+
+ /* found */
+ *lenp = rtm->rtm_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+
+ /* address related checks */
+ sa = (struct sockaddr *)(ifam + 1);
+ get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
+ if ((ifa = rti_info[RTAX_IFA]) == NULL ||
+ (ifa->sa_family != AF_INET &&
+ ifa->sa_family != AF_INET6))
+ continue;
+
+ if (ifa->sa_family == AF_INET6 &&
+ (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
+ continue;
+
+ if (ifindex && ifam->ifam_index != ifindex)
+ continue;
+
+ /* found */
+ *lenp = ifam->ifam_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ case RTM_IFINFO:
+ /* found */
+ *lenp = rtm->rtm_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ }
+ }
+
+ return (char *)rtm;
+}
+#undef FILTER_MATCH
+
+struct in6_addr *
+get_addr(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+ return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
+}
+
+int
+get_rtm_ifindex(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+ return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
+}
+
+int
+get_ifm_ifindex(char *buf)
+{
+ struct if_msghdr *ifm = (struct if_msghdr *)buf;
+
+ return ((int)ifm->ifm_index);
+}
+
+int
+get_ifam_ifindex(char *buf)
+{
+ struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf;
+
+ return ((int)ifam->ifam_index);
+}
+
+int
+get_ifm_flags(char *buf)
+{
+ struct if_msghdr *ifm = (struct if_msghdr *)buf;
+
+ return (ifm->ifm_flags);
+}
+
+int
+get_prefixlen(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ u_char *p, *lim;
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ sa = rti_info[RTAX_NETMASK];
+
+ p = (u_char *)(&SIN6(sa)->sin6_addr);
+ lim = (u_char *)sa + sa->sa_len;
+ return prefixlen(p, lim);
+}
+
+int
+prefixlen(u_char *p, u_char *lim)
+{
+ int masklen;
+
+ for (masklen = 0; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ return(-1);
+ }
+ }
+
+ return(masklen);
+}
+
+int
+rtmsg_type(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+
+ return(rtm->rtm_type);
+}
+
+int
+rtmsg_len(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+
+ return(rtm->rtm_msglen);
+}
+
+int
+ifmsg_len(char *buf)
+{
+ struct if_msghdr *ifm = (struct if_msghdr *)buf;
+
+ return(ifm->ifm_msglen);
+}
+
+/*
+ * alloc buffer and get if_msghdrs block from kernel,
+ * and put them into the buffer
+ */
+static void
+get_iflist(char **buf, size_t *size)
+{
+ int mib[6];
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
+ errorlog("<%s> sysctl: iflist size get failed",
+ __func__);
+ exit(1);
+ }
+ if ((*buf = malloc(*size)) == NULL) {
+ errorlog("<%s> malloc failed", __func__);
+ exit(1);
+ }
+ if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
+ errorlog("<%s> sysctl: iflist get failed",
+ __func__);
+ exit(1);
+ }
+ return;
+}
+
+struct if_msghdr *
+get_interface_entry(int if_index)
+{
+ struct ifinfo *ifi = NULL;
+ struct if_msghdr *ifm = NULL;
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (if_index == ifi->ifm->ifm_index) {
+ ifm = ifi->ifm;
+ break;
+ }
+ }
+ return ifm;
+}
+
+/*
+ * alloc buffer and parse if_msghdrs block passed as arg,
+ * and init the buffer as list of pointers ot each of the if_msghdr.
+ */
+static void
+parse_iflist(char *buf, size_t bufsize)
+{
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ char *lim;
+
+ lim = buf + bufsize;
+ for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
+ if (ifm->ifm_msglen == 0) {
+ errorlog("<%s> ifm_msglen is 0 "
+ "(buf=%p lim=%p ifm=%p)", __func__,
+ buf, lim, ifm);
+ return;
+ }
+
+ if (ifm->ifm_type == RTM_IFINFO) {
+ struct ifinfo *ifi = NULL;
+
+ if (get_interface_entry(ifm->ifm_index) != NULL) {
+ debuglog("Interface entry is already present for "
+ "interface index: %d. Skipping.", ifm->ifm_index);
+ continue;
+ }
+
+ ELM_MALLOC(ifi, exit(1));
+ ifi->ifm = ifm;
+ TAILQ_INSERT_TAIL(&ifilist, ifi, ifi_next);
+ } else {
+ errorlog("out of sync parsing NET_RT_IFLIST\n"
+ "expected %d, got %d\n msglen = %d\n"
+ "buf:%p, ifm:%p, lim:%p\n",
+ RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
+ buf, ifm, lim);
+ exit (1);
+ }
+ for (ifam = (struct ifa_msghdr *)
+ ((char *)ifm + ifm->ifm_msglen);
+ ifam < (struct ifa_msghdr *)lim;
+ ifam = (struct ifa_msghdr *)
+ ((char *)ifam + ifam->ifam_msglen)) {
+ /* just for safety */
+ if (!ifam->ifam_msglen) {
+ errorlog("<%s> ifa_msglen is 0 "
+ "(buf=%p lim=%p ifam=%p)", __func__,
+ buf, lim, ifam);
+ return;
+ }
+ if (ifam->ifam_type != RTM_NEWADDR)
+ break;
+ }
+ ifm = (struct if_msghdr *)ifam;
+ }
+}
+
+static void
+purge_iflist()
+{
+ struct ifinfo *ifi = NULL;
+ if (!TAILQ_EMPTY(&ifilist)) {
+ while ((ifi = TAILQ_FIRST(&ifilist)) != NULL) {
+ TAILQ_REMOVE(&ifilist, ifi, ifi_next);
+ free(ifi);
+ }
+ }
+}
+
+void
+init_iflist()
+{
+ purge_iflist();
+
+ if (ifblock) {
+ free(ifblock);
+ ifblock_size = 0;
+ }
+
+ /* get iflist block from kernel */
+ get_iflist(&ifblock, &ifblock_size);
+
+ /* make list of pointers to each if_msghdr */
+ parse_iflist(ifblock, ifblock_size);
+}
diff --git a/network_cmds/rtadvd.tproj/if.h b/network_cmds/rtadvd.tproj/if.h
new file mode 100644
index 0000000..e733d63
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/if.h
@@ -0,0 +1,64 @@
+/* $KAME: if.h,v 1.10 2003/02/24 11:29:10 ono Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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.
+ */
+
+#define RTADV_TYPE2BITMASK(type) (0x1 << type)
+
+extern size_t ifblock_size;
+extern char *ifblock;
+
+struct nd_opt_hdr;
+struct sockaddr_dl *if_nametosdl(char *);
+int if_getmtu(char *);
+int if_getflags(int, int);
+int lladdropt_length(struct sockaddr_dl *);
+void lladdropt_fill(struct sockaddr_dl *, struct nd_opt_hdr *);
+int rtbuf_len(void);
+char *get_next_msg(char *, char *, int, size_t *, int);
+struct in6_addr *get_addr(char *);
+int get_rtm_ifindex(char *);
+int get_ifm_ifindex(char *);
+int get_ifam_ifindex(char *);
+int get_ifm_flags(char *);
+int get_prefixlen(char *);
+int prefixlen(u_char *, u_char *);
+int rtmsg_type(char *);
+int ifmsg_type(char *);
+int rtmsg_len(char *);
+int ifmsg_len(char *);
+void init_iflist(void);
+
+struct ifinfo {
+ TAILQ_ENTRY(ifinfo) ifi_next;
+ struct if_msghdr * ifm;
+};
+
+struct if_msghdr *get_interface_entry(int if_index);
+
diff --git a/network_cmds/rtadvd.tproj/pathnames.h b/network_cmds/rtadvd.tproj/pathnames.h
new file mode 100644
index 0000000..d288ab9
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/pathnames.h
@@ -0,0 +1,4 @@
+/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */
+/* $FreeBSD: src/usr.sbin/rtadvd/pathnames.h,v 1.2.2.2 2001/07/03 11:02:14 ume Exp $ */
+
+#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
diff --git a/network_cmds/rtadvd.tproj/rrenum.c b/network_cmds/rtadvd.tproj/rrenum.c
new file mode 100644
index 0000000..ae04a55
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rrenum.c
@@ -0,0 +1,484 @@
+/* $KAME: rrenum.c,v 1.12 2002/06/10 19:59:47 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.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rtadvd.h"
+#include "rrenum.h"
+#include "if.h"
+
+#define RR_ISSET_SEGNUM(segnum_bits, segnum) \
+ ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0)
+#define RR_SET_SEGNUM(segnum_bits, segnum) \
+ (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31)))
+
+struct rr_operation {
+ u_long rro_seqnum;
+ u_long rro_segnum_bits[8];
+};
+
+static struct rr_operation rro;
+static int rr_rcvifindex;
+static int rrcmd2pco[RPM_PCO_MAX] = {
+ 0,
+ SIOCAIFPREFIX_IN6,
+ SIOCCIFPREFIX_IN6,
+ SIOCSGIFPREFIX_IN6
+};
+static int s = -1;
+
+/*
+ * Check validity of a Prefix Control Operation(PCO).
+ * Return 0 on success, 1 on failure.
+ */
+static int
+rr_pco_check(int len, struct rr_pco_match *rpm)
+{
+ struct rr_pco_use *rpu, *rpulim;
+ int checklen;
+
+ /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */
+ if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */
+ (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */
+ errorlog("<%s> rpm_len %d is not 4N * 3",
+ __func__, rpm->rpm_len);
+ return 1;
+ }
+ /* rpm->rpm_code must be valid value */
+ switch (rpm->rpm_code) {
+ case RPM_PCO_ADD:
+ case RPM_PCO_CHANGE:
+ case RPM_PCO_SETGLOBAL:
+ break;
+ default:
+ errorlog("<%s> unknown rpm_code %d", __func__,
+ rpm->rpm_code);
+ return 1;
+ }
+ /* rpm->rpm_matchlen must be 0 to 128 inclusive */
+ if (rpm->rpm_matchlen > 128) {
+ errorlog("<%s> rpm_matchlen %d is over 128",
+ __func__, rpm->rpm_matchlen);
+ return 1;
+ }
+
+ /*
+ * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be
+ * between 0 and 128 inclusive
+ */
+ for (rpu = (struct rr_pco_use *)(rpm + 1),
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+ rpu < rpulim;
+ rpu += 1) {
+ checklen = rpu->rpu_uselen;
+ checklen += rpu->rpu_keeplen;
+ /*
+ * omit these check, because either of rpu_uselen
+ * and rpu_keeplen is unsigned char
+ * (128 > rpu_uselen > 0)
+ * (128 > rpu_keeplen > 0)
+ * (rpu_uselen + rpu_keeplen > 0)
+ */
+ if (checklen > 128) {
+ errorlog("<%s> sum of rpu_uselen %d and"
+ " rpu_keeplen %d is %d(over 128)",
+ __func__, rpu->rpu_uselen,
+ rpu->rpu_keeplen,
+ rpu->rpu_uselen + rpu->rpu_keeplen);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+do_use_prefix(int len, struct rr_pco_match *rpm,
+ struct in6_rrenumreq *irr, int ifindex)
+{
+ struct rr_pco_use *rpu, *rpulim;
+ struct rainfo *rai;
+ struct prefix *pp;
+
+ rpu = (struct rr_pco_use *)(rpm + 1);
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+
+ if (rpu == rpulim) { /* no use prefix */
+ if (rpm->rpm_code == RPM_PCO_ADD)
+ return;
+
+ irr->irr_u_uselen = 0;
+ irr->irr_u_keeplen = 0;
+ irr->irr_raf_mask_onlink = 0;
+ irr->irr_raf_mask_auto = 0;
+ irr->irr_vltime = 0;
+ irr->irr_pltime = 0;
+ memset(&irr->irr_flags, 0, sizeof(irr->irr_flags));
+ irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */
+ irr->irr_useprefix.sin6_family = 0;
+ irr->irr_useprefix.sin6_addr = in6addr_any;
+ if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
+ errno != EADDRNOTAVAIL)
+ errorlog("<%s> ioctl: %s", __func__,
+ strerror(errno));
+ return;
+ }
+
+ for (rpu = (struct rr_pco_use *)(rpm + 1),
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+ rpu < rpulim;
+ rpu += 1) {
+ /* init in6_rrenumreq fields */
+ irr->irr_u_uselen = rpu->rpu_uselen;
+ irr->irr_u_keeplen = rpu->rpu_keeplen;
+ irr->irr_raf_mask_onlink =
+ !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
+ irr->irr_raf_mask_auto =
+ !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
+ irr->irr_vltime = ntohl(rpu->rpu_vltime);
+ irr->irr_pltime = ntohl(rpu->rpu_pltime);
+ irr->irr_raf_onlink =
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1;
+ irr->irr_raf_auto =
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1;
+ irr->irr_rrf_decrvalid =
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1;
+ irr->irr_rrf_decrprefd =
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1;
+ irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix);
+ irr->irr_useprefix.sin6_family = AF_INET6;
+ irr->irr_useprefix.sin6_addr = rpu->rpu_prefix;
+
+ if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
+ errno != EADDRNOTAVAIL)
+ errorlog("<%s> ioctl: %s", __func__,
+ strerror(errno));
+
+ /* very adhoc: should be rewritten */
+ if (rpm->rpm_code == RPM_PCO_CHANGE &&
+ IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) &&
+ rpm->rpm_matchlen == rpu->rpu_uselen &&
+ rpu->rpu_uselen == rpu->rpu_keeplen) {
+ if ((rai = if_indextorainfo(ifindex)) == NULL)
+ continue; /* non-advertising IF */
+
+ for (pp = rai->prefix.next; pp != &rai->prefix;
+ pp = pp->next) {
+ struct timeval now;
+
+ if (prefix_match(&pp->prefix, pp->prefixlen,
+ &rpm->rpm_prefix,
+ rpm->rpm_matchlen)) {
+ /* change parameters */
+ pp->validlifetime = ntohl(rpu->rpu_vltime);
+ pp->preflifetime = ntohl(rpu->rpu_pltime);
+ if (irr->irr_rrf_decrvalid) {
+ gettimeofday(&now, 0);
+ pp->vltimeexpire =
+ now.tv_sec + pp->validlifetime;
+ } else
+ pp->vltimeexpire = 0;
+ if (irr->irr_rrf_decrprefd) {
+ gettimeofday(&now, 0);
+ pp->pltimeexpire =
+ now.tv_sec + pp->preflifetime;
+ } else
+ pp->pltimeexpire = 0;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * process a Prefix Control Operation(PCO).
+ * return 0 on success, 1 on failure
+ */
+static int
+do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
+{
+ int ifindex = 0;
+ struct in6_rrenumreq irr;
+
+ if ((rr_pco_check(len, rpm) != 0))
+ return 1;
+
+ if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+
+ memset(&irr, 0, sizeof(irr));
+ irr.irr_origin = PR_ORIG_RR;
+ irr.irr_m_len = rpm->rpm_matchlen;
+ irr.irr_m_minlen = rpm->rpm_minlen;
+ irr.irr_m_maxlen = rpm->rpm_maxlen;
+ irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix);
+ irr.irr_matchprefix.sin6_family = AF_INET6;
+ irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
+
+ while (if_indextoname(++ifindex, irr.irr_name)) {
+ struct if_msghdr * ifm = get_interface_entry(ifindex);
+ if (ifm == NULL) {
+ debuglog("Couldn't find interface entry for %d. Skipping.", ifindex);
+ continue;
+ }
+ /*
+ * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
+ * the interface is not applied
+ */
+ if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
+ (ifm->ifm_flags & IFF_UP) == 0)
+ continue;
+ /* TODO: interface scope check */
+ do_use_prefix(len, rpm, &irr, ifindex);
+ }
+ if (errno == ENXIO)
+ return 0;
+ else if (errno) {
+ errorlog("<%s> if_indextoname: %s", __func__,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * call do_pco() for each Prefix Control Operations(PCOs) in a received
+ * Router Renumbering Command packet.
+ * return 0 on success, 1 on failure
+ */
+static int
+do_rr(int len, struct icmp6_router_renum *rr)
+{
+ struct rr_pco_match *rpm;
+ char *cp, *lim;
+
+ lim = (char *)rr + len;
+ cp = (char *)(rr + 1);
+ len -= sizeof(struct icmp6_router_renum);
+
+ /* get iflist block from kernel again, to get up-to-date information */
+ init_iflist();
+
+ while (cp < lim) {
+ int rpmlen;
+
+ rpm = (struct rr_pco_match *)cp;
+ if (len < sizeof(struct rr_pco_match)) {
+ tooshort:
+ errorlog("<%s> pkt too short. left len = %d. "
+ "gabage at end of pkt?", __func__, len);
+ return 1;
+ }
+ rpmlen = rpm->rpm_len << 3;
+ if (len < rpmlen)
+ goto tooshort;
+
+ if (do_pco(rr, rpmlen, rpm)) {
+ errorlog("<%s> invalid PCO", __func__);
+ goto next;
+ }
+
+ next:
+ cp += rpmlen;
+ len -= rpmlen;
+ }
+
+ return 0;
+}
+
+/*
+ * check validity of a router renumbering command packet
+ * return 0 on success, 1 on failure
+ */
+static int
+rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
+ struct in6_addr *dst)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ /* omit rr minimal length check. hope kernel have done it. */
+ /* rr_command length check */
+ if (len < (sizeof(struct icmp6_router_renum) +
+ sizeof(struct rr_pco_match))) {
+ errorlog("<%s> rr_command len %d is too short",
+ __func__, len);
+ return 1;
+ }
+
+ /* destination check. only for multicast. omit unicast check. */
+ if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) &&
+ !IN6_IS_ADDR_MC_SITELOCAL(dst)) {
+ errorlog("<%s> dst mcast addr %s is illegal",
+ __func__,
+ inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN));
+ return 1;
+ }
+
+ /* seqnum and segnum check */
+ if (rro.rro_seqnum > rr->rr_seqnum) {
+ errorlog("<%s> rcvd old seqnum %d from %s",
+ __func__, (u_int32_t)ntohl(rr->rr_seqnum),
+ inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN));
+ return 1;
+ }
+ if (rro.rro_seqnum == rr->rr_seqnum &&
+ (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 &&
+ RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) {
+ if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0)
+ errorlog("<%s> rcvd duped segnum %d from %s",
+ __func__, rr->rr_segnum,
+ inet_ntop(AF_INET6, from, ntopbuf,
+ INET6_ADDRSTRLEN));
+ return 0;
+ }
+
+ /* update seqnum */
+ if (rro.rro_seqnum != rr->rr_seqnum) {
+ /* then must be "<" */
+
+ /* init rro_segnum_bits */
+ memset(rro.rro_segnum_bits, 0,
+ sizeof(rro.rro_segnum_bits));
+ }
+ rro.rro_seqnum = rr->rr_seqnum;
+
+ return 0;
+}
+
+static void
+rr_command_input(int len, struct icmp6_router_renum *rr,
+ struct in6_addr *from, struct in6_addr *dst)
+{
+ /* rr_command validity check */
+ if (rr_command_check(len, rr, from, dst))
+ goto failed;
+ if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) ==
+ ICMP6_RR_FLAGS_TEST)
+ return;
+
+ /* do router renumbering */
+ if (do_rr(len, rr)) {
+ goto failed;
+ }
+
+ /* update segnum */
+ RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum);
+
+ return;
+
+ failed:
+ errorlog("<%s> received RR was invalid", __func__);
+ return;
+}
+
+void
+rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
+ struct sockaddr_in6 *from, struct in6_addr *dst)
+{
+ char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+
+ debuglog("<%s> RR received from %s to %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* packet validation based on Section 4.1 of RFC2894 */
+ if (len < sizeof(struct icmp6_router_renum)) {
+ noticelog("<%s>: RR short message (size %d) from %s to %s on %s",
+ __func__, len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * If the IPv6 destination address is neither an All Routers multicast
+ * address [AARCH] nor one of the receiving router's unicast addresses,
+ * the message MUST be discarded and SHOULD be logged to network
+ * management.
+ * We rely on the kernel input routine for unicast addresses, and thus
+ * check multicast destinations only.
+ */
+ if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) &&
+ !IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) {
+ noticelog("<%s>: RR message with invalid destination (%s) "
+ "from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ rr_rcvifindex = pi->ipi6_ifindex;
+
+ switch (rr->rr_code) {
+ case ICMP6_ROUTER_RENUMBERING_COMMAND:
+ rr_command_input(len, rr, &from->sin6_addr, dst);
+ /* TODO: send reply msg */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_RESULT:
+ /* RESULT will be processed by rrenumd */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
+ /* TODO: sequence number reset */
+ break;
+ default:
+ errorlog("<%s> received unknown code %d",
+ __func__, rr->rr_code);
+ break;
+
+ }
+
+ return;
+}
diff --git a/network_cmds/rtadvd.tproj/rrenum.h b/network_cmds/rtadvd.tproj/rrenum.h
new file mode 100644
index 0000000..b6ed486
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rrenum.h
@@ -0,0 +1,33 @@
+/* $KAME: rrenum.h,v 1.3 2001/01/21 15:37:14 itojun Exp $ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+void rr_input(int, struct icmp6_router_renum *, struct in6_pktinfo *,
+ struct sockaddr_in6 *, struct in6_addr *);
diff --git a/network_cmds/rtadvd.tproj/rtadvd.8 b/network_cmds/rtadvd.tproj/rtadvd.8
new file mode 100644
index 0000000..27429de
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.8
@@ -0,0 +1,207 @@
+.\" $FreeBSD: src/usr.sbin/rtadvd/rtadvd.8,v 1.3.2.6 2001/08/16 15:56:30 ru Exp $
+.\" $KAME: rtadvd.8,v 1.24 2002/05/31 16:16:08 jinmei 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.
+.\"
+.Dd August 27, 2011
+.Dt RTADVD 8
+.Os
+.Sh NAME
+.Nm rtadvd
+.Nd router advertisement daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl dDfMRs
+.Op Fl c Ar configfile
+.Op Fl F Ar dumpfile
+.Op Fl p Ar pidfile
+.Ar interface ...
+.Sh DESCRIPTION
+.Nm
+sends router advertisement packets to the specified
+.Ar interfaces .
+.Pp
+The program will daemonize itself on invocation.
+It will then send router advertisement packets periodically, as well
+as in response to router solicitation messages sent by end hosts.
+.Pp
+Router advertisements can be configured on a per-interface basis, as
+described in
+.Xr rtadvd.conf 5 .
+.Pp
+If there is no configuration file entry for an interface,
+or if the configuration file does not exist altogether,
+.Nm
+sets all the parameters to their default values.
+In particular,
+.Nm
+reads all the interface routes from the routing table and advertises
+them as on-link prefixes.
+.Pp
+.Nm
+also watches the routing table.
+If an interface direct route is
+added on an advertising interface and no static prefixes are
+specified by the configuration file,
+.Nm
+adds the corresponding prefix to its advertising list.
+.Pp
+Similarly, when an interface direct route is deleted,
+.Nm
+will start advertising the prefixes with zero valid and preferred
+lifetimes to help the receiving hosts switch to a new prefix when
+renumbering.
+Note, however, that the zero valid lifetime cannot invalidate the
+autoconfigured addresses at a receiving host immediately.
+According to the specification, the host will retain the address
+for a certain period, which will typically be two hours.
+The zero lifetimes rather intend to make the address deprecated,
+indicating that a new non-deprecated address should be used as the
+source address of a new connection.
+This behavior will last for two hours.
+Then
+.Nm
+will completely remove the prefix from the advertising list,
+and succeeding advertisements will not contain the prefix information.
+.Pp
+Moreover, if the status of an advertising interface changes,
+.Nm
+will start or stop sending router advertisements according
+to the latest status.
+.Pp
+The
+.Fl s
+option may be used to disable this behavior;
+.Nm
+will not watch the routing table and the whole functionality described
+above will be suppressed.
+.Pp
+Basically, hosts MUST NOT send Router Advertisement messages at any
+time (RFC 2461, Section 6.2.3).
+However, it would sometimes be useful to allow hosts to advertise some
+parameters such as prefix information and link MTU.
+Thus,
+.Nm
+can be invoked if router lifetime is explicitly set zero on every
+advertising interface.
+.Pp
+The command line options are:
+.Bl -tag -width indent
+.\"
+.It Fl c
+Specify an alternate location,
+.Ar configfile ,
+for the configuration file.
+By default,
+.Pa /etc/rtadvd.conf
+is used.
+.It Fl d
+Print debugging information.
+.It Fl D
+Even more debugging information is printed.
+.It Fl f
+This option is now deprecated and ignored.
+.It Fl F
+Specify an alternative file in which to dump internal states when
+.Nm
+receives signal
+.Dv SIGUSR1 .
+The default is
+.Pa /var/run/rtadvd.dump .
+.It Fl M
+Specify an interface to join the all-routers site-local multicast group.
+By default,
+.Nm
+tries to join the first advertising interface appearing on the command
+line.
+This option has meaning only with the
+.Fl R
+option, which enables routing renumbering protocol support.
+.It Fl p
+Specify an alternative file in which to store the process ID.
+The default is
+.Pa /var/run/rtadvd.pid.
+.It Fl R
+Accept router renumbering requests.
+If you enable it, certain IPsec setup is suggested for security reasons.
+This option is currently disabled, and is ignored by
+.Nm
+with a warning message.
+.It Fl s
+Do not add or delete prefixes dynamically.
+Only statically configured prefixes, if any, will be advertised.
+.El
+.Pp
+Upon receipt of signal
+.Dv SIGUSR1 ,
+.Nm
+will dump the current internal state into
+.Pa /var/run/rtadvd.dump
+or the file specified with option
+.Fl F .
+.Pp
+Use
+.Dv SIGTERM
+to kill
+.Nm
+gracefully.
+In this case,
+.Nm
+will transmit router advertisement with router lifetime 0
+to all the interfaces
+.Pq in accordance with RFC2461 6.2.5 .
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/rtadvd.conf
+The default configuration file.
+.It Pa /var/run/rtadvd.pid
+The default process ID file.
+.It Pa /var/run/rtadvd.dump
+The default file in which
+.Nm
+dumps its internal state.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr rtadvd.conf 5 ,
+.Xr rtsol 8
+.Sh HISTORY
+The
+.Nm
+command first appeared in the WIDE Hydrangea IPv6 protocol stack kit.
+.Sh BUGS
+There used to be some text that recommended users not to let
+.Nm
+advertise Router Advertisement messages on an upstream link to avoid
+undesirable
+.Xr icmp6 4
+redirect messages.
+However, based on the later discussion in the IETF ipng working group,
+all routers should rather advertise the messages regardless of
+the network topology, in order to ensure reachability.
diff --git a/network_cmds/rtadvd.tproj/rtadvd.c b/network_cmds/rtadvd.tproj/rtadvd.c
new file mode 100644
index 0000000..be5c0f8
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.c
@@ -0,0 +1,1650 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: rtadvd.c,v 1.82 2003/08/05 12:34:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rtadvd.h"
+#include "rrenum.h"
+#include "advcap.h"
+#include "timer.h"
+#include "if.h"
+#include "config.h"
+#include "dump.h"
+
+struct msghdr rcvmhdr;
+static u_char *rcvcmsgbuf;
+static size_t rcvcmsgbuflen;
+static u_char *sndcmsgbuf = NULL;
+static size_t sndcmsgbuflen;
+volatile sig_atomic_t do_dump;
+volatile sig_atomic_t do_die;
+struct msghdr sndmhdr;
+struct iovec rcviov[2];
+struct iovec sndiov[2];
+struct sockaddr_in6 rcvfrom;
+struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
+struct in6_addr in6a_site_allrouters;
+static char *dumpfilename = "/var/run/rtadvd.dump";
+static char *pidfilename = "/var/run/rtadvd.pid";
+static struct pidfh *pfh;
+static char *mcastif;
+int sock;
+int rtsock = -1;
+int accept_rr = 0;
+int dflag = 0, sflag = 0;
+int so_traffic_class = SO_TC_CTL; /* use control class, by default */
+char *conffile = NULL;
+
+struct rainfo *ralist = NULL;
+
+struct nd_optlist {
+ struct nd_optlist *next;
+ struct nd_opt_hdr *opt;
+};
+union nd_opts {
+ struct nd_opt_hdr *nd_opt_array[9];
+ struct {
+ struct nd_opt_hdr *zero;
+ struct nd_opt_hdr *src_lladdr;
+ struct nd_opt_hdr *tgt_lladdr;
+ struct nd_opt_prefix_info *pi;
+ struct nd_opt_rd_hdr *rh;
+ struct nd_opt_mtu *mtu;
+ struct nd_optlist *list;
+ } nd_opt_each;
+};
+#define nd_opts_src_lladdr nd_opt_each.src_lladdr
+#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
+#define nd_opts_pi nd_opt_each.pi
+#define nd_opts_rh nd_opt_each.rh
+#define nd_opts_mtu nd_opt_each.mtu
+#define nd_opts_list nd_opt_each.list
+
+#define NDOPT_FLAG_SRCLINKADDR 0x1
+#define NDOPT_FLAG_TGTLINKADDR 0x2
+#define NDOPT_FLAG_PREFIXINFO 0x4
+#define NDOPT_FLAG_RDHDR 0x8
+#define NDOPT_FLAG_MTU 0x10
+
+u_int32_t ndopt_flags[] = {
+ 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
+ NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU,
+};
+
+int main(int, char *[]);
+static void set_die(int);
+static void die(void);
+static void sock_open(void);
+static void rtsock_open(void);
+static void rtadvd_input(void);
+static void rs_input(int, struct nd_router_solicit *,
+ struct in6_pktinfo *, struct sockaddr_in6 *);
+static void ra_input(int, struct nd_router_advert *,
+ struct in6_pktinfo *, struct sockaddr_in6 *);
+static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
+ struct sockaddr_in6 *);
+static int nd6_options(struct nd_opt_hdr *, int,
+ union nd_opts *, u_int32_t);
+static void free_ndopts(union nd_opts *);
+static void ra_output(struct rainfo *);
+static void rtmsg_input(void);
+static void rtadvd_set_dump_file(int);
+static void set_short_delay(struct rainfo *);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ fd_set *fdsetp, *selectfdp;
+ int fdmasks;
+ int maxfd = 0;
+ struct timeval *timeout;
+ int i, ch;
+ int fflag = 0;
+ pid_t pid, otherpid;
+
+ /* get command line options and arguments */
+ while ((ch = getopt(argc, argv, "c:dDF:fMp:Rs")) != -1) {
+ switch (ch) {
+ case 'c':
+ conffile = optarg;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'D':
+ dflag = 2;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'M':
+ mcastif = optarg;
+ break;
+ case 'R':
+ fprintf(stderr, "rtadvd: "
+ "the -R option is currently ignored.\n");
+ /* accept_rr = 1; */
+ /* run anyway... */
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'p':
+ pidfilename = optarg;
+ break;
+ case 'F':
+ dumpfilename = optarg;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0) {
+ fprintf(stderr,
+ "usage: rtadvd [-dDfMRs] [-c conffile] "
+ "[-F dumpfile] [-p pidfile] interfaces...\n");
+ exit(1);
+ }
+
+ /* timer initialization */
+ rtadvd_timer_init();
+
+ /* random value initialization */
+ srandom((u_long)time(NULL));
+
+ /* get iflist block from kernel */
+ init_iflist();
+
+ while (argc--)
+ getconfig(*argv++);
+
+ if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
+ fprintf(stderr, "fatal: inet_pton failed\n");
+ exit(1);
+ }
+
+ pfh = pidfile_open(pidfilename, 0600, &otherpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST)
+ errx(1, "%s already running, pid: %d",
+ getprogname(), otherpid);
+ errorlog("<%s> failed to open the pid log file, run anyway.",
+ __func__);
+ }
+
+ if (!fflag)
+ daemon(1, 0);
+
+ sock_open();
+
+ /* record the current PID */
+ pid = getpid();
+ pidfile_write(pfh);
+
+ maxfd = sock;
+ if (sflag == 0) {
+ rtsock_open();
+ if (rtsock > sock)
+ maxfd = rtsock;
+ } else
+ rtsock = -1;
+
+ fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
+ if ((fdsetp = malloc(fdmasks)) == NULL) {
+ err(1, "malloc");
+ /*NOTREACHED*/
+ }
+ if ((selectfdp = malloc(fdmasks)) == NULL) {
+ err(1, "malloc");
+ /*NOTREACHED*/
+ }
+ memset(fdsetp, 0, fdmasks);
+ FD_SET(sock, fdsetp);
+ if (rtsock >= 0)
+ FD_SET(rtsock, fdsetp);
+
+ signal(SIGTERM, set_die);
+ signal(SIGUSR1, rtadvd_set_dump_file);
+
+ while (1) {
+ memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */
+
+ if (do_dump) { /* SIGUSR1 */
+ do_dump = 0;
+ rtadvd_dump_file(dumpfilename);
+ }
+
+ if (do_die) {
+ die();
+ /*NOTREACHED*/
+ }
+
+ /* timer expiration check and reset the timer */
+ timeout = rtadvd_check_timer();
+
+ if (timeout != NULL) {
+ debuglog("<%s> set timer to %ld:%ld. waiting for "
+ "inputs or timeout", __func__,
+ (long int)timeout->tv_sec,
+ (long int)timeout->tv_usec);
+ } else {
+ debuglog("<%s> there's no timer. waiting for inputs",
+ __func__);
+ }
+
+ if ((i = select(maxfd + 1, selectfdp, NULL, NULL,
+ timeout)) < 0) {
+ /* EINTR would occur upon SIGUSR1 for status dump */
+ if (errno != EINTR)
+ errorlog( "<%s> select: %s",
+ __func__, strerror(errno));
+ continue;
+ }
+ if (i == 0) /* timeout */
+ continue;
+ if (rtsock != -1 && FD_ISSET(rtsock, selectfdp))
+ rtmsg_input();
+ if (FD_ISSET(sock, selectfdp))
+ rtadvd_input();
+ }
+ exit(0); /* NOTREACHED */
+}
+
+static void
+rtadvd_set_dump_file(sig)
+ int sig;
+{
+ do_dump = 1;
+}
+
+static void
+set_die(sig)
+ int sig;
+{
+ do_die = 1;
+}
+
+static void
+die()
+{
+ struct rainfo *ra;
+ int i;
+ const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
+
+ if (dflag > 1) {
+ debuglog("<%s> cease to be an advertising router\n",
+ __func__);
+ }
+
+ for (ra = ralist; ra; ra = ra->next) {
+ ra->lifetime = 0;
+ make_packet(ra);
+ }
+ for (i = 0; i < retrans; i++) {
+ for (ra = ralist; ra; ra = ra->next)
+ ra_output(ra);
+
+ if (retrans != 1)
+ sleep(MIN_DELAY_BETWEEN_RAS);
+ }
+ pidfile_remove(pfh);
+ exit(0);
+ /*NOTREACHED*/
+}
+
+static void
+rtmsg_input()
+{
+ int n, type, ifindex = 0, plen;
+ size_t len;
+ char msg[2048], *next, *lim;
+ char ifname[IF_NAMESIZE];
+ struct prefix *prefix;
+ struct rainfo *rai;
+ struct in6_addr *addr;
+ char addrbuf[INET6_ADDRSTRLEN];
+ int prefixchange = 0;
+
+ n = read(rtsock, msg, sizeof(msg));
+ if (dflag > 1) {
+ debuglog( "<%s> received a routing message "
+ "(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
+ }
+ if (n > rtmsg_len(msg)) {
+ /*
+ * This usually won't happen for messages received on
+ * a routing socket.
+ */
+ if (dflag > 1)
+ debuglog("<%s> received data length is larger than "
+ "1st routing message len. multiple messages? "
+ "read %d bytes, but 1st msg len = %d",
+ __func__, n, rtmsg_len(msg));
+#if 0
+ /* adjust length */
+ n = rtmsg_len(msg);
+#endif
+ }
+
+ lim = msg + n;
+ for (next = msg; next < lim; next += len) {
+ struct if_msghdr * ifm = NULL;
+ int oldifflags;
+
+ next = get_next_msg(next, lim, 0, &len,
+ RTADV_TYPE2BITMASK(RTM_ADD) |
+ RTADV_TYPE2BITMASK(RTM_DELETE) |
+ RTADV_TYPE2BITMASK(RTM_NEWADDR) |
+ RTADV_TYPE2BITMASK(RTM_DELADDR) |
+ RTADV_TYPE2BITMASK(RTM_IFINFO));
+ if (len == 0)
+ break;
+ type = rtmsg_type(next);
+ switch (type) {
+ case RTM_ADD:
+ case RTM_DELETE:
+ ifindex = get_rtm_ifindex(next);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifindex = get_ifam_ifindex(next);
+ break;
+ case RTM_IFINFO:
+ ifindex = get_ifm_ifindex(next);
+ break;
+ default:
+ /* should not reach here */
+ if (dflag > 1) {
+ debuglog("<%s:%d> unknown rtmsg %d on %s",
+ __func__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ }
+ continue;
+ }
+
+ if ((rai = if_indextorainfo(ifindex)) == NULL) {
+ if (dflag > 1) {
+ debuglog("<%s> route changed on "
+ "non advertising interface(%s)",
+ __func__,
+ if_indextoname(ifindex, ifname));
+ }
+ continue;
+ }
+ ifm = get_interface_entry(ifindex);
+ if (ifm == NULL) {
+ debuglog("Couldn't find interface entry for %d. Skipping.", ifindex);
+ continue;
+ }
+ oldifflags = ifm->ifm_flags;
+
+ switch (type) {
+ case RTM_ADD:
+ /* init ifflags because it may have changed */
+ ifm->ifm_flags =
+ if_getflags(ifindex, ifm->ifm_flags);
+
+ if (sflag)
+ break; /* we aren't interested in prefixes */
+
+ addr = get_addr(msg);
+ plen = get_prefixlen(msg);
+ /* sanity check for plen */
+ /* as RFC2373, prefixlen is at least 4 */
+ if (plen < 4 || plen > 127) {
+ infolog("<%s> new interface route's"
+ "plen %d is invalid for a prefix",
+ __func__, plen);
+ break;
+ }
+ prefix = find_prefix(rai, addr, plen);
+ if (prefix) {
+ if (prefix->timer) {
+ /*
+ * If the prefix has been invalidated,
+ * make it available again.
+ */
+ update_prefix(prefix);
+ prefixchange = 1;
+ } else if (dflag > 1) {
+ debuglog("<%s> new prefix(%s/%d) "
+ "added on %s, "
+ "but it was already in list",
+ __func__,
+ inet_ntop(AF_INET6, addr,
+ (char *)addrbuf, INET6_ADDRSTRLEN),
+ plen, rai->ifname);
+ }
+ break;
+ }
+ make_prefix(rai, ifindex, addr, plen);
+ prefixchange = 1;
+ break;
+ case RTM_DELETE:
+ /* init ifflags because it may have changed */
+ ifm->ifm_flags = if_getflags(ifindex, ifm->ifm_flags);
+
+ if (sflag)
+ break;
+
+ addr = get_addr(msg);
+ plen = get_prefixlen(msg);
+ /* sanity check for plen */
+ /* as RFC2373, prefixlen is at least 4 */
+ if (plen < 4 || plen > 127) {
+ infolog("<%s> deleted interface route's "
+ "plen %d is invalid for a prefix",
+ __func__, plen);
+ break;
+ }
+ prefix = find_prefix(rai, addr, plen);
+ if (prefix == NULL) {
+ if (dflag > 1) {
+ debuglog("<%s> prefix(%s/%d) was "
+ "deleted on %s, "
+ "but it was not in list",
+ __func__,
+ inet_ntop(AF_INET6, addr,
+ (char *)addrbuf, INET6_ADDRSTRLEN),
+ plen, rai->ifname);
+ }
+ break;
+ }
+ invalidate_prefix(prefix);
+ prefixchange = 1;
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ /* init ifflags because it may have changed */
+ ifm->ifm_flags = if_getflags(ifindex, ifm->ifm_flags);
+ break;
+ case RTM_IFINFO:
+ ifm->ifm_flags = get_ifm_flags(next);
+ break;
+ default:
+ /* should not reach here */
+ if (dflag > 1) {
+ debuglog("<%s:%d> unknown rtmsg %d on %s",
+ __func__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ }
+ return;
+ }
+
+ /* check if an interface flag is changed */
+ if ((oldifflags & IFF_UP) && /* UP to DOWN */
+ !(ifm->ifm_flags & IFF_UP)) {
+ infolog("<%s> interface %s becomes down. stop timer.",
+ __func__, rai->ifname);
+ rtadvd_remove_timer(&rai->timer);
+ } else if (!(oldifflags & IFF_UP) && /* DOWN to UP */
+ (ifm->ifm_flags & IFF_UP)) {
+ infolog("<%s> interface %s becomes up. restart timer.",
+ __func__, rai->ifname);
+
+ rai->initcounter = 0; /* reset the counter */
+ rai->waiting = 0; /* XXX */
+ rai->timer = rtadvd_add_timer(ra_timeout,
+ ra_timer_update, rai, rai);
+ ra_timer_update((void *)rai, &rai->timer->tm);
+ rtadvd_set_timer(&rai->timer->tm, rai->timer);
+ } else if (prefixchange &&
+ (ifm->ifm_flags & IFF_UP)) {
+ /*
+ * An advertised prefix has been added or invalidated.
+ * Will notice the change in a short delay.
+ */
+ rai->initcounter = 0;
+ set_short_delay(rai);
+ }
+ }
+
+ return;
+}
+
+void
+rtadvd_input()
+{
+ int i;
+ int *hlimp = NULL;
+#ifdef OLDRAWSOCKET
+ struct ip6_hdr *ip;
+#endif
+ struct icmp6_hdr *icp;
+ int ifindex = 0;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi = NULL;
+ char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ struct in6_addr dst = in6addr_any;
+ struct if_msghdr *ifm = NULL;
+
+ /*
+ * Get message. We reset msg_controllen since the field could
+ * be modified if we had received a message before setting
+ * receive options.
+ */
+ rcvmhdr.msg_controllen = rcvcmsgbuflen;
+ if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0)
+ return;
+
+ /* extract optional information via Advanced API */
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
+ cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
+ pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+ ifindex = pi->ipi6_ifindex;
+ dst = pi->ipi6_addr;
+ }
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+ if (ifindex == 0) {
+ errorlog("<%s> failed to get receiving interface",
+ __func__);
+ return;
+ }
+ if (hlimp == NULL) {
+ errorlog("<%s> failed to get receiving hop limit",
+ __func__);
+ return;
+ }
+
+ ifm = get_interface_entry(pi->ipi6_ifindex);
+ /*
+ * If we happen to receive data on an interface which is now gone
+ * or down, just discard the data.
+ */
+ if (ifm == NULL ||
+ (ifm->ifm_flags & IFF_UP) == 0) {
+ infolog("<%s> received data on a disabled interface (%s)",
+ __func__,
+ (ifm == NULL) ? "[gone]" :
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+#ifdef OLDRAWSOCKET
+ if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
+ errorlog("<%s> packet size(%d) is too short",
+ __func__, i);
+ return;
+ }
+
+ ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+ icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
+#else
+ if (i < sizeof(struct icmp6_hdr)) {
+ errorlog("<%s> packet size(%d) is too short",
+ __func__, i);
+ return;
+ }
+
+ icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+#endif
+
+ switch (icp->icmp6_type) {
+ case ND_ROUTER_SOLICIT:
+ /*
+ * Message verification - RFC-2461 6.1.1
+ * XXX: these checks must be done in the kernel as well,
+ * but we can't completely rely on them.
+ */
+ if (*hlimp != 255) {
+ noticelog("<%s> RS with invalid hop limit(%d) "
+ "received from %s on %s",
+ __func__, *hlimp,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (icp->icmp6_code) {
+ noticelog("<%s> RS with invalid ICMP6 code(%d) "
+ "received from %s on %s",
+ __func__, icp->icmp6_code,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (i < sizeof(struct nd_router_solicit)) {
+ noticelog("<%s> RS from %s on %s does not have enough "
+ "length (len = %d)",
+ __func__,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
+ return;
+ }
+ rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom);
+ break;
+ case ND_ROUTER_ADVERT:
+ /*
+ * Message verification - RFC-2461 6.1.2
+ * XXX: there's a same dilemma as above...
+ */
+ if (*hlimp != 255) {
+ noticelog("<%s> RA with invalid hop limit(%d) "
+ "received from %s on %s",
+ __func__, *hlimp,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (icp->icmp6_code) {
+ noticelog("<%s> RA with invalid ICMP6 code(%d) "
+ "received from %s on %s",
+ __func__, icp->icmp6_code,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (i < sizeof(struct nd_router_advert)) {
+ noticelog("<%s> RA from %s on %s does not have enough "
+ "length (len = %d)",
+ __func__,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
+ return;
+ }
+ ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom);
+ break;
+ case ICMP6_ROUTER_RENUMBERING:
+ if (accept_rr == 0) {
+ errorlog("<%s> received a router renumbering "
+ "message, but not allowed to be accepted",
+ __func__);
+ break;
+ }
+ rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom,
+ &dst);
+ break;
+ default:
+ /*
+ * Note that this case is POSSIBLE, especially just
+ * after invocation of the daemon. This is because we
+ * could receive message after opening the socket and
+ * before setting ICMP6 type filter(see sock_open()).
+ */
+ errorlog("<%s> invalid icmp type(%d)",
+ __func__, icp->icmp6_type);
+ return;
+ }
+
+ return;
+}
+
+static void
+rs_input(int len, struct nd_router_solicit *rs,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from)
+{
+ char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ union nd_opts ndopts;
+ struct rainfo *ra;
+ struct soliciter *sol;
+
+ debuglog(
+ "<%s> RS received from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* ND option check */
+ memset(&ndopts, 0, sizeof(ndopts));
+ if (nd6_options((struct nd_opt_hdr *)(rs + 1),
+ len - sizeof(struct nd_router_solicit),
+ &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
+ infolog("<%s> ND option check failed for an RS from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * If the IP source address is the unspecified address, there
+ * must be no source link-layer address option in the message.
+ * (RFC-2461 6.1.1)
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
+ ndopts.nd_opts_src_lladdr) {
+ infolog("<%s> RS from unspecified src on %s has a link-layer"
+ " address option",
+ __func__,
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+
+ ra = ralist;
+ while (ra != NULL) {
+ if (pi->ipi6_ifindex == ra->ifindex)
+ break;
+ ra = ra->next;
+ }
+ if (ra == NULL) {
+ infolog("<%s> RS received on non advertising interface(%s)",
+ __func__,
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+
+ ra->rsinput++; /* increment statistics */
+
+ /*
+ * Decide whether to send RA according to the rate-limit
+ * consideration.
+ */
+
+ /* record sockaddr waiting for RA, if possible */
+ sol = (struct soliciter *)malloc(sizeof(*sol));
+ if (sol) {
+ sol->addr = *from;
+ /* XXX RFC2553 need clarification on flowinfo */
+ sol->addr.sin6_flowinfo = 0;
+ sol->next = ra->soliciter;
+ ra->soliciter = sol;
+ }
+
+ /*
+ * If there is already a waiting RS packet, don't
+ * update the timer.
+ */
+ if (ra->waiting++)
+ goto done;
+
+ set_short_delay(ra);
+
+ done:
+ free_ndopts(&ndopts);
+ return;
+}
+
+static void
+set_short_delay(rai)
+ struct rainfo *rai;
+{
+ long delay; /* must not be greater than 1000000 */
+ struct timeval interval, now, min_delay, tm_tmp, *rest;
+
+ if (rai->timer == NULL)
+ return;
+ /*
+ * Compute a random delay. If the computed value
+ * corresponds to a time later than the time the next
+ * multicast RA is scheduled to be sent, ignore the random
+ * delay and send the advertisement at the
+ * already-scheduled time. RFC-2461 6.2.6
+ */
+#ifdef HAVE_ARC4RANDOM
+ delay = arc4random_uniform(MAX_RA_DELAY_TIME);
+#else
+ delay = random() % MAX_RA_DELAY_TIME;
+#endif
+ interval.tv_sec = 0;
+ interval.tv_usec = delay;
+ rest = rtadvd_timer_rest(rai->timer);
+ if (TIMEVAL_LT(*rest, interval)) {
+ debuglog("<%s> random delay is larger than "
+ "the rest of the current timer", __func__);
+ interval = *rest;
+ }
+
+ /*
+ * If we sent a multicast Router Advertisement within
+ * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
+ * the advertisement to be sent at a time corresponding to
+ * MIN_DELAY_BETWEEN_RAS plus the random value after the
+ * previous advertisement was sent.
+ */
+ gettimeofday(&now, NULL);
+ TIMEVAL_SUB(&now, &rai->lastsent, &tm_tmp);
+ min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
+ min_delay.tv_usec = 0;
+ if (TIMEVAL_LT(tm_tmp, min_delay)) {
+ TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
+ TIMEVAL_ADD(&min_delay, &interval, &interval);
+ }
+ rtadvd_set_timer(&interval, rai->timer);
+}
+
+static void
+ra_input(int len, struct nd_router_advert *ra,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from)
+{
+ struct rainfo *rai;
+ char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ union nd_opts ndopts;
+ char *on_off[] = {"OFF", "ON"};
+ u_int32_t reachabletime, retranstimer, mtu;
+ int inconsistent = 0;
+
+ debuglog("<%s> RA received from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* ND option check */
+ memset(&ndopts, 0, sizeof(ndopts));
+ if (nd6_options((struct nd_opt_hdr *)(ra + 1),
+ len - sizeof(struct nd_router_advert),
+ &ndopts, NDOPT_FLAG_SRCLINKADDR |
+ NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
+ infolog("<%s> ND option check failed for an RA from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * RA consistency check according to RFC-2461 6.2.7
+ */
+ if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
+ infolog("<%s> received RA from %s on non-advertising"
+ " interface(%s)",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+ rai->rainput++; /* increment statistics */
+
+ /* Cur Hop Limit value */
+ if (ra->nd_ra_curhoplimit && rai->hoplimit &&
+ ra->nd_ra_curhoplimit != rai->hoplimit) {
+ infolog("<%s> CurHopLimit inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname,
+ ra->nd_ra_curhoplimit,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->hoplimit);
+ inconsistent++;
+ }
+ /* M flag */
+ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
+ rai->managedflg) {
+ infolog("<%s> M flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __func__,
+ rai->ifname,
+ on_off[!rai->managedflg],
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ on_off[rai->managedflg]);
+ inconsistent++;
+ }
+ /* O flag */
+ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
+ rai->otherflg) {
+ infolog("<%s> O flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __func__,
+ rai->ifname,
+ on_off[!rai->otherflg],
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ on_off[rai->otherflg]);
+ inconsistent++;
+ }
+ /* Reachable Time */
+ reachabletime = ntohl(ra->nd_ra_reachable);
+ if (reachabletime && rai->reachabletime &&
+ reachabletime != rai->reachabletime) {
+ infolog("<%s> ReachableTime inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname,
+ reachabletime,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->reachabletime);
+ inconsistent++;
+ }
+ /* Retrans Timer */
+ retranstimer = ntohl(ra->nd_ra_retransmit);
+ if (retranstimer && rai->retranstimer &&
+ retranstimer != rai->retranstimer) {
+ infolog("<%s> RetranceTimer inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname,
+ retranstimer,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->retranstimer);
+ inconsistent++;
+ }
+ /* Values in the MTU options */
+ if (ndopts.nd_opts_mtu) {
+ mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
+ if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
+ infolog("<%s> MTU option value inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname, mtu,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->linkmtu);
+ inconsistent++;
+ }
+ }
+ /* Preferred and Valid Lifetimes for prefixes */
+ {
+ struct nd_optlist *optp = ndopts.nd_opts_list;
+
+ if (ndopts.nd_opts_pi) {
+ if (prefix_check(ndopts.nd_opts_pi, rai, from))
+ inconsistent++;
+ }
+ while (optp) {
+ if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
+ rai, from))
+ inconsistent++;
+ optp = optp->next;
+ }
+ }
+
+ if (inconsistent)
+ rai->rainconsistent++;
+
+ done:
+ free_ndopts(&ndopts);
+ return;
+}
+
+/* return a non-zero value if the received prefix is inconsitent with ours */
+static int
+prefix_check(struct nd_opt_prefix_info *pinfo,
+ struct rainfo *rai, struct sockaddr_in6 *from)
+{
+ u_int32_t preferred_time, valid_time;
+ struct prefix *pp;
+ int inconsistent = 0;
+ char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
+ struct timeval now;
+
+#if 0 /* impossible */
+ if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
+ return(0);
+#endif
+
+ /*
+ * log if the adveritsed prefix has link-local scope(sanity check?)
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
+ infolog("<%s> link-local prefix %s/%d is advertised "
+ "from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->ifname);
+ }
+
+ if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
+ pinfo->nd_opt_pi_prefix_len)) == NULL) {
+ infolog("<%s> prefix %s/%d from %s on %s is not in our list",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->ifname);
+ return(0);
+ }
+
+ preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
+ if (pp->pltimeexpire) {
+ /*
+ * The lifetime is decremented in real time, so we should
+ * compare the expiration time.
+ * (RFC 2461 Section 6.2.7.)
+ * XXX: can we really expect that all routers on the link
+ * have synchronized clocks?
+ */
+ gettimeofday(&now, NULL);
+ preferred_time += now.tv_sec;
+
+ if (!pp->timer && rai->clockskew &&
+ preferred_time - pp->pltimeexpire > rai->clockskew) {
+ infolog("<%s> preferred lifetime for %s/%d"
+ " (decr. in real time) inconsistent on %s:"
+ " %d from %s, %ld from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->pltimeexpire);
+ inconsistent++;
+ }
+ } else if (!pp->timer && preferred_time != pp->preflifetime) {
+ infolog("<%s> preferred lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->preflifetime);
+ }
+
+ valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
+ if (pp->vltimeexpire) {
+ gettimeofday(&now, NULL);
+ valid_time += now.tv_sec;
+
+ if (!pp->timer && rai->clockskew &&
+ valid_time - pp->vltimeexpire > rai->clockskew) {
+ infolog("<%s> valid lifetime for %s/%d"
+ " (decr. in real time) inconsistent on %s:"
+ " %d from %s, %ld from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->vltimeexpire);
+ inconsistent++;
+ }
+ } else if (!pp->timer && valid_time != pp->validlifetime) {
+ infolog("<%s> valid lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, valid_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->validlifetime);
+ inconsistent++;
+ }
+
+ return(inconsistent);
+}
+
+struct prefix *
+find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
+{
+ struct prefix *pp;
+ int bytelen, bitlen;
+ u_char bitmask;
+
+ for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
+ if (plen != pp->prefixlen)
+ continue;
+ bytelen = plen / 8;
+ bitlen = plen % 8;
+ bitmask = 0xff << (8 - bitlen);
+ if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
+ continue;
+ if (bitlen == 0 ||
+ ((prefix->s6_addr[bytelen] & bitmask) ==
+ (pp->prefix.s6_addr[bytelen] & bitmask))) {
+ return(pp);
+ }
+ }
+
+ return(NULL);
+}
+
+/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */
+int
+prefix_match(struct in6_addr *p0, int plen0,
+ struct in6_addr *p1, int plen1)
+{
+ int bytelen, bitlen;
+ u_char bitmask;
+
+ if (plen0 < plen1)
+ return(0);
+ bytelen = plen1 / 8;
+ bitlen = plen1 % 8;
+ bitmask = 0xff << (8 - bitlen);
+ if (memcmp((void *)p0, (void *)p1, bytelen))
+ return(0);
+ if (bitlen == 0 ||
+ ((p0->s6_addr[bytelen] & bitmask) ==
+ (p1->s6_addr[bytelen] & bitmask))) {
+ return(1);
+ }
+
+ return(0);
+}
+
+static int
+nd6_options(struct nd_opt_hdr *hdr, int limit,
+ union nd_opts *ndopts, u_int32_t optflags)
+{
+ int optlen = 0;
+
+ for (; limit > 0; limit -= optlen) {
+ if (limit < sizeof(struct nd_opt_hdr)) {
+ infolog("<%s> short option header", __func__);
+ goto bad;
+ }
+
+ hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen);
+ if (hdr->nd_opt_len == 0) {
+ infolog("<%s> bad ND option length(0) (type = %d)",
+ __func__, hdr->nd_opt_type);
+ goto bad;
+ }
+ optlen = hdr->nd_opt_len << 3;
+ if (optlen > limit) {
+ infolog("<%s> short option", __func__);
+ goto bad;
+ }
+
+ if (hdr->nd_opt_type > ND_OPT_MTU) {
+ infolog("<%s> unknown ND option(type %d)",
+ __func__, hdr->nd_opt_type);
+ continue;
+ }
+
+ if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
+ infolog("<%s> unexpected ND option(type %d)",
+ __func__, hdr->nd_opt_type);
+ continue;
+ }
+
+ /*
+ * Option length check. Do it here for all fixed-length
+ * options.
+ */
+ if ((hdr->nd_opt_type == ND_OPT_MTU &&
+ (optlen != sizeof(struct nd_opt_mtu))) ||
+ ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
+ optlen != sizeof(struct nd_opt_prefix_info)))) {
+ infolog("<%s> invalid option length",
+ __func__);
+ continue;
+ }
+
+ switch (hdr->nd_opt_type) {
+ case ND_OPT_TARGET_LINKADDR:
+ case ND_OPT_REDIRECTED_HEADER:
+ break; /* we don't care about these options */
+ case ND_OPT_SOURCE_LINKADDR:
+ case ND_OPT_MTU:
+ if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
+ infolog("<%s> duplicated ND option (type = %d)",
+ __func__, hdr->nd_opt_type);
+ }
+ ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
+ break;
+ case ND_OPT_PREFIX_INFORMATION:
+ {
+ struct nd_optlist *pfxlist;
+
+ if (ndopts->nd_opts_pi == 0) {
+ ndopts->nd_opts_pi =
+ (struct nd_opt_prefix_info *)hdr;
+ continue;
+ }
+ if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
+ errorlog("<%s> can't allocate memory",
+ __func__);
+ goto bad;
+ }
+ pfxlist->next = ndopts->nd_opts_list;
+ pfxlist->opt = hdr;
+ ndopts->nd_opts_list = pfxlist;
+
+ break;
+ }
+ default: /* impossible */
+ break;
+ }
+ }
+
+ return(0);
+
+ bad:
+ free_ndopts(ndopts);
+
+ return(-1);
+}
+
+static void
+free_ndopts(union nd_opts *ndopts)
+{
+ struct nd_optlist *opt = ndopts->nd_opts_list, *next;
+
+ while (opt) {
+ next = opt->next;
+ free(opt);
+ opt = next;
+ }
+}
+
+void
+sock_open()
+{
+ struct icmp6_filter filt;
+ struct ipv6_mreq mreq;
+ struct rainfo *ra = ralist;
+ int on;
+ /* XXX: should be max MTU attached to the node */
+ static u_char answer[1500];
+
+ rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen);
+ if (rcvcmsgbuf == NULL) {
+ errorlog("<%s> not enough core", __func__);
+ exit(1);
+ }
+
+ sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen);
+ if (sndcmsgbuf == NULL) {
+ errorlog("<%s> not enough core", __func__);
+ exit(1);
+ }
+
+ if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+
+ (void) setsockopt(sock, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&so_traffic_class, sizeof (so_traffic_class));
+
+ /* specify to tell receiving interface */
+ on = 1;
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_RECVPKTINFO: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_PKTINFO: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ on = 1;
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ errorlog( "<%s> IPV6_RECVHOPLIMIT: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_HOPLIMIT: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ on = 1;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_DONTFRAG, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_DONTFRAG: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+ if (accept_rr)
+ ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
+ if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0) {
+ errorlog("<%s> IICMP6_FILTER: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * join all routers multicast address on each advertising interface.
+ */
+ if (inet_pton(AF_INET6, ALLROUTERS_LINK,
+ &mreq.ipv6mr_multiaddr.s6_addr)
+ != 1) {
+ errorlog("<%s> inet_pton failed(library bug?)",
+ __func__);
+ exit(1);
+ }
+ while (ra) {
+ mreq.ipv6mr_interface = ra->ifindex;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
+ sizeof(mreq)) < 0) {
+ errorlog("<%s> IPV6_JOIN_GROUP(link) on %s: %s",
+ __func__, ra->ifname, strerror(errno));
+ exit(1);
+ }
+ ra = ra->next;
+ }
+
+ /*
+ * When attending router renumbering, join all-routers site-local
+ * multicast group.
+ */
+ if (accept_rr) {
+ if (inet_pton(AF_INET6, ALLROUTERS_SITE,
+ &in6a_site_allrouters) != 1) {
+ errorlog("<%s> inet_pton failed(library bug?)",
+ __func__);
+ exit(1);
+ }
+ mreq.ipv6mr_multiaddr = in6a_site_allrouters;
+ if (mcastif) {
+ if ((mreq.ipv6mr_interface = if_nametoindex(mcastif))
+ == 0) {
+ errorlog("<%s> invalid interface: %s",
+ __func__, mcastif);
+ exit(1);
+ }
+ } else
+ mreq.ipv6mr_interface = ralist->ifindex;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq, sizeof(mreq)) < 0) {
+ errorlog("<%s> IPV6_JOIN_GROUP(site) on %s: %s",
+ __func__,
+ mcastif ? mcastif : ralist->ifname,
+ strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)answer;
+ rcviov[0].iov_len = sizeof(answer);
+ rcvmhdr.msg_name = (caddr_t)&rcvfrom;
+ rcvmhdr.msg_namelen = sizeof(rcvfrom);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = rcvcmsgbuflen;
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = sndcmsgbuflen;
+
+ return;
+}
+
+/* open a routing socket to watch the routing table */
+static void
+rtsock_open()
+{
+ if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__, strerror(errno));
+ exit(1);
+ }
+}
+
+struct rainfo *
+if_indextorainfo(int idx)
+{
+ struct rainfo *rai = ralist;
+
+ for (rai = ralist; rai; rai = rai->next) {
+ if (rai->ifindex == idx)
+ return(rai);
+ }
+
+ return(NULL); /* search failed */
+}
+
+static void
+ra_output(rainfo)
+struct rainfo *rainfo;
+{
+ int i;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi;
+ struct soliciter *sol, *nextsol;
+ struct if_msghdr *ifm = get_interface_entry(rainfo->ifindex);
+
+ if (ifm == NULL ||
+ (ifm->ifm_flags & IFF_UP) == 0) {
+ debuglog("<%s> %s is not up, skip sending RA",
+ __func__, rainfo->ifname);
+ return;
+ }
+
+ make_packet(rainfo); /* XXX: inefficient */
+
+ sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
+ sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = rainfo->ifindex;
+
+ /* specify the hop limit of the packet */
+ {
+ int hoplimit = 255;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ debuglog("<%s> send RA on %s, # of waitings = %d",
+ __func__, rainfo->ifname, rainfo->waiting);
+
+ i = sendmsg(sock, &sndmhdr, 0);
+
+ if (i < 0 || i != rainfo->ra_datalen) {
+ if (i < 0) {
+ errorlog("<%s> sendmsg on %s: %s",
+ __func__, rainfo->ifname,
+ strerror(errno));
+ }
+ }
+ /* update counter */
+ if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
+ rainfo->initcounter++;
+ rainfo->raoutput++;
+
+ /*
+ * unicast advertisements
+ * XXX commented out. reason: though spec does not forbit it, unicast
+ * advert does not really help
+ */
+ for (sol = rainfo->soliciter; sol; sol = nextsol) {
+ nextsol = sol->next;
+
+ sol->next = NULL;
+ free(sol);
+ }
+ rainfo->soliciter = NULL;
+
+ /* update timestamp */
+ gettimeofday(&rainfo->lastsent, NULL);
+
+ /* reset waiting conter */
+ rainfo->waiting = 0;
+}
+
+/* process RA timer */
+struct rtadvd_timer *
+ra_timeout(void *data)
+{
+ struct rainfo *rai = (struct rainfo *)data;
+
+#ifdef notyet
+ /* if necessary, reconstruct the packet. */
+#endif
+
+ debuglog("<%s> RA timer on %s is expired",
+ __func__, rai->ifname);
+
+ ra_output(rai);
+
+ return(rai->timer);
+}
+
+/* update RA timer */
+void
+ra_timer_update(void *data, struct timeval *tm)
+{
+ struct rainfo *rai = (struct rainfo *)data;
+ long interval;
+
+ /*
+ * Whenever a multicast advertisement is sent from an interface,
+ * the timer is reset to a uniformly-distributed random value
+ * between the interface's configured MinRtrAdvInterval and
+ * MaxRtrAdvInterval (RFC2461 6.2.4).
+ */
+ interval = rai->mininterval;
+ interval += random() % (rai->maxinterval - rai->mininterval);
+
+ /*
+ * The first advertisement is sent as soon as rtadvd starts up
+ * and for the next few advertisements (up to
+ * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
+ * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
+ * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
+ * (RFC-2461 6.2.4)
+ */
+ if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
+ interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
+ interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
+
+ tm->tv_sec = rai->initcounter == 0 ? 0 : interval;
+ tm->tv_usec = 0;
+
+ debuglog("<%s> RA timer on %s is set to %ld:%ld",
+ __func__, rai->ifname,
+ (long int)tm->tv_sec, (long int)tm->tv_usec);
+
+ return;
+}
diff --git a/network_cmds/rtadvd.tproj/rtadvd.conf b/network_cmds/rtadvd.tproj/rtadvd.conf
new file mode 100644
index 0000000..6d109b2
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.conf
@@ -0,0 +1,20 @@
+# $KAME: rtadvd.conf,v 1.13 2003/06/25 03:45:21 itojun Exp $
+#
+# Note: All of the following parameters have default values defined
+# in specifications, and hence you usually do not have to set them
+# by hand unless you need special non-default values.
+#
+# You even do not need to create the configuration file. rtadvd
+# would usually work well without a configuration file.
+# See also: rtadvd(8)
+
+# per-interface definitions.
+# Mainly IPv6 prefixes are configured in this part. However, rtadvd
+# automatically learns appropriate prefixes from the kernel's routing
+# table, and advertises the prefixes, so you don't have to configure
+# this part, either.
+# If you don't want the automatic advertisement, (uncomment and) configure
+# this part by hand, and then invoke rtadvd with the -s option.
+
+#ef0:\
+# :addr="3ffe:501:ffff:1000::":prefixlen#64:
diff --git a/network_cmds/rtadvd.tproj/rtadvd.conf.5 b/network_cmds/rtadvd.tproj/rtadvd.conf.5
new file mode 100644
index 0000000..87978fc
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.conf.5
@@ -0,0 +1,509 @@
+.\" $KAME: rtadvd.conf.5,v 1.50 2005/01/14 05:30:59 jinmei 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.
+.\"
+.Dd February 24, 2012
+.Dt RTADVD.CONF 5
+.Os
+.Sh NAME
+.Nm rtadvd.conf
+.Nd config file for router advertisement daemon
+.Sh DESCRIPTION
+This file describes how the router advertisement packets must be constructed
+for each of the interfaces.
+.Pp
+As described in
+.Xr rtadvd 8 ,
+you do not have to set this configuration file up at all,
+unless you need some special configurations.
+You may even omit the file as a whole.
+In such cases, the
+.Nm rtadvd
+daemon will automatically configure itself using default values
+specified in the specification.
+.Pp
+It obeys the famous
+.Xr termcap 5
+file format.
+Each line in the file describes a network interface.
+Fields are separated by a colon
+.Pq Sq \&: ,
+and each field contains one capability description.
+Lines may be concatenated by the
+.Sq \e
+character.
+The comment marker is the
+.Sq \&#
+character.
+.Sh CAPABILITIES
+Capabilities describe the value to be filled into ICMPv6 router
+advertisement messages and to control
+.Xr rtadvd 8
+behavior.
+Therefore, you are encouraged to read IETF neighbor discovery documents
+if you would like to modify the sample configuration file.
+.Pp
+Note that almost all items have default values.
+If you omit an item, the default value of the item will be used.
+.Pp
+There are two items which control the interval of sending router advertisements.
+These items can be omitted, then
+.Nm rtadvd
+will use the default values.
+.Bl -tag -width indent
+.It Cm \&maxinterval
+(num) The maximum time allowed between sending unsolicited
+multicast router advertisements
+.Pq unit: seconds .
+The default value is 600.
+Its value must be no less than 4 seconds
+and no greater than 1800 seconds.
+.It Cm \&mininterval
+(num) The minimum time allowed between sending unsolicited multicast
+router advertisements
+.Pq unit: seconds .
+The default value is the one third of value of
+.Cm maxinterval .
+Its value must be no less than 3 seconds and no greater than .75 *
+the value of
+.Cm maxinterval .
+.El
+.Pp
+The following items are for ICMPv6 router advertisement message
+header.
+These items can be omitted, then
+.Nm rtadvd
+will use the default values.
+.Bl -tag -width indent
+.It Cm \&chlim
+(num) The value for Cur Hop Limit field.
+The default value is 64.
+.It Cm \&raflags
+(str or num) A 8-bit flags field in router advertisement message header.
+This field can be specified either as a case-sensitive string or as an
+integer.
+A string consists of characters each of which corresponds to a
+particular flag bit(s).
+An integer should be the logical OR of all enabled bits.
+Bit 7
+.Po
+.Li 'm' or 0x80
+.Pc
+means Managed address configuration flag bit,
+and Bit 6
+.Po
+.Li 'o' or 0x40
+.Pc
+means Other stateful configuration flag bit.
+Bit 4
+.Po
+.Li 0x10
+.Pc
+and Bit 3
+.Po
+.Li 0x08
+.Pc
+are used to encode router preference.
+Bits 01
+.Po
+or 'h'
+.Pc
+means high, 00 means medium, and 11
+.Po
+or 'l'
+.Pc
+means low.
+Bits 10 is reserved, and must not be specified.
+There is no character to specify the medium preference explicitly.
+The default value of the entire flag is 0
+.Po
+or a null string,
+.Pc
+which means no additional
+configuration methods, and the medium router preference.
+.It Cm \&rltime
+(num) Router lifetime field
+.Pq unit: seconds .
+The value must be either zero or between
+the value of
+.Cm maxinterval
+and 9000.
+When
+.Nm rtadvd
+runs on a host, this value must explicitly set 0 on all the
+advertising interfaces as described in
+.Xr rtadvd 8 .
+The default value is 1800.
+.It Cm \&rtime
+(num) Reachable time field
+.Pq unit: milliseconds .
+The default value is 0, which means unspecified by this router.
+.It Cm \&retrans
+(num) Retrans Timer field
+.Pq unit: milliseconds .
+The default value is 0, which means unspecified by this router.
+.El
+.Pp
+The following items are for ICMPv6 prefix information option,
+which will be attached to router advertisement header.
+These items can be omitted, then
+.Nm rtadvd
+will automatically get appropriate prefixes from the kernel's routing table,
+and advertise the prefixes with the default parameters.
+Keywords other than
+.Cm clockskew
+can be augmented with a number, like
+.Dq Li prefix2 ,
+to specify multiple prefixes.
+.Bl -tag -width indent
+.It Cm \&clockskew
+(num) Time skew to adjust link propagation delays and clock skews
+between routers on the link
+.Pq unit: seconds .
+This value is used in consistency check for locally-configured and
+advertised prefix lifetimes, and has its meaning when the local router
+configures a prefix on the link with a lifetime that decrements in
+real time.
+If the value is 0, it means the consistency check will be skipped
+for such prefixes.
+The default value is 0.
+.It Cm \&prefixlen
+(num) Prefix length field.
+The default value is 64.
+.It Cm \&pinfoflags
+(str or num) A 8-bit flags field in prefix information option.
+This field can be specified either as a case-sensitive string or as an
+integer.
+A string consists of characters each of which corresponds to a
+particular flag bit(s).
+An integer should be the logical OR of all enabled bits.
+Bit 7
+.Po
+.Li 'l' or 0x80
+.Pc
+means On-link flag bit,
+and Bit 6
+.Po
+.Li 'a' or 0x40
+.Pc
+means Autonomous address-configuration flag bit.
+The default value is "la" or 0xc0, i.e., both bits are set.
+.It Cm \&addr
+(str) The address filled into Prefix field.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+.It Cm \&vltime
+(num) Valid lifetime field
+.Pq unit: seconds .
+The default value is 2592000 (30 days).
+.It Cm \&vltimedecr
+(bool) This item means the advertised valid lifetime will decrement
+in real time, which is disabled by default.
+.It Cm \&pltime
+(num) Preferred lifetime field
+.Pq unit: seconds .
+The default value is 604800 (7 days).
+.It Cm \&pltimedecr
+(bool) This item means the advertised preferred lifetime will decrement
+in real time, which is disabled by default.
+.El
+.Pp
+The following item is for ICMPv6 MTU option,
+which will be attached to router advertisement header.
+This item can be omitted, then
+.Nm rtadvd
+will use the default value.
+.Bl -tag -width indent
+.It Cm \&mtu
+(num or str) MTU (maximum transmission unit) field.
+If 0 is specified, it means that the option will not be included.
+The default value is 0.
+If the special string
+.Dq auto
+is specified for this item, MTU option will be included and its value
+will be set to the interface MTU automatically.
+.El
+.Pp
+The following item controls ICMPv6 source link-layer address option,
+which will be attached to router advertisement header.
+As noted above, you can just omit the item, then
+.Nm rtadvd
+will use the default value.
+.Bl -tag -width indent
+.It Cm \&nolladdr
+(bool) By default
+.Po
+if
+.Cm \&nolladdr
+is not specified
+.Pc ,
+.Xr rtadvd 8
+will try to get link-layer address for the interface from the kernel,
+and attach that in source link-layer address option.
+If this capability exists,
+.Xr rtadvd 8
+will not attach source link-layer address option to
+router advertisement packets.
+.El
+.Pp
+The following item controls ICMPv6 home agent information option,
+which was defined with mobile IPv6 support.
+It will be attached to router advertisement header just like other options do.
+.Bl -tag -width indent
+.It Cm \&hapref
+(num) Specifies home agent preference.
+If set to non-zero,
+.Cm \&hatime
+must be present as well.
+.It Cm \&hatime
+(num) Specifies home agent lifetime.
+.El
+.Pp
+When mobile IPv6 support is turned on for
+.Xr rtadvd 8 ,
+advertisement interval option will be attached to router advertisement
+packet, by configuring
+.Cm \&maxinterval
+explicitly.
+.Pp
+The following items are for ICMPv6 route information option,
+which will be attached to router advertisement header.
+These items are optional.
+Each items can be augmented with number, like
+.Dq Li rtplen2 ,
+to specify multiple routes.
+.Bl -tag -width indent
+.It Cm \&rtprefix
+(str) The prefix filled into the Prefix field of route information option.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+.It Cm \&rtplen
+(num) Prefix length field in route information option.
+The default value is 64.
+.It Cm \&rtflags
+(str or num) A 8-bit flags field in route information option.
+Currently only the preference values are defined.
+The notation is same as that of the raflags field.
+Bit 4
+.Po
+.Li 0x10
+.Pc
+and
+Bit 3
+.Po
+.Li 0x08
+.Pc
+are used to encode the route preference for the route.
+The default value is 0x00, i.e., medium preference.
+.It Cm \&rtltime
+(num) route lifetime field in route information option.
+.Pq unit: seconds .
+Since the specification does not define the default value of this
+item, the value for this item should be specified by hand.
+However,
+.Nm rtadvd
+allows this item to be unspecified, and uses the router lifetime
+as the default value in such a case, just for compatibility with an
+old version of the program.
+.El
+.Pp
+In the above list, each keyword beginning with
+.Dq Li rt
+could be replaced with the one beginning with
+.Dq Li rtr
+for backward compatibility reason.
+For example,
+.Cm rtrplen
+is accepted instead of
+.Cm rtplen .
+However, keywords that start with
+.Dq Li rtr
+have basically been obsoleted, and should not be used any more.
+.Pp
+You can also refer one line from another by using
+.Cm tc
+capability.
+See
+.Xr termcap 5
+for details on the capability.
+.Pp
+The following items are for the ICMPv6 recursive DNS server (RDNSS) option,
+which will be attached to the router advertisement header.
+.Bl -tag -width indent
+.It Cm \&rdnssaddrs
+(num) Number of recursive DNS server addresses.
+Its default is 0, so it must explicitly be set to positive values
+if you want to specify any DNS server address.
+If its value is 0, no DNS server information is sent.
+If its value is more than 1, you must specify the index of the address
+for the
+.Cm rdnssaddr
+item below.
+Indices vary from 0 to N-1, where N is the
+value of
+.Cm rdnssaddrs .
+Each index shall follow the name of
+.Cm rdnssaddr ,
+e.g.,
+.Dq rdnssaddr0 .
+.It Cm \&rdnssaddr
+(str) The IPv6 address of the recursive DNS server.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+This field cannot be
+omitted if the value of
+.Cm rdnssaddrs
+is more than 0.
+.It Cm \&rdnsslifetime
+(num) The lifetime field in RDNSS option.
+(unit: seconds).
+The default value is 2 * the value of
+.Cm \&maxinterval ,
+which is also the maximum value that should be set. The minimum value is
+.Cm \&maxinterval .
+If you specify a value outside of this range, a message is logged.
+.El
+.Pp
+The following items are for the ICMPv6 DNS search list (DNSSL) option,
+which will be attached to the router advertisement header.
+.Bl -tag -width indent
+.It Cm \&dnssldomains
+(num) Number of DNS search domains.
+Its default is 0, so it must explicitly be set to positive values
+if you want to specify any DNS search domains.
+If its value is 0, no DNS search domain information is sent.
+If its value is more than 1, you must specify the index of the search domain
+for the
+.Cm dnssldomain
+item below.
+Indices vary from 0 to N-1, where N is the
+value of
+.Cm dnssldomains .
+Each index shall follow the name of
+.Cm dnssldomain ,
+e.g.,
+.Dq dnssldomain0 .
+.It Cm \&dnssldomain
+(str) The DNS search domain.
+This field cannot be
+omitted if the value of
+.Cm dnssldomains
+is more than 0.
+.It Cm \&dnssllifetime
+(num) The lifetime field in the DNSSL option.
+(unit: seconds).
+The default value is 2 * the value of
+.Cm \&maxinterval ,
+which is also the maximum value that should be set. The minimum value is
+.Cm \&maxinterval .
+If you specify a value outside of this range, a message is logged.
+.El
+.Sh EXAMPLES
+As presented above, all of the advertised parameters have default values
+defined in specifications, and hence you usually do not have to set them
+by hand, unless you need special non-default values.
+It can cause interoperability problem if you use an ill-configured
+parameter.
+.Pp
+To override a configuration parameter, you can specify the parameter alone.
+With the following configuration,
+.Xr rtadvd 8
+overrides the router lifetime parameter for the
+.Li ne0
+interface.
+.Bd -literal -offset
+ne0:\\
+ :rltime#0:
+.Ed
+.Pp
+The following example manually configures prefixes advertised from the
+.Li ef0
+interface.
+The configuration must be used with the
+.Fl s
+option to
+.Xr rtadvd 8 .
+.Bd -literal -offset
+ef0:\\
+ :addr="3ffe:501:ffff:1000::":prefixlen#64:
+.Ed
+.Pp
+The following example presents the default values in an explicit manner.
+The configuration is provided just for reference purposes;
+YOU DO NOT NEED TO HAVE IT AT ALL.
+.Bd -literal -offset
+default:\\
+ :chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
+ :pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
+ef0:\\
+ :addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
+.Ed
+.Sh SEE ALSO
+.Xr termcap 5 ,
+.Xr rtadvd 8 ,
+.Xr rtsol 8
+.Rs
+.%A Thomas Narten
+.%A Erik Nordmark
+.%A W. A. Simpson
+.%T Neighbor Discovery for IP version 6 (IPv6)
+.%R RFC 2461
+.Re
+.Rs
+.%A Richard Draves
+.%T Default Router Preferences and More-Specific Routes
+.%R draft-ietf-ipngwg-router-selection-xx.txt
+.Re
+.Rs
+.%A J. Jeong
+.%A S. Park
+.%A L. Beloeil
+.%A S. Madanapalli
+.%T IPv6 Router Advertisement Option for DNS Configuration
+.%R RFC 5006
+.Re
+.Sh HISTORY
+The
+.Xr rtadvd 8
+and the configuration file
+.Nm
+first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/network_cmds/rtadvd.tproj/rtadvd.h b/network_cmds/rtadvd.tproj/rtadvd.h
new file mode 100644
index 0000000..504f398
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.h
@@ -0,0 +1,205 @@
+/* $KAME: rtadvd.h,v 1.26 2003/08/05 12:34:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
+ * 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.
+ */
+#include "rtadvd_logging.h"
+
+#define ELM_MALLOC(p, error_action) \
+ do { \
+ p = malloc(sizeof(*p)); \
+ if (p == NULL) { \
+ errorlog("<%s> malloc failed: %s", \
+ __func__, strerror(errno)); \
+ error_action; \
+ } \
+ memset(p, 0, sizeof(*p)); \
+ } while(0)
+
+#define ROUTEINFO 1
+
+#define ALLNODES "ff02::1"
+#define ALLROUTERS_LINK "ff02::2"
+#define ALLROUTERS_SITE "ff05::2"
+#define ANY "::"
+#define RTSOLLEN 8
+
+/* protocol constants and default values */
+#define DEF_MAXRTRADVINTERVAL 600
+#define DEF_ADVLINKMTU 0
+#define DEF_ADVREACHABLETIME 0
+#define DEF_ADVRETRANSTIMER 0
+#define DEF_ADVCURHOPLIMIT 64
+#define DEF_ADVVALIDLIFETIME 2592000
+#define DEF_ADVPREFERREDLIFETIME 604800
+
+#define MAXROUTERLIFETIME 9000
+#define MIN_MAXINTERVAL 4
+#define MAX_MAXINTERVAL 1800
+#define MIN_MININTERVAL 3
+#define MAXREACHABLETIME 3600000
+
+#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16
+#define MAX_INITIAL_RTR_ADVERTISEMENTS 3
+#define MAX_FINAL_RTR_ADVERTISEMENTS 1
+#define MIN_DELAY_BETWEEN_RAS 3
+#define MAX_RA_DELAY_TIME 500000 /* usec */
+
+#define PREFIX_FROM_KERNEL 1
+#define PREFIX_FROM_CONFIG 2
+#define PREFIX_FROM_DYNAMIC 3
+
+struct prefix {
+ struct prefix *next; /* forward link */
+ struct prefix *prev; /* previous link */
+
+ struct rainfo *rainfo; /* back pointer to the interface */
+
+ struct rtadvd_timer *timer; /* expiration timer. used when a prefix
+ * derived from the kernel is deleted.
+ */
+
+ u_int32_t validlifetime; /* AdvValidLifetime */
+ long vltimeexpire; /* expiration of vltime; decrement case only */
+ u_int32_t preflifetime; /* AdvPreferredLifetime */
+ long pltimeexpire; /* expiration of pltime; decrement case only */
+ u_int onlinkflg; /* bool: AdvOnLinkFlag */
+ u_int autoconfflg; /* bool: AdvAutonomousFlag */
+ int prefixlen;
+ int origin; /* from kernel or config */
+ struct in6_addr prefix;
+};
+
+#ifdef ROUTEINFO
+struct rtinfo {
+ struct rtinfo *prev; /* previous link */
+ struct rtinfo *next; /* forward link */
+
+ u_int32_t ltime; /* route lifetime */
+ u_int rtpref; /* route preference */
+ int prefixlen;
+ struct in6_addr prefix;
+};
+#endif
+
+struct soliciter {
+ struct soliciter *next;
+ struct sockaddr_in6 addr;
+};
+
+struct rdnss {
+ struct rdnss *next; /* forward link */
+ struct rdnss *prev; /* previous link */
+
+ struct in6_addr addr;
+};
+
+struct dnssl {
+ struct dnssl *next;
+ struct dnssl *prev;
+
+ char domain[1];
+};
+
+struct rainfo {
+ /* pointer for list */
+ struct rainfo *next;
+
+ /* timer related parameters */
+ struct rtadvd_timer *timer;
+ int initcounter; /* counter for the first few advertisements */
+ struct timeval lastsent; /* timestamp when the latest RA was sent */
+ int waiting; /* number of RS waiting for RA */
+
+ /* interface information */
+ int ifindex;
+ int advlinkopt; /* bool: whether include link-layer addr opt */
+ struct sockaddr_dl *sdl;
+ char ifname[16];
+ int phymtu; /* mtu of the physical interface */
+
+ /* Router configuration variables */
+ u_short lifetime; /* AdvDefaultLifetime */
+ u_int maxinterval; /* MaxRtrAdvInterval */
+ u_int mininterval; /* MinRtrAdvInterval */
+ int managedflg; /* AdvManagedFlag */
+ int otherflg; /* AdvOtherConfigFlag */
+
+ int rtpref; /* router preference */
+ u_int32_t linkmtu; /* AdvLinkMTU */
+ u_int32_t reachabletime; /* AdvReachableTime */
+ u_int32_t retranstimer; /* AdvRetransTimer */
+ u_int hoplimit; /* AdvCurHopLimit */
+ struct prefix prefix; /* AdvPrefixList(link head) */
+ int pfxs; /* number of prefixes */
+ long clockskew; /* used for consisitency check of lifetimes */
+
+#ifdef ROUTEINFO
+ struct rtinfo route; /* route information option (link head) */
+ int routes; /* number of route information options */
+#endif
+
+ /* Recursive DNS Servers RFC5006 */
+ struct rdnss rdnss_list;
+ int rdnss_length;
+ u_int32_t rdnss_lifetime;
+
+ /* DNS Search List RFC6106 */
+ struct dnssl dnssl_list;
+ int dnssl_length;
+ u_int32_t dnssl_lifetime;
+ u_int32_t dnssl_option_length;
+
+ /* Captive Portal RFC 7710 */
+ char * capport;
+ u_int32_t capport_length;
+ u_int32_t capport_option_length;
+
+ /* actual RA packet data and its length */
+ size_t ra_datalen;
+ u_char *ra_data;
+
+ /* statistics */
+ u_quad_t raoutput; /* number of RAs sent */
+ u_quad_t rainput; /* number of RAs received */
+ u_quad_t rainconsistent; /* number of RAs inconsistent with ours */
+ u_quad_t rsinput; /* number of RSs received */
+
+ /* info about soliciter */
+ struct soliciter *soliciter; /* recent solication source */
+};
+
+struct rtadvd_timer *ra_timeout(void *);
+void ra_timer_update(void *, struct timeval *);
+
+int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
+struct rainfo *if_indextorainfo(int);
+struct prefix *find_prefix(struct rainfo *, struct in6_addr *, int);
+
+extern struct in6_addr in6a_site_allrouters;
diff --git a/network_cmds/rtadvd.tproj/rtadvd_logging.c b/network_cmds/rtadvd.tproj/rtadvd_logging.c
new file mode 100644
index 0000000..90dec08
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd_logging.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * This document is the property of Apple Inc.
+ * It is considered confidential and proprietary.
+ *
+ * This document may not be reproduced or transmitted in any form,
+ * in whole or in part, without the express written permission of
+ * Apple Inc.
+ */
+#include <assert.h>
+#include <os/log_private.h>
+
+#define kRtadvdLoggerID "com.apple.rtadvd"
+static os_log_t rtadvdLogger = NULL; /* Handle for Logger */
+
+static boolean_t rtadvd_logger_create(void);
+
+static boolean_t
+rtadvd_logger_create(void)
+{
+ assert(rtadvdLogger == NULL);
+ rtadvdLogger = os_log_create(kRtadvdLoggerID, "daemon");
+
+ if (rtadvdLogger == NULL) {
+ os_log_error(OS_LOG_DEFAULT, "Couldn't create os log object");
+ }
+
+ return (rtadvdLogger != NULL);
+}
+
+void
+rtadvdLog(int level, const char *format, ...)
+{
+ va_list args;
+
+ if (rtadvdLogger == NULL && !rtadvd_logger_create()) {
+ return;
+ }
+
+ va_start(args, format);
+ os_log_with_args(rtadvdLogger, level, format, args, __builtin_return_address(0));
+ va_end(args);
+ return;
+}
diff --git a/network_cmds/rtadvd.tproj/rtadvd_logging.h b/network_cmds/rtadvd.tproj/rtadvd_logging.h
new file mode 100644
index 0000000..11273e6
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd_logging.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * This document is the property of Apple Inc.
+ * It is considered confidential and proprietary.
+ *
+ * This document may not be reproduced or transmitted in any form,
+ * in whole or in part, without the express written permission of
+ * Apple Inc.
+ */
+#include <os/log.h>
+extern void rtadvdLog(int level, const char *format, ...);
+
+#define errorlog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_DEFAULT, __format, ## __VA_ARGS__)
+
+#define noticelog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_DEFAULT, __format, ## __VA_ARGS__)
+
+#define infolog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_INFO, __format, ## __VA_ARGS__)
+
+#define debuglog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_DEBUG, __format, ## __VA_ARGS__)
diff --git a/network_cmds/rtadvd.tproj/timer.c b/network_cmds/rtadvd.tproj/timer.c
new file mode 100644
index 0000000..3134fc0
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/timer.c
@@ -0,0 +1,205 @@
+/* $KAME: timer.c,v 1.9 2002/06/10 19:59:47 itojun Exp $ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#include <sys/time.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+#include "timer.h"
+#include "rtadvd_logging.h"
+
+static struct rtadvd_timer timer_head;
+
+#define MILLION 1000000
+#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
+ (t1)->tv_usec == (t2)->tv_usec)
+
+static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
+
+void
+rtadvd_timer_init()
+{
+ memset(&timer_head, 0, sizeof(timer_head));
+
+ timer_head.next = timer_head.prev = &timer_head;
+ timer_head.tm = tm_max;
+}
+
+struct rtadvd_timer *
+rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
+ void (*update)(void *, struct timeval *),
+ void *timeodata, void *updatedata)
+{
+ struct rtadvd_timer *newtimer;
+
+ if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
+ errorlog("<%s> can't allocate memory", __func__);
+ exit(1);
+ }
+
+ memset(newtimer, 0, sizeof(*newtimer));
+
+ if (timeout == NULL) {
+ errorlog("<%s> timeout function unspecified", __func__);
+ exit(1);
+ }
+ newtimer->expire = timeout;
+ newtimer->update = update;
+ newtimer->expire_data = timeodata;
+ newtimer->update_data = updatedata;
+ newtimer->tm = tm_max;
+
+ /* link into chain */
+ insque(newtimer, &timer_head);
+
+ return(newtimer);
+}
+
+void
+rtadvd_remove_timer(struct rtadvd_timer **timer)
+{
+ remque(*timer);
+ free(*timer);
+ *timer = NULL;
+}
+
+void
+rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
+{
+ struct timeval now;
+
+ /* reset the timer */
+ gettimeofday(&now, NULL);
+
+ TIMEVAL_ADD(&now, tm, &timer->tm);
+
+ /* update the next expiration time */
+ if (TIMEVAL_LT(timer->tm, timer_head.tm))
+ timer_head.tm = timer->tm;
+
+ return;
+}
+
+/*
+ * Check expiration for each timer. If a timer expires,
+ * call the expire function for the timer and update the timer.
+ * Return the next interval for select() call.
+ */
+struct timeval *
+rtadvd_check_timer()
+{
+ static struct timeval returnval;
+ struct timeval now;
+ struct rtadvd_timer *tm = timer_head.next, *tm_next;
+
+ gettimeofday(&now, NULL);
+
+ timer_head.tm = tm_max;
+
+ for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
+ tm_next = tm->next;
+
+ if (TIMEVAL_LEQ(tm->tm, now)) {
+ if (((*tm->expire)(tm->expire_data) == NULL))
+ continue; /* the timer was removed */
+ if (tm->update)
+ (*tm->update)(tm->update_data, &tm->tm);
+ TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
+ }
+
+ if (TIMEVAL_LT(tm->tm, timer_head.tm))
+ timer_head.tm = tm->tm;
+ }
+
+ if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
+ /* no need to timeout */
+ return(NULL);
+ } else if (TIMEVAL_LT(timer_head.tm, now)) {
+ /* this may occur when the interval is too small */
+ returnval.tv_sec = returnval.tv_usec = 0;
+ } else
+ TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
+ return(&returnval);
+}
+
+struct timeval *
+rtadvd_timer_rest(struct rtadvd_timer *timer)
+{
+ static struct timeval returnval, now;
+
+ gettimeofday(&now, NULL);
+ if (TIMEVAL_LEQ(timer->tm, now)) {
+ debuglog("<%s> a timer must be expired, but not yet",
+ __func__);
+ returnval.tv_sec = returnval.tv_usec = 0;
+ }
+ else
+ TIMEVAL_SUB(&timer->tm, &now, &returnval);
+
+ return(&returnval);
+}
+
+/* result = a + b */
+void
+TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec + b->tv_usec) < MILLION) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec + b->tv_sec;
+ }
+ else {
+ result->tv_usec = l - MILLION;
+ result->tv_sec = a->tv_sec + b->tv_sec + 1;
+ }
+}
+
+/*
+ * result = a - b
+ * XXX: this function assumes that a >= b.
+ */
+void
+TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec - b->tv_usec) >= 0) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec - b->tv_sec;
+ }
+ else {
+ result->tv_usec = MILLION + l;
+ result->tv_sec = a->tv_sec - b->tv_sec - 1;
+ }
+}
diff --git a/network_cmds/rtadvd.tproj/timer.h b/network_cmds/rtadvd.tproj/timer.h
new file mode 100644
index 0000000..78314b7
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/timer.h
@@ -0,0 +1,64 @@
+/* $KAME: timer.h,v 1.5 2002/05/31 13:30:38 jinmei Exp $ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+/* a < b */
+#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) && \
+ ((a).tv_usec < (b).tv_usec)))
+
+/* a <= b */
+#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) &&\
+ ((a).tv_usec <= (b).tv_usec)))
+
+struct rtadvd_timer {
+ struct rtadvd_timer *next;
+ struct rtadvd_timer *prev;
+ struct rainfo *rai;
+ struct timeval tm;
+
+ struct rtadvd_timer *(*expire)(void *); /* expiration function */
+ void *expire_data;
+ void (*update)(void *, struct timeval *); /* update function */
+ void *update_data;
+};
+
+void rtadvd_timer_init(void);
+struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
+ void (*)(void *, struct timeval *), void *, void *);
+void rtadvd_set_timer(struct timeval *, struct rtadvd_timer *);
+void rtadvd_remove_timer(struct rtadvd_timer **);
+struct timeval * rtadvd_check_timer(void);
+struct timeval * rtadvd_timer_rest(struct rtadvd_timer *);
+void TIMEVAL_ADD(struct timeval *, struct timeval *,
+ struct timeval *);
+void TIMEVAL_SUB(struct timeval *, struct timeval *,
+ struct timeval *);
diff --git a/network_cmds/rtsol.tproj/dump.c b/network_cmds/rtsol.tproj/dump.c
new file mode 100644
index 0000000..69937f0
--- /dev/null
+++ b/network_cmds/rtsol.tproj/dump.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: dump.c,v 1.8 2000/10/05 22:20:39 itojun Exp $ */
+
+/*
+ * Copyright (C) 1999 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.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/dump.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <syslog.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "rtsold.h"
+
+static FILE *fp;
+
+extern struct ifinfo *iflist;
+
+static void dump_interface_status __P((void));
+static char *sec2str __P((time_t));
+char *ifstatstr[] = {
+ "IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE", "OPTIMISTIC"
+};
+
+static void
+dump_interface_status()
+{
+ struct ifinfo *ifinfo;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
+ fprintf(fp, "Interface %s\n", ifinfo->ifname);
+ fprintf(fp, " probe interval: ");
+ if (ifinfo->probeinterval) {
+ fprintf(fp, "%d\n", ifinfo->probeinterval);
+ fprintf(fp, " probe timer: %d\n", ifinfo->probetimer);
+ }
+ else {
+ fprintf(fp, "infinity\n");
+ fprintf(fp, " no probe timer\n");
+ }
+ fprintf(fp, " interface status: %s\n",
+ ifinfo->active > 0 ? "active" : "inactive");
+ fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]);
+ fprintf(fp, " carrier detection: %s\n",
+ ifinfo->mediareqok ? "available" : "unavailable");
+ fprintf(fp, " probes: %d, dadcount = %d\n",
+ ifinfo->probes, ifinfo->dadcount);
+ if (ifinfo->timer.tv_sec == tm_max.tv_sec &&
+ ifinfo->timer.tv_usec == tm_max.tv_usec)
+ fprintf(fp, " no timer\n");
+ else {
+ fprintf(fp, " timer: interval=%d:%d, expire=%s\n",
+ (int)ifinfo->timer.tv_sec,
+ (int)ifinfo->timer.tv_usec,
+ (ifinfo->expire.tv_sec < now.tv_sec) ? "expired"
+ : sec2str(ifinfo->expire.tv_sec - now.tv_sec));
+ }
+ fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
+ }
+}
+
+void
+rtsold_dump_file(dumpfile)
+ char *dumpfile;
+{
+ if ((fp = fopen(dumpfile, "w")) == NULL) {
+ warnmsg(LOG_WARNING, __FUNCTION__, "open a dump file(%s): %s",
+ dumpfile, strerror(errno));
+ return;
+ }
+
+ dump_interface_status();
+
+ fclose(fp);
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
diff --git a/network_cmds/rtsol.tproj/if.c b/network_cmds/rtsol.tproj/if.c
new file mode 100644
index 0000000..b46c781
--- /dev/null
+++ b/network_cmds/rtsol.tproj/if.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: if.c,v 1.15 2001/05/22 06:04:17 jinmei 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.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/if.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
+#include <net/if_var.h>
+#endif /* __FreeBSD__ >= 3 */
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#if defined ( __FreeBSD__) || defined (__APPLE__)
+# include <net/ethernet.h>
+#endif
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#endif
+#if defined(__bsdi__) || defined(__OpenBSD__)
+# include <netinet/in.h>
+# include <netinet/if_ether.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <netinet6/in6_var.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#endif
+
+#include "rtsold.h"
+
+extern int rssock;
+static int ifsock;
+
+static int get_llflag __P((const char *name));
+#ifndef HAVE_GETIFADDRS
+static unsigned int if_maxindex __P((void));
+#endif
+static void get_rtaddrs __P((int addrs, struct sockaddr *sa,
+ struct sockaddr **rti_info));
+
+int
+ifinit()
+{
+ ifsock = rssock;
+
+ return(0);
+}
+
+int
+interface_up(char *name)
+{
+ struct ifreq ifr;
+ int llflag;
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warnmsg(LOG_WARNING, __FUNCTION__, "ioctl(SIOCGIFFLAGS): %s",
+ strerror(errno));
+ return(-1);
+ }
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "ioctl(SIOCSIFFLAGS): %s", strerror(errno));
+ }
+ return(-1);
+ }
+
+ warnmsg(LOG_DEBUG, __FUNCTION__, "checking if %s is ready...", name);
+
+ llflag = get_llflag(name);
+ if (llflag < 0) {
+ warnmsg(LOG_WARNING, __FUNCTION__,
+ "get_llflag() failed, anyway I'll try");
+ return 0;
+ }
+
+ if (!(llflag & (IN6_IFF_NOTREADY | IN6_IFF_DADPROGRESS))) {
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "%s is ready", name);
+ return(0);
+ } else {
+ if (llflag & IN6_IFF_TENTATIVE) {
+ warnmsg(LOG_DEBUG, __FUNCTION__, "%s is tentative",
+ name);
+ return IFS_TENTATIVE;
+ }
+ if (llflag & IN6_IFF_OPTIMISTIC) {
+ warnmsg(LOG_DEBUG, __FUNCTION__, "%s is optimistic",
+ name);
+ return IFS_OPTIMISTIC;
+ }
+ if (llflag & IN6_IFF_DUPLICATED)
+ warnmsg(LOG_DEBUG, __FUNCTION__, "%s is duplicated",
+ name);
+ return -1;
+ }
+}
+
+int
+interface_status(struct ifinfo *ifinfo)
+{
+ char *ifname = ifinfo->ifname;
+ struct ifreq ifr;
+ struct ifmediareq ifmr;
+
+ /* get interface flags */
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFFLAGS) on %s: %s",
+ ifname, strerror(errno));
+ return(-1);
+ }
+ /*
+ * if one of UP and RUNNING flags is dropped,
+ * the interface is not active.
+ */
+ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ goto inactive;
+ }
+
+ /* Next, check carrier on the interface, if possible */
+ if (!ifinfo->mediareqok)
+ goto active;
+ memset(&ifmr, 0, sizeof(ifmr));
+ strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+
+ if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ if (errno != EINVAL) {
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "ioctl(SIOCGIFMEDIA) on %s: %s",
+ ifname, strerror(errno));
+ return(-1);
+ }
+ /*
+ * EINVAL simply means that the interface does not support
+ * the SIOCGIFMEDIA ioctl. We regard it alive.
+ */
+ ifinfo->mediareqok = 0;
+ goto active;
+ }
+
+ if (ifmr.ifm_status & IFM_AVALID) {
+ switch(ifmr.ifm_active & IFM_NMASK) {
+ case IFM_ETHER:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ goto active;
+ else
+ goto inactive;
+ break;
+ default:
+ goto inactive;
+ }
+ }
+
+ inactive:
+ return(0);
+
+ active:
+ return(1);
+}
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
+ sizeof(uint32_t)) :\
+ sizeof(uint32_t)))
+#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
+
+int
+lladdropt_length(struct sockaddr_dl *sdl)
+{
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
+ return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ default:
+ return(0);
+ }
+}
+
+void
+lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
+{
+ char *addr;
+
+ ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
+
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
+ ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
+ addr = (char *)(ndopt + 1);
+ memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ default:
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "unsupported link type(%d)", sdl->sdl_type);
+ exit(1);
+ }
+
+ return;
+}
+
+struct sockaddr_dl *
+if_nametosdl(char *name)
+{
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
+ char *buf, *next, *lim;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ struct sockaddr_dl *sdl = NULL, *ret_sdl;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(NULL);
+ if ((buf = malloc(len)) == NULL)
+ return(NULL);
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return(NULL);
+ }
+
+ lim = buf + len;
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sa = (struct sockaddr *)(ifm + 1);
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
+ if ((sa = rti_info[RTAX_IFP]) != NULL) {
+ if (sa->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)sa;
+ if (strlen(name) != sdl->sdl_nlen)
+ continue; /* not same len */
+ if (strncmp(&sdl->sdl_data[0],
+ name,
+ sdl->sdl_nlen) == 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (next == lim) {
+ /* search failed */
+ free(buf);
+ return(NULL);
+ }
+
+ if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
+ return(NULL);
+ memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
+
+ free(buf);
+ return(ret_sdl);
+}
+
+int
+getinet6sysctl(int code)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+ int value;
+ size_t size;
+
+ mib[3] = code;
+ size = sizeof(value);
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
+ return -1;
+ else
+ return value;
+}
+
+/*------------------------------------------------------------*/
+
+/* get ia6_flags for link-local addr on if. returns -1 on error. */
+static int
+get_llflag(const char *name)
+{
+#ifdef HAVE_GETIFADDRS
+ struct ifaddrs *ifap, *ifa;
+ struct in6_ifreq ifr6;
+ struct sockaddr_in6 *sin6;
+ int s;
+
+ if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s",
+ strerror(errno));
+ exit(1);
+ }
+ if (getifaddrs(&ifap) != 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "etifaddrs: %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (strlen(ifa->ifa_name) != strlen(name)
+ || strncmp(ifa->ifa_name, name, strlen(name)) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ continue;
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
+ memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len);
+ if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno));
+ exit(1);
+ }
+
+ freeifaddrs(ifap);
+ close(s);
+ return ifr6.ifr_ifru.ifru_flags6;
+ }
+
+ freeifaddrs(ifap);
+ close(s);
+ return -1;
+#else
+ int s;
+ unsigned int maxif;
+ struct ifreq *iflist;
+ struct ifconf ifconf;
+ struct ifreq *ifr, *ifr_end;
+ struct sockaddr_in6 *sin6;
+ struct in6_ifreq ifr6;
+
+ maxif = if_maxindex() + 1;
+ iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */
+ if (iflist == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__, "not enough core");
+ exit(1);
+ }
+
+ if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s",
+ strerror(errno));
+ exit(1);
+ }
+ memset(&ifconf, 0, sizeof(ifconf));
+ ifconf.ifc_req = iflist;
+ ifconf.ifc_len = maxif * BUFSIZ; /* XXX */
+ if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFCONF): %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ /* Look for this interface in the list */
+ ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
+ for (ifr = ifconf.ifc_req;
+ ifr < ifr_end;
+ ifr = (struct ifreq *) ((char *) &ifr->ifr_addr
+ + ifr->ifr_addr.sa_len)) {
+ if (strlen(ifr->ifr_name) != strlen(name)
+ || strncmp(ifr->ifr_name, name, strlen(name)) != 0)
+ continue;
+ if (ifr->ifr_addr.sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr;
+ if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ continue;
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
+ memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len);
+ if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno));
+ exit(1);
+ }
+
+ free(iflist);
+ close(s);
+ return ifr6.ifr_ifru.ifru_flags6;
+ }
+
+ free(iflist);
+ close(s);
+ return -1;
+#endif
+}
+
+#ifndef HAVE_GETIFADDRS
+static unsigned int
+if_maxindex()
+{
+ struct if_nameindex *p, *p0;
+ unsigned int max = 0;
+
+ p0 = if_nameindex();
+ for (p = p0; p && p->if_index && p->if_name; p++) {
+ if (max < p->if_index)
+ max = p->if_index;
+ }
+ if_freenameindex(p0);
+ return max;
+}
+#endif
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ NEXT_SA(sa);
+ }
+ else
+ rti_info[i] = NULL;
+ }
+}
diff --git a/network_cmds/rtsol.tproj/probe.c b/network_cmds/rtsol.tproj/probe.c
new file mode 100644
index 0000000..305d0a2
--- /dev/null
+++ b/network_cmds/rtsol.tproj/probe.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */
+
+/*
+ * Copyright (C) 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.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/probe.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <net/if_var.h>
+#endif /* __FreeBSD__ >= 3 */
+
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+
+#include "rtsold.h"
+
+static struct msghdr sndmhdr;
+static struct iovec sndiov[2];
+static int probesock;
+static void sendprobe __P((struct in6_addr *addr, int ifindex));
+
+
+int
+probe_init()
+{
+ int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ static u_char *sndcmsgbuf = NULL;
+
+ if (sndcmsgbuf == NULL &&
+ (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__, "malloc failed");
+ return(-1);
+ }
+
+ if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
+ return(-1);
+ }
+
+#ifndef __APPLE__
+ /* make the socket send-only */
+ if (shutdown(probesock, 0)) {
+ warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno));
+ return(-1);
+ }
+#endif /* __APPLE__ */
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = scmsglen;
+
+ return(0);
+}
+
+/*
+ * Probe if each router in the default router list is still alive.
+ */
+void
+defrouter_probe(int ifindex)
+{
+ struct in6_drlist dr;
+ int s, i;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
+ return;
+ }
+ bzero(&dr, sizeof(dr));
+ strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy interface */
+ if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s",
+ strerror(errno));
+ goto closeandend;
+ }
+
+ for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) {
+ if (ifindex && dr.defrouter[i].if_index == ifindex) {
+ /* sanity check */
+ if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "default router list contains a "
+ "non-linklocal address(%s)",
+ inet_ntop(AF_INET6,
+ &dr.defrouter[i].rtaddr,
+ (char *)ntopbuf, INET6_ADDRSTRLEN));
+ continue; /* ignore the address */
+ }
+ sendprobe(&dr.defrouter[i].rtaddr,
+ dr.defrouter[i].if_index);
+ }
+ }
+
+ closeandend:
+ close(s);
+ return;
+}
+
+static void
+sendprobe(struct in6_addr *addr, int ifindex)
+{
+ struct sockaddr_in6 sa6_probe;
+ struct in6_pktinfo *pi;
+ struct cmsghdr *cm;
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];;
+
+ bzero(&sa6_probe, sizeof(sa6_probe));
+ sa6_probe.sin6_family = AF_INET6;
+ sa6_probe.sin6_len = sizeof(sa6_probe);
+ sa6_probe.sin6_addr = *addr;
+
+ sndmhdr.msg_name = (caddr_t)&sa6_probe;
+ sndmhdr.msg_iov[0].iov_base = NULL;
+ sndmhdr.msg_iov[0].iov_len = 0;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = ifindex;
+
+ /* specify the hop limit of the packet for safety */
+ {
+ int hoplimit = 1;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s",
+ inet_ntop(AF_INET6, addr, (char *)ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(ifindex, (char *)ifnamebuf));
+
+ if (sendmsg(probesock, &sndmhdr, 0))
+ warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s",
+ if_indextoname(ifindex, (char *)ifnamebuf), strerror(errno));
+
+ return;
+}
diff --git a/network_cmds/rtsol.tproj/rtsock.c b/network_cmds/rtsol.tproj/rtsock.c
new file mode 100644
index 0000000..e3f16e4
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsock.c
@@ -0,0 +1,179 @@
+/* $KAME: rtsock.c,v 1.3 2000/10/10 08:46:45 itojun Exp $ */
+/* $FreeBSD: src/usr.sbin/rtsold/rtsock.c,v 1.1.2.1 2001/07/03 11:02:16 ume Exp $ */
+
+/*
+ * Copyright (C) 2000 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.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include "rtsold.h"
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + \
+ ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(uint32_t)) \
+ : sizeof(uint32_t)))
+
+#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
+static int rtsock_input_ifannounce __P((int, struct rt_msghdr *, char *));
+#endif
+
+static struct {
+ u_char type;
+ size_t minlen;
+ int (*func) __P((int, struct rt_msghdr *, char *));
+} rtsock_dispatch[] = {
+#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
+ { RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr),
+ rtsock_input_ifannounce },
+#endif
+ { 0, 0UL, NULL },
+};
+
+int
+rtsock_open()
+{
+
+ return socket(PF_ROUTE, SOCK_RAW, 0);
+}
+
+int
+rtsock_input(s)
+ int s;
+{
+ ssize_t n;
+ char msg[2048];
+ char *lim, *next;
+ struct rt_msghdr *rtm;
+ int idx;
+ size_t len;
+ int ret = 0;
+ const size_t lenlim =
+ offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen);
+
+ n = read(s, msg, sizeof(msg));
+
+ lim = msg + n;
+ for (next = msg; next < lim; next += len) {
+ rtm = (struct rt_msghdr *)next;
+ if (lim - next < lenlim)
+ break;
+ len = rtm->rtm_msglen;
+ if (len < lenlim)
+ break;
+
+ if (dflag > 1) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "rtmsg type %d, len=%lu", rtm->rtm_type,
+ (u_long)len);
+ }
+
+ for (idx = 0; rtsock_dispatch[idx].func; idx++) {
+ if (rtm->rtm_type != rtsock_dispatch[idx].type)
+ continue;
+ if (rtm->rtm_msglen < rtsock_dispatch[idx].minlen) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "rtmsg type %d too short!", rtm->rtm_type);
+ continue;
+ }
+
+ ret = (*rtsock_dispatch[idx].func)(s, rtm, lim);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
+static int
+rtsock_input_ifannounce(s, rtm, lim)
+ int s;
+ struct rt_msghdr *rtm;
+ char *lim;
+{
+ struct if_announcemsghdr *ifan;
+ struct ifinfo *ifinfo;
+
+ ifan = (struct if_announcemsghdr *)rtm;
+ if ((char *)(ifan + 1) > lim)
+ return -1;
+
+ switch (ifan->ifan_what) {
+ case IFAN_ARRIVAL:
+ /*
+ * XXX for NetBSD 1.5, interface index will monotonically be
+ * increased as new pcmcia card gets inserted.
+ * we may be able to do a name-based interface match,
+ * and call ifreconfig() to enable the interface again.
+ */
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "interface %s inserted", ifan->ifan_name);
+ break;
+ case IFAN_DEPARTURE:
+ warnmsg(LOG_WARNING, __FUNCTION__,
+ "interface %s removed", ifan->ifan_name);
+ ifinfo = find_ifinfo(ifan->ifan_index);
+ if (ifinfo) {
+ if (dflag > 1) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "bring interface %s to DOWN state",
+ ifan->ifan_name);
+ }
+ ifinfo->state = IFS_DOWN;
+ }
+ break;
+ }
+
+ return 0;
+}
+#endif
diff --git a/network_cmds/rtsol.tproj/rtsol.8 b/network_cmds/rtsol.tproj/rtsol.8
new file mode 100644
index 0000000..30c3768
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsol.8
@@ -0,0 +1,224 @@
+.\" $KAME: rtsold.8,v 1.16 2000/10/15 13:19:05 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/rtsold/rtsold.8,v 1.1.2.5 2001/08/16 15:56:30 ru Exp $
+.\"
+.Dd May 17, 1998
+.Dt RTSOLD 8
+.Os
+.\"
+.Sh NAME
+.Nm rtsold
+.Nd router solicitation daemon
+.\"
+.Sh SYNOPSIS
+.Nm
+.Op Fl dDfm1
+.Ar interface ...
+.Nm
+.Op Fl dDfm1
+.Fl a
+.Nm rtsol
+.Op Fl dD
+.Ar interface ...
+.Nm rtsol
+.Op Fl dD
+.Fl a
+.\"
+.Sh DESCRIPTION
+.Nm
+is the daemon program to send ICMPv6 Router Solicitation messages
+on the specified interfaces.
+If a node (re)attaches to a link,
+.Nm
+sends some Router Solicitations on the link destined to the link-local scope
+all-routers multicast address to discover new routers
+and to get non link-local addresses.
+.Pp
+.Nm
+should be used on IPv6 hosts
+(non-router nodes)
+only.
+.Pp
+If you invoke the program as
+.Nm rtsol ,
+it will transmit probes from the specified
+.Ar interface ,
+without becoming a daemon.
+In other words,
+.Nm rtsol
+behaves as
+.Do
+.Nm
+.Fl f1
+.Ar interfaces
+.Dc .
+.Pp
+Specifically,
+.Nm
+sends at most 3 Router Solicitations on an interface
+after one of the following events:
+.Pp
+.Bl -bullet -compact
+.It
+Just after invocation of
+.Nm
+daemon.
+.It
+The interface is up after a temporary interface failure.
+.Nm
+detects such failures by periodically probing to see if the status
+of the interface is active or not.
+Note that some network cards and drivers do not allow the extraction
+of link state.
+In such cases,
+.Nm
+cannot detect the change of the interface status.
+.It
+Every 60 seconds if the
+.Fl m
+option is specified and the
+.Nm
+daemon cannot get the interface status.
+This feature does not conform to the IPv6 neighbor discovery
+specification, but is provided for mobile stations.
+The default interval for router advertisements, which is on the order of 10
+minutes, is slightly long for mobile stations.
+This feature is provided
+for such stations so that they can find new routers as soon as possible
+when they attach to another link.
+.El
+.Lp
+Once
+.Nm
+has sent a Router Solicitation, and has received a valid Router Advertisement,
+it refrains from sending additional solicitations on that interface, until
+the next time one of the above events occurs.
+.Lp
+When sending a Router Solicitation on an interface,
+.Nm
+includes a Source Link-layer address option if the interface
+has a link-layer address.
+.Pp
+Upon receipt of signal
+.Dv SIGUSR1 ,
+.Nm
+will dump the current internal state into
+.Pa /var/run/rtsold.dump .
+.\"
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl a
+Autoprobe outgoing interface.
+.Nm
+will try to find a non-loopback, non-point-to-point, IPv6-capable interface.
+If
+.Nm
+finds multiple interfaces,
+.Nm
+will exit with error.
+.\"
+.It Fl d
+Enable debugging.
+.It Fl D
+Enable more debugging including the printing of internal timer information.
+.It Fl f
+.Fl f
+prevents
+.Nm
+from becoming a daemon (foreground mode).
+Warning messages are generated to standard error
+instead of
+.Xr syslog 3 .
+.It Fl m
+Enable mobility support.
+If this option is specified,
+.Nm
+sends probing packets to default routers that have advertised Router
+Advertisements
+when the node (re)attaches to an interface.
+Moreover, if the option is specified,
+.Nm
+periodically sends Router Solicitation on an interface that does not support
+.Dv SIOCGIFMEDIA
+ioctl.
+.It Fl 1
+Perform only one probe.
+Transmit Router Solicitation packets until at least one valid Router
+Advertisement packet has arrived on each
+.Ar interface ,
+then exit.
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.\"
+.Sh FILES
+.Bl -tag -width /var/run/rtsold.dump -compact
+.It Pa /var/run/rtsold.pid
+the pid of the currently running
+.Nm .
+.It Pa /var/run/rtsold.dump
+dumps internal state on.
+.El
+.\"
+.Sh SEE ALSO
+.Xr rtadvd 8 ,
+.Xr sysctl 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command is based on the
+.Nm rtsol
+command, which first appeared in WIDE/KAME IPv6 protocol stack kit.
+.Nm rtsol
+is now integrated into
+.Xr rtsold 8 .
+.\"
+.Sh BUGS
+In some operating systems, when a PCMCIA network card is removed
+and reinserted, the corresponding interface index is changed.
+However,
+.Nm
+assumes such changes will not occur, and always uses the index that
+it got at invocation. As a result,
+.Nm
+may not work if you reinsert a network card.
+In such a case,
+.Nm
+should be killed and restarted.
+.Pp
+The IPv6 autoconfiguration specification assumes a single-interface host.
+You may see kernel error messages if you try to autoconfigure a host with
+multiple interfaces.
+Also, it seems contradictory for
+.Nm
+to accept multiple
+.Ar interface
+arguments.
diff --git a/network_cmds/rtsol.tproj/rtsol.c b/network_cmds/rtsol.tproj/rtsol.c
new file mode 100644
index 0000000..e1b9bff
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsol.c
@@ -0,0 +1,343 @@
+/* $KAME: rtsol.c,v 1.11 2000/08/13 06:14:59 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.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/rtsol.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include "rtsold.h"
+
+#define ALLROUTER "ff02::2"
+
+static struct msghdr rcvmhdr;
+static struct msghdr sndmhdr;
+static struct iovec rcviov[2];
+static struct iovec sndiov[2];
+static struct sockaddr_in6 from;
+
+int rssock;
+
+static struct sockaddr_in6 sin6_allrouters = {sizeof(sin6_allrouters), AF_INET6};
+
+int
+sockopen()
+{
+ int on;
+ struct icmp6_filter filt;
+ static u_char answer[1500];
+ int rcvcmsglen, sndcmsglen;
+ static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL;
+
+ sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "malloc for receive msghdr failed");
+ return(-1);
+ }
+ if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "malloc for send msghdr failed");
+ return(-1);
+ }
+ memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6));
+ if (inet_pton(AF_INET6, ALLROUTER,
+ &sin6_allrouters.sin6_addr.s6_addr) != 1) {
+ warnmsg(LOG_ERR, __FUNCTION__, "inet_pton failed for %s",
+ ALLROUTER);
+ return(-1);
+ }
+
+ if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
+ return(-1);
+ }
+
+ /* specify to tell receiving interface */
+ on = 1;
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVPKTINFO: %s",
+ strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_PKTINFO: %s",
+ strerror(errno));
+ exit(1);
+ }
+#endif
+
+ on = 1;
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVHOPLIMIT: %s",
+ strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_HOPLIMIT: %s",
+ strerror(errno));
+ exit(1);
+ }
+#endif
+
+ /* specfiy to accept only router advertisements on the socket */
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+ if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) == -1) {
+ warnmsg(LOG_ERR, __FUNCTION__, "setsockopt(ICMP6_FILTER): %s",
+ strerror(errno));
+ return(-1);
+ }
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)answer;
+ rcviov[0].iov_len = sizeof(answer);
+ rcvmhdr.msg_name = (caddr_t)&from;
+ rcvmhdr.msg_namelen = sizeof(from);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = rcvcmsglen;
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = sndcmsglen;
+
+ return(rssock);
+}
+
+void
+sendpacket(struct ifinfo *ifinfo)
+{
+ int i;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi;
+
+ sndmhdr.msg_name = (caddr_t)&sin6_allrouters;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data;
+ sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = ifinfo->sdl->sdl_index;
+
+ /* specify the hop limit of the packet */
+ {
+ int hoplimit = 255;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ warnmsg(LOG_DEBUG,
+ __FUNCTION__, "send RS on %s, whose state is %d",
+ ifinfo->ifname, ifinfo->state);
+
+ i = sendmsg(rssock, &sndmhdr, 0);
+
+ if (i < 0 || i != ifinfo->rs_datalen) {
+ /*
+ * ENETDOWN is not so serious, especially when using several
+ * network cards on a mobile node. We ignore it.
+ */
+ if (errno != ENETDOWN || dflag > 0)
+ warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s",
+ ifinfo->ifname, strerror(errno));
+ }
+
+ /* update counter */
+ ifinfo->probes++;
+}
+
+void
+rtsol_input(int s)
+{
+ int i;
+ int *hlimp = NULL;
+ struct icmp6_hdr *icp;
+ int ifindex = 0;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi = NULL;
+ struct ifinfo *ifi = NULL;
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+
+ /* get message */
+ if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "recvmsg: %s", strerror(errno));
+ return;
+ }
+
+ /* extract optional information via Advanced API */
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
+ cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
+ pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+ ifindex = pi->ipi6_ifindex;
+ }
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+
+ if (ifindex == 0) {
+ warnmsg(LOG_ERR,
+ __FUNCTION__, "failed to get receiving interface");
+ return;
+ }
+ if (hlimp == NULL) {
+ warnmsg(LOG_ERR,
+ __FUNCTION__, "failed to get receiving hop limit");
+ return;
+ }
+
+ if (i < sizeof(struct nd_router_advert)) {
+ warnmsg(LOG_ERR,
+ __FUNCTION__, "packet size(%d) is too short", i);
+ return;
+ }
+
+ icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+
+ if (icp->icmp6_type != ND_ROUTER_ADVERT) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "invalid icmp type(%d) from %s on %s", icp->icmp6_type,
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ if (icp->icmp6_code != 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "invalid icmp code(%d) from %s on %s", icp->icmp6_code,
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ if (*hlimp != 255) {
+ warnmsg(LOG_NOTICE, __FUNCTION__,
+ "invalid RA with hop limit(%d) from %s on %s",
+ *hlimp,
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
+ warnmsg(LOG_NOTICE, __FUNCTION__,
+ "invalid RA with non link-local source from %s on %s",
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ /* xxx: more validation? */
+
+ if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) {
+ warnmsg(LOG_NOTICE, __FUNCTION__,
+ "received RA from %s on an unexpeced IF(%s)",
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "received RA from %s on %s, state is %d",
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ ifi->ifname, ifi->state);
+
+ ifi->racnt++;
+
+ switch(ifi->state) {
+ case IFS_IDLE: /* should be ignored */
+ case IFS_DELAY: /* right? */
+ break;
+ case IFS_PROBE:
+ ifi->state = IFS_IDLE;
+ ifi->probes = 0;
+ rtsol_timer_update(ifi);
+ break;
+ }
+}
diff --git a/network_cmds/rtsol.tproj/rtsold.c b/network_cmds/rtsol.tproj/rtsold.c
new file mode 100644
index 0000000..68923ec
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsold.c
@@ -0,0 +1,791 @@
+/* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei 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.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/rtsold.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <signal.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <err.h>
+#include <stdarg.h>
+#include <ifaddrs.h>
+#include "rtsold.h"
+
+struct ifinfo *iflist;
+struct timeval tm_max = {0x7fffffff, 0x7fffffff};
+int aflag = 0;
+int dflag = 0;
+static int log_upto = 999;
+static int fflag = 0;
+
+/* protocol constatns */
+#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
+#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
+#define MAX_RTR_SOLICITATIONS 3 /* times */
+
+/* implementation dependent constants */
+#define PROBE_INTERVAL 60 /* secondes XXX: should be configurable */
+
+/* utility macros */
+/* a < b */
+#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) && \
+ ((a).tv_usec < (b).tv_usec)))
+
+/* a <= b */
+#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) &&\
+ ((a).tv_usec <= (b).tv_usec)))
+
+/* a == b */
+#define TIMEVAL_EQ(a, b) (((a).tv_sec==(b).tv_sec) && ((a).tv_usec==(b).tv_usec))
+
+int main __P((int argc, char *argv[]));
+
+/* static variables and functions */
+static int mobile_node = 0;
+static int do_dump;
+static char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
+static char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
+
+static int ifconfig __P((char *ifname));
+#if 0
+static int ifreconfig __P((char *ifname));
+#endif
+static int make_packet __P((struct ifinfo *ifinfo));
+static struct timeval *rtsol_check_timer __P((void));
+static void TIMEVAL_ADD __P((struct timeval *a, struct timeval *b,
+ struct timeval *result));
+static void TIMEVAL_SUB __P((struct timeval *a, struct timeval *b,
+ struct timeval *result));
+
+static void rtsold_set_dump_file __P((void));
+static void usage __P((char *progname));
+static char **autoifprobe __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int s, rtsock, maxfd, ch;
+ int once = 0;
+ struct timeval *timeout;
+ struct fd_set fdset;
+ char *argv0;
+ char *opts;
+
+ /*
+ * Initialization
+ */
+ argv0 = argv[0];
+
+ /* get option */
+ if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
+ fflag = 1;
+ once = 1;
+ opts = "adD";
+ } else
+ opts = "adDfm1";
+
+ while ((ch = getopt(argc, argv, opts)) != -1) {
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'D':
+ dflag = 2;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'm':
+ mobile_node = 1;
+ break;
+ case '1':
+ once = 1;
+ break;
+ default:
+ usage(argv0);
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (aflag) {
+ int i;
+
+ if (argc != 0) {
+ usage(argv0);
+ /*NOTREACHED*/
+ }
+
+ argv = autoifprobe();
+ if (!argv) {
+ errx(1, "could not autoprobe interface");
+ /*NOTREACHED*/
+ }
+
+ for (i = 0; argv[i]; i++)
+ ;
+ argc = i;
+ }
+ if (argc == 0) {
+ usage(argv0);
+ /*NOTREACHED*/
+ }
+
+ /* set log level */
+ if (dflag == 0)
+ log_upto = LOG_NOTICE;
+ if (!fflag) {
+ char *ident;
+ ident = strrchr(argv0, '/');
+ if (!ident)
+ ident = argv0;
+ else
+ ident++;
+ openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
+ if (log_upto >= 0)
+ setlogmask(LOG_UPTO(log_upto));
+ }
+
+#ifndef HAVE_ARC4RANDOM
+ /* random value initilization */
+ srandom((u_long)time(NULL));
+#endif
+
+ /* warn if accept_rtadv is down */
+ if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
+ warnx("kernel is configured not to accept RAs");
+ /* warn if forwarding is up */
+ if (getinet6sysctl(IPV6CTL_FORWARDING))
+ warnx("kernel is configured as a router, not a host");
+
+ /* initialization to dump internal status to a file */
+ if (signal(SIGUSR1, (void *)rtsold_set_dump_file) < 0) {
+ errx(1, "failed to set signal for dump status");
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Open a socket for sending RS and receiving RA.
+ * This should be done before calling ifinit(), since the function
+ * uses the socket.
+ */
+ if ((s = sockopen()) < 0) {
+ errx(1, "failed to open a socket");
+ /*NOTREACHED*/
+ }
+ maxfd = s;
+ if ((rtsock = rtsock_open()) < 0) {
+ errx(1, "failed to open a socket");
+ /*NOTREACHED*/
+ }
+ if (rtsock > maxfd)
+ maxfd = rtsock;
+
+ /* configuration per interface */
+ if (ifinit()) {
+ errx(1, "failed to initilizatoin interfaces");
+ /*NOTREACHED*/
+ }
+ while (argc--) {
+ if (ifconfig(*argv)) {
+ errx(1, "failed to initialize %s", *argv);
+ /*NOTREACHED*/
+ }
+ argv++;
+ }
+
+ /* setup for probing default routers */
+ if (probe_init()) {
+ errx(1, "failed to setup for probing routers");
+ /*NOTREACHED*/
+ }
+
+ if (!fflag)
+ daemon(0, 0); /* act as a daemon */
+
+ /* dump the current pid */
+ if (!once) {
+ pid_t pid = getpid();
+ FILE *fp;
+
+ if ((fp = fopen(pidfilename, "w")) == NULL)
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "failed to open a log file(%s): %s",
+ pidfilename, strerror(errno));
+ else {
+ fprintf(fp, "%d\n", pid);
+ fclose(fp);
+ }
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(s, &fdset);
+ FD_SET(rtsock, &fdset);
+ while (1) { /* main loop */
+ int e;
+ struct fd_set select_fd = fdset;
+
+ if (do_dump) { /* SIGUSR1 */
+ do_dump = 0;
+ rtsold_dump_file(dumpfilename);
+ }
+
+ timeout = rtsol_check_timer();
+
+ if (once) {
+ struct ifinfo *ifi;
+
+ /* if we have no timeout, we are done (or failed) */
+ if (timeout == NULL)
+ break;
+
+ /* if all interfaces have got RA packet, we are done */
+ for (ifi = iflist; ifi; ifi = ifi->next) {
+ if (ifi->state != IFS_DOWN && ifi->racnt == 0)
+ break;
+ }
+ if (ifi == NULL)
+ break;
+ }
+ e = select(maxfd + 1, &select_fd, NULL, NULL, timeout);
+ if (e < 1) {
+ if (e < 0 && errno != EINTR) {
+ warnmsg(LOG_ERR, __FUNCTION__, "select: %s",
+ strerror(errno));
+ }
+ continue;
+ }
+
+ /* packet reception */
+ if (FD_ISSET(rtsock, &select_fd))
+ rtsock_input(rtsock);
+ if (FD_ISSET(s, &select_fd))
+ rtsol_input(s);
+ }
+ /* NOTREACHED */
+
+ return 0;
+}
+
+static int
+ifconfig(char *ifname)
+{
+ struct ifinfo *ifinfo;
+ struct sockaddr_dl *sdl;
+ int flags;
+
+ if ((sdl = if_nametosdl(ifname)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "failed to get link layer information for %s", ifname);
+ return(-1);
+ }
+ if (find_ifinfo(sdl->sdl_index)) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "interface %s was already cofigured", ifname);
+ free(sdl);
+ return(-1);
+ }
+
+ if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__, "memory allocation failed");
+ free(sdl);
+ return(-1);
+ }
+ memset(ifinfo, 0, sizeof(*ifinfo));
+ ifinfo->sdl = sdl;
+
+ strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
+
+ /* construct a router solicitation message */
+ if (make_packet(ifinfo))
+ goto bad;
+
+ /*
+ * check if the interface is available.
+ * also check if SIOCGIFMEDIA ioctl is OK on the interface.
+ */
+ ifinfo->mediareqok = 1;
+ ifinfo->active = interface_status(ifinfo);
+ if (!ifinfo->mediareqok) {
+ /*
+ * probe routers periodically even if the link status
+ * does not change.
+ */
+ ifinfo->probeinterval = PROBE_INTERVAL;
+ }
+
+ /* activate interface: interface_up returns 0 on success */
+ flags = interface_up(ifinfo->ifname);
+ if (flags == 0)
+ ifinfo->state = IFS_DELAY;
+ else if (flags == IFS_TENTATIVE)
+ ifinfo->state = IFS_TENTATIVE;
+ else
+ ifinfo->state = IFS_DOWN;
+
+ rtsol_timer_update(ifinfo);
+
+ /* link into chain */
+ if (iflist)
+ ifinfo->next = iflist;
+ iflist = ifinfo;
+
+ return(0);
+
+ bad:
+ free(ifinfo->sdl);
+ free(ifinfo);
+ return(-1);
+}
+
+#if 0
+static int
+ifreconfig(char *ifname)
+{
+ struct ifinfo *ifi, *prev;
+ int rv;
+
+ prev = NULL;
+ for (ifi = iflist; ifi; ifi = ifi->next) {
+ if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
+ break;
+ prev = ifi;
+ }
+ prev->next = ifi->next;
+
+ rv = ifconfig(ifname);
+
+ /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
+ if (ifi->rs_data)
+ free(ifi->rs_data);
+ free(ifi->sdl);
+ free(ifi);
+
+ return rv;
+}
+#endif
+
+struct ifinfo *
+find_ifinfo(int ifindex)
+{
+ struct ifinfo *ifi;
+
+ for (ifi = iflist; ifi; ifi = ifi->next)
+ if (ifi->sdl->sdl_index == ifindex)
+ return(ifi);
+
+ return(NULL);
+}
+
+static int
+make_packet(struct ifinfo *ifinfo)
+{
+ char *buf;
+ struct nd_router_solicit *rs;
+ size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
+
+ if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "link-layer address option has null length"
+ " on %s. Treat as not included.", ifinfo->ifname);
+ }
+ packlen += lladdroptlen;
+ ifinfo->rs_datalen = packlen;
+
+ /* allocate buffer */
+ if ((buf = malloc(packlen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "memory allocation failed for %s", ifinfo->ifname);
+ return(-1);
+ }
+ ifinfo->rs_data = (u_char *)buf;
+
+ /* fill in the message */
+ rs = (struct nd_router_solicit *)buf;
+ rs->nd_rs_type = ND_ROUTER_SOLICIT;
+ rs->nd_rs_code = 0;
+ rs->nd_rs_cksum = 0;
+ rs->nd_rs_reserved = 0;
+ buf += sizeof(*rs);
+
+ /* fill in source link-layer address option */
+ if (lladdroptlen)
+ lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
+
+ return(0);
+}
+
+static struct timeval *
+rtsol_check_timer()
+{
+ static struct timeval returnval;
+ struct timeval now, rtsol_timer;
+ struct ifinfo *ifinfo;
+ int flags;
+
+ gettimeofday(&now, NULL);
+
+ rtsol_timer = tm_max;
+
+ for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
+ if (TIMEVAL_LEQ(ifinfo->expire, now)) {
+ if (dflag > 1)
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "timer expiration on %s, "
+ "state = %d", ifinfo->ifname,
+ ifinfo->state);
+
+ switch (ifinfo->state) {
+ case IFS_DOWN:
+ case IFS_TENTATIVE:
+ /* interface_up returns 0 on success */
+ flags = interface_up(ifinfo->ifname);
+ if (flags == 0)
+ ifinfo->state = IFS_DELAY;
+ else if (flags == IFS_TENTATIVE)
+ ifinfo->state = IFS_TENTATIVE;
+ else
+ ifinfo->state = IFS_DOWN;
+ break;
+ case IFS_IDLE:
+ {
+ int oldstatus = ifinfo->active;
+ int probe = 0;
+
+ ifinfo->active =
+ interface_status(ifinfo);
+
+ if (oldstatus != ifinfo->active) {
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "%s status is changed"
+ " from %d to %d",
+ ifinfo->ifname,
+ oldstatus, ifinfo->active);
+ probe = 1;
+ ifinfo->state = IFS_DELAY;
+ }
+ else if (ifinfo->probeinterval &&
+ (ifinfo->probetimer -=
+ ifinfo->timer.tv_sec) <= 0) {
+ /* probe timer expired */
+ ifinfo->probetimer =
+ ifinfo->probeinterval;
+ probe = 1;
+ ifinfo->state = IFS_PROBE;
+ }
+
+ if (probe && mobile_node)
+ defrouter_probe(ifinfo->sdl->sdl_index);
+ break;
+ }
+ case IFS_DELAY:
+ ifinfo->state = IFS_PROBE;
+ sendpacket(ifinfo);
+ break;
+ case IFS_PROBE:
+ if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
+ sendpacket(ifinfo);
+ else {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "No answer "
+ "after sending %d RSs",
+ ifinfo->probes);
+ ifinfo->probes = 0;
+ ifinfo->state = IFS_IDLE;
+ }
+ break;
+ }
+ rtsol_timer_update(ifinfo);
+ }
+
+ if (TIMEVAL_LT(ifinfo->expire, rtsol_timer))
+ rtsol_timer = ifinfo->expire;
+ }
+
+ if (TIMEVAL_EQ(rtsol_timer, tm_max)) {
+ warnmsg(LOG_DEBUG, __FUNCTION__, "there is no timer");
+ return(NULL);
+ }
+ else if (TIMEVAL_LT(rtsol_timer, now))
+ /* this may occur when the interval is too small */
+ returnval.tv_sec = returnval.tv_usec = 0;
+ else
+ TIMEVAL_SUB(&rtsol_timer, &now, &returnval);
+
+ if (dflag > 1)
+ warnmsg(LOG_DEBUG, __FUNCTION__, "New timer is %ld:%08ld",
+ (long)returnval.tv_sec, (long)returnval.tv_usec);
+
+ return(&returnval);
+}
+
+void
+rtsol_timer_update(struct ifinfo *ifinfo)
+{
+#define MILLION 1000000
+#define DADRETRY 10 /* XXX: adhoc */
+ long interval;
+ struct timeval now;
+
+ bzero(&ifinfo->timer, sizeof(ifinfo->timer));
+
+ switch (ifinfo->state) {
+ case IFS_DOWN:
+ case IFS_TENTATIVE:
+ if (++ifinfo->dadcount > DADRETRY) {
+ ifinfo->dadcount = 0;
+ ifinfo->timer.tv_sec = PROBE_INTERVAL;
+ }
+ else
+ ifinfo->timer.tv_sec = 1;
+ break;
+ case IFS_IDLE:
+ if (mobile_node) {
+ /* XXX should be configurable */
+ ifinfo->timer.tv_sec = 3;
+ }
+ else
+ ifinfo->timer = tm_max; /* stop timer(valid?) */
+ break;
+ case IFS_DELAY:
+#ifndef HAVE_ARC4RANDOM
+ interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
+#else
+ interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
+#endif
+ ifinfo->timer.tv_sec = interval / MILLION;
+ ifinfo->timer.tv_usec = interval % MILLION;
+ break;
+ case IFS_PROBE:
+ if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
+ ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
+ else {
+ /*
+ * After sending MAX_RTR_SOLICITATIONS solicitations,
+ * we're just waiting for possible replies; there
+ * will be no more solicatation. Thus, we change
+ * the timer value to MAX_RTR_SOLICITATION_DELAY based
+ * on RFC 2461, Section 6.3.7.
+ */
+ ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
+ }
+ break;
+ default:
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "illegal interface state(%d) on %s",
+ ifinfo->state, ifinfo->ifname);
+ return;
+ }
+
+ /* reset the timer */
+ if (TIMEVAL_EQ(ifinfo->timer, tm_max)) {
+ ifinfo->expire = tm_max;
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "stop timer for %s", ifinfo->ifname);
+ }
+ else {
+ gettimeofday(&now, NULL);
+ TIMEVAL_ADD(&now, &ifinfo->timer, &ifinfo->expire);
+
+ if (dflag > 1)
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "set timer for %s to %d:%d", ifinfo->ifname,
+ (int)ifinfo->timer.tv_sec,
+ (int)ifinfo->timer.tv_usec);
+ }
+
+#undef MILLION
+}
+
+/* timer related utility functions */
+#define MILLION 1000000
+
+/* result = a + b */
+static void
+TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec + b->tv_usec) < MILLION) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec + b->tv_sec;
+ }
+ else {
+ result->tv_usec = l - MILLION;
+ result->tv_sec = a->tv_sec + b->tv_sec + 1;
+ }
+}
+
+/*
+ * result = a - b
+ * XXX: this function assumes that a >= b.
+ */
+void
+TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec - b->tv_usec) >= 0) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec - b->tv_sec;
+ }
+ else {
+ result->tv_usec = MILLION + l;
+ result->tv_sec = a->tv_sec - b->tv_sec - 1;
+ }
+}
+
+static void
+rtsold_set_dump_file()
+{
+ do_dump = 1;
+}
+
+static void
+usage(char *progname)
+{
+ if (progname && progname[strlen(progname) - 1] != 'd') {
+ fprintf(stderr, "usage: rtsol [-dD] interfaces...\n");
+ fprintf(stderr, "usage: rtsol [-dD] -a\n");
+ } else {
+ fprintf(stderr, "usage: rtsold [-adDfm1] interfaces...\n");
+ fprintf(stderr, "usage: rtsold [-dDfm1] -a\n");
+ }
+ exit(1);
+}
+
+void
+#if __STDC__
+warnmsg(int priority, const char *func, const char *msg, ...)
+#else
+warnmsg(priority, func, msg, va_alist)
+ int priority;
+ const char *func;
+ const char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+ char buf[BUFSIZ];
+
+ va_start(ap, msg);
+ if (fflag) {
+ if (priority <= log_upto) {
+ (void)vfprintf(stderr, msg, ap);
+ (void)fprintf(stderr, "\n");
+ }
+ } else {
+ snprintf(buf, sizeof(buf), "<%s> %s", func, msg);
+ msg = buf;
+ vsyslog(priority, msg, ap);
+ }
+ va_end(ap);
+}
+
+static char **
+autoifprobe()
+{
+#ifndef HAVE_GETIFADDRS
+ errx(1, "-a is not available with the configuration");
+#else
+ static char ifname[IFNAMSIZ + 1];
+ static char *argv[2];
+ struct ifaddrs *ifap, *ifa, *target;
+
+ if (getifaddrs(&ifap) != 0)
+ return NULL;
+
+ target = NULL;
+ /* find an ethernet */
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if ((ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
+ continue;
+
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ if (target && strcmp(target->ifa_name, ifa->ifa_name) == 0)
+ continue;
+
+ if (!target)
+ target = ifa;
+ else {
+ /* if we find multiple candidates, failure. */
+ if (dflag > 1)
+ warnx("multiple interfaces found");
+ target = NULL;
+ break;
+ }
+ }
+
+ if (target) {
+ strlcpy(ifname, target->ifa_name, sizeof(ifname));
+ argv[0] = ifname;
+ argv[1] = NULL;
+
+ if (dflag > 0)
+ warnx("probing %s", argv[0]);
+ }
+ freeifaddrs(ifap);
+ if (target)
+ return argv;
+ else
+ return (char **)NULL;
+#endif
+}
diff --git a/network_cmds/rtsol.tproj/rtsold.h b/network_cmds/rtsol.tproj/rtsold.h
new file mode 100644
index 0000000..fdda539
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsold.h
@@ -0,0 +1,96 @@
+/* $KAME: rtsold.h,v 1.11 2000/10/10 06:18:04 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.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/rtsold.h,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+struct ifinfo {
+ struct ifinfo *next; /* pointer to the next interface */
+
+ struct sockaddr_dl *sdl; /* link-layer address */
+ char ifname[IF_NAMESIZE]; /* interface name */
+ int active; /* interface status */
+ int probeinterval; /* interval of probe timer(if necessary) */
+ int probetimer; /* rest of probe timer */
+ int mediareqok; /* wheter the IF supports SIOCGIFMEDIA */
+ int state;
+ int probes;
+ int dadcount;
+ struct timeval timer;
+ struct timeval expire;
+ int errors; /* # of errors we've got - detect wedge */
+
+ int racnt; /* total # of valid RAs it have got */
+
+ size_t rs_datalen;
+ u_char *rs_data;
+};
+
+/* per interface status */
+#define IFS_IDLE 0
+#define IFS_DELAY 1
+#define IFS_PROBE 2
+#define IFS_DOWN 3
+#define IFS_TENTATIVE 4
+#define IFS_OPTIMISTIC 5
+
+/* rtsold.c */
+extern struct timeval tm_max;
+extern int dflag;
+struct ifinfo *find_ifinfo __P((int ifindex));
+void rtsol_timer_update __P((struct ifinfo *ifinfo));
+extern void warnmsg __P((int, const char *, const char *, ...))
+ __attribute__((__format__(__printf__, 3, 4)));
+
+/* if.c */
+extern int ifinit __P((void));
+extern int interface_up __P((char *name));
+extern int interface_status __P((struct ifinfo*));
+extern int lladdropt_length __P((struct sockaddr_dl *sdl));
+extern void lladdropt_fill __P((struct sockaddr_dl *sdl,
+ struct nd_opt_hdr *ndopt));
+extern struct sockaddr_dl *if_nametosdl __P((char *name));
+extern int getinet6sysctl __P((int code));
+
+/* rtsol.c */
+extern int sockopen __P((void));
+extern void sendpacket __P((struct ifinfo *ifinfo));
+extern void rtsol_input __P((int s));
+
+/* probe.c */
+extern int probe_init __P((void));
+extern void defrouter_probe __P((int ifindex));
+
+/* dump.c */
+extern void rtsold_dump_file __P((char *));
+
+/* rtsock.c */
+extern int rtsock_open __P((void));
+extern int rtsock_input __P((int));
diff --git a/network_cmds/spray.tproj/spray.8 b/network_cmds/spray.tproj/spray.8
new file mode 100644
index 0000000..0f61422
--- /dev/null
+++ b/network_cmds/spray.tproj/spray.8
@@ -0,0 +1,74 @@
+.\"
+.\" Copyright (c) 1994 James A. Jegers
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.Dd July 10, 1995
+.Dt SPRAY 8
+.Os
+.Sh NAME
+.Nm spray
+.Nd send many packets to host
+.Sh SYNOPSIS
+.Nm spray
+.Op Fl c Ar count
+.Op Fl d Ar delay
+.Op Fl l Ar length
+.Ar host
+\&...
+.Sh DESCRIPTION
+.Nm Spray
+sends multiple RPC packets to
+.Ar host
+and records how many of them were correctly received and how long it took.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar count
+Send
+.Ar count
+packets.
+.It Fl d Ar delay
+Pause
+.Ar delay
+microseconds between sending each packet.
+.It Fl l Ar length
+Set the length of the packet that holds the RPC call message to
+.Ar length
+bytes.
+Not all values of
+.Ar length
+are possible because RPC data is encoded using XDR.
+.Nm Spray
+rounds up to the nearest possible value.
+.El
+.Pp
+.Nm Spray
+is intended for use in network testing, measurement, and management.
+This command
+.Bf -emphasis
+can be very hard on a network and should be used with caution.
+.Ef
+.Pp
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ifconfig 8 ,
+.Xr ping 8
diff --git a/network_cmds/spray.tproj/spray.c b/network_cmds/spray.tproj/spray.c
new file mode 100644
index 0000000..70fd8db
--- /dev/null
+++ b/network_cmds/spray.tproj/spray.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1993 Winning Strategies, Inc.
+ * 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 Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: spray.c,v 1.2 2006/02/07 06:22:44 lindak Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/spray.h>
+
+#ifndef SPRAYOVERHEAD
+#define SPRAYOVERHEAD 86
+#endif
+
+void usage ();
+void print_xferstats ();
+
+/* spray buffer */
+char spray_buffer[SPRAYMAX];
+
+/* RPC timeouts */
+struct timeval NO_DEFAULT = { -1, -1 };
+struct timeval ONE_WAY = { 0, 0 };
+struct timeval TIMEOUT = { 25, 0 };
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *progname;
+ spraycumul host_stats;
+ sprayarr host_array;
+ CLIENT *cl;
+ int c;
+ int i;
+ int count = 0;
+ int delay = 0;
+ int length = 0;
+ double xmit_time; /* time to receive data */
+
+ progname = *argv;
+ while ((c = getopt(argc, argv, "c:d:l:")) != -1) {
+ switch (c) {
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case 'd':
+ delay = atoi(optarg);
+ break;
+ case 'l':
+ length = atoi(optarg);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ usage();
+ /* NOTREACHED */
+ }
+
+
+ /* Correct packet length. */
+ if (length > SPRAYMAX) {
+ length = SPRAYMAX;
+ } else if (length < SPRAYOVERHEAD) {
+ length = SPRAYOVERHEAD;
+ } else {
+ /* The RPC portion of the packet is a multiple of 32 bits. */
+ length -= SPRAYOVERHEAD - 3;
+ length &= ~3;
+ length += SPRAYOVERHEAD;
+ }
+
+
+ /*
+ * The default value of count is the number of packets required
+ * to make the total stream size 100000 bytes.
+ */
+ if (!count) {
+ count = 100000 / length;
+ }
+
+ /* Initialize spray argument */
+ host_array.sprayarr_len = length - SPRAYOVERHEAD;
+ host_array.sprayarr_val = spray_buffer;
+
+
+ /* create connection with server */
+ cl = clnt_create(*argv, SPRAYPROG, SPRAYVERS, "udp");
+ if (cl == NULL) {
+ clnt_pcreateerror(progname);
+ exit(1);
+ }
+
+
+ /*
+ * For some strange reason, RPC 4.0 sets the default timeout,
+ * thus timeouts specified in clnt_call() are always ignored.
+ *
+ * The following (undocumented) hack resets the internal state
+ * of the client handle.
+ */
+ clnt_control(cl, CLSET_TIMEOUT, (char *)&NO_DEFAULT);
+
+
+ /* Clear server statistics */
+ if (clnt_call(cl, SPRAYPROC_CLEAR, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
+ clnt_perror(cl, progname);
+ exit(1);
+ }
+
+
+ /* Spray server with packets */
+ printf ("sending %d packets of lnth %d to %s ...", count, length, *argv);
+ fflush (stdout);
+
+ for (i = 0; i < count; i++) {
+ clnt_call(cl, SPRAYPROC_SPRAY, (xdrproc_t)xdr_sprayarr, &host_array, (xdrproc_t)xdr_void, NULL, ONE_WAY);
+
+ if (delay) {
+ usleep(delay);
+ }
+ }
+
+
+ /* Collect statistics from server */
+ if (clnt_call(cl, SPRAYPROC_GET, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_spraycumul, &host_stats, TIMEOUT) != RPC_SUCCESS) {
+ clnt_perror(cl, progname);
+ exit(1);
+ }
+
+ xmit_time = host_stats.clock.sec +
+ (host_stats.clock.usec / 1000000.0);
+
+ printf ("\n\tin %.2f seconds elapsed time\n", xmit_time);
+
+
+ /* report dropped packets */
+ if (host_stats.counter != count) {
+ int packets_dropped = count - host_stats.counter;
+
+ printf("\t%d packets (%.2f%%) dropped\n",
+ packets_dropped,
+ 100.0 * packets_dropped / count );
+ } else {
+ printf("\tno packets dropped\n");
+ }
+
+ printf("Sent:");
+ print_xferstats(count, length, xmit_time);
+
+ printf("Rcvd:");
+ print_xferstats(host_stats.counter, length, xmit_time);
+
+ exit (0);
+}
+
+
+void
+print_xferstats(packets, packetlen, xfertime)
+ int packets;
+ int packetlen;
+ double xfertime;
+{
+ int datalen;
+ double pps; /* packets per second */
+ double bps; /* bytes per second */
+
+ datalen = packets * packetlen;
+ pps = packets / xfertime;
+ bps = datalen / xfertime;
+
+ printf("\t%.0f packets/sec, ", pps);
+
+ if (bps >= 1024)
+ printf ("%.1fK ", bps / 1024);
+ else
+ printf ("%.0f ", bps);
+
+ printf("bytes/sec\n");
+}
+
+
+void
+usage ()
+{
+ fprintf(stderr, "usage: spray [-c count] [-l length] [-d delay] host\n");
+ exit(1);
+}
diff --git a/network_cmds/spray.tproj/spray.x b/network_cmds/spray.tproj/spray.x
new file mode 100644
index 0000000..5d2f883
--- /dev/null
+++ b/network_cmds/spray.tproj/spray.x
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <rpcsvc/spray.x>
diff --git a/network_cmds/traceroute.tproj/README b/network_cmds/traceroute.tproj/README
new file mode 100644
index 0000000..6d33c6c
--- /dev/null
+++ b/network_cmds/traceroute.tproj/README
@@ -0,0 +1,126 @@
+Tue Dec 27 06:24:24 PST 1988
+
+Traceroute is a system administrators utility to trace the route
+ip packets from the current system take in getting to some
+destination system. See the comments at the front of the
+program for a description of its use.
+
+This program
+
+ a) can only be run by root (it uses raw ip sockets).
+
+ b) REQUIRES A KERNEL MOD to the raw ip output code to run.
+
+If you want to hack on your kernel, my modified version of the
+routine rip_output (in file /sys/netinet/raw_ip.c) is attached.
+This code may or may not resemble the code in your kernel.
+It may offer you a place to start but I make no promises.
+If you do hack your kernel, remember to test everything that uses
+raw ip sockets (e.g., ping and egpup/gated) & make sure they still
+work. I wish you the best of luck and you're on your own.
+
+If your system has the ttl bug mentioned in the source, you
+might want to fix it while you're in the kernel. (This bug
+appears in all releases of BSD up to but not including 4.3tahoe.
+If your version of netinet/ip_icmp.c is any earlier than 7.3
+(April, '87), it has the bug.) The fix is just to add the line
+ ip->ip_ttl = MAXTTL;
+after the line
+ ip->ip_src = t;
+(or anywhere before the call to icmp_send) in routine icmp_reflect.
+
+If you're running this on a pre-4.3bsd system (e.g., Sun 3.x,
+Ultrix) that strips ip headers from icmp messages, add -DARCHAIC
+to CFLAGS in the Makefile. Also note that rip_output contains
+a conditional for a 4.2/4.3 change in the location of a raw
+socket's protocol number. I've checked this under 4.3 & Sun OS
+3.5 but you should double-check your system to make sure the
+appropriate branch of the #if is taken (check the line that
+assigned to ip->ip_p in your system's original rip_output).
+
+A couple of awk programs to massage the traceroute output are
+included. "mean.awk" and "median.awk" compute the mean and median
+time to each hop, respectively. I've found that something like
+
+ traceroute -q 7 foo.somewhere >t
+ awk -f median.awk t | graph
+
+can give you a quick picture of the bad spots on a long
+path (median is usually a better noise filter than mean).
+
+Enjoy.
+
+ - Van Jacobson (van@helios.ee.lbl.gov)
+
+-------------------- rip_output from /sys/netinet/raw_ip.c
+rip_output(m, so)
+ register struct mbuf *m;
+ struct socket *so;
+{
+ register struct ip *ip;
+ int error;
+ struct rawcb *rp = sotorawcb(so);
+ struct sockaddr_in *sin;
+#if BSD>=43
+ short proto = rp->rcb_proto.sp_protocol;
+#else
+ short proto = so->so_proto->pr_protocol;
+#endif
+ /*
+ * if the protocol is IPPROTO_RAW, the user handed us a
+ * complete IP packet. Otherwise, allocate an mbuf for a
+ * header and fill it in as needed.
+ */
+ if (proto != IPPROTO_RAW) {
+ /*
+ * Calculate data length and get an mbuf
+ * for IP header.
+ */
+ int len = 0;
+ struct mbuf *m0;
+
+ for (m0 = m; m; m = m->m_next)
+ len += m->m_len;
+
+ m = m_get(M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ m = m0;
+ error = ENOBUFS;
+ goto bad;
+ }
+ m->m_off = MMAXOFF - sizeof(struct ip);
+ m->m_len = sizeof(struct ip);
+ m->m_next = m0;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = proto;
+ ip->ip_len = sizeof(struct ip) + len;
+ ip->ip_ttl = MAXTTL;
+ } else
+ ip = mtod(m, struct ip *);
+
+ if (rp->rcb_flags & RAW_LADDR) {
+ sin = (struct sockaddr_in *)&rp->rcb_laddr;
+ if (sin->sin_family != AF_INET) {
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+ ip->ip_src.s_addr = sin->sin_addr.s_addr;
+ } else
+ ip->ip_src.s_addr = 0;
+
+ ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr;
+
+#if BSD>=43
+ return (ip_output(m, rp->rcb_options, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#else
+ return (ip_output(m, (struct mbuf *)0, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#endif
+bad:
+ m_freem(m);
+ return (error);
+}
diff --git a/network_cmds/traceroute.tproj/as.c b/network_cmds/traceroute.tproj/as.c
new file mode 100644
index 0000000..eb96851
--- /dev/null
+++ b/network_cmds/traceroute.tproj/as.c
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/contrib/traceroute/as.c,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
+/* $NetBSD: as.c,v 1.1 2001/11/04 23:14:36 atatat Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "as.h"
+
+#define DEFAULT_AS_SERVER "whois.radb.net"
+#undef AS_DEBUG_FILE
+
+struct aslookup {
+ FILE *as_f;
+#ifdef AS_DEBUG_FILE
+ FILE *as_debug;
+#endif /* AS_DEBUG_FILE */
+};
+
+void *
+as_setup(server)
+ char *server;
+{
+ struct aslookup *asn;
+ struct hostent *he = NULL;
+ struct servent *se;
+ struct sockaddr_in in;
+ FILE *f;
+ int s;
+
+ if (server == NULL)
+ server = DEFAULT_AS_SERVER;
+
+ (void)memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ in.sin_len = sizeof(in);
+ if ((se = getservbyname("whois", "tcp")) == NULL) {
+ warnx("warning: whois/tcp service not found");
+ in.sin_port = ntohs(43);
+ } else
+ in.sin_port = se->s_port;
+
+ if (inet_aton(server, &in.sin_addr) == 0 &&
+ ((he = gethostbyname(server)) == NULL ||
+ he->h_addr == NULL)) {
+ warnx("%s: %s", server, hstrerror(h_errno));
+ return (NULL);
+ }
+
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+ warn("socket");
+ return (NULL);
+ }
+
+ do {
+ if (he != NULL) {
+ memcpy(&in.sin_addr, he->h_addr, he->h_length);
+ he->h_addr_list++;
+ }
+ if (connect(s, (struct sockaddr *)&in, sizeof(in)) == 0)
+ break;
+ if (he == NULL || he->h_addr == NULL) {
+ close(s);
+ s = -1;
+ break;
+ }
+ } while (1);
+
+ if (s == -1) {
+ warn("connect");
+ return (NULL);
+ }
+
+ f = fdopen(s, "r+");
+ (void)fprintf(f, "!!\n");
+ (void)fflush(f);
+
+ asn = malloc(sizeof(struct aslookup));
+ if (asn == NULL)
+ (void)fclose(f);
+ else
+ asn->as_f = f;
+
+#ifdef AS_DEBUG_FILE
+ asn->as_debug = fopen(AS_DEBUG_FILE, "w");
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !!\n");
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ return (asn);
+}
+
+int
+as_lookup(_asn, addr)
+ void *_asn;
+ struct in_addr *addr;
+{
+ struct aslookup *asn = _asn;
+ char buf[1024];
+ int as, rc, dlen;
+
+ as = rc = dlen = 0;
+ (void)fprintf(asn->as_f, "!r%s/32,l\n", inet_ntoa(*addr));
+ (void)fflush(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !r%s/32,l\n",
+ inet_ntoa(*addr));
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
+ buf[sizeof(buf) - 1] = '\0';
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, "<< %s", buf);
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ if (rc == 0) {
+ rc = buf[0];
+ switch (rc) {
+ case 'A':
+ /* A - followed by # bytes of answer */
+ sscanf(buf, "A%d\n", &dlen);
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug,
+ "dlen: %d\n", dlen);
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+ break;
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ /* C - no data returned */
+ /* D - key not found */
+ /* E - multiple copies of key */
+ /* F - some other error */
+ break;
+ }
+ if (rc == 'A')
+ /* skip to next input line */
+ continue;
+ }
+
+ if (dlen == 0)
+ /* out of data, next char read is end code */
+ rc = buf[0];
+ if (rc != 'A')
+ /* either an error off the bat, or a done code */
+ break;
+
+ /* data received, thank you */
+ dlen -= strlen(buf);
+
+ /* origin line is the interesting bit */
+ if (as == 0 && strncasecmp(buf, "origin:", 7) == 0) {
+ sscanf(buf + 7, " AS%d", &as);
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, "as: %d\n", as);
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+ }
+ }
+
+ return (as);
+}
+
+void
+as_shutdown(_asn)
+ void *_asn;
+{
+ struct aslookup *asn = _asn;
+
+ (void)fprintf(asn->as_f, "!q\n");
+ (void)fclose(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !q\n");
+ (void)fclose(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ free(asn);
+}
diff --git a/network_cmds/traceroute.tproj/as.h b/network_cmds/traceroute.tproj/as.h
new file mode 100644
index 0000000..a4c6f47
--- /dev/null
+++ b/network_cmds/traceroute.tproj/as.h
@@ -0,0 +1,42 @@
+/* $FreeBSD: src/contrib/traceroute/as.h,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
+/* $NetBSD: as.h,v 1.1 2001/11/04 23:14:36 atatat Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+void *as_setup __P((char *));
+int as_lookup __P((void *, struct in_addr *));
+void as_shutdown __P((void *));
diff --git a/network_cmds/traceroute.tproj/findsaddr-socket.c b/network_cmds/traceroute.tproj/findsaddr-socket.c
new file mode 100644
index 0000000..01dcef1
--- /dev/null
+++ b/network_cmds/traceroute.tproj/findsaddr-socket.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 2000
+ * 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ *
+ * $FreeBSD: src/contrib/traceroute/findsaddr-socket.c,v 1.2 2002/07/30 04:49:13 fenner Exp $
+ */
+
+/* XXX Yes this is WAY too complicated */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h> /* concession to AIX */
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "findsaddr.h"
+
+#ifdef HAVE_SOCKADDR_SA_LEN
+#define SALEN(sa) ((sa)->sa_len)
+#else
+#define SALEN(sa) salen(sa)
+#endif
+
+#ifndef roundup
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
+#endif
+
+struct rtmsg {
+ struct rt_msghdr rtmsg;
+ u_char data[512];
+};
+
+static struct rtmsg rtmsg = {
+ { 0, RTM_VERSION, RTM_GET, 0,
+ RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC,
+ RTA_DST | RTA_IFA, 0, 0, 0, 0, 0, { 0 } },
+ { 0 }
+};
+
+#ifndef HAVE_SOCKADDR_SA_LEN
+static int salen(struct sockaddr *);
+#endif
+
+/*
+ * Return the source address for the given destination address
+ */
+const char *
+findsaddr(register const struct sockaddr_in *to,
+ register struct sockaddr_in *from)
+{
+ register struct rt_msghdr *rp;
+ register u_char *cp;
+
+ register struct sockaddr_in *sp, *ifa;
+ register struct sockaddr *sa;
+ register int s, size, cc, seq, i;
+ register pid_t pid;
+ static char errbuf[512];
+
+ s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
+ if (s < 0) {
+ snprintf(errbuf, sizeof(errbuf), "socket: %.128s", strerror(errno));
+ return (errbuf);
+ }
+
+ seq = 0;
+ pid = getpid();
+
+ rp = &rtmsg.rtmsg;
+ rp->rtm_seq = ++seq;
+ cp = (u_char *)(rp + 1);
+
+ sp = (struct sockaddr_in *)cp;
+ *sp = *to;
+ cp += roundup(SALEN((struct sockaddr *)sp), sizeof(u_int32_t));
+
+ size = cp - (u_char *)rp;
+ rp->rtm_msglen = size;
+
+ cc = write(s, (char *)rp, size);
+ if (cc < 0) {
+ snprintf(errbuf, sizeof(errbuf), "write: %.128s", strerror(errno));
+ close(s);
+ return (errbuf);
+ }
+ if (cc != size) {
+ snprintf(errbuf, sizeof(errbuf), "short write (%d != %d)", cc, size);
+ close(s);
+ return (errbuf);
+ }
+
+ size = sizeof(rtmsg);
+ do {
+ memset(rp, 0, size);
+ cc = read(s, (char *)rp, size);
+ if (cc < 0) {
+ snprintf(errbuf, sizeof(errbuf), "read: %.128s", strerror(errno));
+ close(s);
+ return (errbuf);
+ }
+
+ } while (rp->rtm_seq != seq || rp->rtm_pid != pid);
+ close(s);
+
+
+ if (rp->rtm_version != RTM_VERSION) {
+ snprintf(errbuf, sizeof(errbuf), "bad version %d", rp->rtm_version);
+ return (errbuf);
+ }
+ if (rp->rtm_msglen > cc) {
+ snprintf(errbuf, sizeof(errbuf), "bad msglen %d > %d", rp->rtm_msglen, cc);
+ return (errbuf);
+ }
+ if (rp->rtm_errno != 0) {
+ snprintf(errbuf, sizeof(errbuf), "rtm_errno: %.128s", strerror(rp->rtm_errno));
+ return (errbuf);
+ }
+
+ /* Find the interface sockaddr */
+ cp = (u_char *)(rp + 1);
+ for (i = 1; i != 0; i <<= 1)
+ if ((i & rp->rtm_addrs) != 0) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+
+ case RTA_IFA:
+ if (sa->sa_family == AF_INET) {
+ ifa = (struct sockaddr_in *)cp;
+ if (ifa->sin_addr.s_addr != 0) {
+ *from = *ifa;
+ return (NULL);
+ }
+ }
+ break;
+
+ default:
+ break;
+ /* empty */
+ }
+
+ if (SALEN(sa) == 0)
+ cp += sizeof (u_int32_t);
+ else
+ cp += roundup(SALEN(sa), sizeof (u_int32_t));
+ }
+
+ return ("failed!");
+}
+
+#ifndef HAVE_SOCKADDR_SA_LEN
+static int
+salen(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ return (sizeof(struct sockaddr_in));
+
+ case AF_LINK:
+ return (sizeof(struct sockaddr_dl));
+
+ default:
+ return (sizeof(struct sockaddr));
+ }
+}
+#endif
diff --git a/network_cmds/traceroute.tproj/findsaddr.h b/network_cmds/traceroute.tproj/findsaddr.h
new file mode 100644
index 0000000..49ed9e1
--- /dev/null
+++ b/network_cmds/traceroute.tproj/findsaddr.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2000
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Id: findsaddr.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+const char *findsaddr(const struct sockaddr_in *, struct sockaddr_in *);
diff --git a/network_cmds/traceroute.tproj/gnuc.h b/network_cmds/traceroute.tproj/gnuc.h
new file mode 100644
index 0000000..f13c0be
--- /dev/null
+++ b/network_cmds/traceroute.tproj/gnuc.h
@@ -0,0 +1,43 @@
+/* @(#) $Header: /Volumes/george/fs-svn/network_cmds/traceroute.tproj/gnuc.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL) */
+
+/* Define __P() macro, if necessary */
+#ifndef __P
+#if __STDC__
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+
+/* inline foo */
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+
+/*
+ * Handle new and old "dead" routine prototypes
+ *
+ * For example:
+ *
+ * __dead void foo(void) __attribute__((volatile));
+ *
+ */
+#ifdef __GNUC__
+#ifndef __dead
+#define __dead volatile
+#endif
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
+#else
+#ifndef __dead
+#define __dead
+#endif
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
diff --git a/network_cmds/traceroute.tproj/ifaddrlist.c b/network_cmds/traceroute.tproj/ifaddrlist.c
new file mode 100644
index 0000000..17b1026
--- /dev/null
+++ b/network_cmds/traceroute.tproj/ifaddrlist.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h> /* concession to AIX */
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "ifaddrlist.h"
+
+/*
+ * Return the interface list
+ */
+int
+ifaddrlist(register struct ifaddrlist **ipaddrp, register char *errbuf, size_t errbuflen)
+{
+ register int fd, nipaddr;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ register int n;
+#endif
+ register struct ifreq *ifrp, *ifend, *ifnext, *mp;
+ register struct sockaddr_in *sin;
+ register struct ifaddrlist *al;
+ struct ifconf ifc;
+ struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
+#define MAX_IPADDR (sizeof(ibuf) / sizeof(ibuf[0]))
+ static struct ifaddrlist ifaddrlist[MAX_IPADDR];
+ char device[sizeof(ifr.ifr_name) + 1];
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ (void)snprintf(errbuf, errbuflen, "socket: %s", strerror(errno));
+ return (-1);
+ }
+ ifc.ifc_len = sizeof(ibuf);
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ if (errno == EINVAL)
+ (void)snprintf(errbuf, sizeof(errbuf),
+ "SIOCGIFCONF: ifreq struct too small (%d bytes)",
+ (int)sizeof(ibuf));
+ else
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFCONF: %s",
+ strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ al = ifaddrlist;
+ mp = NULL;
+ nipaddr = 0;
+ for (; ifrp < ifend; ifrp = ifnext) {
+#ifdef HAVE_SOCKADDR_SA_LEN
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ifnext = ifrp + 1;
+ else
+ ifnext = (struct ifreq *)((char *)ifrp + n);
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+#else
+ ifnext = ifrp + 1;
+#endif
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ strlcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ if (errno == ENXIO)
+ continue;
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFFLAGS: %.*s: %s",
+ (int)sizeof(ifr.ifr_name), ifr.ifr_name,
+ strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+
+ /* Must be up */
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ continue;
+
+
+ (void)strlcpy(device, ifr.ifr_name, sizeof(device));
+#ifdef sun
+ /* Ignore sun virtual interfaces */
+ if (strchr(device, ':') != NULL)
+ continue;
+#endif
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFADDR: %s: %s",
+ device, strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+
+ if (nipaddr >= MAX_IPADDR) {
+ (void)snprintf(errbuf, errbuflen, "Too many interfaces (%d)",
+ (int)MAX_IPADDR);
+ (void)close(fd);
+ return (-1);
+ }
+ sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ al->addr = sin->sin_addr.s_addr;
+ al->device = strdup(device);
+ ++al;
+ ++nipaddr;
+ }
+ (void)close(fd);
+
+ *ipaddrp = ifaddrlist;
+ return (nipaddr);
+}
diff --git a/network_cmds/traceroute.tproj/ifaddrlist.h b/network_cmds/traceroute.tproj/ifaddrlist.h
new file mode 100644
index 0000000..53d91d9
--- /dev/null
+++ b/network_cmds/traceroute.tproj/ifaddrlist.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: /Volumes/george/fs-svn/network_cmds/traceroute.tproj/ifaddrlist.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+
+struct ifaddrlist {
+ u_int32_t addr;
+ char *device;
+};
+
+int ifaddrlist(struct ifaddrlist **, char *, size_t );
diff --git a/network_cmds/traceroute.tproj/mean.awk b/network_cmds/traceroute.tproj/mean.awk
new file mode 100644
index 0000000..e97a56f
--- /dev/null
+++ b/network_cmds/traceroute.tproj/mean.awk
@@ -0,0 +1,50 @@
+#!/bin/awk -f
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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.
+#
+# @(#)mean.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the average time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ tottime += $(f - 1)
+ ++n
+ }
+ }
+ if (n > 0)
+ print $1, tottime/n, median
+}
diff --git a/network_cmds/traceroute.tproj/median.awk b/network_cmds/traceroute.tproj/median.awk
new file mode 100644
index 0000000..1a8d81d
--- /dev/null
+++ b/network_cmds/traceroute.tproj/median.awk
@@ -0,0 +1,67 @@
+#!/bin/awk -f
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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.
+#
+# @(#)median.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the median time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ ++n
+ time[n] = $(f - 1)
+ }
+ }
+ if (n > 0) {
+ # insertion sort the times to find the median
+ for (i = 2; i <= n; ++i) {
+ v = time[i]; j = i - 1;
+ while (time[j] > v) {
+ time[j+1] = time[j];
+ j = j - 1;
+ if (j < 0)
+ break;
+ }
+ time[j+1] = v;
+ }
+ if (n > 1 && (n % 2) == 0)
+ median = (time[n/2] + time[(n/2) + 1]) / 2
+ else
+ median = time[(n+1)/2]
+
+ print $1, median
+ }
+}
diff --git a/network_cmds/traceroute.tproj/traceroute.8 b/network_cmds/traceroute.tproj/traceroute.8
new file mode 100644
index 0000000..c726d7a
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.8
@@ -0,0 +1,439 @@
+.\" Copyright (c) 1989, 1995, 1996, 1997, 1999, 2000
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.Dd May 29, 2008
+.Dt TRACEROUTE 8
+.Os BSD 4.3
+.Sh NAME
+.Nm traceroute
+.Nd print the route packets take to network host
+.Sh SYNOPSIS
+.Nm traceroute
+.Op Fl adeFISdNnrvx
+.Op Fl A Ar as_server
+.Op Fl f Ar first_ttl
+.Op Fl g Ar gateway
+.Op Fl i Ar iface
+.Op Fl M Ar first_ttl
+.Op Fl m Ar max_ttl
+.Op Fl P Ar proto
+.Op Fl p Ar port
+.Op Fl q Ar nqueries
+.Op Fl s Ar src_addr
+.Op Fl t Ar tos
+.Op Fl w Ar waittime
+.Op Fl z Ar pausemsecs
+.Ar host
+.Op Ar packetsize
+.Sh DESCRIPTION
+The Internet is a large and complex aggregation of
+network hardware, connected together by gateways.
+Tracking the route one's packets follow (or finding the miscreant
+gateway that's discarding your packets) can be difficult.
+.Nm
+utilizes the IP protocol `time to live' field and attempts to elicit an
+.Tn ICMP
+.Dv TIME_EXCEEDED
+response from each gateway along the path to some
+host.
+.Pp
+The only mandatory parameter is the destination host name or IP number.
+The default probe datagram length is 40 bytes, but this may be increased
+by specifying a packet size (in bytes) after the destination host
+name.
+.Pp
+Other options are:
+.Bl -tag -width Ds
+.It Fl a
+Turn on AS# lookups for each hop encountered.
+.It Fl A Ar as_server
+Turn on AS# lookups and use the given server instead of the
+default.
+.It Fl d
+Enable socket level debugging.
+.It Fl D
+When an ICMP response to our probe datagram is received,
+print the differences between the transmitted packet and
+the packet quoted by the ICMP response.
+A key showing the location of fields within the transmitted packet is printed,
+followed by the original packet in hex,
+followed by the quoted packet in hex.
+Bytes that are unchanged in the quoted packet are shown as underscores.
+Note,
+the IP checksum and the TTL of the quoted packet are not expected to match.
+By default, only one probe per hop is sent with this option.
+.It Fl e
+Firewall evasion mode.
+Use fixed destination ports for UDP and TCP probes.
+The destination port does NOT increment with each packet sent.
+.It Fl f Ar first_ttl
+Set the initial time-to-live used in the first outgoing probe packet.
+.It Fl F
+Set the "don't fragment" bit.
+.It Fl g Ar gateway
+Specify a loose source route gateway (8 maximum).
+.It Fl i Ar iface
+Specify a network interface to obtain the source IP address for
+outgoing probe packets. This is normally only useful on a multi-homed
+host. (See the
+.Fl s
+flag for another way to do this.)
+.It Fl I
+Use
+.Tn ICMP
+ECHO instead of
+.Tn UDP
+datagrams. (A synonym for "-P icmp").
+.It Fl M Ar first_ttl
+Set the initial time-to-live value used in outgoing probe packets.
+The default is 1, i.e., start with the first hop.
+.It Fl m Ar max_ttl
+Set the max time-to-live (max number of hops) used in outgoing probe
+packets. The default is
+.Em net.inet.ip.ttl
+hops (the same default used for
+.Tn TCP
+connections).
+.It Fl n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each gateway found on the
+path).
+.It Fl P Ar proto
+Send packets of specified IP protocol. The currently supported protocols
+are:
+.Tn UDP
+,
+.Tn TCP
+,
+.Tn GRE
+and
+.Tn ICMP
+Other protocols may also be specified (either by name or by number), though
+.Nm
+does not implement any special knowledge of their packet formats. This
+option is useful for determining which router along a path may be
+blocking packets based on IP protocol number. But see BUGS below.
+.It Fl p Ar port
+Protocol specific. For
+.Tn UDP
+and
+.Tn TCP,
+sets the base
+.Ar port
+number used in probes (default is 33434).
+.Nm
+hopes that nothing is listening on
+.Tn UDP
+ports
+.Em base
+to
+.Em base+nhops-1
+at the destination host (so an
+.Tn ICMP
+.Dv PORT_UNREACHABLE
+message will
+be returned to terminate the route tracing). If something is
+listening on a port in the default range, this option can be used
+to pick an unused port range.
+.It Fl q Ar nqueries
+Set the number of probes per ``ttl'' to
+.Ar nqueries
+(default is three probes).
+.It Fl r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network,
+an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it (e.g., after the interface was dropped by
+.Xr routed 8 ) .
+.It Fl s Ar src_addr
+Use the following IP address
+(which must be given as an IP number, not
+a hostname) as the source address in outgoing probe packets. On
+hosts with more than one IP address, this option can be used to
+force the source address to be something other than the IP address
+of the interface the probe packet is sent on. If the IP address
+is not one of this machine's interface addresses, an error is
+returned and nothing is sent.
+(See the
+.Fl i
+flag for another way to do this.)
+.It Fl S
+Print a summary of how many probes were not answered for each hop.
+.It Fl t Ar tos
+Set the
+.Em type-of-service
+in probe packets to the following value (default zero). The value must be
+a decimal integer in the range 0 to 255. This option can be used to
+see if different types-of-service result in different paths. (If you
+are not running a
+.Bx 4.4
+or later system, this may be academic since the normal network
+services like telnet and ftp don't let you control the
+.Dv TOS ) .
+Not all values of
+.Dv TOS
+are legal or
+meaningful \- see the IP spec for definitions. Useful values are
+probably
+.Ql \-t 16
+(low delay) and
+.Ql \-t 8
+(high throughput).
+.It Fl v
+Verbose output. Received
+.Tn ICMP
+packets other than
+.Dv TIME_EXCEEDED
+and
+.Dv UNREACHABLE Ns s
+are listed.
+.It Fl w
+Set the time (in seconds) to wait for a response to a probe (default 5 sec.).
+.It Fl x
+Toggle IP checksums. Normally, this prevents
+.Nm
+from calculating
+IP checksums. In some cases, the operating system can overwrite parts of
+the outgoing packet but not recalculate the checksum (so in some cases
+the default is to not calculate checksums and using
+.Fl x
+causes them to be calculated). Note that checksums are usually required
+for the last hop when using
+.Tn ICMP
+ECHO probes (
+.Fl I
+). So they are always calculated when using ICMP.
+.It Fl z Ar pausemsecs
+Set the time (in milliseconds) to pause between probes (default 0).
+Some systems such as Solaris and routers such as Ciscos rate limit
+ICMP messages. A good value to use with this this is 500 (e.g. 1/2 second).
+.El
+.Pp
+This program attempts to trace the route an IP packet would follow to some
+internet host by launching
+.Tn UDP
+probe
+packets with a small ttl (time to live) then listening for an
+.Tn ICMP
+"time exceeded" reply from a gateway. We start our probes
+with a ttl of one and increase by one until we get an
+.Tn ICMP
+"port unreachable"
+(which means we got to "host") or hit a max (which
+defaults to
+.Em net.inet.ip.ttl
+hops & can be changed with the
+.Fl m
+flag). Three
+probes (changed with
+.Fl q
+flag) are sent at each ttl setting and a
+line is printed showing the ttl, address of the gateway and
+round trip time of each probe. If the probe answers come from
+different gateways, the address of each responding system will
+be printed. If there is no response within a 5 sec. timeout
+interval (changed with the
+.Fl w
+flag), a "*" is printed for that
+probe.
+.Pp
+We don't want the destination
+host to process the
+.Tn UDP
+probe packets so the destination port is set to an
+unlikely value (if some clod on the destination is using that
+value, it can be changed with the
+.Fl p
+flag).
+.Pp
+A sample use and output might be:
+.Bd -literal
+[yak 71]% traceroute nis.nsf.net.
+traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 38 byte packet
+1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+
+.Ed
+Note that lines 2 & 3 are the same. This is due to a buggy
+kernel on the 2nd hop system \- lbl-csam.arpa \- that forwards
+packets with a zero ttl (a bug in the distributed version
+of 4.3
+.Tn BSD ) .
+Note that you have to guess what path
+the packets are taking cross-country since the
+.Tn NSFNet
+(129.140)
+doesn't supply address-to-name translations for its
+.Tn NSS Ns es .
+.Pp
+A more interesting example is:
+.Bd -literal
+[yak 72]% traceroute allspice.lcs.mit.edu.
+traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
+1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+12 * * *
+13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+14 * * *
+15 * * *
+16 * * *
+17 * * *
+18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+
+.Ed
+Note that the gateways 12, 14, 15, 16 & 17 hops away
+either don't send
+.Tn ICMP
+"time exceeded" messages or send them
+with a ttl too small to reach us. 14 \- 17 are running the
+.Tn MIT
+C Gateway code that doesn't send "time exceeded"s. God
+only knows what's going on with 12.
+.Pp
+The silent gateway 12 in the above may be the result of a bug in
+the 4.[23]
+.Tn BSD
+network code (and its derivatives): 4.x (x <= 3)
+sends an unreachable message using whatever ttl remains in the
+original datagram. Since, for gateways, the remaining ttl is
+zero, the
+.Tn ICMP
+"time exceeded" is guaranteed to not make it back
+to us. The behavior of this bug is slightly more interesting
+when it appears on the destination system:
+.Bd -literal
+1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+7 * * *
+8 * * *
+9 * * *
+10 * * *
+11 * * *
+12 * * *
+13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+
+.Ed
+Notice that there are 12 "gateways" (13 is the final
+destination) and exactly the last half of them are "missing".
+What's really happening is that rip (a Sun-3 running Sun OS3.5)
+is using the ttl from our arriving datagram as the ttl in its
+.Tn ICMP
+reply. So, the reply will time out on the return path
+(with no notice sent to anyone since
+.Tn ICMP's
+aren't sent for
+.Tn ICMP's )
+until we probe with a ttl that's at least twice the path
+length. I.e., rip is really only 7 hops away. A reply that
+returns with a ttl of 1 is a clue this problem exists.
+.Nm
+prints a "!" after the time if the ttl is <= 1.
+Since vendors ship a lot of obsolete
+.Pf ( Tn DEC Ns \'s
+Ultrix, Sun 3.x) or
+non-standard
+.Pq Tn HPUX
+software, expect to see this problem
+frequently and/or take care picking the target host of your
+probes.
+.Pp
+Other possible annotations after the time are
+.Sy !H ,
+.Sy !N ,
+or
+.Sy !P
+(host, network or protocol unreachable),
+.Sy !S
+(source route failed),
+.B !F\-<pmtu>
+(fragmentation needed \- the RFC1191 Path MTU Discovery value is displayed),
+.Sy !U
+or
+.Sy !W
+(destination network/host unknown),
+.Sy !I
+(source host is isolated),
+.Sy !A
+(communication with destination network administratively prohibited),
+.Sy !Z
+(communication with destination host administratively prohibited),
+.Sy !Q
+(for this ToS the destination network is unreachable),
+.Sy !T
+(for this ToS the destination host is unreachable),
+.Sy !X
+(communication administratively prohibited),
+.Sy !V
+(host precedence violation),
+.Sy !C
+(precedence cutoff in effect), or
+.Sy !<num>
+(ICMP unreachable code <num>).
+These are defined by RFC1812 (which supersedes RFC1716).
+If almost all the probes result in some kind of unreachable,
+.Nm
+will give up and exit.
+.Pp
+This program is intended for use in network testing, measurement
+and management.
+It should be used primarily for manual fault isolation.
+Because of the load it could impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.Sh AUTHOR
+Implemented by Van Jacobson from a suggestion by Steve Deering. Debugged
+by a cast of thousands with particularly cogent suggestions or fixes from
+C. Philip Wood, Tim Seaver and Ken Adelman.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ping 8 ,
+.Xr traceroute6 8
+.Sh BUGS
+When using protocols other than UDP, functionality is reduced.
+In particular, the last packet will often appear to be lost, because
+even though it reaches the destination host, there's no way to know
+that because no ICMP message is sent back.
+In the TCP case,
+.Nm
+should listen for a RST from the destination host (or an intermediate
+router that's filtering packets), but this is not implemented yet.
+.Pp
+The AS number capability reports information that may sometimes be
+inaccurate due to discrepancies between the contents of the
+routing database server and the current state of the Internet.
diff --git a/network_cmds/traceroute.tproj/traceroute.c b/network_cmds/traceroute.tproj/traceroute.c
new file mode 100644
index 0000000..a411d0a
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+ "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
+The Regents of the University of California. All rights reserved.\n";
+#endif
+
+/*
+ * traceroute host - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host. We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway. We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to net.inet.ip.ttl hops & can be changed with the -m flag).
+ * Three probes (change with -q flag) are sent at each ttl setting and
+ * a line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe. If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed. If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format. We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ * [yak 71]% traceroute nis.nsf.net.
+ * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
+ * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+ * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+ * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+ * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+ *
+ * Note that lines 2 & 3 are the same. This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ * [yak 72]% traceroute allspice.lcs.mit.edu.
+ * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+ * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+ * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+ * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+ * 12 * * *
+ * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+ * 14 * * *
+ * 15 * * *
+ * 16 * * *
+ * 17 * * *
+ * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us. 14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s. God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram. Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us. The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+ * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+ * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+ * 7 * * *
+ * 8 * * *
+ * 9 * * *
+ * 10 * * *
+ * 11 * * *
+ * 12 * * *
+ * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply. So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length. I.e., rip is really only 7 hops away. A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one). If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid. (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley: A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in a ip datagram). See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
+ * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram. 8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id). So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range). To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example. I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep. I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering. Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis. I don't know (or care) who came up with
+ * the idea first. I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself. Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless. Maybe one day...
+ *
+ * -- Van Jacobson (van@ee.lbl.gov)
+ * Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#include <sys/time.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <arpa/inet.h>
+
+#ifdef IPSEC
+#include <net/route.h>
+#include <netinet6/ipsec.h> /* XXX */
+#endif /* IPSEC */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <memory.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+/* rfc1716 */
+#ifndef ICMP_UNREACH_FILTER_PROHIB
+#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */
+#endif
+#ifndef ICMP_UNREACH_HOST_PRECEDENCE
+#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */
+#endif
+#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
+#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */
+#endif
+
+#include "findsaddr.h"
+#include "ifaddrlist.h"
+#include "as.h"
+#include "traceroute.h"
+
+/* Maximum number of gateways (include room for one noop) */
+#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define Fprintf (void)fprintf
+#define Printf (void)printf
+
+/* What a GRE packet header looks like */
+struct grehdr {
+ u_int16_t flags;
+ u_int16_t proto;
+ u_int16_t length; /* PPTP version of these fields */
+ u_int16_t callId;
+};
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+/* For GRE, we prepare what looks like a PPTP packet */
+#define GRE_PPTP_PROTO 0x880b
+
+/* Host name and address list */
+struct hostinfo {
+ char *name;
+ int n;
+ u_int32_t *addrs;
+};
+
+/* Data section of the probe packet */
+struct outdata {
+ u_char seq; /* sequence number of this packet */
+ u_char ttl; /* ttl packet left with */
+ struct timeval tv; /* time packet left */
+};
+
+#ifndef HAVE_ICMP_NEXTMTU
+/* Path MTU Discovery (RFC1191) */
+struct my_pmtu {
+ u_short ipm_void;
+ u_short ipm_nextmtu;
+};
+#endif
+
+u_char packet[512]; /* last inbound (icmp) packet */
+
+struct ip *outip; /* last output ip packet */
+u_char *outp; /* last output inner protocol packet */
+
+struct ip *hip = NULL; /* Quoted IP header */
+int hiplen = 0;
+
+/* loose source route gateway list (including room for final destination) */
+u_int32_t gwlist[NGATEWAYS + 1];
+
+int s; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+
+struct sockaddr whereto; /* Who to try to reach */
+struct sockaddr wherefrom; /* Who we are */
+int packlen; /* total length of packet */
+int protlen; /* length of protocol part of packet */
+int minpacket; /* min ip packet size */
+int maxpacket = 32 * 1024; /* max ip packet size */
+int pmtu; /* Path MTU Discovery (RFC1191) */
+u_int pausemsecs;
+
+char *prog;
+char *source;
+char *hostname;
+char *device;
+static const char devnull[] = "/dev/null";
+
+int nprobes = -1;
+int max_ttl;
+int first_ttl = 1;
+u_short ident;
+u_short port; /* protocol specific base "port" */
+
+int options; /* socket options */
+int verbose;
+int waittime = 5; /* time to wait for response (in seconds) */
+int nflag; /* print addresses numerically */
+int as_path; /* print as numbers for each hop */
+char *as_server = NULL;
+void *asn;
+#ifdef CANT_HACK_IPCKSUM
+int doipcksum = 0; /* don't calculate ip checksums by default */
+#else
+int doipcksum = 1; /* calculate ip checksums by default */
+#endif
+int optlen; /* length of ip options */
+int fixedPort = 0; /* Use fixed destination port for TCP and UDP */
+int printdiff = 0; /* Print the difference between sent and quoted */
+
+extern int optind;
+extern int opterr;
+extern char *optarg;
+
+/* Forwards */
+double deltaT(struct timeval *, struct timeval *);
+void freehostinfo(struct hostinfo *);
+void getaddr(u_int32_t *, char *);
+struct hostinfo *gethostinfo(char *);
+u_short in_cksum(u_short *, int);
+char *inetname(struct in_addr);
+int main(int, char **);
+u_short p_cksum(struct ip *, u_short *, int);
+int packet_ok(u_char *, int, struct sockaddr_in *, int);
+char *pr_type(u_char);
+void print(u_char *, int, struct sockaddr_in *);
+#ifdef IPSEC
+int setpolicy __P((int so, char *policy));
+#endif
+void send_probe(int, int);
+struct outproto *setproto(char *);
+int str2val(const char *, const char *, int, int);
+void tvsub(struct timeval *, struct timeval *);
+void usage(void);
+int wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
+void pkt_compare(const u_char *, int, const u_char *, int);
+#ifndef HAVE_USLEEP
+int usleep(u_int);
+#endif
+
+void udp_prep(struct outdata *);
+int udp_check(const u_char *, int);
+void tcp_prep(struct outdata *);
+int tcp_check(const u_char *, int);
+void gre_prep(struct outdata *);
+int gre_check(const u_char *, int);
+void gen_prep(struct outdata *);
+int gen_check(const u_char *, int);
+void icmp_prep(struct outdata *);
+int icmp_check(const u_char *, int);
+
+/* Descriptor structure for each outgoing protocol we support */
+struct outproto {
+ char *name; /* name of protocol */
+ const char *key; /* An ascii key for the bytes of the header */
+ u_char num; /* IP protocol number */
+ u_short hdrlen; /* max size of protocol header */
+ u_short port; /* default base protocol-specific "port" */
+ void (*prepare)(struct outdata *);
+ /* finish preparing an outgoing packet */
+ int (*check)(const u_char *, int);
+ /* check an incoming packet */
+};
+
+/* List of supported protocols. The first one is the default. The last
+ one is the handler for generic protocols not explicitly listed. */
+struct outproto protos[] = {
+ {
+ "udp",
+ "spt dpt len sum",
+ IPPROTO_UDP,
+ sizeof(struct udphdr),
+ 32768 + 666,
+ udp_prep,
+ udp_check
+ },
+ {
+ "tcp",
+ "spt dpt seq ack xxflwin sum urp",
+ IPPROTO_TCP,
+ sizeof(struct tcphdr),
+ 32768 + 666,
+ tcp_prep,
+ tcp_check
+ },
+ {
+ "gre",
+ "flg pro len clid",
+ IPPROTO_GRE,
+ sizeof(struct grehdr),
+ GRE_PPTP_PROTO,
+ gre_prep,
+ gre_check
+ },
+ {
+ "icmp",
+ "typ cod sum ",
+ IPPROTO_ICMP,
+ sizeof(struct icmp),
+ 0,
+ icmp_prep,
+ icmp_check
+ },
+ {
+ NULL,
+ NULL,
+ 0,
+ 2 * sizeof(u_short),
+ 0,
+ gen_prep,
+ gen_check
+ },
+};
+struct outproto *proto = &protos[0];
+
+const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts";
+
+int
+main(int argc, char **argv)
+{
+ register int op, code, n;
+ register char *cp;
+ register const char *err;
+ register u_int32_t *ap;
+ register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
+ register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
+ register struct hostinfo *hi;
+ int on = 1;
+ register struct protoent *pe;
+ register int ttl, probe, i;
+ register int seq = 0;
+ int tos = 0, settos = 0;
+ register int lsrr = 0;
+ register u_short off = 0;
+ struct ifaddrlist *al;
+ char errbuf[132];
+ int requestPort = -1;
+ int sump = 0;
+ int sockerrno = 0;
+
+ if (argv[0] == NULL)
+ prog = "traceroute";
+ else if ((cp = strrchr(argv[0], '/')) != NULL)
+ prog = cp + 1;
+ else
+ prog = argv[0];
+
+ /* Insure the socket fds won't be 0, 1 or 2 */
+ if (open(devnull, O_RDONLY) < 0 ||
+ open(devnull, O_RDONLY) < 0 ||
+ open(devnull, O_RDONLY) < 0) {
+ Fprintf(stderr, "%s: open \"%s\": %s\n",
+ prog, devnull, strerror(errno));
+ exit(1);
+ }
+ /*
+ * Do the setuid-required stuff first, then lose priveleges ASAP.
+ * Do error checking for these two calls where they appeared in
+ * the original code.
+ */
+ cp = "icmp";
+ pe = getprotobyname(cp);
+ if (pe) {
+ if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
+ sockerrno = errno;
+ else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+ sockerrno = errno;
+ }
+
+ setuid(getuid());
+
+#ifdef IPCTL_DEFTTL
+ {
+ int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+ size_t sz = sizeof(max_ttl);
+
+ if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
+ perror("sysctl(net.inet.ip.ttl)");
+ exit(1);
+ }
+ }
+#else
+ max_ttl = 30;
+#endif
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+ switch (op) {
+ case 'a':
+ as_path = 1;
+ break;
+
+ case 'A':
+ as_path = 1;
+ as_server = optarg;
+ break;
+
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+
+ case 'D':
+ printdiff = 1;
+ break;
+
+ case 'e':
+ fixedPort = 1;
+ break;
+
+ case 'f':
+ case 'M': /* FreeBSD compat. */
+ first_ttl = str2val(optarg, "first ttl", 1, 255);
+ break;
+
+ case 'F':
+ off = IP_DF;
+ break;
+
+ case 'g':
+ if (lsrr >= NGATEWAYS) {
+ Fprintf(stderr,
+ "%s: No more than %d gateways\n",
+ prog, NGATEWAYS);
+ exit(1);
+ }
+ getaddr(gwlist + lsrr, optarg);
+ ++lsrr;
+ break;
+
+ case 'i':
+ device = optarg;
+ break;
+
+ case 'I':
+ proto = setproto("icmp");
+ break;
+
+ case 'm':
+ max_ttl = str2val(optarg, "max ttl", 1, 255);
+ break;
+
+ case 'n':
+ ++nflag;
+ break;
+
+ case 'P':
+ proto = setproto(optarg);
+ break;
+
+ case 'p':
+ requestPort = (u_short)str2val(optarg, "port",
+ 1, (1 << 16) - 1);
+ break;
+
+ case 'q':
+ nprobes = str2val(optarg, "nprobes", 1, -1);
+ break;
+
+ case 'r':
+ options |= SO_DONTROUTE;
+ break;
+
+ case 's':
+ /*
+ * set the ip source address of the outbound
+ * probe (e.g., on a multi-homed host).
+ */
+ source = optarg;
+ break;
+
+ case 'S':
+ sump = 1;
+ break;
+
+ case 't':
+ tos = str2val(optarg, "tos", 0, 255);
+ ++settos;
+ break;
+
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'x':
+ doipcksum = (doipcksum == 0);
+ break;
+
+ case 'w':
+ waittime = str2val(optarg, "wait time",
+ 1, 24 * 60 * 60);
+ break;
+
+ case 'z':
+ pausemsecs = str2val(optarg, "pause msecs",
+ 0, 60 * 60 * 1000);
+ break;
+
+ default:
+ usage();
+ }
+
+ /* Set requested port, if any, else default for this protocol */
+ port = (requestPort != -1) ? requestPort : proto->port;
+
+ if (nprobes == -1)
+ nprobes = printdiff ? 1 : 3;
+
+ if (first_ttl > max_ttl) {
+ Fprintf(stderr,
+ "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
+ prog, first_ttl, max_ttl);
+ exit(1);
+ }
+
+ if (!doipcksum)
+ Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
+
+ if (lsrr > 0)
+ optlen = (lsrr + 1) * sizeof(gwlist[0]);
+ minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
+ packlen = minpacket; /* minimum sized packet */
+
+ /* Process destination and optional packet size */
+ switch (argc - optind) {
+
+ case 2:
+ packlen = str2val(argv[optind + 1],
+ "packet length", minpacket, maxpacket);
+ /* Fall through */
+
+ case 1:
+ hostname = argv[optind];
+ hi = gethostinfo(hostname);
+ setsin(to, hi->addrs[0]);
+ if (hi->n > 1)
+ Fprintf(stderr,
+ "%s: Warning: %s has multiple addresses; using %s\n",
+ prog, hostname, inet_ntoa(to->sin_addr));
+ hostname = hi->name;
+ hi->name = NULL;
+ freehostinfo(hi);
+ break;
+
+ default:
+ usage();
+ }
+
+#ifdef HAVE_SETLINEBUF
+ setlinebuf (stdout);
+#else
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
+
+ protlen = packlen - sizeof(*outip) - optlen;
+
+ outip = (struct ip *)malloc((unsigned)packlen);
+ if (outip == NULL) {
+ Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ memset((char *)outip, 0, packlen);
+
+ outip->ip_v = IPVERSION;
+ if (settos)
+ outip->ip_tos = tos;
+#ifdef BYTESWAP_IP_HDR
+ outip->ip_len = htons(packlen);
+ outip->ip_off = htons(off);
+#else
+ outip->ip_len = packlen;
+ outip->ip_off = off;
+#endif
+ outip->ip_p = proto->num;
+ outp = (u_char *)(outip + 1);
+#ifdef HAVE_RAW_OPTIONS
+ if (lsrr > 0) {
+ register u_char *optlist;
+
+ optlist = outp;
+ outp += optlen;
+
+ /* final hop */
+ gwlist[lsrr] = to->sin_addr.s_addr;
+
+ outip->ip_dst.s_addr = gwlist[0];
+
+ /* force 4 byte alignment */
+ optlist[0] = IPOPT_NOP;
+ /* loose source route option */
+ optlist[1] = IPOPT_LSRR;
+ i = lsrr * sizeof(gwlist[0]);
+ optlist[2] = i + 3;
+ /* Pointer to LSRR addresses */
+ optlist[3] = IPOPT_MINOFF;
+ memcpy(optlist + 4, gwlist + 1, i);
+ } else
+#endif
+ outip->ip_dst = to->sin_addr;
+
+ outip->ip_hl = (outp - (u_char *)outip) >> 2;
+ ident = (getpid() & 0xffff) | 0x8000;
+
+ if (pe == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+ if (s < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&on,
+ sizeof(on));
+ if (options & SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(s, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(s, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ if (sndsock < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+
+#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
+ if (lsrr > 0) {
+ u_char optlist[MAX_IPOPTLEN];
+
+ cp = "ip";
+ if ((pe = getprotobyname(cp)) == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+
+ /* final hop */
+ gwlist[lsrr] = to->sin_addr.s_addr;
+ ++lsrr;
+
+ /* force 4 byte alignment */
+ optlist[0] = IPOPT_NOP;
+ /* loose source route option */
+ optlist[1] = IPOPT_LSRR;
+ i = lsrr * sizeof(gwlist[0]);
+ optlist[2] = i + 3;
+ /* Pointer to LSRR addresses */
+ optlist[3] = IPOPT_MINOFF;
+ memcpy(optlist + 4, gwlist, i);
+
+ if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
+ (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
+ Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+ }
+#endif
+
+#ifdef SO_SNDBUF
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
+ sizeof(packlen)) < 0) {
+ Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+#endif
+#ifdef IP_HDRINCL
+ if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+ sizeof(on)) < 0) {
+ Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+#else
+#ifdef IP_TOS
+ if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(tos)) < 0) {
+ Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
+ prog, tos, strerror(errno));
+ exit(1);
+ }
+#endif
+#endif
+ if (options & SO_DEBUG)
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+ /* Get the interface address list */
+ n = ifaddrlist(&al, errbuf, sizeof(errbuf));
+ if (n < 0) {
+ Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
+ exit(1);
+ }
+ if (n == 0) {
+ Fprintf(stderr,
+ "%s: Can't find any network interfaces\n", prog);
+ exit(1);
+ }
+
+ /* Look for a specific device */
+ if (device != NULL) {
+ for (i = n; i > 0; --i, ++al)
+ if (strcmp(device, al->device) == 0)
+ break;
+ if (i <= 0) {
+ Fprintf(stderr, "%s: Can't find interface %.32s\n",
+ prog, device);
+ exit(1);
+ }
+ }
+
+ /* Determine our source address */
+ if (source == NULL) {
+ /*
+ * If a device was specified, use the interface address.
+ * Otherwise, try to determine our source address.
+ */
+ if (device != NULL)
+ setsin(from, al->addr);
+ else if ((err = findsaddr(to, from)) != NULL) {
+ Fprintf(stderr, "%s: findsaddr: %s\n",
+ prog, err);
+ exit(1);
+ }
+ } else {
+ hi = gethostinfo(source);
+ source = hi->name;
+ hi->name = NULL;
+ /*
+ * If the device was specified make sure it
+ * corresponds to the source address specified.
+ * Otherwise, use the first address (and warn if
+ * there are more than one).
+ */
+ if (device != NULL) {
+ for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
+ if (*ap == al->addr)
+ break;
+ if (i <= 0) {
+ Fprintf(stderr,
+ "%s: %s is not on interface %.32s\n",
+ prog, source, device);
+ exit(1);
+ }
+ setsin(from, *ap);
+ } else {
+ setsin(from, hi->addrs[0]);
+ if (hi->n > 1)
+ Fprintf(stderr,
+ "%s: Warning: %s has multiple addresses; using %s\n",
+ prog, source, inet_ntoa(from->sin_addr));
+ }
+ freehostinfo(hi);
+ }
+
+ outip->ip_src = from->sin_addr;
+
+ /* Check the source address (-s), if any, is valid */
+ if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
+ Fprintf(stderr, "%s: bind: %s\n",
+ prog, strerror(errno));
+ exit (1);
+ }
+
+ if (as_path) {
+ asn = as_setup(as_server);
+ if (asn == NULL) {
+ Fprintf(stderr, "%s: as_setup failed, AS# lookups"
+ " disabled\n", prog);
+ (void)fflush(stderr);
+ as_path = 0;
+ }
+ }
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(sndsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(sndsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ Fprintf(stderr, "%s to %s (%s)",
+ prog, hostname, inet_ntoa(to->sin_addr));
+ if (source)
+ Fprintf(stderr, " from %s", source);
+ Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
+ (void)fflush(stderr);
+
+ for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
+ u_int32_t lastaddr = 0;
+ int gotlastaddr = 0;
+ int got_there = 0;
+ int unreachable = 0;
+ int sentfirst = 0;
+ int loss;
+
+ Printf("%2d ", ttl);
+ for (probe = 0, loss = 0; probe < nprobes; ++probe) {
+ register int cc;
+ struct timeval t1, t2;
+ struct timezone tz;
+ register struct ip *ip;
+ struct outdata outdata;
+
+ if (sentfirst && pausemsecs > 0)
+ usleep(pausemsecs * 1000);
+ /* Prepare outgoing data */
+ outdata.seq = ++seq;
+ outdata.ttl = ttl;
+
+ /* Avoid alignment problems by copying bytewise: */
+ (void)gettimeofday(&t1, &tz);
+ memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
+
+ /* Finalize and send packet */
+ (*proto->prepare)(&outdata);
+ send_probe(seq, ttl);
+ ++sentfirst;
+
+ /* Wait for a reply */
+ while ((cc = wait_for_reply(s, from, &t1)) != 0) {
+ double T;
+ int precis;
+
+ (void)gettimeofday(&t2, &tz);
+ i = packet_ok(packet, cc, from, seq);
+ /* Skip short packet */
+ if (i == 0)
+ continue;
+ if (!gotlastaddr ||
+ from->sin_addr.s_addr != lastaddr) {
+ if (gotlastaddr) printf("\n ");
+ print(packet, cc, from);
+ lastaddr = from->sin_addr.s_addr;
+ ++gotlastaddr;
+ }
+ T = deltaT(&t1, &t2);
+#ifdef SANE_PRECISION
+ if (T >= 1000.0)
+ precis = 0;
+ else if (T >= 100.0)
+ precis = 1;
+ else if (T >= 10.0)
+ precis = 2;
+ else
+#endif
+ precis = 3;
+ Printf(" %.*f ms", precis, T);
+ if (printdiff) {
+ Printf("\n");
+ Printf("%*.*s%s\n",
+ -(outip->ip_hl << 3),
+ outip->ip_hl << 3,
+ ip_hdr_key,
+ proto->key);
+ pkt_compare((void *)outip, packlen,
+ (void *)hip, hiplen);
+ }
+ if (i == -2) {
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif
+ ++got_there;
+ break;
+ }
+ /* time exceeded in transit */
+ if (i == -1)
+ break;
+ code = i - 1;
+ switch (code) {
+
+ case ICMP_UNREACH_PORT:
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif
+ ++got_there;
+ break;
+
+ case ICMP_UNREACH_NET:
+ ++unreachable;
+ Printf(" !N");
+ break;
+
+ case ICMP_UNREACH_HOST:
+ ++unreachable;
+ Printf(" !H");
+ break;
+
+ case ICMP_UNREACH_PROTOCOL:
+ ++got_there;
+ Printf(" !P");
+ break;
+
+ case ICMP_UNREACH_NEEDFRAG:
+ ++unreachable;
+ Printf(" !F-%d", pmtu);
+ break;
+
+ case ICMP_UNREACH_SRCFAIL:
+ ++unreachable;
+ Printf(" !S");
+ break;
+
+ case ICMP_UNREACH_NET_UNKNOWN:
+ ++unreachable;
+ Printf(" !U");
+ break;
+
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ ++unreachable;
+ Printf(" !W");
+ break;
+
+ case ICMP_UNREACH_ISOLATED:
+ ++unreachable;
+ Printf(" !I");
+ break;
+
+ case ICMP_UNREACH_NET_PROHIB:
+ ++unreachable;
+ Printf(" !A");
+ break;
+
+ case ICMP_UNREACH_HOST_PROHIB:
+ ++unreachable;
+ Printf(" !Z");
+ break;
+
+ case ICMP_UNREACH_TOSNET:
+ ++unreachable;
+ Printf(" !Q");
+ break;
+
+ case ICMP_UNREACH_TOSHOST:
+ ++unreachable;
+ Printf(" !T");
+ break;
+
+ case ICMP_UNREACH_FILTER_PROHIB:
+ ++unreachable;
+ Printf(" !X");
+ break;
+
+ case ICMP_UNREACH_HOST_PRECEDENCE:
+ ++unreachable;
+ Printf(" !V");
+ break;
+
+ case ICMP_UNREACH_PRECEDENCE_CUTOFF:
+ ++unreachable;
+ Printf(" !C");
+ break;
+
+ default:
+ ++unreachable;
+ Printf(" !<%d>", code);
+ break;
+ }
+ break;
+ }
+ if (cc == 0) {
+ loss++;
+ Printf(" *");
+ }
+ (void)fflush(stdout);
+ }
+ if (sump) {
+ Printf(" (%d%% loss)", (loss * 100) / nprobes);
+ }
+ putchar('\n');
+ if (got_there ||
+ (unreachable > 0 && unreachable >= nprobes - 1))
+ break;
+ }
+ if (as_path)
+ as_shutdown(asn);
+ exit(0);
+}
+
+int
+wait_for_reply(register int sock, register struct sockaddr_in *fromp,
+ register const struct timeval *tp)
+{
+ fd_set *fdsp;
+ size_t nfds;
+ struct timeval now, wait;
+ struct timezone tz;
+ register int cc = 0;
+ register int error;
+ socklen_t fromlen = sizeof(*fromp);
+
+ nfds = howmany(sock + 1, NFDBITS);
+ if ((fdsp = malloc(nfds * sizeof(fd_set))) == NULL)
+ err(1, "malloc");
+ memset(fdsp, 0, nfds * sizeof(fd_set));
+ FD_SET(sock, fdsp);
+
+ wait.tv_sec = tp->tv_sec + waittime;
+ wait.tv_usec = tp->tv_usec;
+ (void)gettimeofday(&now, &tz);
+ tvsub(&wait, &now);
+ if (wait.tv_sec < 0) {
+ wait.tv_sec = 0;
+ wait.tv_usec = 1;
+ }
+
+ error = select(sock + 1, fdsp, NULL, NULL, &wait);
+ if (error == -1 && errno == EINVAL) {
+ Fprintf(stderr, "%s: botched select() args\n", prog);
+ exit(1);
+ }
+ if (error > 0)
+ cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
+ (struct sockaddr *)fromp, &fromlen);
+
+ free(fdsp);
+ return(cc);
+}
+
+void
+send_probe(int seq, int ttl)
+{
+ register int cc;
+
+ outip->ip_ttl = ttl;
+ outip->ip_id = htons(ident + seq);
+
+ /* XXX undocumented debugging hack */
+ if (verbose > 1) {
+ register const u_short *sp;
+ register int nshorts, i;
+
+ sp = (u_short *)outip;
+ nshorts = (u_int)packlen / sizeof(u_short);
+ i = 0;
+ Printf("[ %d bytes", packlen);
+ while (--nshorts >= 0) {
+ if ((i++ % 8) == 0)
+ Printf("\n\t");
+ Printf(" %04x", ntohs(*sp++));
+ }
+ if (packlen & 1) {
+ if ((i % 8) == 0)
+ Printf("\n\t");
+ Printf(" %02x", *(u_char *)sp);
+ }
+ Printf("]\n");
+ }
+
+#if !defined(IP_HDRINCL) && defined(IP_TTL)
+ if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0) {
+ Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
+ prog, ttl, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ cc = sendto(sndsock, (char *)outip,
+ packlen, 0, &whereto, sizeof(whereto));
+ if (cc < 0 || cc != packlen) {
+ if (cc < 0)
+ Fprintf(stderr, "%s: sendto: %s\n",
+ prog, strerror(errno));
+ Printf("%s: wrote %s %d chars, ret=%d\n",
+ prog, hostname, packlen, cc);
+ (void)fflush(stdout);
+ }
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+int
+setpolicy(so, policy)
+ int so;
+ char *policy;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ warnx("%s", ipsec_strerror());
+ return -1;
+ }
+ (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf));
+
+ free(buf);
+
+ return 0;
+}
+#endif
+
+double
+deltaT(struct timeval *t1p, struct timeval *t2p)
+{
+ register double dt;
+
+ dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+ (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+ return (dt);
+}
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+char *
+pr_type(register u_char t)
+{
+ static char *ttab[] = {
+ "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
+ "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
+ "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
+ "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
+ "Info Reply"
+ };
+
+ if (t > 16)
+ return("OUT-OF-RANGE");
+
+ return(ttab[t]);
+}
+
+int
+packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
+ register int seq)
+{
+ register struct icmp *icp;
+ register u_char type, code;
+ register int hlen;
+#ifndef ARCHAIC
+ register struct ip *ip;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ if (cc < hlen + ICMP_MINLEN) {
+ if (verbose)
+ Printf("packet too short (%d bytes) from %s\n", cc,
+ inet_ntoa(from->sin_addr));
+ return (0);
+ }
+ cc -= hlen;
+ icp = (struct icmp *)(buf + hlen);
+#else
+ icp = (struct icmp *)buf;
+#endif
+ type = icp->icmp_type;
+ code = icp->icmp_code;
+ /* Path MTU Discovery (RFC1191) */
+ if (code != ICMP_UNREACH_NEEDFRAG)
+ pmtu = 0;
+ else {
+#ifdef HAVE_ICMP_NEXTMTU
+ pmtu = ntohs(icp->icmp_nextmtu);
+#else
+ pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
+#endif
+ }
+ if (type == ICMP_ECHOREPLY
+ && proto->num == IPPROTO_ICMP
+ && (*proto->check)((u_char *)icp, (u_char)seq))
+ return -2;
+ if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
+ type == ICMP_UNREACH) {
+ u_char *inner;
+
+ hip = &icp->icmp_ip;
+ hiplen = ((u_char *)icp + cc) - (u_char *)hip;
+ hlen = hip->ip_hl << 2;
+ inner = (u_char *)((u_char *)hip + hlen);
+ if (hlen + 12 <= cc
+ && hip->ip_p == proto->num
+ && (*proto->check)(inner, (u_char)seq))
+ return (type == ICMP_TIMXCEED ? -1 : code + 1);
+ }
+#ifndef ARCHAIC
+ if (verbose) {
+ register int i;
+ u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
+
+ Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
+ Printf("%s: icmp type %d (%s) code %d\n",
+ inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
+ for (i = 4; i < cc ; i += sizeof(*lp))
+ Printf("%2d: x%8.8x\n", i, *lp++);
+ }
+#endif
+ return(0);
+}
+
+void
+icmp_prep(struct outdata *outdata)
+{
+ struct icmp *const icmpheader = (struct icmp *) outp;
+
+ icmpheader->icmp_type = ICMP_ECHO;
+ icmpheader->icmp_id = htons(ident);
+ icmpheader->icmp_seq = htons(outdata->seq);
+ icmpheader->icmp_cksum = 0;
+ icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
+ if (icmpheader->icmp_cksum == 0)
+ icmpheader->icmp_cksum = 0xffff;
+}
+
+int
+icmp_check(const u_char *data, int seq)
+{
+ struct icmp *const icmpheader = (struct icmp *) data;
+
+ return (icmpheader->icmp_id == htons(ident)
+ && icmpheader->icmp_seq == htons(seq));
+}
+
+void
+udp_prep(struct outdata *outdata)
+{
+ struct udphdr *const outudp = (struct udphdr *) outp;
+
+ outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
+ outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ outudp->uh_ulen = htons((u_short)protlen);
+ outudp->uh_sum = 0;
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
+ outudp->uh_sum = (sum) ? sum : 0xffff;
+ }
+
+ return;
+}
+
+int
+udp_check(const u_char *data, int seq)
+{
+ struct udphdr *const udp = (struct udphdr *) data;
+
+ return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
+ ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
+}
+
+void
+tcp_prep(struct outdata *outdata)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) outp;
+
+ tcp->th_sport = htons(ident);
+ tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
+ (fixedPort ? outdata->seq : 0));
+ tcp->th_ack = 0;
+ tcp->th_off = 5;
+ tcp->th_flags = TH_SYN;
+ tcp->th_sum = 0;
+
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
+ tcp->th_sum = (sum) ? sum : 0xffff;
+ }
+}
+
+int
+tcp_check(const u_char *data, int seq)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) data;
+
+ return (ntohs(tcp->th_sport) == ident
+ && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+ && tcp->th_seq == ((ident << 16) | (port + seq));
+}
+
+void
+gre_prep(struct outdata *outdata)
+{
+ struct grehdr *const gre = (struct grehdr *) outp;
+
+ gre->flags = htons(0x2001);
+ gre->proto = htons(port);
+ gre->length = 0;
+ gre->callId = htons(ident + outdata->seq);
+}
+
+int
+gre_check(const u_char *data, int seq)
+{
+ struct grehdr *const gre = (struct grehdr *) data;
+
+ return(ntohs(gre->proto) == port
+ && ntohs(gre->callId) == ident + seq);
+}
+
+void
+gen_prep(struct outdata *outdata)
+{
+ u_int16_t *const ptr = (u_int16_t *) outp;
+
+ ptr[0] = htons(ident);
+ ptr[1] = htons(port + outdata->seq);
+}
+
+int
+gen_check(const u_char *data, int seq)
+{
+ u_int16_t *const ptr = (u_int16_t *) data;
+
+ return(ntohs(ptr[0]) == ident
+ && ntohs(ptr[1]) == port + seq);
+}
+
+void
+print(register u_char *buf, register int cc, register struct sockaddr_in *from)
+{
+ register struct ip *ip;
+ register int hlen;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ cc -= hlen;
+
+ if (as_path)
+ Printf(" [AS%d]", as_lookup(asn, &from->sin_addr));
+
+ if (nflag)
+ Printf(" %s", inet_ntoa(from->sin_addr));
+ else
+ Printf(" %s (%s)", inetname(from->sin_addr),
+ inet_ntoa(from->sin_addr));
+
+ if (verbose)
+ Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+}
+
+/*
+ * Checksum routine for UDP and TCP headers.
+ */
+u_short
+p_cksum(struct ip *ip, u_short *data, int len)
+{
+ static struct ipovly ipo;
+ u_short sumh, sumd;
+ u_int32_t sumt;
+
+ ipo.ih_pr = ip->ip_p;
+ ipo.ih_len = htons(len);
+ ipo.ih_src = ip->ip_src;
+ ipo.ih_dst = ip->ip_dst;
+
+ sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
+ sumd = in_cksum((u_short*)data, len); /* payload data cksum */
+ sumt = (sumh << 16) | (sumd);
+
+ return ~in_cksum((u_short*)&sumt, sizeof(sumt));
+}
+
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+u_short
+in_cksum(register u_short *addr, register int len)
+{
+ register int nleft = len;
+ register u_short *w = addr;
+ register u_short answer;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nleft == 1)
+ sum += *(u_char *)w;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
+
+/*
+ * Subtract 2 timeval structs: out = out - in.
+ * Out is assumed to be within about LONG_MAX seconds of in.
+ */
+void
+tvsub(register struct timeval *out, register struct timeval *in)
+{
+
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ --out->tv_sec;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(struct in_addr in)
+{
+ register char *cp;
+ register struct hostent *hp;
+ static int first = 1;
+ static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, sizeof(domain) - 1) < 0)
+ domain[0] = '\0';
+ else {
+ cp = strchr(domain, '.');
+ if (cp == NULL) {
+ hp = gethostbyname(domain);
+ if (hp != NULL)
+ cp = strchr(hp->h_name, '.');
+ }
+ if (cp == NULL)
+ domain[0] = '\0';
+ else {
+ ++cp;
+ memmove(domain, cp, strlen(cp) + 1);
+ }
+ }
+ }
+ if (!nflag && in.s_addr != INADDR_ANY) {
+ hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
+ if (hp != NULL) {
+ if ((cp = strchr(hp->h_name, '.')) != NULL &&
+ strcmp(cp + 1, domain) == 0)
+ *cp = '\0';
+ (void)strlcpy(line, hp->h_name, sizeof(line));
+ return (line);
+ }
+ }
+ return (inet_ntoa(in));
+}
+
+struct hostinfo *
+gethostinfo(register char *hostname)
+{
+ register int n;
+ register struct hostent *hp;
+ register struct hostinfo *hi;
+ register char **p;
+ register u_int32_t addr, *ap;
+
+ if (strlen(hostname) > 64) {
+ Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
+ prog, hostname);
+ exit(1);
+ }
+ hi = calloc(1, sizeof(*hi));
+ if (hi == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ addr = inet_addr(hostname);
+ if ((int32_t)addr != -1) {
+ hi->name = strdup(hostname);
+ hi->n = 1;
+ hi->addrs = calloc(1, sizeof(hi->addrs[0]));
+ if (hi->addrs == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+ hi->addrs[0] = addr;
+ return (hi);
+ }
+
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+ Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
+ exit(1);
+ }
+ if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
+ Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
+ exit(1);
+ }
+ hi->name = strdup(hp->h_name);
+ for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
+ continue;
+ hi->n = n;
+ hi->addrs = calloc(n, sizeof(hi->addrs[0]));
+ if (hi->addrs == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
+ memcpy(ap, *p, sizeof(*ap));
+ return (hi);
+}
+
+void
+freehostinfo(register struct hostinfo *hi)
+{
+ if (hi->name != NULL) {
+ free(hi->name);
+ hi->name = NULL;
+ }
+ free((char *)hi->addrs);
+ free((char *)hi);
+}
+
+void
+getaddr(register u_int32_t *ap, register char *hostname)
+{
+ register struct hostinfo *hi;
+
+ hi = gethostinfo(hostname);
+ *ap = hi->addrs[0];
+ freehostinfo(hi);
+}
+
+void
+setsin(register struct sockaddr_in *sin, register u_int32_t addr)
+{
+
+ memset(sin, 0, sizeof(*sin));
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+#endif
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr;
+}
+
+/* String to value with optional min and max. Handles decimal and hex. */
+int
+str2val(register const char *str, register const char *what,
+ register int mi, register int ma)
+{
+ register const char *cp;
+ register int val;
+ char *ep;
+
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ cp = str + 2;
+ val = (int)strtol(cp, &ep, 16);
+ } else
+ val = (int)strtol(str, &ep, 10);
+ if (*ep != '\0') {
+ Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
+ prog, str, what);
+ exit(1);
+ }
+ if (val < mi && mi >= 0) {
+ if (mi == 0)
+ Fprintf(stderr, "%s: %s must be >= %d\n",
+ prog, what, mi);
+ else
+ Fprintf(stderr, "%s: %s must be > %d\n",
+ prog, what, mi - 1);
+ exit(1);
+ }
+ if (val > ma && ma >= 0) {
+ Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
+ exit(1);
+ }
+ return (val);
+}
+
+struct outproto *
+setproto(char *pname)
+{
+ struct outproto *proto;
+ int i;
+
+ for (i = 0; protos[i].name != NULL; i++) {
+ if (strcasecmp(protos[i].name, pname) == 0) {
+ break;
+ }
+ }
+ proto = &protos[i];
+ if (proto->name == NULL) { /* generic handler */
+ struct protoent *pe;
+ u_int32_t pnum;
+
+ /* Determine the IP protocol number */
+ if ((pe = getprotobyname(pname)) != NULL)
+ pnum = pe->p_proto;
+ else
+ pnum = str2val(optarg, "proto number", 1, 255);
+ proto->num = pnum;
+ }
+ return proto;
+}
+
+void
+pkt_compare(const u_char *a, int la, const u_char *b, int lb) {
+ int l;
+ int i;
+
+ for (i = 0; i < la; i++)
+ Printf("%02x", (unsigned int)a[i]);
+ Printf("\n");
+ l = (la <= lb) ? la : lb;
+ for (i = 0; i < l; i++)
+ if (a[i] == b[i])
+ Printf("__");
+ else
+ Printf("%02x", (unsigned int)b[i]);
+ for (; i < lb; i++)
+ Printf("%02x", (unsigned int)b[i]);
+ Printf("\n");
+}
+
+
+void
+usage(void)
+{
+ extern char version[];
+
+ Fprintf(stderr, "Version %s\n", version);
+ Fprintf(stderr,
+ "Usage: %s [-adDeFInrSvx] [-A as_server] [-f first_ttl] [-g gateway] [-i iface]\n"
+ "\t[-M first_ttl] [-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
+ "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog);
+ exit(1);
+}
diff --git a/network_cmds/traceroute.tproj/traceroute.h b/network_cmds/traceroute.tproj/traceroute.h
new file mode 100644
index 0000000..31154d8
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2000
+ * 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: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Id: traceroute.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+
+extern char *prog;
+
+void setsin(struct sockaddr_in *, u_int32_t);
diff --git a/network_cmds/traceroute.tproj/version.c b/network_cmds/traceroute.tproj/version.c
new file mode 100644
index 0000000..680dcd4
--- /dev/null
+++ b/network_cmds/traceroute.tproj/version.c
@@ -0,0 +1 @@
+char version[] = "1.4a12+Darwin";
diff --git a/network_cmds/traceroute6.tproj/traceroute6.8 b/network_cmds/traceroute6.tproj/traceroute6.8
new file mode 100644
index 0000000..b5b220b
--- /dev/null
+++ b/network_cmds/traceroute6.tproj/traceroute6.8
@@ -0,0 +1,178 @@
+.\" $KAME: traceroute6.8,v 1.10 2004/06/06 12:35:15 suz 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/traceroute6/traceroute6.8,v 1.17 2008/02/10 21:06:38 dwmalone Exp $
+.\"
+.Dd May 17, 1998
+.Dt TRACEROUTE6 8
+.Os
+.\"
+.Sh NAME
+.Nm traceroute6
+.Nd "print the route IPv6 packets will take to a network node"
+.\"
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl dIlnNrvU
+.Ek
+.Bk -words
+.Op Fl f Ar firsthop
+.Ek
+.Bk -words
+.Op Fl g Ar gateway
+.Ek
+.Bk -words
+.Op Fl m Ar hoplimit
+.Ek
+.Bk -words
+.Op Fl p Ar port
+.Ek
+.Bk -words
+.Op Fl q Ar probes
+.Ek
+.Bk -words
+.Op Fl s Ar src
+.Ek
+.Bk -words
+.Op Fl w Ar waittime
+.Ek
+.Bk -words
+.Ar target
+.Op Ar datalen
+.Ek
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+utility
+uses the IPv6 protocol hop limit field to elicit an ICMPv6 TIME_EXCEEDED
+response from each gateway along the path to some host.
+.Pp
+The only mandatory parameter is the destination host name or IPv6 address.
+The default probe datagram carries 12 bytes of payload,
+in addition to the IPv6 header.
+The size of the payload can be specified by giving a length
+(in bytes)
+after the destination host name.
+.Pp
+Other options are:
+.Bl -tag -width Ds
+.It Fl d
+Debug mode.
+.It Fl f Ar firsthop
+Specify how many hops to skip in trace.
+.It Fl g Ar gateway
+Specify intermediate gateway
+.Nm (
+uses routing header).
+.It Fl I
+Use ICMP6 ECHO instead of UDP datagrams.
+.It Fl l
+Print both host hostnames and numeric addresses.
+Normally
+.Nm
+prints only hostnames if
+.Fl n
+is not specified, and only numeric addresses if
+.Fl n
+is specified.
+.It Fl m Ar hoplimit
+Specify maximum hoplimit, up to 255.
+The default is 30 hops.
+.It Fl n
+Do not resolve numeric address to hostname.
+.It Fl N
+Use a packet with no upper layer header for the probes,
+instead of UDP datagrams.
+.It Fl p Ar port
+Set UDP port number to
+.Ar port .
+.It Fl q Ar probes
+Set the number of probe per hop count to
+.Ar probes .
+.It Fl r
+Bypass the normal routing tables and send directly to a host
+on an attached network.
+If the host is not on a directly-connected network,
+an error is returned.
+This option corresponds to the
+.Dv SO_DONTROUTE
+socket option;
+it can be used to ping a local host through an interface
+that has no route through it
+(e.g., after the interface was dropped by a routing daemon).
+.It Fl s Ar src
+.Ar Src
+specifies the source IPv6 address to be used.
+.It Fl U
+Use UDP datagrams for the probes.
+This is the default.
+.It Fl v
+Be verbose.
+.It Fl w Ar waittime
+Specify the delay time between probes.
+.El
+.Pp
+This program prints the route to the given destination and the round-trip
+time to each gateway, in the same manner as traceroute.
+.Pp
+Here is a list of possible annotations after the round-trip time for each gateway:
+.Bl -hang -offset indent
+.It !N
+Destination Unreachable - No Route to Host.
+.It !P
+Destination Unreachable - Administratively Prohibited.
+.It !S
+Destination Unreachable - Not a Neighbour.
+.It !A
+Destination Unreachable - Address Unreachable.
+.It !\&
+This is printed if the hop limit is <= 1 on a port unreachable message.
+This means that the packet got to the destination,
+but that the reply had a hop limit that was just large enough to
+allow it to get back to the source of the traceroute6.
+This was more interesting in the IPv4 case,
+where some IP stack bugs could be identified by this behaviour.
+.El
+.\"
+.Sh RETURN VALUES
+The
+.Nm
+utility will exit with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr ping 8 ,
+.Xr ping6 8 ,
+.Xr traceroute 8
+.\"
+.Sh HISTORY
+The
+.Nm
+utility first appeared in WIDE hydrangea IPv6 protocol stack kit.
diff --git a/network_cmds/traceroute6.tproj/traceroute6.c b/network_cmds/traceroute6.tproj/traceroute6.c
new file mode 100644
index 0000000..1de7809
--- /dev/null
+++ b/network_cmds/traceroute6.tproj/traceroute6.c
@@ -0,0 +1,1423 @@
+/* $KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz 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) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * traceroute host - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host. We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway. We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to 30 hops & can be changed with the -m flag). Three
+ * probes (change with -q flag) are sent at each ttl setting and a
+ * line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe. If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed. If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format. We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ * [yak 71]% traceroute nis.nsf.net.
+ * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+ * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+ * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+ * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+ * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+ *
+ * Note that lines 2 & 3 are the same. This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ * [yak 72]% traceroute allspice.lcs.mit.edu.
+ * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+ * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+ * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+ * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+ * 12 * * *
+ * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+ * 14 * * *
+ * 15 * * *
+ * 16 * * *
+ * 17 * * *
+ * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us. 14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s. God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram. Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us. The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+ * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+ * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+ * 7 * * *
+ * 8 * * *
+ * 9 * * *
+ * 10 * * *
+ * 11 * * *
+ * 12 * * *
+ * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply. So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length. I.e., rip is really only 7 hops away. A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one). If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid. (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley: A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in an ip datagram). See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
+ * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram. 8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id). So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range). To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example. I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep. I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering. Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis. I don't know (or care) who came up with
+ * the idea first. I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself. Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless. Maybe one day...
+ *
+ * -- Van Jacobson (van@helios.ee.lbl.gov)
+ * Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <err.h>
+#ifdef HAVE_POLL
+#include <poll.h>
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/udp.h>
+
+#ifdef IPSEC
+#include <net/route.h>
+#include <netinet6/ipsec.h>
+#endif
+
+#define DUMMY_PORT 10010
+
+#define MAXPACKET 65535 /* max ip packet size */
+
+#ifndef HAVE_GETIPNODEBYNAME
+#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y))
+#define freehostent(x)
+#endif
+
+/*
+ * format of a (udp) probe packet.
+ */
+struct tv32 {
+ u_int32_t tv32_sec;
+ u_int32_t tv32_usec;
+};
+
+struct opacket {
+ u_char seq; /* sequence number of this packet */
+ u_char hops; /* hop limit of the packet */
+ u_char pad[2];
+ struct tv32 tv; /* time packet left */
+} __attribute__((__packed__));
+
+u_char packet[512]; /* last inbound (icmp) packet */
+struct opacket *outpacket; /* last output (udp) packet */
+
+int main(int, char *[]);
+int wait_for_reply(int, struct msghdr *);
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+int setpolicy(int so, char *policy);
+#endif
+#endif
+void send_probe(int, u_long);
+void *get_uphdr(struct ip6_hdr *, u_char *);
+int get_hoplim(struct msghdr *);
+double deltaT(struct timeval *, struct timeval *);
+char *pr_type(int);
+int packet_ok(struct msghdr *, int, int);
+void print(struct msghdr *, int);
+const char *inetname(struct sockaddr *);
+void usage(void);
+
+int rcvsock; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+
+struct msghdr rcvmhdr;
+struct iovec rcviov[2];
+int rcvhlim;
+struct in6_pktinfo *rcvpktinfo;
+
+struct sockaddr_in6 Src, Dst, Rcv;
+u_long datalen; /* How much data */
+#define ICMP6ECHOLEN 8
+/* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
+char rtbuf[2064];
+#ifdef USE_RFC2292BIS
+struct ip6_rthdr *rth;
+#endif
+struct cmsghdr *cmsg;
+
+char *source = 0;
+char *hostname;
+
+u_long nprobes = 3;
+u_long first_hop = 1;
+u_long max_hops = 30;
+u_int16_t srcport;
+u_int16_t port = 32768+666; /* start udp dest port # for probe packets */
+u_int16_t ident;
+int options; /* socket options */
+int verbose;
+int waittime = 5; /* time to wait for response (in seconds) */
+int nflag; /* print addresses numerically */
+int useproto = IPPROTO_UDP; /* protocol to use to send packet */
+int lflag; /* print both numerical address & hostname */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
+ char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
+ int ch, i, on = 1, seq, rcvcmsglen, error, minlen;
+ struct addrinfo hints, *res;
+ static u_char *rcvcmsgbuf;
+ u_long probe, hops, lport;
+ struct hostent *hp;
+ size_t size;
+
+ /*
+ * Receive ICMP
+ */
+ if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ perror("socket(ICMPv6)");
+ exit(5);
+ }
+
+ size = sizeof(i);
+ (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
+ max_hops = i;
+
+ /* specify to tell receiving interface */
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_RECVPKTINFO)");
+#else /* old adv. API */
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_PKTINFO)");
+#endif
+
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
+#else /* old adv. API */
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_HOPLIMIT)");
+#endif
+
+ seq = 0;
+
+ while ((ch = getopt(argc, argv, "df:g:Ilm:nNp:q:rs:Uvw:")) != -1)
+ switch (ch) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'f':
+ ep = NULL;
+ errno = 0;
+ first_hop = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep || first_hop > 255) {
+ fprintf(stderr,
+ "traceroute6: invalid min hoplimit.\n");
+ exit(1);
+ }
+ break;
+ case 'g':
+ hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
+ if (hp == NULL) {
+ fprintf(stderr,
+ "traceroute6: unknown host %s\n", optarg);
+ exit(1);
+ }
+#ifdef USE_RFC2292BIS
+ if (rth == NULL) {
+ /*
+ * XXX: We can't detect the number of
+ * intermediate nodes yet.
+ */
+ if ((rth = inet6_rth_init((void *)rtbuf,
+ sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
+ 0)) == NULL) {
+ fprintf(stderr,
+ "inet6_rth_init failed.\n");
+ exit(1);
+ }
+ }
+ if (inet6_rth_add((void *)rth,
+ (struct in6_addr *)hp->h_addr)) {
+ fprintf(stderr,
+ "inet6_rth_add failed for %s\n",
+ optarg);
+ exit(1);
+ }
+#else /* old advanced API */
+ if (cmsg == NULL)
+ cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0);
+ inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr,
+ IPV6_RTHDR_LOOSE);
+#endif
+ freehostent(hp);
+ break;
+ case 'I':
+ useproto = IPPROTO_ICMPV6;
+ ident = htons(getpid() & 0xffff); /* same as ping6 */
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 'm':
+ ep = NULL;
+ errno = 0;
+ max_hops = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep || max_hops > 255) {
+ fprintf(stderr,
+ "traceroute6: invalid max hoplimit.\n");
+ exit(1);
+ }
+ break;
+ case 'n':
+ nflag++;
+ break;
+ case 'N':
+ useproto = IPPROTO_NONE;
+ break;
+ case 'p':
+ ep = NULL;
+ errno = 0;
+ lport = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep) {
+ fprintf(stderr, "traceroute6: invalid port.\n");
+ exit(1);
+ }
+ if (lport == 0 || lport != (lport & 0xffff)) {
+ fprintf(stderr,
+ "traceroute6: port out of range.\n");
+ exit(1);
+ }
+ port = lport & 0xffff;
+ break;
+ case 'q':
+ ep = NULL;
+ errno = 0;
+ nprobes = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep) {
+ fprintf(stderr,
+ "traceroute6: invalid nprobes.\n");
+ exit(1);
+ }
+ if (nprobes < 1) {
+ fprintf(stderr,
+ "traceroute6: nprobes must be >0.\n");
+ exit(1);
+ }
+ break;
+ case 'r':
+ options |= SO_DONTROUTE;
+ break;
+ case 's':
+ /*
+ * set the ip source address of the outbound
+ * probe (e.g., on a multi-homed host).
+ */
+ source = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'U':
+ useproto = IPPROTO_UDP;
+ break;
+ case 'w':
+ ep = NULL;
+ errno = 0;
+ waittime = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep) {
+ fprintf(stderr,
+ "traceroute6: invalid wait time.\n");
+ exit(1);
+ }
+ if (waittime < 1) {
+ fprintf(stderr,
+ "traceroute6: wait must be >= 1 sec.\n");
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Open socket to send probe packets.
+ */
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ sndsock = rcvsock;
+ break;
+ case IPPROTO_UDP:
+ if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("socket(SOCK_DGRAM)");
+ exit(5);
+ }
+ break;
+ case IPPROTO_NONE:
+ if ((sndsock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
+ perror("socket(SOCK_RAW)");
+ exit(5);
+ }
+ break;
+ default:
+ fprintf(stderr, "traceroute6: unknown probe protocol %d",
+ useproto);
+ exit(5);
+ }
+ if (max_hops < first_hop) {
+ fprintf(stderr,
+ "traceroute6: max hoplimit must be larger than first hoplimit.\n");
+ exit(1);
+ }
+
+ /* revoke privs */
+ seteuid(getuid());
+ setuid(getuid());
+
+ if (argc < 1 || argc > 2)
+ usage();
+
+#if 1
+ setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(stdout);
+#endif
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(*argv, NULL, &hints, &res);
+ if (error) {
+ fprintf(stderr,
+ "traceroute6: %s\n", gai_strerror(error));
+ exit(1);
+ }
+ if (res->ai_addrlen != sizeof(Dst)) {
+ fprintf(stderr,
+ "traceroute6: size of sockaddr mismatch\n");
+ exit(1);
+ }
+ memcpy(&Dst, res->ai_addr, res->ai_addrlen);
+ hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
+ if (!hostname) {
+ fprintf(stderr, "traceroute6: not enough core\n");
+ exit(1);
+ }
+ if (res->ai_next) {
+ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ fprintf(stderr, "traceroute6: Warning: %s has multiple "
+ "addresses; using %s\n", hostname, hbuf);
+ }
+
+ if (*++argv) {
+ ep = NULL;
+ errno = 0;
+ datalen = strtoul(*argv, &ep, 0);
+ if (errno || !*argv || *ep) {
+ fprintf(stderr,
+ "traceroute6: invalid packet length.\n");
+ exit(1);
+ }
+ }
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ minlen = ICMP6ECHOLEN + sizeof(struct tv32);
+ break;
+ case IPPROTO_UDP:
+ minlen = sizeof(struct opacket);
+ break;
+ case IPPROTO_NONE:
+ minlen = 0;
+ datalen = 0;
+ break;
+ default:
+ fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
+ useproto);
+ exit(1);
+ }
+ if (datalen < minlen)
+ datalen = minlen;
+ else if (datalen >= MAXPACKET) {
+ fprintf(stderr,
+ "traceroute6: packet size must be %d <= s < %ld.\n",
+ minlen, (long)MAXPACKET);
+ exit(1);
+ }
+ outpacket = (struct opacket *)malloc((unsigned)datalen);
+ if (!outpacket) {
+ perror("malloc");
+ exit(1);
+ }
+ (void) bzero((char *)outpacket, datalen);
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)packet;
+ rcviov[0].iov_len = sizeof(packet);
+ rcvmhdr.msg_name = (caddr_t)&Rcv;
+ rcvmhdr.msg_namelen = sizeof(Rcv);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
+ fprintf(stderr, "traceroute6: malloc failed\n");
+ exit(1);
+ }
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = rcvcmsglen;
+
+ (void) setsockopt(rcvsock, SOL_SOCKET, SO_RECV_ANYIF, (char *)&on,
+ sizeof(on));
+ if (options & SO_DEBUG)
+ (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
+ (char *)&on, sizeof(on));
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ /*
+ * do not raise error even if setsockopt fails, kernel may have ipsec
+ * turned off.
+ */
+ if (setpolicy(rcvsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+ if (setpolicy(rcvsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#else
+ {
+ int level = IPSEC_LEVEL_NONE;
+
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
+ sizeof(level));
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
+ sizeof(level));
+#ifdef IP_AUTH_TRANS_LEVEL
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
+ sizeof(level));
+#else
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
+ sizeof(level));
+#endif
+#ifdef IP_AUTH_NETWORK_LEVEL
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
+ sizeof(level));
+#endif
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+#ifdef SO_SNDBUF
+ i = datalen;
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
+ sizeof(i)) < 0 && useproto != IPPROTO_NONE) {
+ perror("setsockopt(SO_SNDBUF)");
+ exit(6);
+ }
+#endif /* SO_SNDBUF */
+ if (options & SO_DEBUG)
+ (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
+ (char *)&on, sizeof(on));
+#ifdef USE_RFC2292BIS
+ if (rth) {/* XXX: there is no library to finalize the header... */
+ rth->ip6r_len = rth->ip6r_segleft * 2;
+ if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
+ (void *)rth, (rth->ip6r_len + 1) << 3)) {
+ fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+#else /* old advanced API */
+ if (cmsg != NULL) {
+ inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
+ if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS,
+ rtbuf, cmsg->cmsg_len) < 0) {
+ fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+#endif /* USE_RFC2292BIS */
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ /*
+ * do not raise error even if setsockopt fails, kernel may have ipsec
+ * turned off.
+ */
+ if (setpolicy(sndsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+ if (setpolicy(sndsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#else
+ {
+ int level = IPSEC_LEVEL_BYPASS;
+
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
+ sizeof(level));
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
+ sizeof(level));
+#ifdef IP_AUTH_TRANS_LEVEL
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
+ sizeof(level));
+#else
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
+ sizeof(level));
+#endif
+#ifdef IP_AUTH_NETWORK_LEVEL
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
+ sizeof(level));
+#endif
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+ /*
+ * Source selection
+ */
+ bzero(&Src, sizeof(Src));
+ if (source) {
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(source, "0", &hints, &res);
+ if (error) {
+ printf("traceroute6: %s: %s\n", source,
+ gai_strerror(error));
+ exit(1);
+ }
+ if (res->ai_addrlen > sizeof(Src)) {
+ printf("traceroute6: %s: %s\n", source,
+ gai_strerror(error));
+ exit(1);
+ }
+ memcpy(&Src, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ } else {
+ struct sockaddr_in6 Nxt;
+ int dummy;
+ socklen_t len;
+
+ Nxt = Dst;
+ Nxt.sin6_port = htons(DUMMY_PORT);
+ if (cmsg != NULL)
+ bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
+ sizeof(Nxt.sin6_addr));
+ if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
+ perror("connect");
+ exit(1);
+ }
+ len = sizeof(Src);
+ if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
+ perror("getsockname");
+ exit(1);
+ }
+ if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len,
+ src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
+ fprintf(stderr, "getnameinfo failed for source\n");
+ exit(1);
+ }
+ source = src0;
+ close(dummy);
+ }
+
+ Src.sin6_port = htons(0);
+ if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
+ perror("bind");
+ exit(1);
+ }
+
+ {
+ socklen_t len;
+
+ len = sizeof(Src);
+ if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
+ perror("getsockname");
+ exit(1);
+ }
+ srcport = ntohs(Src.sin6_port);
+ }
+
+ /*
+ * Message to users
+ */
+ if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
+ strlcpy(hbuf, "(invalid)", sizeof(hbuf));
+ fprintf(stderr, "traceroute6");
+ fprintf(stderr, " to %s (%s)", hostname, hbuf);
+ if (source)
+ fprintf(stderr, " from %s", source);
+ fprintf(stderr, ", %lu hops max, %lu byte packets\n",
+ max_hops, datalen);
+ (void) fflush(stderr);
+
+ if (first_hop > 1)
+ printf("Skipping %lu intermediate hops\n", first_hop - 1);
+
+ /*
+ * Main loop
+ */
+ for (hops = first_hop; hops <= max_hops; ++hops) {
+ struct in6_addr lastaddr;
+ int got_there = 0;
+ int unreachable = 0;
+
+ printf("%2lu ", hops);
+ bzero(&lastaddr, sizeof(lastaddr));
+ for (probe = 0; probe < nprobes; ++probe) {
+ int cc;
+ struct timeval t1, t2;
+
+ (void) gettimeofday(&t1, NULL);
+ send_probe(++seq, hops);
+ while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
+ (void) gettimeofday(&t2, NULL);
+ if ((i = packet_ok(&rcvmhdr, cc, seq))) {
+ if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
+ &lastaddr)) {
+ if (probe > 0)
+ fputs("\n ", stdout);
+ print(&rcvmhdr, cc);
+ lastaddr = Rcv.sin6_addr;
+ }
+ printf(" %.3f ms", deltaT(&t1, &t2));
+ switch (i - 1) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ ++unreachable;
+ printf(" !N");
+ break;
+ case ICMP6_DST_UNREACH_ADMIN:
+ ++unreachable;
+ printf(" !P");
+ break;
+ case ICMP6_DST_UNREACH_NOTNEIGHBOR:
+ ++unreachable;
+ printf(" !S");
+ break;
+ case ICMP6_DST_UNREACH_ADDR:
+ ++unreachable;
+ printf(" !A");
+ break;
+ case ICMP6_DST_UNREACH_NOPORT:
+ if (rcvhlim >= 0 &&
+ rcvhlim <= 1)
+ printf(" !");
+ ++got_there;
+ break;
+ }
+ break;
+ }
+ }
+ if (cc == 0)
+ printf(" *");
+ (void) fflush(stdout);
+ }
+ putchar('\n');
+ if (got_there ||
+ (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
+ exit(0);
+ }
+ }
+
+ exit(0);
+}
+
+int
+wait_for_reply(sock, mhdr)
+ int sock;
+ struct msghdr *mhdr;
+{
+#ifdef HAVE_POLL
+ struct pollfd pfd[1];
+ int cc = 0;
+
+ pfd[0].fd = sock;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+
+ if (poll(pfd, 1, waittime * 1000) > 0)
+ cc = recvmsg(rcvsock, mhdr, 0);
+
+ return(cc);
+#else
+ fd_set *fdsp;
+ struct timeval wait;
+ int cc = 0, fdsn;
+
+ fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
+ if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ memset(fdsp, 0, fdsn);
+ FD_SET(sock, fdsp);
+ wait.tv_sec = waittime; wait.tv_usec = 0;
+
+ if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
+ cc = recvmsg(rcvsock, mhdr, 0);
+
+ free(fdsp);
+ return(cc);
+#endif
+}
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+int
+setpolicy(so, policy)
+ int so;
+ char *policy;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ warnx("%s", ipsec_strerror());
+ return -1;
+ }
+ (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf));
+
+ free(buf);
+
+ return 0;
+}
+#endif
+#endif
+
+void
+send_probe(seq, hops)
+ int seq;
+ u_long hops;
+{
+ struct icmp6_hdr *icp;
+ struct opacket *op;
+ struct timeval tv;
+ struct tv32 tv32;
+ int i;
+
+ i = hops;
+ if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ (char *)&i, sizeof(i)) < 0) {
+ perror("setsockopt IPV6_UNICAST_HOPS");
+ }
+
+ Dst.sin6_port = htons(port + seq);
+ (void) gettimeofday(&tv, NULL);
+ tv32.tv32_sec = htonl(tv.tv_sec);
+ tv32.tv32_usec = htonl(tv.tv_usec);
+
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ icp = (struct icmp6_hdr *)outpacket;
+
+ icp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icp->icmp6_code = 0;
+ icp->icmp6_cksum = 0;
+ icp->icmp6_id = ident;
+ icp->icmp6_seq = htons(seq);
+ bcopy(&tv32, ((u_int8_t *)outpacket + ICMP6ECHOLEN),
+ sizeof(tv32));
+ break;
+ case IPPROTO_UDP:
+ op = outpacket;
+
+ op->seq = seq;
+ op->hops = hops;
+ bcopy(&tv32, &op->tv, sizeof tv32);
+ break;
+ case IPPROTO_NONE:
+ /* No space for anything. No harm as seq/tv32 are decorative. */
+ break;
+ default:
+ fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
+ exit(1);
+ }
+
+ i = sendto(sndsock, (char *)outpacket, datalen, 0,
+ (struct sockaddr *)&Dst, Dst.sin6_len);
+ if (i < 0 || i != datalen) {
+ if (i < 0)
+ perror("sendto");
+ printf("traceroute6: wrote %s %lu chars, ret=%d\n",
+ hostname, datalen, i);
+ (void) fflush(stdout);
+ }
+}
+
+int
+get_hoplim(mhdr)
+ struct msghdr *mhdr;
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+double
+deltaT(t1p, t2p)
+ struct timeval *t1p, *t2p;
+{
+ double dt;
+
+ dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+ (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+ return (dt);
+}
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+char *
+pr_type(t0)
+ int t0;
+{
+ u_char t = t0 & 0xff;
+ char *cp;
+
+ switch (t) {
+ case ICMP6_DST_UNREACH:
+ cp = "Destination Unreachable";
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ cp = "Packet Too Big";
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ cp = "Time Exceeded";
+ break;
+ case ICMP6_PARAM_PROB:
+ cp = "Parameter Problem";
+ break;
+ case ICMP6_ECHO_REQUEST:
+ cp = "Echo Request";
+ break;
+ case ICMP6_ECHO_REPLY:
+ cp = "Echo Reply";
+ break;
+ case ICMP6_MEMBERSHIP_QUERY:
+ cp = "Group Membership Query";
+ break;
+ case ICMP6_MEMBERSHIP_REPORT:
+ cp = "Group Membership Report";
+ break;
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ cp = "Group Membership Reduction";
+ break;
+ case ND_ROUTER_SOLICIT:
+ cp = "Router Solicitation";
+ break;
+ case ND_ROUTER_ADVERT:
+ cp = "Router Advertisement";
+ break;
+ case ND_NEIGHBOR_SOLICIT:
+ cp = "Neighbor Solicitation";
+ break;
+ case ND_NEIGHBOR_ADVERT:
+ cp = "Neighbor Advertisement";
+ break;
+ case ND_REDIRECT:
+ cp = "Redirect";
+ break;
+ default:
+ cp = "Unknown";
+ break;
+ }
+ return cp;
+}
+
+int
+packet_ok(mhdr, cc, seq)
+ struct msghdr *mhdr;
+ int cc;
+ int seq;
+{
+ struct icmp6_hdr *icp;
+ struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
+ u_char type, code;
+ char *buf = (char *)mhdr->msg_iov[0].iov_base;
+ struct cmsghdr *cm;
+ int *hlimp;
+ char hbuf[NI_MAXHOST];
+
+#ifdef OLDRAWSOCKET
+ int hlen;
+ struct ip6_hdr *ip;
+#endif
+
+#ifdef OLDRAWSOCKET
+ ip = (struct ip6_hdr *) buf;
+ hlen = sizeof(struct ip6_hdr);
+ if (cc < hlen + sizeof(struct icmp6_hdr)) {
+ if (verbose) {
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "invalid", sizeof(hbuf));
+ printf("packet too short (%d bytes) from %s\n", cc,
+ hbuf);
+ }
+ return (0);
+ }
+ cc -= hlen;
+ icp = (struct icmp6_hdr *)(buf + hlen);
+#else
+ if (cc < sizeof(struct icmp6_hdr)) {
+ if (verbose) {
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "invalid", sizeof(hbuf));
+ printf("data too short (%d bytes) from %s\n", cc, hbuf);
+ }
+ return(0);
+ }
+ icp = (struct icmp6_hdr *)buf;
+#endif
+ /* get optional information via advanced API */
+ rcvpktinfo = NULL;
+ hlimp = NULL;
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len ==
+ CMSG_LEN(sizeof(struct in6_pktinfo)))
+ rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+ if (rcvpktinfo == NULL || hlimp == NULL) {
+ warnx("failed to get received hop limit or packet info");
+#if 0
+ return(0);
+#else
+ rcvhlim = 0; /*XXX*/
+#endif
+ }
+ else
+ rcvhlim = *hlimp;
+
+ type = icp->icmp6_type;
+ code = icp->icmp6_code;
+ if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
+ || type == ICMP6_DST_UNREACH) {
+ struct ip6_hdr *hip;
+ void *up;
+
+ hip = (struct ip6_hdr *)(icp + 1);
+ if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
+ if (verbose)
+ warnx("failed to get upper layer header");
+ return(0);
+ }
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ if (((struct icmp6_hdr *)up)->icmp6_id == ident &&
+ ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq))
+ return (type == ICMP6_TIME_EXCEEDED ?
+ -1 : code + 1);
+ break;
+ case IPPROTO_UDP:
+ if (((struct udphdr *)up)->uh_sport == htons(srcport) &&
+ ((struct udphdr *)up)->uh_dport == htons(port + seq))
+ return (type == ICMP6_TIME_EXCEEDED ?
+ -1 : code + 1);
+ break;
+ case IPPROTO_NONE:
+ return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
+ default:
+ fprintf(stderr, "Unknown probe proto %d.\n", useproto);
+ break;
+ }
+ } else if (useproto == IPPROTO_ICMPV6 && type == ICMP6_ECHO_REPLY) {
+ if (icp->icmp6_id == ident &&
+ icp->icmp6_seq == htons(seq))
+ return (ICMP6_DST_UNREACH_NOPORT + 1);
+ }
+ if (verbose) {
+ char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
+ u_int8_t *p;
+ int i;
+
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(sbuf, "invalid", sizeof(sbuf));
+ printf("\n%d bytes from %s to %s", cc, sbuf,
+ rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
+ dbuf, sizeof(dbuf)) : "?");
+ printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
+ icp->icmp6_code);
+ p = (u_int8_t *)(icp + 1);
+#define WIDTH 16
+ for (i = 0; i < cc; i++) {
+ if (i % WIDTH == 0)
+ printf("%04x:", i);
+ if (i % 4 == 0)
+ printf(" ");
+ printf("%02x", p[i]);
+ if (i % WIDTH == WIDTH - 1)
+ printf("\n");
+ }
+ if (cc % WIDTH != 0)
+ printf("\n");
+ }
+ return(0);
+}
+
+/*
+ * Increment pointer until find the UDP or ICMP header.
+ */
+void *
+get_uphdr(ip6, lim)
+ struct ip6_hdr *ip6;
+ u_char *lim;
+{
+ u_char *cp = (u_char *)ip6, nh;
+ int hlen;
+ static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
+
+ if (cp + sizeof(*ip6) > lim)
+ return(NULL);
+
+ nh = ip6->ip6_nxt;
+ cp += sizeof(struct ip6_hdr);
+
+ while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
+ switch (nh) {
+ case IPPROTO_ESP:
+ case IPPROTO_TCP:
+ return(NULL);
+ case IPPROTO_ICMPV6:
+ return(useproto == nh ? cp : NULL);
+ case IPPROTO_UDP:
+ return(useproto == nh ? cp : NULL);
+ case IPPROTO_NONE:
+ return(useproto == nh ? none_hdr : NULL);
+ case IPPROTO_FRAGMENT:
+ hlen = sizeof(struct ip6_frag);
+ nh = ((struct ip6_frag *)cp)->ip6f_nxt;
+ break;
+ case IPPROTO_AH:
+ hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
+ nh = ((struct ip6_ext *)cp)->ip6e_nxt;
+ break;
+ default:
+ hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
+ nh = ((struct ip6_ext *)cp)->ip6e_nxt;
+ break;
+ }
+
+ cp += hlen;
+ }
+
+ return(NULL);
+}
+
+void
+print(mhdr, cc)
+ struct msghdr *mhdr;
+ int cc;
+{
+ struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
+ char hbuf[NI_MAXHOST];
+
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "invalid", sizeof(hbuf));
+ if (nflag)
+ printf(" %s", hbuf);
+ else if (lflag)
+ printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
+ else
+ printf(" %s", inetname((struct sockaddr *)from));
+
+ if (verbose) {
+#ifdef OLDRAWSOCKET
+ printf(" %d bytes to %s", cc,
+ rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
+ hbuf, sizeof(hbuf)) : "?");
+#else
+ printf(" %d bytes of data to %s", cc,
+ rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
+ hbuf, sizeof(hbuf)) : "?");
+#endif
+ }
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+const char *
+inetname(sa)
+ struct sockaddr *sa;
+{
+ static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+ char *cp;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, sizeof(domain)) == 0 &&
+ (cp = strchr(domain, '.')))
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = NULL;
+ if (!nflag) {
+ if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
+ NI_NAMEREQD) == 0) {
+ if ((cp = strchr(line, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = line;
+ }
+ }
+ if (cp)
+ return cp;
+
+ if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ strlcpy(line, "invalid", sizeof(line));
+ return line;
+}
+
+void
+usage()
+{
+
+ fprintf(stderr,
+"usage: traceroute6 [-dIlnNrUv] [-f firsthop] [-g gateway] [-m hoplimit]\n"
+" [-p port] [-q probes] [-s src] [-w waittime] target [datalen]\n");
+ exit(1);
+}