Compare commits

...

86 Commits
trunk ... ROY

Author SHA1 Message Date
roy 986d1710a8 Update to dhcpcd-10.0.8 with the following fixes:
* Fixed compile without ARP
 * Fixed spelling of ADVERTISEMENT
2024-05-24 16:07:42 +00:00
roy e355904211 Update to dhcpcd-10.0.7 with the following changes:
* DHCP: use request_time, fallback_time and ipv4ll_time rather than reboot timeout
* DHCP6: Wait for IRT to elapse before requesting advertisments
* DHCPv6: Don't re-INFORM if the RA changes
* privsep: Reduce fd use
* dhcpcd: Add support for arp persist defence
* Move dhcp(v4) packet size check earlier
* Define the Azure Endpoint and other site-specific options
* add RFC4191 support by @goertzenator in #297
* dhcpcd: Respect IPV6_PREFERRED_ONLY flag regardless of state
* Fix time_offset to be int to match RFC-2132
* hooks/30-hostname: Exit with 0 if setting hostname is not needed
2024-05-24 11:28:00 +00:00
roy a7f052dc0d Import dhcpcd-10.0.6 with the following changes:
privsep: Stop proxying stderr to console and fix some detachment issues
    non-privsep: Fix launcher hangup
    DHCP6: Allow the invalid interface name - to mean don't assign an address from a delegated prefix
    DHCP6: Load the configuration for the interface being activated from prefix delegation
2023-12-18 15:56:32 +00:00
roy 0ea6469f35 Import dhcpcd-10.0.6 with the following changes:
* privsep: Stop proxying stderr to console and fix some detachment issues
 * non-privsep: Fix launcher hangup
 * DHCP6: Allow the invalid interface name - to mean don't assign an address from a delegated prefix
 * DHCP6: Load the configuration for the interface being activated from prefix delegation
2023-12-18 15:49:41 +00:00
roy 6d263e5669 Import dhcpcd-10.0.4 with the following change:
privsep: Notify processes that dhcpcd has daemonised so they dup
         stdout and stderr to /dev/null.
         This avoids scripts failing with SIGPIPE if they try and write
         to these streams.
2023-10-19 11:25:17 +00:00
roy 5f00958399 Import dhcpcd-10.0.3 with the following changes:
DHCP: Don't crash on a test run
dhcpcd: Fix off-by-one overflow when read() writes full BUFSIZ
privsep: fix strlcpy overflow in psp_ifname
privsep: Fix a FD leak when processes exit
dhcpcd: Use a local variable instead of the optind
dhcpcd: Guard against handling many SIGTERM/SIGINT
DHCP6: Send correct amount of used buffer for prefix exclude option
options: andsf6 is DHCPv6, not DHCP
options: introduce the uri option as opposed to a string
DHCP6: Set all requested addrs as not stale when starting discovery
2023-10-06 08:46:21 +00:00
roy 4fce98e7fd Import dhcpcd-10.0.2 with the following changes:
* BSD: When we get RTM_NEWADDR the interface must have IFF_UP
 * BSD: Fix non INET6 builds
 * DHCP: Don't enforce the message came port 67
 * privsep: Allow zero length messages through
 * dhcpcd: deal with HANGUP and EPIPE better
 * dhcpcd: Fix waitip address family
 * privsep: Check if we have a root process before sending it stuff
 * privsep: Only unlink control sockets if we created them
 * common: Improve valid_domain and check correct return
 * common: Allow hwaddr_ntoa to print an empty string
 * privsep: Send only what we have put in the buffer to script env
2023-07-19 13:51:07 +00:00
roy 5ba815c7a7 openresolv: Update to 3.13.2 with the following changes:
* Do not return error from -i when no interfaces are configured
* unbound can now add generic options to forward zones
2023-06-27 17:04:19 +00:00
roy b21ddb5395 Update to dhcpcd-10.0.1 with the following changes:
* privsep: keep resources open rather than open/close
 * dhcp6: OPTION_NTP_SERVER is now preferred over OPTION_SNTP_SERVER
 * Misc bug fixes mainly around privsep for many platforms.
 * Fix for reading the some BSD routing table entries.
 * Fix reading authtokens from config.

Big new release, mainly around better privsep process management
which allows us to detect when they exit unexpectedly.
2023-04-21 16:52:28 +00:00
roy 33445a79ae Update to dhcpcd-9.4.1 with the following changes:
* BSD: Find the correct interface for tunnelled routes
 * OpenBSD: Fix uniqueness of routes for matching priorities
 * Linux: Support more platforms for seccomp (thanks to Fabrice Fontaine)
 * eloop: Process all waiting fd's as they come in
 * control: Unlink sockets when not in privsep
 * privsep: Renamed Master to Manager
 * privsep: Renamed Privilged Actioneer to Privileged Proxy
 * privsep: Fix getting interface VLANID on BSD
 * privsep: Enforce proper alignment of serialized struct cmsghdr
 * IPv4LL: Don't remove statically assigned addresses
 * routes: Fix route comparision for network prefixes with different masks
 * DHCP6: Only send FQDN for SOLICIT, REQUEST, RENEW, or REBIND messages
 * DHCP6: Don't spam the log when a RA repeatedly triggers an INFORM
 * DHCP: Fix infinite INFORM messages
2021-10-22 13:21:58 +00:00
roy c9893f654b Update to dhcpcd-9.4.0 with the following changes:
* DHCP: For anonymous, just use a generic ClientID
 * link: Split hardware address randomisation out of anonymous option
 * link: Only report hardware changes for active interfaces
 * link: Report errors obtaining recv buffer size on overflow
 * hooks: Add NOCARRIER_ROAMING reason
 * hooks: interface_order now reflects priorities again
2020-12-28 13:56:25 +00:00
roy ee4e0574e8 Update to openresolv-3.12.0 with the following changes:
* Allow configurations to be marked as Deprecated and Acivtated
 * Harden resolvconf lock detection
2020-12-27 18:25:08 +00:00
roy b81737046b Upate to dhcpcd-9.3.4 with the following changes:
With the following changes:
 * DHCP: If error adding the address in oneshot, exit with failure
 * DHCP: Only listen to the address if we successfully added it
 * DHCP6: Fix segfault introduced in dhcpcd-9.3.3
 * DHCP6: Abort in test mode when an error is returned by server
 * options: allow --ia_na=1 and --ia_pd=2 on the command line
 * options: Allow duid to take a value
2020-11-28 14:26:16 +00:00
roy c5770ceb10 Update to dhcpcd-9.3.3 with the following changes:
* dhcpcd: Don't create a launcher process if keeping in foreground
 * dhcpcd: Add --noconfigure option
 * control: Create an unpriv socket for non master mode
 * options: Don't log unknown ones when printing pidfile location
2020-11-20 13:23:38 +00:00
roy c44edc208c Update to dhcpcd-9.3.2 with the following changes:
* DHCP: Add support for IPv6-Only Preferred option, RFC 8925.
 * BSD: `LINK_STATE_UNKNOWN` is treated as UP once again
 * privsep: pass logging to the privileged actioneer
 * privsep: allow logfile re-opening to work
 * privsep: close BPF socket on ENXIO
 * privsep: don't leave a BOOTP BPF listener rebooting in non master mode
2020-11-01 14:23:02 +00:00
roy b1246fe72f Update to dhcpcd-9.3.1 with the following changes:
* dhcpcd: carrier handling issue fixed from 9.3.0
 * dhcpcd: log if interface type is unsupported in debug
 * duid: memory leak fixed if UUID wanted but none available
 * privsep: fix receiving inet and no BPF running
 * privsep: allow gettimeofday for SECCOMP
 * privsep: fix stderr redirection again
2020-10-12 14:07:55 +00:00
roy b90aaaef64 Update to dhcpcd-9.3.0 with the following changes:
* dhcpcd: Backticks have been removed from quoting filenames
 * dhcpcd: Only manipulate stdin, stdout and stderr if they are valid
 * duid: Adjust option so the type can be specified
 * logerr: Don't leak logfile fd to scripts
 * privsep: Run the launcher process in the sandbox
 * BSD: Use `ifi_link_state` as the single source of truth about carrier
 * BSD: Ignore vether(4) devices by default
2020-10-05 16:01:13 +00:00
roy cd40ae1fd5 Update to dhcpcd-9.2.0 with the following changes:
* route: ensure IPv4LL routes come last in priority
 * DHCP: fix many issues with extending the last lease
 * privsep: don't read control group from config in privsep
 * privsep: only the master process responds to signals
 * privsep: use a socketpair for stderr/stdin rather than dupping /dev/null
 * privsep: right limit stdin/stderr/stdout
 * privsep: dumping a lease is now run in a sandbox
 * options: check if kernel supports INET or INET6 before enabling default
 * options: let clientid override a prior duid
 * options: allow -1 to represent infinity for requested lease time
 * dhcpcd: fix a crash initing a new interface after route overflow
2020-09-06 14:54:28 +00:00
roy 61b23c6195 Update to openresolv-3.11.0 with the following changes:
*  notify avahi-daemon of resolv.conf being changed
  *  notify mdnsd of resolv.conf being changed
2020-07-22 13:18:01 +00:00
roy 404637bd06 Update to dhcpcd-9.1.4 with the following changes:
* Fix SMALL builds
 * Ensure DBDIR exists at startup
2020-07-03 10:45:43 +00:00
roy 83a86239b0 Update to dhcpcd-9.1.3 with the following changes:
* inet6: Add support for reporting Mobile IPv6 RA's
 * inet6: Report RA Proxy flag if set
 * BSD: Allow non NetBSD and OpenBSD to set IN6_IFF_AUTOCONF
 * privsep: Don't handle any signals meant for the main process
 * eloop: Try and survive a signal storm
 * dhcpcd: Add an option to poll the interface carrier state
 * script: Make visible some link level parameters to lease dumping
 * inet6: Don't regen temp addresses we didn't add
 * privsep: Don't limit file writes if logging to a file
 * DHCP6: Fix lease timings with nodelay option
2020-07-02 13:57:40 +00:00
roy aac4420686 Update to dhcpcd-9.1.2 with the following changes:
* NetBSD: free ARP state once IPv4LL address announced
* NetBSD: Mark RA dervied addresses as AUTOCONF
* BSD: Only mark static routes from dhcpcd.conf as static
* DHCP6: Ensure requested addresses are requested
* DHCP6: Fix prefix length calculation when no prefix specified
* privsep: Implement a resource limited sandbox
2020-06-15 16:58:01 +00:00
roy 55689a1efa Update to dhcpcd-9.1.1 with the following changes:
* Restore dumping leases from stdin
 * auth: Only accept RECONFIGURE messages from LL addresses
 * auth: Access the RDM monotonic counter file via privsep
 * ARP: call arp_announced() when cancelling it
 * BSD: fwip(4) interfaces are now ignored by default
 * privsep: Ensure IPC buffers are large enough to carry messages
 * privsep: Only open RAW sockets for the needed protocols
 * privsep: Fix indirect ioctls returning data
 * privsep: wait for processes on SIGCHLD rather than when sent a STOP cmd
 * eloop: just use ppoll/pollts(2), falling back to pselect(2)
2020-06-04 13:07:12 +00:00
roy 961d2a0db3 Update to dhcpcd-9.1.0 with the following changes:
* Leases are stored outside the chroot again
 * The chroot directory can now be (and should be) empty [1]
 * ARP is now per address rather than per interface
 * Filter allowed ioctls in the privileged actioneer
 * Filter allowed UDP ports used by sendto(2) in the privileged actioneer
 * Filter allowed file paths in the privileged actioneer
 * route socket is now drained on overflow as it cannot be
   re-opened by the unpriviledged user

 * hostname can no longer be clobbered by SLAAC
 * grep is no longer used by the test hook
 * Interface hardware address type changes are now picked up
 * Fixed some RA timing issues
 * Fixed nd_* option parsing in dhcpcd.conf
 * Allow SIGPIPE in scripts
 * Default dhcpcd.conf no longer sends the current hostname
 * Default dhcpcd.conf no longer sends a vendorclassid
2020-05-31 12:50:46 +00:00
roy 603fb519dd Update to dhcpcd-9.0.2 with the following changes:
* Control sockets are not opened in test mode
 * privsep: no longer aborts if protocol not available
 * inet6: Don't regen temporary addresses without a state
 * inet6: Reduce RA log spam
 * dhcp6: Don't log when things consitently fail
 * inet6: Add temporary directive to slaac option [1]
 * Ensure current interface flags persist when setting a flag
 * DHCP via BPF is now aligned correctly
 * CMSG buffers are now aligned correctly
 * hostnames are no longer clobbered when being forced and a RA is recieved

[1] dhcpcd no longer looks at any possible kernel settings when deciding to
manage IPv6 temporary addresses or not. You now instruct dhcpcd to do this
in dhcpcd.conf. Playing whack-a-mole with various kernel knobs wasn't fun
and some OS's have or are removing RA and thus temporary address managemnt
from the kernel so said knobs are no longer there.
2020-04-21 09:54:16 +00:00
roy 3d6c38e070 Update to dhcpcd-9.0.1 with the following changes:
* privsep: Improve error when we don't have permission to write lease
  PR bin/55135
* privsep: Fix hooks restarting other daemons
2020-04-13 15:42:20 +00:00
roy 98dee57b86 Update to dhcpcd-9.0.0 with the following changes:
* Decode interface complex interface names eth0.100:2 eth0i100:2.
   This allows us to ignore some virtual interfaces by default
 * ARP: Report L2 header address on conflict for more clarity
 * DHCP: Support jumbo frames (untested)
 * DHCP6: Clean up old lease on failure to confirm/rebind, etc
 * RA: Prefer older routers
 * INET6: Obscure prefixes are now calculated correctly

 * Privilege Separation
 * default hostname is now a blank string rather than localhost
 * Leases are now dumped over the control socket - you get RA's now as well.
 * Better support for many IPv6 routers
 * RTM_MISS filtering
 * RA: Deprecate stale addresses by setting pltime 0
 * DHCP6: Deprecate stale addresses by setting pltime 0
2020-04-02 12:38:54 +00:00
roy 173e555c9e Update to openresolv-3.10.0 with the following change:
Add allow_interfaces and deny_interfaces configuration knobs
2020-01-27 21:11:12 +00:00
roy 568a64c5ec Update to dhcpcd-8.1.6 with the following changes:
* INET6: Support a /128 prefix advertised via RA
 * BSD: More address validation from route(4) messages
 * DHCP: Fix a potential segfault on DaD failure
 * IPv4LL: Fix a potential segfault when dropping IPv4LL addresses
2020-01-27 20:41:58 +00:00
roy d4128c3af8 Update to dhcpcd-8.1.5 with the following changes:
* inet: Allow forcing a host route from an interface without a lease
 * dhcpcd: Don't wait for an address family to complete if not using it
2020-01-03 12:38:14 +00:00
roy f31da2ae25 Update to dhcpcd-8.1.4 with the following change:
* options: Fix allocating the script option
2019-12-20 22:23:55 +00:00
roy 3ded1c87fc Import dhcpcd-8.1.3 with the following changes:
* dhcpcd: Only report SSID when we have a carrier
 * IPv6ND: Fix reachable test
 * DHCP6: Work better with infinite addresses
 * DHCP6: Suboption 3 of NTP Server is a FQDN
 * DHCP6: Fix deprecating a delegated prefix
 * DHCP: Ensure we have a lease to extract options from
2019-12-20 12:00:18 +00:00
roy 8105b4b2ec Import dhcpcd-8.1.2 with the following changes:
* hooks: STOPPED is now run on timeout and exit
 * BSD: Use IP_REVCIF rather than IN_PKTINFO
 * DHCP: When rebinding, ensure we have a DHCP ARP state
 * RA: Sort routers when reachability changes
 * RA: Apply hoplimit, reachable and retrans timer values to kernel
 * RA: Warn if advertised MTU > interface MTU
 * dhcpcd: Report SSID connection to when we gain carrier
 * DHCP: Fix corruption of address flags when renewing
2019-11-13 10:49:19 +00:00
roy 40ee987d84 Import dhcpcd-8.1.1 with the following changes:
* IPv6: Fix a potential crash when learning interface addresses.
 * DHCP: Fix fallout from dhcpcd-8.1.0 for checksum calculation.
2019-10-16 14:53:22 +00:00
roy 1cc3fcda30 Import dhcpcd-8.1.1 with the following changes:
* IPv6: Fix a potential crash when learning interface addresses.
 * DHCP: Fix fallout from dhcpcd-8.1.0 for checksum calculation.
2019-10-16 14:50:27 +00:00
roy 3191a42627 Import dhcpcd-8.1.0 with the following changes:
* Fix carrier status after a route socket overflow
 * Allow domain spaced options
 * DHCP: Allow not sending Force Renew Nonce or Reconf Accept
 * IPv4LL: Now passes Apple Bonjour test versions 1.4 and 1.5
 * ARP: Fix a typo and remove pragma (thus working with old gcc)
 * DHCP6: Fix a cosmetic issue with infinite leases
 * DHCP6: SLA 0 and Prefix Len 0 will now add a delegatd /64 address
 * Ignore some virtual interfaces such as Tap and Bridge by default
 * BPF: Move validation logic out of BPF and back into dhcpcd
2019-10-11 11:00:49 +00:00
roy 8c55aad609 Import dhcpcd-8.0.6 with the following changes:
*  DHCP: Ensure we have enough data to checksum IP and UDP (really fix)
  *  dhcpcd-embedded.{c,h} no longer needs generating
2019-09-13 11:52:31 +00:00
roy 5921161ee0 Import dhcpcd-8.0.5 with the following changes:
*  inet6: Fix default route not being installed
  *  DHCP: If root fs is network mounted, enable last lease extend
  *  man: Fix lint errors.
  *  DHCP: Give a better message when packet validation fails
  *  DHCP: Ensure we have enough data to checksum IP and UDP

The last change fixes a potential DoS attack introduced in dhcpcd-8.0.3 when
the checksuming code was changed to accomodate variable length IP headers.
2019-09-13 10:58:31 +00:00
roy 7dfda7b4f5 Import openresolv-3.9.2 with the following changes:
*  dnsmasq: clear cache after updating servers via dbus
  *  pdns_recursor: Fix global forwards (thus now installed by default)
  *  man: layout and misc fixes
2019-09-08 20:46:17 +00:00
roy b83bc1b66c Import dhcpcd-8.0.4 with the following changes:
* BSD: Fixed router reachability tests
 * inet6: If router unreachable, just solicit a new one
 * inet6: Fon't install a default route if only lladdresses
 * inet6: Stop listening to NA messages
 * BSD: Listen to RTM_MISS messages
 * DHCP: Fix in_cksum for Big Endian
 * DHCP{,6}: Don't log an error if the lease file is truncated
2019-09-04 13:27:50 +00:00
roy 4dfdf2681a Import dhcpcd-8.0.3 With the following changes:
*  DHCP: Work with IP headers with options
 *  script: Assert that env string are correctly terminated
 *  script: Terminate env strings with no value
 *  script: Don't attempt to use an invalid env string
 *  route: Fix NULL deference error when using static routes
 *  ARP: Respect IFF_NOARP
 *  DHCP: Allow full DHCP support for PtP interfaces, but not by default
 *  control: sends correct buffer to listeners

dhcpcd-ui now correctly reports SSD association and all the addresses obtained (regression from dhcpcd-7)
2019-08-21 17:10:29 +00:00
roy b6a3a94eb1 Import dhcpcd-8.0.2 with the following changes:
*  NetBSD: Can be build without ARP support but listen to kernel DaD
  *  ND6: Removed NA support from SMALL builds
  *  DHCP: Avoid duplicate read of UDP socket when BPF is also open
  *  IP: Avoid adding address if already exists on OS other than Linux
  *  route: Fixed a NULL de-reference error on static routes
  *  DHCP6: Move to REQUEST if any IA has no-binding in REWNEW/REBIND
  *  IP: Accept packets with IP header options
2019-07-30 10:23:02 +00:00
roy cb0b7d2b9f Import dhcpcd-8.0.1 with the following changes:
*  Compile fixes for various build options on various platforms
  *  IPv4LL is fixed on NetBSD-8
  *  Script buffers are freed on forking
2019-07-25 08:53:54 +00:00
roy 141ff30ff1 Import dhcpcd-8.0.0 with the following changes:
*  ARP now supports many requests
  *  Routing tables now use Red-Black Trees
  *  Script variables are no longer allocated manually
2019-07-24 09:54:49 +00:00
roy 6964063b9b Import openresolv-3.9.1 with the following changes:
*  More strict POSIX shell support
  *  Interfaces have an implicit metric of 0 unless specified
  *  Inline comments are stripped from nameserver and domain entries
2019-07-17 18:24:23 +00:00
roy 3ed23301ff Import dhcpcd-7.2.3 with the following changes:
*  BSD: Check RTM lengths incase of kernel issues
  *  DHCP6: Don't stop even when last router goes away
  *  DHCP6: Fix inform from RA
  *  hostname: Fix short hostname check
2019-06-26 17:46:09 +00:00
roy ec73a3e813 Import dhcpcd-7.2.2 with the following changes:
*  DHCP: Ensure dhcp is running on the interface received from
  *  BSD: Link handling has been simplified, however it is expected
     that if an interface supports SIOCGIFMEDIA then it reports
     the correct link status via route(4) for reliable operations
  *  BPF: ARP filter is more robust
  *  BSD: Validate RTM message lengths

This security issue has been addressed:
  *  DHCPv6: Fix a potential read overflow with D6_OPTION_PD_EXCLUDE

Many thanks to Maxime Villard <max@m00nbsd.net> for discovering this issue.
2019-05-04 09:40:27 +00:00
roy dc127b4bb4 Import dhcpcd-7.2.1 with the following changes:
*  auth: Use consttime_memequal to avoid latency attack
*  DHCP: Fix a potential 1 byte read overflow with DHO_OPTSOVERLOADED
*  DHCPv6: Fix a potential buffer overflow reading NA/TA addresses
2019-04-26 14:32:27 +00:00
roy dbd4cee32e Import dhcpcd-7.2.0 with the following changes:
*  BSD: PF_LINK sockets now closed when no longer needed
  *  BSD: Fix detecting interface for scoped routes
  *  script: Allow "" to mean /dev/null
  *  script: Add static routers and routes to env
  *  DHCP: outbound interface is no longer dictated with IP_PKTINFO
  *  DHCP: BPF sockets now closed when no longer needed
  *  DHCPv6: Allow nooption dhcp6_unicast to work
  *  DHCPv6: Don't spam syslog if we always get the same error
  *  route: Log pid which deleted routes of interest

This release fixes PR bin/53705.
2019-04-17 23:33:08 +00:00
roy a5e54c894f Import dhcpcd-7.1.1 with the following changes:
* IPv4LL: Fixed build with this disabled
* IPv4LL: Remember last address between carrier resets
* BSD: Fixed initial link infos reported as LINK_STATE_UNKNOWN
2019-02-07 21:34:30 +00:00
roy 2d8cdccce8 Import dhcpcd-7.1.0 with the following changes:
* NetBSD: sets SO_RERROR on to detect receive socket overflow
* BSD: route improvements to avoid listening for own changes
* IP6: implement IP6 address sharing
* BSD: catch UP/DOWN events when interfaces does support media changes
* IPv4LL: remember old address when carrier is lost
2019-01-22 15:16:24 +00:00
roy 0fda18bd0d Import dhcpcd-7.0.8 with the following changes:
*  Don't use IP_PKTINFO on NetBSD-7 as it's incomplete.
  *  Workaround RTM_NEWADDR sending the wrong broadcast address
     on NetBSD-7.
  *  Silence diagnostics if an address vanishes when reading
     it's flags on all BSD's.
  *  Misc compiler warnings fixed.
2018-08-20 10:55:03 +00:00
roy 78f6e36f5b Import dhcpcd-7.0.7 with the following changes:
*  host routes work correctly again
  *  vlanid is also used to calculate slaac stable private addresses
2018-07-24 07:58:31 +00:00
roy 3b33a0ebf3 Import dhcpcd-7.0.6 with the following changes:
*  fixed compile issues with prior release
  *  fixed carrier loss not being detected for IPv4
  *  UUID based DUID is used where available and no prior DUID exists
2018-06-21 11:55:19 +00:00
roy 12f1dee606 Import dhcpcd-7.0.5b to fix a builds without IPv4LL (SMALLPROG builds) 2018-06-04 16:44:45 +00:00
roy afa3b9b888 Import dhcpcd-7.0.5a.
Only change is to fix builds without INET6.
2018-06-04 09:55:13 +00:00
roy 259182f30d Import dhcpcd-7.0.5 with the following changes:
*  dhcp: Clarified some checksumming code, style and commentary
     (thanks to Maxime Villard)
  *  dhcp6: IAID is now unique per IA type rather than global
  *  ip6: if an IA callback causes a fork, exit earlier
2018-06-02 09:42:48 +00:00
roy 483cca5a38 Import dhcpcd-7.0.4 with the following changes:
* Routing: Fix case when cloning route changes but needs to be replaced
 * DHCP6: Transpose DHCP userclass option into DHCP6
 * DHCP6: Fix sending custom vendor class option
 * Auth: Allow zero value replay detection data
 * Auth: Allow different tokens for send and receive
 * ND6: Warn if router lifetime is set to zero
 * DHCP6: Softwire Address and Port-Mapped Clients, RFC7598
2018-05-02 22:06:41 +00:00
roy 71c9531719 Import dhcpcd-7.0.3 with the following changes:
*  dhcp6: fix a null termination overflow on status messages
  *  options: static routes can be setup in global context again
  *  routes: dhcpcd added host routes are now reported correctly
2018-04-06 10:46:37 +00:00
roy 6909e9fcde Import dhcpcd-7.0.2 with the following changes:
*  Added support for setproctitle(3)
  *  Kernel RA is no longer disabled when IPv6 is disabled in dhcpcd
  *  DHCPv6 PD is no longer stopped if no Routers are found
  *  If the DHCP leased address is deleted, enter the reboot state
  *  DHCPv6 unicast is no longer performed when not in master mode
  *  dhcpcd will now detect netlink/route socket overflows ad re-sync
2018-03-27 06:14:39 +00:00
roy 19ee775ace Import dhcpcd-7.0.1 with the following changes:
*  hooks: remove use of local builtin for better portability
*  dhcpcd: don't log errors working out carrier for departed interfaces
*  ipv4: allow configuration of static broadcast address
*  if: don't set MTU during interface discovery
*  if: don't activate non matching interfaces to commandline ones
*  eloop-bench: fix hangs when using a large number of cycles
*  dhcp: don't bind when we've just probed an address to inform
2018-01-29 11:11:22 +00:00
roy 8f03b3ce8d Import dhcpcd-7.0.0 with the following changes:
*  dhcp: when unicasting on L3, unicast on L2 as well
  *  dhcp: when rebooting, don't set cidaddr
  *  dhcp6: don't listen on IPv6 addresses when not using DHCPv6
  *  dhcp: only set probe state when probing (fixes REBOOT reason)
  *  ipv6: disable kernel RA if interface is active
  *  hooks: set protocol to link for link layer events
2018-01-01 11:48:51 +00:00
roy 011165c38b Import dhcpcd-7.0.0-rc4 with the following changes:
*  Don't flush prefix routes/routers if kernel does not support RA
  *  dhcp: improve errors around UDP checksum failure
  *  dhcp: announce existing addresses before rebooting
  *  bpf: rework loop so that we can close/reopen fd inside and abort
  *  ipv6nd: don't handle NA/RA for non active interfaces
  *  dhcp6: listen on all addresses in non master mode
  *  dhcpcd-run-hooks: set protocol in dhcpcd, don't guess
  *  Ensure that xid is unique across all interfaces
  *  dhcp6: redirect message to interface which uses the xid
  *  bsd: strip scope from LL addresses when detecting their addition
  *  ipv6nd: fix address lifetime overflow on carrier up
  *  dhcp6: fix confirmation of lease on carrier up
2017-12-06 10:33:29 +00:00
roy 1f8b775ce0 Import dhcpcd-7.0.0-rc3 with the following noteable changes:
*  Fixed handling RA's from multiple routers
  *  Fixed changing to a better route based on gateway
  *  IPv6 default route is now deleted when config is not persistent
  *  Use hmac(3) if available in libc to reduce binary size

Fixes PR bin/52554
2017-10-07 14:05:36 +00:00
roy f9f6f284e0 Import dhcpcd-7.0.0-rc2 with the following changes:
*  dhcp: fixed classless static routes
  *  prefix delegation: build routes after assigning addresses
  *  dhcp: on lease expiration, discover only when carrier
  *  ip6: fix potential segfault when lifetime overflows
  *  dhcp: fix reporting of DNS encoded SIP servers
  *  dhcp6: fix unicast in non master mode
2017-09-19 19:16:48 +00:00
roy d0f9585b51 Import dhcpcd-7.0.0-rc1 with the following changes:
*  Default to use VLANID>0 for IAID instead of MAC address
  *  Stop sharing the DHCPv6 port in master mode with other processes
  *  Fix some prefix delegation issues when the carrier drops or
     addresses become stale
  *  Fix a crash when starting dhcpcd with -n
  *  Fix test for preferring a fake lease over a real one
  *  Show to real address lifetimes being added when adding IPv6
     addresses
  *  Restore the -G, --nogateway option
2017-05-10 11:00:37 +00:00
roy a0f00732f7 Import dhcpcd-7.0.0-beta3 with the following changes:
*  restored --logfile support as a few people complained it vanished
     The new logging code even makes the overall binary size smaller
     on most platforms.
  *  BPF filter now trims garbage trailing the payload
     OK, it's not garbage, but userland doesn't know some drivers append
     FCS to it.
  *  support NetBSD's RO_MSGFILTER socket option to reduce avoid context
     switching for route(4) messages that don't interest us.
  *  Don't open sockets if just sending signals.
  *  HMAC-MD5 test's now check expectations in code rather than relying
     on visual confirmation.
  *  added eloop-bench to test performance of eloop with available
     polling mechanisms.
2017-04-14 09:53:06 +00:00
roy 5231d2c6ff Import dhcpcd-7.0.0-beta2 with the following changes:
*  Builds without AUTH now compile.
  *  Builds without IPv4LL now compile.
     Thanks to Joerg Sonnenberger.
  *  BPF no longer uses a variable length buffer for stack protector.
  *  Minor documentation fix for duid file location.
     Thanks to Peter Colberg.
2017-04-02 18:54:20 +00:00
roy 1d279116c4 Import dhcpcd-7.0.0-beta. Changes from prior version include:
*  source file locations reworked:
       dhcpcd source is in src
       dhcpcd hooks are in hooks
       compat is in compat
  *  README split into README.md and BUILDING.md
  *  internal routing is now protocol agnostic
  *  avoid using __packed and use compile time asserts instead
  *  addresses some alignment issues
  *  disable some ARP code on kernels which support RFC5227
  *  BSD IPv6 kernel settings are now updated to reflect dhcpcd config
  *  custom logger has been removed, syslog handles everything
     as such, the --logfile option has been removed as well.
     If you need better/earlier logging, get a better syslogger!
  *  distinfo and signed distinfo files are now available alongside
     release taraballs from this point onwards
  *  default DBDIR has changed from /var/db to /var/db/dhcpcd
  *  /etc/dhcpcd.duid moves to DBDIR/duid
  *  /etc/dhcpcd.secret moves to DBDIR/secret
  *  lease file names have dhcpcd removed from them as they are now
     inside a directory of the same name
  *  fixed issues with reject routes not working on some platforms
  *  improved nl80211 support on Linux for working out the SSID
  *  no longer request NTP by default in dhcpcd.conf
  *  BPF filtering vastly improved so dhcpcd only wake up on
     ARP or DHCP packets destined for it
  *  support for MUD URL (draft-ietf-opsawg-mud-05)
  *  if the kernel isn't doing DAD, don't insist on waiting for it
     to actually do it
  *  fix a potential crash where the DHCP or ARP states could be
     freed before the packet processing loop naturally breaks
  *  removed gateway and nogateway options
     (these can be controlled by the nooption directive which
     works for more than just gateways)
  *  removed ipv6ra_own and ipv6ra_own_default options
     (these can be controled by the ipv6rs/noipv6rs directive)
  *  fix a crash receiving SIGUSR1
2017-03-31 20:51:15 +00:00
roy 19127286b8 Import openresolv-3.9.0 with the following changes:
*  Added --version option
  *  Fix pdns_recursor restart command
  *  Append a newline when restoring resolv.conf
  *  public_interfaces overrides private interface markings
  *  Fix runit support
  *  inclusive_interfaces overrides exclusive interface markings
2016-12-30 19:42:05 +00:00
roy 917ddb683c Import openresolv-3.8.0 with the following changes:
*  init system detection moved from configure into resolvconf.
  *  Fixed multiple domains not bein separated correctly.
2016-04-11 10:40:21 +00:00
roy 79169177cf Import openresolv-3.7.3 with the following changes:
*  Save the initial working directory and change to it just before
     running any scripts.
     This avoids scripts putting files accidently where they shouldn't.
  *  Strip trailing dot from search and domain names.
  *  man page improvements.
2016-02-22 10:07:26 +00:00
roy 2837f4b649 Import openresolv-3.7.1 with the following changes:
*  Typo's, thanks to Herbert Parentes Fortes Neto
  *  Clarify that private_interfaces="*" will not forward the root zone
  *  ensure that domain-insecure always appears in a server clause for
     the unbound subscriber
2015-09-29 09:10:07 +00:00
roy 5418580eb9 Import openresolv-3.7.0 with the following change:
*  -x marks the resolv.conf as exclusive.
     Only the latest resolv.conf will be processed, if none then
     as normal.
2015-05-01 18:21:17 +00:00
roy b50127bf05 Import openresolv-3.6.1 with the following changes:
*  Don't update when nothing has been deleted
  *  Backup resolv.conf to resolv.conf.bak when it doesn't have an openresolv
     signature
     Restore it when the new resolv.conf only has the openresolv signature
  *  Document prepend_search and prepend_nameservers
  *  Implement append_search and append_nameservers
  *  Implement replace and replace_sub to allow for keyword/value/replacement
2014-10-28 22:37:59 +00:00
roy aa9a7cc616 Import openresolv-3.6.0 with the following changes:
*  dnsmasq subscriber no longer moans if it hasn't written a pidfile
  *  Ensure that name_server_blacklist works for more than one option.
     Thanks to Frederic Barthelery.
  *  unbound_insecure can disable DNSSEC for all domains processed.
  *  local_nameservers now defaults to
     127.* 0.0.0.0 255.255.255.255 ::1
     and is used instead of a hard coded list.
  *  Allow the disabling of resolvconf or optionally an individual
     subscriber.
  *  Don't wait around trying to create a lock if we don't have
     permission.
  *  resolv_conf_passthrough=NULL will update resolv.conf to match
     only what is configured in resolvconf.conf and ignore any
     interface configuration.
2014-10-20 09:09:53 +00:00
roy 9f020fd04f Import openresolv-3.5.6
Highlights include:
name_servers[_append] and search_domains[_append] now work for subscribers
other than libc.
2013-07-12 16:50:27 +00:00
roy 81cde76eff Import openresolv-3.5.5 with the following changes from 3.5.3
* Fix setting IPv6 namservers over DBus to dnsmasq
 * Fix pdnsd config file generation
 * Man page fixes
2013-06-04 09:37:21 +00:00
roy 8313ebff18 Import openresolv-3.5.3 with the following changes:
* man page improvements
* dnsmasq + dbus + IPv6 linklocal support (requires dnsmasq-2.64)
* sort interface protocols as well as interface (bge0, bge0:ra, bge0:dhcp6)
2012-12-06 11:38:17 +00:00
roy 62638c05f8 Import openresolv-3.5.1 to fix resolv_conf_local_only. 2012-03-27 21:21:24 +00:00
roy 45de6d39f8 Import openresolv-3.5.0 with the following changes:
* Added resolv_conf_local_only which defaults to true.
  This means that if you configure a local nameserver we don't add
  any other nameservers to resolv.conf to avoid duplicate queries.
* Add domain_blacklist and name_server_blacklist variables.
  We default name_server_blacklist to 0.0.0.0 to handle some faulty
  routers.
* Add .Lk macro to URLs.
* Fix IPv6 parsing on domains which include an IPv4 server for dnsmasq.
2012-03-26 14:41:33 +00:00
roy 5adcf9c629 Import openresolv-3.4.6 with the following change from 3.4.5
* dnsmasq subscriber correctly sets IPv6 domain specific servers over dbus
2012-01-31 09:19:58 +00:00
roy 9d96839845 Import openresolv-3.4.5 with the following changes since the last version:
* More printf portabitiy fixes.
* Use read -r to avoid backslash problems.
* If we have a valid domain, put that in resolv.conf as well as search.
  This does not fix a technical problem, just stops me getting bug reports.
* Update metric and privacy even if resolv.conf didn't change.
* sortlist is now supported.
* Ensure subscriber config directories exist before writing the configs
* Don't create pdnsd.conf if it doesn't exist or is not writeable.
2011-11-24 00:36:05 +00:00
roy 0165dbff35 Import openresolv-3.4.2 with the following fix:
* Use printf(1) correctly
2011-06-13 11:05:19 +00:00
roy 51e1959dcb Import openresolv-3.3.4
Changes from openresolv-3.3.3 include:
 * private_interfaces is now shell expandable (ie, fxp*)
 * dnsmasq resolver restarting with DBus is now fixed
 * unbound resolver is sent SIGHUP for reload instead of forced restart
 * subscribers with the execute bit are executed, otherwise sourced into
   a subshell for speed
2009-12-04 14:11:49 +00:00
roy 94d183a61c Import openresolv-3.3.3
OK: core@, joerg@
2009-11-21 02:40:55 +00:00
95 changed files with 49765 additions and 0 deletions

23
external/bsd/dhcpcd/dist/LICENSE vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
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.

96
external/bsd/dhcpcd/dist/README.md vendored Normal file
View File

@ -0,0 +1,96 @@
# dhcpcd
dhcpcd is a
[DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) and a
[DHCPv6](https://en.wikipedia.org/wiki/DHCPv6) client.
It's also an IPv4LL (aka [ZeroConf](https://en.wikipedia.org/wiki/Zeroconf))
client.
In layperson's terms, dhcpcd runs on your machine and silently configures your
computer to work on the attached networks without trouble and mostly without
configuration.
If you're a desktop user then you may also be interested in
[Network Configurator (dhcpcd-ui)](http://roy.marples.name/projects/dhcpcd-ui)
which sits in the notification area and monitors the state of the network via
dhcpcd.
It also has a nice configuration dialog and the ability to enter a pass phrase
for wireless networks.
dhcpcd may not be the only daemon running that wants to configure DNS on the
host, so it uses [openresolv](http://roy.marples.name/projects/openresolv)
to ensure they can co-exist.
See [BUILDING.md](BUILDING.md) for how to build dhcpcd.
## Configuration
You should read the dhcpcd.conf man page
and put your options into `/etc/dhcpcd.conf`.
The default configuration file should work for most people just fine.
Here it is, in case you lose it.
```
# A sample configuration for dhcpcd.
# See dhcpcd.conf(5) for details.
# Allow users of this group to interact with dhcpcd via the control socket.
#controlgroup wheel
# Inform the DHCP server of our hostname for DDNS.
hostname
# Use the hardware address of the interface for the Client ID.
#clientid
# or
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
# Some non-RFC compliant DHCP servers do not reply with this set.
# In this case, comment out duid and enable clientid above.
duid
# Persist interface configuration when dhcpcd exits.
persistent
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
option rapid_commit
# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
# Most distributions have NTP support.
#option ntp_servers
# A ServerID is required by RFC2131.
require dhcp_server_identifier
# Generate SLAAC address using the Hardware Address of the interface
#slaac hwaddr
# OR generate Stable Private IPv6 Addresses based from the DUID
slaac private
```
The dhcpcd man page has a lot of the same options and more,
which only apply to calling dhcpcd from the command line.
## Compatibility
dhcpcd-5 is only fully command line compatible with dhcpcd-4.
For compatibility with older versions, use dhcpcd-4.
## Upgrading
dhcpcd-7 defaults the database directory to `/var/db/dhcpcd` instead of
`/var/db` and now stores dhcpcd.duid and dhcpcd.secret in there instead of
in /etc.
dhcpcd-9 defaults the run directory to `/var/run/dhcpcd` instead of
`/var/run` and the prefix of dhcpcd has been removed from the files therein.
## ChangeLog
We no longer supply a ChangeLog.
However, you're more than welcome to read the
[commit log](https://github.com/NetworkConfiguration/dhcpcd/commits) and
[release announcements](https://github.com/NetworkConfiguration/dhcpcd/releases).

11
external/bsd/dhcpcd/dist/hooks/00-linux vendored Normal file
View File

@ -0,0 +1,11 @@
# setup chroot mounts
if [ "$reason" = CHROOT ] && [ -n "$chroot" ]; then
for d in /dev /proc /sys /run/udev; do
[ -d "$d" ] || continue
if ! mountpoint -q "$chroot$d"; then
mkdir -p "$chroot$d"
mount --bind $d "$chroot$d"
fi
done
fi

37
external/bsd/dhcpcd/dist/hooks/01-test vendored Normal file
View File

@ -0,0 +1,37 @@
# Echo the interface flags, reason and message options
if [ "$reason" = "TEST" ]; then
# General variables at the top
set | while read line; do
case "$line" in
interface=*|pid=*|reason=*|protocol=*|profile=*|skip_hooks=*)
echo "$line";;
esac
done
# Interface flags
set | while read line; do
case "$line" in
ifcarrier=*|ifflags=*|ifmetric=*|ifmtu=*|ifwireless=*|ifssid=*)
echo "$line";;
esac
done
# Old lease
set | while read line; do
case "$line" in
old_*) echo "$line";;
esac
done
# New lease
set | while read line; do
case "$line" in
new_*) echo "$line";;
esac
done
# Router Advertisements
set | while read line; do
case "$line" in
nd[0-9]*_*) echo "$line";;
esac
done
exit 0
fi

View File

@ -0,0 +1,8 @@
# Just echo our DHCP options we have
case "$reason" in
DUMP|DUMP6)
set | sed -ne 's/^new_//p' | sort
exit 0
;;
esac

View File

@ -0,0 +1,113 @@
# Start, reconfigure and stop wpa_supplicant per wireless interface.
#
# This is only needed when using wpa_supplicant-2.5 or older, OR
# when wpa_supplicant has not been built with CONFIG_MATCH_IFACE, OR
# wpa_supplicant was launched without the -M flag to activate
# interface matching.
if [ -z "$wpa_supplicant_conf" ]; then
for x in \
/etc/wpa_supplicant/wpa_supplicant-"$interface".conf \
/etc/wpa_supplicant/wpa_supplicant.conf \
/etc/wpa_supplicant-"$interface".conf \
/etc/wpa_supplicant.conf \
; do
if [ -s "$x" ]; then
wpa_supplicant_conf="$x"
break
fi
done
fi
: ${wpa_supplicant_conf:=/etc/wpa_supplicant.conf}
wpa_supplicant_ctrldir()
{
dir=$(key_get_value "[[:space:]]*ctrl_interface=" \
"$wpa_supplicant_conf")
dir=$(trim "$dir")
case "$dir" in
DIR=*)
dir=${dir##DIR=}
dir=${dir%%[[:space:]]GROUP=*}
dir=$(trim "$dir")
;;
esac
printf %s "$dir"
}
wpa_supplicant_start()
{
# If the carrier is up, don't bother checking anything
[ "$ifcarrier" = "up" ] && return 0
# Pre flight checks
if [ ! -s "$wpa_supplicant_conf" ]; then
syslog warn \
"$wpa_supplicant_conf does not exist"
syslog warn "not interacting with wpa_supplicant(8)"
return 1
fi
dir=$(wpa_supplicant_ctrldir)
if [ -z "$dir" ]; then
syslog warn \
"ctrl_interface not defined in $wpa_supplicant_conf"
syslog warn "not interacting with wpa_supplicant(8)"
return 1
fi
wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 && return 0
syslog info "starting wpa_supplicant"
driver=${wpa_supplicant_driver:+-D}$wpa_supplicant_driver
err=$(wpa_supplicant -B -c"$wpa_supplicant_conf" -i"$interface" \
"$driver" 2>&1)
errn=$?
if [ $errn != 0 ]; then
syslog err "failed to start wpa_supplicant"
syslog err "$err"
fi
return $errn
}
wpa_supplicant_reconfigure()
{
dir=$(wpa_supplicant_ctrldir)
[ -z "$dir" ] && return 1
if ! wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1; then
wpa_supplicant_start
return $?
fi
syslog info "reconfiguring wpa_supplicant"
err=$(wpa_cli -p "$dir" -i "$interface" reconfigure 2>&1)
errn=$?
if [ $errn != 0 ]; then
syslog err "failed to reconfigure wpa_supplicant"
syslog err "$err"
fi
return $errn
}
wpa_supplicant_stop()
{
dir=$(wpa_supplicant_ctrldir)
[ -z "$dir" ] && return 1
wpa_cli -p "$dir" -i "$interface" status >/dev/null 2>&1 || return 0
syslog info "stopping wpa_supplicant"
err=$(wpa_cli -i"$interface" terminate 2>&1)
errn=$?
if [ $errn != 0 ]; then
syslog err "failed to stop wpa_supplicant"
syslog err "$err"
fi
return $errn
}
if [ "$ifwireless" = "1" ] && \
command -v wpa_supplicant >/dev/null 2>&1 && \
command -v wpa_cli >/dev/null 2>&1
then
case "$reason" in
PREINIT) wpa_supplicant_start;;
RECONFIGURE) wpa_supplicant_reconfigure;;
DEPARTED|STOPPED) wpa_supplicant_stop;;
esac
fi

View File

@ -0,0 +1,47 @@
# Configure timezone
: ${localtime:=/etc/localtime}
set_zoneinfo()
{
[ -z "$new_tzdb_timezone" ] && return 0
zoneinfo_dir=
for d in \
/usr/share/zoneinfo \
/usr/lib/zoneinfo \
/var/share/zoneinfo \
/var/zoneinfo \
; do
if [ -d "$d" ]; then
zoneinfo_dir="$d"
break
fi
done
if [ -z "$zoneinfo_dir" ]; then
syslog warning "timezone directory not found"
return 1
fi
zone_file="$zoneinfo_dir/$new_tzdb_timezone"
if [ ! -e "$zone_file" ]; then
syslog warning "no timezone definition for $new_tzdb_timezone"
return 1
fi
if copy_file "$zone_file" "$localtime"; then
syslog info "timezone changed to $new_tzdb_timezone"
fi
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_tzdb_timezone="$new_dhcp6_tzdb_timezone"
;;
esac
if $if_configured && $if_up; then
set_zoneinfo
fi

View File

@ -0,0 +1,224 @@
# Generate /etc/resolv.conf
# Support resolvconf(8) if available
# We can merge other dhcpcd resolv.conf files into one like resolvconf,
# but resolvconf is preferred as other applications like VPN clients
# can readily hook into it.
# Also, resolvconf can configure local nameservers such as bind
# or dnsmasq. This is important as the libc resolver isn't that powerful.
resolv_conf_dir="$state_dir/resolv.conf"
nocarrier_roaming_dir="$state_dir/roaming"
NL="
"
: ${resolvconf:=resolvconf}
if command -v "$resolvconf" >/dev/null 2>&1; then
have_resolvconf=true
else
have_resolvconf=false
fi
build_resolv_conf()
{
cf="$state_dir/resolv.conf.$ifname"
# Build a list of interfaces
interfaces=$(list_interfaces "$resolv_conf_dir")
# Build the resolv.conf
header=
if [ -n "$interfaces" ]; then
# Build the header
for x in ${interfaces}; do
header="$header${header:+, }$x"
done
# Build the search list
domain=$(cd "$resolv_conf_dir"; \
key_get_value "domain " ${interfaces})
search=$(cd "$resolv_conf_dir"; \
key_get_value "search " ${interfaces})
set -- ${domain}
domain="$1"
[ -n "$2" ] && search="$search $*"
[ -n "$search" ] && search="$(uniqify $search)"
[ "$domain" = "$search" ] && search=
[ -n "$domain" ] && domain="domain $domain$NL"
[ -n "$search" ] && search="search $search$NL"
# Build the nameserver list
srvs=$(cd "$resolv_conf_dir"; \
key_get_value "nameserver " ${interfaces})
for x in $(uniqify $srvs); do
servers="${servers}nameserver $x$NL"
done
fi
header="$signature_base${header:+ $from }$header"
# Assemble resolv.conf using our head and tail files
[ -f "$cf" ] && rm -f "$cf"
[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
echo "$header" > "$cf"
if [ -f /etc/resolv.conf.head ]; then
cat /etc/resolv.conf.head >> "$cf"
else
echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
fi
printf %s "$domain$search$servers" >> "$cf"
if [ -f /etc/resolv.conf.tail ]; then
cat /etc/resolv.conf.tail >> "$cf"
else
echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
fi
if change_file /etc/resolv.conf "$cf"; then
chmod 644 /etc/resolv.conf
fi
rm -f "$cf"
}
# Extract any ND DNS options from the RA
# Obey the lifetimes
eval_nd_dns()
{
eval rdnsstime=\$nd${i}_rdnss${j}_lifetime
[ -z "$rdnsstime" ] && return 1
ltime=$(($rdnsstime - $offset))
if [ "$ltime" -gt 0 ]; then
eval rdnss=\$nd${i}_rdnss${j}_servers
[ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
fi
eval dnssltime=\$nd${i}_dnssl${j}_lifetime
[ -z "$dnssltime" ] && return 1
ltime=$(($dnssltime - $offset))
if [ "$ltime" -gt 0 ]; then
eval dnssl=\$nd${i}_dnssl${j}_search
[ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
fi
j=$(($j + 1))
return 0
}
add_resolv_conf()
{
conf="$signature$NL"
warn=true
# Loop to extract the ND DNS options using our indexed shell values
i=1
j=1
while true; do
eval acquired=\$nd${i}_acquired
[ -z "$acquired" ] && break
eval now=\$nd${i}_now
[ -z "$now" ] && break
offset=$(($now - $acquired))
while true; do
eval_nd_dns || break
done
i=$(($i + 1))
j=1
done
[ -n "$new_rdnss" ] && \
new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
[ -n "$new_dnssl" ] && \
new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl"
# Derive a new domain from our various hostname options
if [ -z "$new_domain_name" ]; then
if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
new_domain_name="${new_dhcp6_fqdn#*.}"
elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
new_domain_name="${new_fqdn#*.}"
elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
new_domain_name="${new_host_name#*.}"
fi
fi
# If we don't have any configuration, remove it
if [ -z "$new_domain_name_servers" ] &&
[ -z "$new_domain_name" ] &&
[ -z "$new_domain_search" ]; then
remove_resolv_conf
return $?
fi
if [ -n "$new_domain_name" ]; then
set -- $new_domain_name
if valid_domainname "$1"; then
conf="${conf}domain $1$NL"
else
syslog err "Invalid domain name: $1"
fi
# If there is no search this, make this one
if [ -z "$new_domain_search" ]; then
new_domain_search="$new_domain_name"
[ "$new_domain_name" = "$1" ] && warn=true
fi
fi
if [ -n "$new_domain_search" ]; then
new_domain_search=$(uniqify $new_domain_search)
if valid_domainname_list $new_domain_search; then
conf="${conf}search $new_domain_search$NL"
elif ! $warn; then
syslog err "Invalid domain name in list:" \
"$new_domain_search"
fi
fi
new_domain_name_servers=$(uniqify $new_domain_name_servers)
for x in ${new_domain_name_servers}; do
conf="${conf}nameserver $x$NL"
done
if $have_resolvconf; then
[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
printf %s "$conf" | "$resolvconf" -a "$ifname"
return $?
fi
if [ -e "$resolv_conf_dir/$ifname" ]; then
rm -f "$resolv_conf_dir/$ifname"
fi
[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
printf %s "$conf" > "$resolv_conf_dir/$ifname"
build_resolv_conf
}
remove_resolv_conf()
{
if $have_resolvconf; then
"$resolvconf" -d "$ifname" -f
else
if [ -e "$resolv_conf_dir/$ifname" ]; then
rm -f "$resolv_conf_dir/$ifname"
fi
build_resolv_conf
fi
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_domain_name_servers="$new_dhcp6_name_servers"
new_domain_search="$new_dhcp6_domain_search"
;;
esac
if $if_configured; then
if $have_resolvconf && [ "$reason" = NOCARRIER_ROAMING ]; then
# avoid calling resolvconf -c on CARRIER unless we roam
mkdir -p "$nocarrier_roaming_dir"
echo " " >"$nocarrier_roaming_dir/$interface"
"$resolvconf" -C "$interface.*"
elif $have_resolvconf && [ "$reason" = CARRIER ]; then
# Not all resolvconf implementations support -c
if [ -e "$nocarrier_roaming_dir/$interface" ]; then
rm -f "$nocarrier_roaming_dir/$interface"
"$resolvconf" -c "$interface.*"
fi
elif $if_up || [ "$reason" = ROUTERADVERT ]; then
add_resolv_conf
elif $if_down; then
remove_resolv_conf
fi
fi

View File

@ -0,0 +1,39 @@
# Lookup the hostname in DNS if not set
lookup_hostname()
{
[ -z "$new_ip_address" ] && return 1
# Silly ISC programs love to send error text to stdout
if command -v dig >/dev/null 2>&1; then
h=$(dig +short -x $new_ip_address)
if [ $? = 0 ]; then
echo "$h" | sed 's/\.$//'
return 0
fi
elif command -v host >/dev/null 2>&1; then
h=$(host $new_ip_address)
if [ $? = 0 ]; then
echo "$h" \
| sed 's/.* domain name pointer \(.*\)./\1/'
return 0
fi
elif command -v getent >/dev/null 2>&1; then
h=$(getent hosts $new_ip_address)
if [ $? = 0 ]; then
echo "$h" | sed 's/[^ ]* *\([^ ]*\).*/\1/'
return 0
fi
fi
return 1
}
set_hostname()
{
if [ -z "${new_host_name}${new_fqdn_name}" ]; then
export new_host_name="$(lookup_hostname)"
fi
}
if $if_up; then
set_hostname
fi

View File

@ -0,0 +1,158 @@
# Set the hostname from DHCP data if required
# A hostname can either be a short hostname or a FQDN.
# hostname_fqdn=true
# hostname_fqdn=false
# hostname_fqdn=server
# A value of server means just what the server says, don't manipulate it.
# This could lead to an inconsistent hostname on a DHCPv4 and DHCPv6 network
# where the DHCPv4 hostname is short and the DHCPv6 has an FQDN.
# DHCPv6 has no hostname option.
# RFC4702 section 3.1 says FQDN should be prefered over hostname.
#
# As such, the default is hostname_fqdn=true so that a consistent hostname
# is always assigned.
: ${hostname_fqdn:=true}
# If we used to set the hostname, but relinquish control of it, we should
# reset to the default value.
: ${hostname_default=}
# Some systems don't have hostname(1)
_hostname()
{
if [ -z "${1+x}" ]; then
if [ -r /proc/sys/kernel/hostname ]; then
read name </proc/sys/kernel/hostname && echo "$name"
elif command -v hostname >/dev/null 2>/dev/null; then
hostname
elif sysctl kern.hostname >/dev/null 2>&1; then
sysctl -n kern.hostname
elif sysctl kernel.hostname >/dev/null 2>&1; then
sysctl -n kernel.hostname
else
return 1
fi
return $?
fi
if [ -w /proc/sys/kernel/hostname ]; then
echo "$1" >/proc/sys/kernel/hostname
elif [ -n "$1" ] && command -v hostname >/dev/null 2>&1; then
hostname "$1"
elif sysctl kern.hostname >/dev/null 2>&1; then
sysctl -w "kern.hostname=$1" >/dev/null
elif sysctl kernel.hostname >/dev/null 2>&1; then
sysctl -w "kernel.hostname=$1" >/dev/null
else
# May fail to set a blank hostname
hostname "$1"
fi
}
is_default_hostname()
{
case "$1" in
""|"$hostname_default"|localhost|localhost.localdomain)
return 0;;
esac
return 1
}
need_hostname()
{
# Always load the hostname variable for future use
hostname="$(_hostname)"
is_default_hostname "$hostname" && return 0
case "$force_hostname" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) return 0;;
esac
if [ -n "$old_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then
[ "$hostname" = "$old_fqdn" ]
else
[ "$hostname" = "${old_fqdn%%.*}" ]
fi
elif [ -n "$old_host_name" ]; then
if ${hfqdn}; then
if [ -n "$old_domain_name" ] &&
[ "$old_host_name" = "${old_host_name#*.}" ]
then
[ "$hostname" = \
"$old_host_name.$old_domain_name" ]
else
[ "$hostname" = "$old_host_name" ]
fi
elif ${hshort}; then
[ "$hostname" = "${old_host_name%%.*}" ]
else
[ "$hostname" = "$old_host_name" ]
fi
else
# No old hostname
false
fi
}
try_hostname()
{
[ "$hostname" = "$1" ] && return 0
if valid_domainname "$1"; then
syslog info "Setting hostname: $1"
_hostname "$1"
else
syslog err "Invalid hostname: $1"
fi
}
set_hostname()
{
hfqdn=false
hshort=false
case "$hostname_fqdn" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) hfqdn=true;;
""|[Ss][Ee][Rr][Vv][Ee][Rr]) ;;
*) hshort=true;;
esac
need_hostname || return 0
if [ -n "$new_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then
try_hostname "$new_fqdn"
else
try_hostname "${new_fqdn%%.*}"
fi
elif [ -n "$new_host_name" ]; then
if ${hfqdn}; then
if [ -n "$new_domain_name" ] &&
[ "$new_host_name" = "${new_host_name#*.}" ]
then
try_hostname "$new_host_name.$new_domain_name"
else
try_hostname "$new_host_name"
fi
elif ${hshort}; then
try_hostname "${new_host_name%%.*}"
else
try_hostname "$new_host_name"
fi
elif ! is_default_hostname "$hostname"; then
try_hostname "$hostname_default"
fi
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_fqdn="$new_dhcp6_fqdn"
old_fqdn="$old_dhcp6_fqdn"
;;
esac
if $if_configured && $if_up && [ "$reason" != ROUTERADVERT ]; then
set_hostname
fi

View File

@ -0,0 +1,158 @@
# Set the hostname from DHCP data if required
# A hostname can either be a short hostname or a FQDN.
# hostname_fqdn=true
# hostname_fqdn=false
# hostname_fqdn=server
# A value of server means just what the server says, don't manipulate it.
# This could lead to an inconsistent hostname on a DHCPv4 and DHCPv6 network
# where the DHCPv4 hostname is short and the DHCPv6 has an FQDN.
# DHCPv6 has no hostname option.
# RFC4702 section 3.1 says FQDN should be prefered over hostname.
#
# As such, the default is hostname_fqdn=true so that a consistent hostname
# is always assigned.
: ${hostname_fqdn:=true}
# If we used to set the hostname, but relinquish control of it, we should
# reset to the default value.
: ${hostname_default=@DEFAULT_HOSTNAME@}
# Some systems don't have hostname(1)
_hostname()
{
if [ -z "${1+x}" ]; then
if [ -r /proc/sys/kernel/hostname ]; then
read name </proc/sys/kernel/hostname && echo "$name"
elif type hostname >/dev/null 2>/dev/null; then
hostname
elif sysctl kern.hostname >/dev/null 2>&1; then
sysctl -n kern.hostname
elif sysctl kernel.hostname >/dev/null 2>&1; then
sysctl -n kernel.hostname
else
return 1
fi
return $?
fi
if [ -w /proc/sys/kernel/hostname ]; then
echo "$1" >/proc/sys/kernel/hostname
elif [ -n "$1" ] && type hostname >/dev/null 2>&1; then
hostname "$1"
elif sysctl kern.hostname >/dev/null 2>&1; then
sysctl -w "kern.hostname=$1" >/dev/null
elif sysctl kernel.hostname >/dev/null 2>&1; then
sysctl -w "kernel.hostname=$1" >/dev/null
else
# May fail to set a blank hostname
hostname "$1"
fi
}
is_default_hostname()
{
case "$1" in
""|"$hostname_default"|localhost|localhost.localdomain)
return 0;;
esac
return 1
}
need_hostname()
{
# Always load the hostname variable for future use
hostname="$(_hostname)"
is_default_hostname "$hostname" && return 0
case "$force_hostname" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) return 0;;
esac
if [ -n "$old_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then
[ "$hostname" = "$old_fqdn" ]
else
[ "$hostname" = "${old_fqdn%%.*}" ]
fi
elif [ -n "$old_host_name" ]; then
if ${hfqdn}; then
if [ -n "$old_domain_name" ] &&
[ "$old_host_name" = "${old_host_name#*.}" ]
then
[ "$hostname" = \
"$old_host_name.$old_domain_name" ]
else
[ "$hostname" = "$old_host_name" ]
fi
elif ${hshort}; then
[ "$hostname" = "${old_host_name%%.*}" ]
else
[ "$hostname" = "$old_host_name" ]
fi
else
# No old hostname
false
fi
}
try_hostname()
{
[ "$hostname" = "$1" ] && return 0
if valid_domainname "$1"; then
syslog info "Setting hostname: $1"
_hostname "$1"
else
syslog err "Invalid hostname: $1"
fi
}
set_hostname()
{
hfqdn=false
hshort=false
case "$hostname_fqdn" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) hfqdn=true;;
""|[Ss][Ee][Rr][Vv][Ee][Rr]) ;;
*) hshort=true;;
esac
need_hostname || return
if [ -n "$new_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then
try_hostname "$new_fqdn"
else
try_hostname "${new_fqdn%%.*}"
fi
elif [ -n "$new_host_name" ]; then
if ${hfqdn}; then
if [ -n "$new_domain_name" ] &&
[ "$new_host_name" = "${new_host_name#*.}" ]
then
try_hostname "$new_host_name.$new_domain_name"
else
try_hostname "$new_host_name"
fi
elif ${hshort}; then
try_hostname "${new_host_name%%.*}"
else
try_hostname "$new_host_name"
fi
elif ! is_default_hostname "$hostname"; then
try_hostname "$hostname_default"
fi
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_fqdn="$new_dhcp6_fqdn"
old_fqdn="$old_dhcp6_fqdn"
;;
esac
if $if_configured && $if_up && [ "$reason" != ROUTERADVERT ]; then
set_hostname
fi

View File

@ -0,0 +1,144 @@
# Sample dhcpcd hook script for NTP
# It will configure either one of NTP, OpenNTP or Chrony (in that order)
# and will default to NTP if no default config is found.
# Like our resolv.conf hook script, we store a database of ntp.conf files
# and merge into /etc/ntp.conf
# You can set the env var NTP_CONF to override the derived default on
# systems with >1 NTP client installed.
# Here is an example for OpenNTP
# dhcpcd -e NTP_CONF=/usr/pkg/etc/ntpd.conf
# or by adding this to /etc/dhcpcd.conf
# env NTP_CONF=/usr/pkg/etc/ntpd.conf
# or by adding this to /etc/dhcpcd.enter-hook
# NTP_CONF=/usr/pkg/etc/ntpd.conf
# To use Chrony instead, simply change ntpd.conf to chrony.conf in the
# above examples.
: ${ntp_confs:=ntp.conf ntpd.conf chrony.conf}
: ${ntp_conf_dirs=/etc /usr/pkg/etc /usr/local/etc}
ntp_conf_dir="$state_dir/ntp.conf"
# If NTP_CONF is not set, work out a good default
if [ -z "$NTP_CONF" ]; then
for d in ${ntp_conf_dirs}; do
for f in ${ntp_confs}; do
if [ -e "$d/$f" ]; then
NTP_CONF="$d/$f"
break 2
fi
done
done
[ -e "$NTP_CONF" ] || NTP_CONF=/etc/ntp.conf
fi
# Derive service name from configuration
if [ -z "$ntp_service" ]; then
case "$NTP_CONF" in
*chrony.conf) ntp_service=chronyd;;
*) ntp_service=ntpd;;
esac
fi
# Debian has a separate file for DHCP config to avoid stamping on
# the master.
if [ "$ntp_service" = ntpd ] && command -v invoke-rc.d >/dev/null 2>&1; then
[ -e /var/lib/ntp ] || mkdir /var/lib/ntp
: ${ntp_service:=ntp}
: ${NTP_DHCP_CONF:=/var/lib/ntp/ntp.conf.dhcp}
fi
: ${ntp_restart_cmd:=service_condcommand $ntp_service restart}
ntp_conf=${NTP_CONF}
NL="
"
build_ntp_conf()
{
cf="$state_dir/ntp.conf.$ifname"
# Build a list of interfaces
interfaces=$(list_interfaces "$ntp_conf_dir")
header=
servers=
if [ -n "$interfaces" ]; then
# Build the header
for x in ${interfaces}; do
header="$header${header:+, }$x"
done
# Build a server list
srvs=$(cd "$ntp_conf_dir";
key_get_value "server " $interfaces)
if [ -n "$srvs" ]; then
for x in $(uniqify $srvs); do
servers="${servers}server $x$NL"
done
fi
fi
# Merge our config into ntp.conf
[ -e "$cf" ] && rm -f "$cf"
[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
if [ -n "$NTP_DHCP_CONF" ]; then
[ -e "$ntp_conf" ] && cp "$ntp_conf" "$cf"
ntp_conf="$NTP_DHCP_CONF"
elif [ -e "$ntp_conf" ]; then
remove_markers "$signature_base" "$signature_base_end" \
"$ntp_conf" > "$cf"
fi
if [ -n "$servers" ]; then
echo "$signature_base${header:+ $from }$header" >> "$cf"
printf %s "$servers" >> "$cf"
echo "$signature_base_end${header:+ $from }$header" >> "$cf"
else
[ -e "$ntp_conf" ] && [ -e "$cf" ] || return
fi
# If we changed anything, restart ntpd
if change_file "$ntp_conf" "$cf"; then
[ -n "$ntp_restart_cmd" ] && eval $ntp_restart_cmd
fi
}
add_ntp_conf()
{
cf="$ntp_conf_dir/$ifname"
[ -e "$cf" ] && rm "$cf"
[ -d "$ntp_conf_dir" ] || mkdir -p "$ntp_conf_dir"
if [ -n "$new_ntp_servers" ]; then
for x in $(uniqify $new_ntp_servers); do
echo "server $x" >> "$cf"
done
fi
build_ntp_conf
}
remove_ntp_conf()
{
if [ -e "$ntp_conf_dir/$ifname" ]; then
rm "$ntp_conf_dir/$ifname"
fi
build_ntp_conf
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_ntp_servers="$new_dhcp6_sntp_servers $new_dhcp6_ntp_server_addr $new_dhcp6_ntp_server_fqdn"
;;
esac
if $if_configured; then
if $if_up; then
add_ntp_conf
elif $if_down; then
remove_ntp_conf
fi
fi

View File

@ -0,0 +1,84 @@
# Sample dhcpcd hook for ypbind
# This script is only suitable for the BSD versions.
: ${ypbind_restart_cmd:=service_command ypbind restart}
: ${ypbind_stop_cmd:=service_condcommand ypbind stop}
ypbind_dir="$state_dir/ypbind"
: ${ypdomain_dir:=/var/yp}
: ${ypdomain_suffix:=.ypservers}
best_domain()
{
for i in "$ypbind_dir/$interface_order".*; do
if [ -f "$i" ]; then
cat "$i"
return 0
fi
done
return 1
}
make_yp_binding()
{
[ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir"
echo "$new_nis_domain" >"$ypbind_dir/$ifname"
if [ -z "$ypdomain_dir" ]; then
false
else
cf="$ypdomain_dir/$new_nis_domain$ypdomain_suffix"
if [ -n "$new_nis_servers" ]; then
ncf="$cf.$ifname"
rm -f "$ncf"
for x in $new_nis_servers; do
echo "$x" >>"$ncf"
done
change_file "$cf" "$ncf"
else
[ -e "$cf" ] && rm "$cf"
fi
fi
nd="$(best_domain)"
if [ $? = 0 ] && [ "$nd" != "$(domainname)" ]; then
domainname "$nd"
if [ -n "$ypbind_restart_cmd" ]; then
eval $ypbind_restart_cmd
fi
fi
}
restore_yp_binding()
{
rm -f "$ypbind_dir/$ifname"
nd="$(best_domain)"
# We need to stop ypbind if there is no best domain
# otherwise it will just stall as we cannot set domainname
# to blank :/
if [ -z "$nd" ]; then
if [ -n "$ypbind_stop_cmd" ]; then
eval $ypbind_stop_cmd
fi
elif [ "$nd" != "$(domainname)" ]; then
domainname "$nd"
if [ -n "$ypbind_restart_cmd" ]; then
eval $ypbind_restart_cmd
fi
fi
}
if ! $if_configured; then
;
elif [ "$reason" = PREINIT ]; then
rm -f "$ypbind_dir/$interface".*
elif $if_up || $if_down; then
if [ -n "$new_nis_domain" ]; then
if valid_domainname "$new_nis_domain"; then
make_yp_binding
else
syslog err "Invalid NIS domain name: $new_nis_domain"
fi
elif [ -n "$old_nis_domain" ]; then
restore_yp_binding
fi
fi

View File

@ -0,0 +1,85 @@
# Sample dhcpcd hook for ypbind
# This script is only suitable for the BSD versions.
: ${ypbind_restart_cmd:=service_command ypbind restart}
: ${ypbind_stop_cmd:=service_condcommand ypbind stop}
ypbind_dir="$state_dir/ypbind"
: ${ypdomain_dir:=@YPDOMAIN_DIR@}
: ${ypdomain_suffix:=@YPDOMAIN_SUFFIX@}
best_domain()
{
for i in "$ypbind_dir/$interface_order".*; do
if [ -f "$i" ]; then
cat "$i"
return 0
fi
done
return 1
}
make_yp_binding()
{
[ -d "$ypbind_dir" ] || mkdir -p "$ypbind_dir"
echo "$new_nis_domain" >"$ypbind_dir/$ifname"
if [ -z "$ypdomain_dir" ]; then
false
else
cf="$ypdomain_dir/$new_nis_domain$ypdomain_suffix"
if [ -n "$new_nis_servers" ]; then
ncf="$cf.$ifname"
rm -f "$ncf"
for x in $new_nis_servers; do
echo "$x" >>"$ncf"
done
change_file "$cf" "$ncf"
else
[ -e "$cf" ] && rm "$cf"
fi
fi
nd="$(best_domain)"
if [ $? = 0 ] && [ "$nd" != "$(domainname)" ]; then
domainname "$nd"
if [ -n "$ypbind_restart_cmd" ]; then
eval $ypbind_restart_cmd
fi
fi
}
restore_yp_binding()
{
rm -f "$ypbind_dir/$ifname"
nd="$(best_domain)"
# We need to stop ypbind if there is no best domain
# otherwise it will just stall as we cannot set domainname
# to blank :/
if [ -z "$nd" ]; then
if [ -n "$ypbind_stop_cmd" ]; then
eval $ypbind_stop_cmd
fi
elif [ "$nd" != "$(domainname)" ]; then
domainname "$nd"
if [ -n "$ypbind_restart_cmd" ]; then
eval $ypbind_restart_cmd
fi
fi
}
if ! $if_configured; then
;
elif [ "$reason" = PREINIT ]; then
rm -f "$ypbind_dir/$interface".*
elif $if_up || $if_down; then
if [ -n "$new_nis_domain" ]; then
if valid_domainname "$new_nis_domain"; then
make_yp_binding
else
syslog err "Invalid NIS domain name: $new_nis_domain"
fi
elif [ -n "$old_nis_domain" ]; then
restore_yp_binding
fi
fi

View File

@ -0,0 +1,354 @@
#!/bin/sh
# dhcpcd client configuration script
# Handy variables and functions for our hooks to use
ifname="$interface${protocol+.}$protocol"
from=from
signature_base="# Generated by dhcpcd"
signature="$signature_base $from $ifname"
signature_base_end="# End of dhcpcd"
signature_end="$signature_base_end $from $ifname"
state_dir=/var/run/dhcpcd/hook-state
_detected_init=false
: ${if_up:=false}
: ${if_down:=false}
: ${syslog_debug:=false}
# Ensure that all arguments are unique
uniqify()
{
result=
for i do
case " $result " in
*" $i "*);;
*) result="$result${result:+ }$i";;
esac
done
echo "$result"
}
# List interface config files in a directory.
# If dhcpcd is running as a single instance then it will have a list of
# interfaces in the preferred order.
# Otherwise we just use what we have.
list_interfaces()
{
ifaces=
for i in $interface_order; do
for x in "$1"/$i.*; do
[ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
done
done
for x in "$1"/*; do
[ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
done
uniqify $ifaces
}
# Trim function
trim()
{
var="$*"
var=${var#"${var%%[![:space:]]*}"}
var=${var%"${var##*[![:space:]]}"}
if [ -z "$var" ]; then
# So it seems our shell doesn't support wctype(3) patterns
# Fall back to sed
var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//')
fi
printf %s "$var"
}
# We normally use sed to extract values using a key from a list of files
# but sed may not always be available at the time.
key_get_value()
{
key="$1"
shift
if command -v sed >/dev/null 2>&1; then
sed -n "s/^$key//p" $@
else
for x do
while read line; do
case "$line" in
"$key"*) echo "${line##$key}";;
esac
done < "$x"
done
fi
}
# We normally use sed to remove markers from a configuration file
# but sed may not always be available at the time.
remove_markers()
{
m1="$1"
m2="$2"
in_marker=0
shift; shift
if command -v sed >/dev/null 2>&1; then
sed "/^$m1/,/^$m2/d" $@
else
for x do
while read line; do
case "$line" in
"$m1"*) in_marker=1;;
"$m2"*) in_marker=0;;
*) [ $in_marker = 0 ] && echo "$line";;
esac
done < "$x"
done
fi
}
# Compare two files.
comp_file()
{
[ -e "$1" ] && [ -e "$2" ] || return 1
if command -v cmp >/dev/null 2>&1; then
cmp -s "$1" "$2"
elif command -v diff >/dev/null 2>&1; then
diff -q "$1" "$2" >/dev/null
else
# Hopefully we're only working on small text files ...
[ "$(cat "$1")" = "$(cat "$2")" ]
fi
}
# Compare two files.
# If different, replace first with second otherwise remove second.
change_file()
{
if [ -e "$1" ]; then
if comp_file "$1" "$2"; then
rm -f "$2"
return 1
fi
fi
cat "$2" > "$1"
rm -f "$2"
return 0
}
# Compare two files.
# If different, copy or link depending on target type
copy_file()
{
if [ -h "$2" ]; then
[ "$(readlink "$2")" = "$1" ] && return 1
ln -sf "$1" "$2"
else
comp_file "$1" "$2" && return 1
cat "$1" >"$2"
fi
}
# Save a config file
save_conf()
{
if [ -f "$1" ]; then
rm -f "$1-pre.$interface"
cat "$1" > "$1-pre.$interface"
fi
}
# Restore a config file
restore_conf()
{
[ -f "$1-pre.$interface" ] || return 1
cat "$1-pre.$interface" > "$1"
rm -f "$1-pre.$interface"
}
# Write a syslog entry
syslog()
{
lvl="$1"
if [ "$lvl" = debug ]; then
${syslog_debug} || return 0
fi
[ -n "$lvl" ] && shift
[ -n "$*" ] || return 0
case "$lvl" in
err|error) echo "$interface: $*" >&2;;
*) echo "$interface: $*";;
esac
if command -v logger >/dev/null 2>&1; then
logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*"
fi
}
# Check for a valid name as per RFC952 and RFC1123 section 2.1
valid_domainname()
{
name="$1"
[ -z "$name" ] || [ ${#name} -gt 255 ] && return 1
while [ -n "$name" ]; do
label="${name%%.*}"
[ -z "$label" ] || [ ${#label} -gt 63 ] && return 1
case "$label" in
-*|_*|*-|*_) return 1;;
*[![:alnum:]_-]*) return 1;;
"$name") return 0;;
esac
name="${name#*.}"
done
return 0
}
valid_domainname_list()
{
for name do
valid_domainname "$name" || return $?
done
return 0
}
# With the advent of alternative init systems, it's possible to have
# more than one installed. So we need to try to guess what one we're
# using unless overridden by configure.
detect_init()
{
_service_exists=""
_service_cmd=""
_service_status=""
[ -n "$_service_cmd" ] && return 0
if $_detected_init; then
[ -n "$_service_cmd" ]
return $?
fi
# Detect the running init system.
# As systemd and OpenRC can be installed on top of legacy init
# systems we try to detect them first.
status=""
: ${status:=status}
if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then
_service_exists="/bin/systemctl --quiet is-enabled \$1.service"
_service_status="/bin/systemctl --quiet is-active \$1.service"
_service_cmd="/bin/systemctl \$2 --no-block \$1.service"
elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then
_service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service"
_service_status="/usr/bin/systemctl --quiet is-active \$1.service"
_service_cmd="/usr/bin/systemctl \$2 --no-block \$1.service"
elif [ -x /sbin/rc-service ] &&
{ [ -s /libexec/rc/init.d/softlevel ] ||
[ -s /run/openrc/softlevel ]; }
then
_service_exists="/sbin/rc-service -e \$1"
_service_cmd="/sbin/rc-service \$1 -- -D \$2"
elif [ -x /usr/sbin/invoke-rc.d ]; then
_service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]"
_service_cmd="/usr/sbin/invoke-rc.d \$1 \$2"
elif [ -x /sbin/service ]; then
_service_exists="/sbin/service \$1 >/dev/null 2>&1"
_service_cmd="/sbin/service \$1 \$2"
elif [ -x /usr/sbin/service ]; then
_service_exists="/usr/sbin/service \$1 $status >/dev/null 2>&1"
_service_cmd="/usr/sbin/service \$1 \$2"
elif [ -x /bin/sv ]; then
_service_exists="/bin/sv status \$1 >/dev/null 2>&1"
_service_cmd="/bin/sv \$2 \$1"
elif [ -x /usr/bin/sv ]; then
_service_exists="/usr/bin/sv status \$1 >/dev/null 2>&1"
_service_cmd="/usr/bin/sv \$2 \$1"
elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then
_service_exists="[ -x /etc/rc.d/rc.\$1 ]"
_service_cmd="/etc/rc.d/rc.\$1 \$2"
_service_status="/etc/rc.d/rc.\$1 status >/dev/null 2>&1"
else
for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
if [ -d $x ]; then
_service_exists="[ -x $x/\$1 ]"
_service_cmd="$x/\$1 \$2"
_service_status="$x/\$1 $status >/dev/null 2>&1"
break
fi
done
if [ -e /etc/arch-release ]; then
_service_status="[ -e /var/run/daemons/\$1 ]"
elif [ "$x" = "/etc/rc.d" ] && [ -e /etc/rc.d/rc.subr ]; then
_service_status="$x/\$1 check >/dev/null 2>&1"
fi
fi
_detected_init=true
if [ -z "$_service_cmd" ]; then
syslog err "could not detect a useable init system"
return 1
fi
return 0
}
# Check a system service exists
service_exists()
{
if [ -z "$_service_exists" ]; then
detect_init || return 1
fi
eval $_service_exists
}
# Send a command to a system service
service_cmd()
{
if [ -z "$_service_cmd" ]; then
detect_init || return 1
fi
eval $_service_cmd
}
# Send a command to a system service if it is running
service_status()
{
if [ -z "$_service_cmd" ]; then
detect_init || return 1
fi
if [ -n "$_service_status" ]; then
eval $_service_status
else
service_command $1 status >/dev/null 2>&1
fi
}
# Handy macros for our hooks
service_command()
{
service_exists $1 && service_cmd $1 $2
}
service_condcommand()
{
service_exists $1 && service_status $1 && service_cmd $1 $2
}
# We source each script into this one so that scripts run earlier can
# remove variables from the environment so later scripts don't see them.
# Thus, the user can create their dhcpcd.enter/exit-hook script to configure
# /etc/resolv.conf how they want and stop the system scripts ever updating it.
for hook in \
/etc/dhcpcd.enter-hook \
/libexec/dhcpcd-hooks/* \
/etc/dhcpcd.exit-hook
do
case "$hook" in
*/*~) continue;;
esac
for skip in $skip_hooks; do
case "$hook" in
*/"$skip") continue 2;;
*/[0-9][0-9]"-$skip") continue 2;;
*/[0-9][0-9]"-$skip.sh") continue 2;;
esac
done
if [ -f "$hook" ]; then
. "$hook"
fi
done

View File

@ -0,0 +1,233 @@
.\" Copyright (c) 2006-2023 Roy Marples
.\" 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.
.\"
.Dd August 31, 2022
.Dt DHCPCD-RUN-HOOKS 8
.Os
.Sh NAME
.Nm dhcpcd-run-hooks
.Nd DHCP client configuration script
.Sh DESCRIPTION
.Nm
is used by
.Xr dhcpcd 8
to run any system and user defined hook scripts.
System hook scripts are found in
.Pa /libexec/dhcpcd-hooks
and the user defined hooks are
.Pa /etc/dhcpcd.enter-hook .
and
.Pa /etc/dhcpcd.exit-hook .
The default install supplies hook scripts for configuring
.Pa /etc/resolv.conf
and the hostname.
Your distribution may have included other hook scripts to say configure
ntp or ypbind.
A test hook is also supplied that simply echos the dhcp variables to the
console from DISCOVER message.
.Pp
The hooks scripts are loaded into the current shell rather than executed
in their own process.
This allows each hook script, such as
.Pa /etc/dhcpcd.enter-hook
to customise environment variables or provide alternative functions to hooks
further down the chain.
As such, using the shell builtins
.Ic exit ,
.Ic exec
or similar will cause
.Nm
to exit at that point.
.Pp
Each time
.Nm
is invoked,
.Ev $interface
is set to the interface that
.Nm dhcpcd
is run on and
.Ev $reason
is set to the reason why
.Nm
was invoked.
DHCP information to be configured is held in variables starting with the word
new_ and old DHCP information to be removed is held in variables starting with
the word old_.
.Nm dhcpcd
can display the full list of variables it knows about by using the
.Fl V , -variables
argument.
.Pp
Here's a list of reasons why
.Nm
could be invoked:
.Bl -tag -width EXPIREXXXEXPIRE6
.It Dv PREINIT
dhcpcd is starting up and any pre-initialisation required should be performed now.
.It Dv CARRIER
dhcpcd has detected the carrier is up.
This is generally just a notification and no action need be taken.
.It Dv NOCARRIER
dhcpcd lost the carrier.
The cable may have been unplugged or association to the wireless point lost.
.It Dv NOCARRIER_ROAMING
dhcpcd lost the carrier but the interface configuration is persisted.
The OS has to support wireless roaming or IP Persistence for this to happen.
.It Dv INFORM | Dv INFORM6
dhcpcd informed a DHCP server about its address and obtained other
configuration details.
.It Dv BOUND | Dv BOUND6
dhcpcd obtained a new lease from a DHCP server.
.It Dv RENEW | Dv RENEW6
dhcpcd renewed its lease.
.It Dv REBIND | Dv REBIND6
dhcpcd has rebound to a new DHCP server.
.It Dv REBOOT | Dv REBOOT6
dhcpcd successfully requested a lease from a DHCP server.
.It Dv DELEGATED6
dhcpcd assigned a delegated prefix to the interface.
.It Dv IPV4LL
dhcpcd obtained an IPV4LL address, or one was removed.
.It Dv STATIC
dhcpcd has been configured with a static configuration which has not been
obtained from a DHCP server.
.It Dv 3RDPARTY
dhcpcd is monitoring the interface for a 3rd party to give it an IP address.
.It Dv TIMEOUT
dhcpcd failed to contact any DHCP servers but was able to use an old lease.
.It Dv EXPIRE | EXPIRE6
dhcpcd's lease or state expired and it failed to obtain a new one.
.It Dv NAK
dhcpcd received a NAK from the DHCP server.
This should be treated as EXPIRE.
.It Dv RECONFIGURE
dhcpcd has been instructed to reconfigure an interface.
.It Dv ROUTERADVERT
dhcpcd has received an IPv6 Router Advertisement, or one has expired.
.It Dv STOP | Dv STOP6
dhcpcd stopped running on the interface.
.It Dv STOPPED
dhcpcd has stopped entirely.
.It Dv DEPARTED
The interface has been removed.
.It Dv FAIL
dhcpcd failed to operate on the interface.
This normally happens when dhcpcd does not support the raw interface, which
means it cannot work as a DHCP or ZeroConf client.
Static configuration and DHCP INFORM is still allowed.
.It Dv TEST
dhcpcd received an OFFER from a DHCP server but will not configure the
interface.
This is primarily used to test the variables are filled correctly for the
script to process them.
.El
.Sh ENVIRONMENT
.Nm dhcpcd
will clear the environment variables aside from
.Ev $PATH .
The following variables will then be set, along with any protocol supplied
ones.
.Bl -tag -width xnew_delegated_dhcp6_prefix
.It Ev $interface
the name of the interface.
.It Ev $protocol
the protocol that triggered the event.
.It Ev $reason
as described above.
.It Ev $pid
the pid of
.Nm dhcpcd .
.It Ev $ifcarrier
the link status of
.Ev $interface :
.Dv unknown ,
.Dv up
or
.Dv down .
.It Ev $ifmetric
.Ev $interface
preference, lower is better.
.It Ev $ifwireless
.Dv 1 if
.Ev $interface
is wireless, otherwise
.Dv 0 .
.It Ev $ifflags
.Ev $interface
flags.
.It Ev $ifmtu
.Ev $interface
MTU.
.It Ev $ifssid
the SSID the
.Ev interface
is connected to.
.It Ev $interface_order
A list of interfaces, in order of preference.
.It Ev $if_up
.Dv true
if the
.Ev interface
is up, otherwise
.Dv false .
This is more than IFF_UP and may not be equal.
.It Ev $if_down
.Dv true
if the
.Ev interface
is down, otherwise
.Dv false .
This is more than IFF_UP and may not be equal.
.It Ev $af_waiting
Address family waiting for, as defined in
.Xr dhcpcd.conf 5 .
.It Ev $profile
the name of the profile selected from
.Xr dhcpcd.conf 5 .
.It Ev $new_delegated_dhcp6_prefix
space-separated list of delegated prefixes.
.El
.Sh FILES
When
.Nm
runs, it loads
.Pa /etc/dhcpcd.enter-hook ,
any scripts found in
.Pa /libexec/dhcpcd-hooks
in lexical order, then finally
.Pa /etc/dhcpcd.exit-hook .
.Sh SEE ALSO
.Xr dhcpcd 8
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Please report them to
.Lk https://roy.marples.name/projects/dhcpcd
.Sh SECURITY CONSIDERATIONS
.Nm dhcpcd
will validate the content of each option against its encoding.
For string, ascii, raw or binhex encoding it's up to the user to validate it
for the intended purpose.
.Pp
When used in a shell script, each variable must be quoted correctly.

View File

@ -0,0 +1,234 @@
.\" Copyright (c) 2006-2020 Roy Marples
.\" 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.
.\"
.Dd December 27, 2020
.Dt DHCPCD-RUN-HOOKS 8
.Os
.Sh NAME
.Nm dhcpcd-run-hooks
.Nd DHCP client configuration script
.Sh DESCRIPTION
.Nm
is used by
.Xr dhcpcd 8
to run any system and user defined hook scripts.
System hook scripts are found in
.Pa @HOOKDIR@
and the user defined hooks are
.Pa @SYSCONFDIR@/dhcpcd.enter-hook .
and
.Pa @SYSCONFDIR@/dhcpcd.exit-hook .
The default install supplies hook scripts for configuring
.Pa /etc/resolv.conf
and the hostname.
Your distribution may have included other hook scripts to say configure
ntp or ypbind.
A test hook is also supplied that simply echos the dhcp variables to the
console from DISCOVER message.
.Pp
The hooks scripts are loaded into the current shell rather than executed
in their own process.
This allows each hook script, such as
.Pa @SYSCONFDIR@/dhcpcd.enter-hook
to customise environment variables or provide alternative functions to hooks
further down the chain.
As such, using the shell builtins
.Ic exit ,
.Ic exec
or similar will cause
.Nm
to exit at that point.
.Pp
Each time
.Nm
is invoked,
.Ev $interface
is set to the interface that
.Nm dhcpcd
is run on and
.Ev $reason
is to the reason why
q
.Nm
was invoked.
DHCP information to be configured is held in variables starting with the word
new_ and old DHCP information to be removed is held in variables starting with
the word old_.
.Nm dhcpcd
can display the full list of variables it knows how about by using the
.Fl V , -variables
argument.
.Pp
Here's a list of reasons why
.Nm
could be invoked:
.Bl -tag -width EXPIREXXXEXPIRE6
.It Dv PREINIT
dhcpcd is starting up and any pre-initialisation should be done.
.It Dv CARRIER
dhcpcd has detected the carrier is up.
This is generally just a notification and no action need be taken.
.It Dv NOCARRIER
dhcpcd lost the carrier.
The cable may have been unplugged or association to the wireless point lost.
.It Dv NOCARRIER_ROAMING
dhcpcd lost the carrier but the interface configuration is persisted.
The OS has to support wireless roaming or IP Persistance for this to happen.
.It Dv INFORM | Dv INFORM6
dhcpcd informed a DHCP server about its address and obtained other
configuration details.
.It Dv BOUND | Dv BOUND6
dhcpcd obtained a new lease from a DHCP server.
.It Dv RENEW | Dv RENEW6
dhcpcd renewed it's lease.
.It Dv REBIND | Dv REBIND6
dhcpcd has rebound to a new DHCP server.
.It Dv REBOOT | Dv REBOOT6
dhcpcd successfully requested a lease from a DHCP server.
.It Dv DELEGATED6
dhcpcd assigned a delegated prefix to the interface.
.It Dv IPV4LL
dhcpcd obtained an IPV4LL address, or one was removed.
.It Dv STATIC
dhcpcd has been configured with a static configuration which has not been
obtained from a DHCP server.
.It Dv 3RDPARTY
dhcpcd is monitoring the interface for a 3rd party to give it an IP address.
.It Dv TIMEOUT
dhcpcd failed to contact any DHCP servers but was able to use an old lease.
.It Dv EXPIRE | EXPIRE6
dhcpcd's lease or state expired and it failed to obtain a new one.
.It Dv NAK
dhcpcd received a NAK from the DHCP server.
This should be treated as EXPIRE.
.It Dv RECONFIGURE
dhcpcd has been instructed to reconfigure an interface.
.It Dv ROUTERADVERT
dhcpcd has received an IPv6 Router Advertisement, or one has expired.
.It Dv STOP | Dv STOP6
dhcpcd stopped running on the interface.
.It Dv STOPPED
dhcpcd has stopped entirely.
.It Dv DEPARTED
The interface has been removed.
.It Dv FAIL
dhcpcd failed to operate on the interface.
This normally happens when dhcpcd does not support the raw interface, which
means it cannot work as a DHCP or ZeroConf client.
Static configuration and DHCP INFORM is still allowed.
.It Dv TEST
dhcpcd received an OFFER from a DHCP server but will not configure the
interface.
This is primarily used to test the variables are filled correctly for the
script to process them.
.El
.Sh ENVIRONMENT
.Nm dhcpcd
will clear the environment variables aside from
.Ev $PATH .
The following variables will then be set, along with any protocol supplied
ones.
.Bl -tag -width xnew_delegated_dhcp6_prefix
.It Ev $interface
the name of the interface.
.It Ev $protocol
the protocol that triggered the event.
.It Ev $reason
as described above.
.It Ev $pid
the pid of
.Nm dhcpcd .
.It Ev $ifcarrier
the link status of
.Ev $interface :
.Dv unknown ,
.Dv up
or
.Dv down .
.It Ev $ifmetric
.Ev $interface
preference, lower is better.
.It Ev $ifwireless
.Dv 1 if
.Ev $interface
is wireless, otherwise
.Dv 0 .
.It Ev $ifflags
.Ev $interface
flags.
.It Ev $ifmtu
.Ev $interface
MTU.
.It Ev $ifssid
the name of the SSID the
.Ev interface
is connected to.
.It Ev $interface_order
A list of interfaces, in order of preference.
.It Ev $if_up
.Dv true
if the
.Ev interface
is up, otherwise
.Dv false .
This is more than IFF_UP and may not be equal.
.It Ev $if_down
.Dv true
if the
.Ev interface
is down, otherwise
.Dv false .
This is more than IFF_UP and may not be equal.
.It Ev $af_waiting
Address family waiting for, as defined in
.Xr dhcpcd.conf 5 .
.It Ev $profile
the name of the profile selected from
.Xr dhcpcd.conf 5 .
.It Ev $new_delegated_dhcp6_prefix
space separated list of delegated prefixes.
.El
.Sh FILES
When
.Nm
runs, it loads
.Pa @SYSCONFDIR@/dhcpcd.enter-hook
and any scripts found in
.Pa @HOOKDIR@
in a lexical order and then finally
.Pa @SYSCONFDIR@/dhcpcd.exit-hook
.Sh SEE ALSO
.Xr dhcpcd 8
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd
.Sh SECURITY CONSIDERATIONS
.Nm dhcpcd
will validate the content of each option against its encoding.
For string, ascii, raw or binhex encoding it's up to the user to validate it
for the intended purpose.
.Pp
When used in a shell script, each variable must be quoted correctly.

View File

@ -0,0 +1,352 @@
#!/bin/sh
# dhcpcd client configuration script
# Handy variables and functions for our hooks to use
ifname="$interface${protocol+.}$protocol"
from=from
signature_base="# Generated by dhcpcd"
signature="$signature_base $from $ifname"
signature_base_end="# End of dhcpcd"
signature_end="$signature_base_end $from $ifname"
state_dir=@RUNDIR@/hook-state
_detected_init=false
: ${if_up:=false}
: ${if_down:=false}
: ${syslog_debug:=false}
# Ensure that all arguments are unique
uniqify()
{
result=
for i do
case " $result " in
*" $i "*);;
*) result="$result${result:+ }$i";;
esac
done
echo "$result"
}
# List interface config files in a directory.
# If dhcpcd is running as a single instance then it will have a list of
# interfaces in the preferred order.
# Otherwise we just use what we have.
list_interfaces()
{
ifaces=
for i in $interface_order; do
for x in "$1"/$i.*; do
[ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
done
done
for x in "$1"/*; do
[ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
done
uniqify $ifaces
}
# Trim function
trim()
{
var="$*"
var=${var#"${var%%[![:space:]]*}"}
var=${var%"${var##*[![:space:]]}"}
if [ -z "$var" ]; then
# So it seems our shell doesn't support wctype(3) patterns
# Fall back to sed
var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//')
fi
printf %s "$var"
}
# We normally use sed to extract values using a key from a list of files
# but sed may not always be available at the time.
key_get_value()
{
key="$1"
shift
if type sed >/dev/null 2>&1; then
sed -n "s/^$key//p" $@
else
for x do
while read line; do
case "$line" in
"$key"*) echo "${line##$key}";;
esac
done < "$x"
done
fi
}
# We normally use sed to remove markers from a configuration file
# but sed may not always be available at the time.
remove_markers()
{
m1="$1"
m2="$2"
in_marker=0
shift; shift
if type sed >/dev/null 2>&1; then
sed "/^$m1/,/^$m2/d" $@
else
for x do
while read line; do
case "$line" in
"$m1"*) in_marker=1;;
"$m2"*) in_marker=0;;
*) [ $in_marker = 0 ] && echo "$line";;
esac
done < "$x"
done
fi
}
# Compare two files.
comp_file()
{
[ -e "$1" ] && [ -e "$2" ] || return 1
if type cmp >/dev/null 2>&1; then
cmp -s "$1" "$2"
elif type diff >/dev/null 2>&1; then
diff -q "$1" "$2" >/dev/null
else
# Hopefully we're only working on small text files ...
[ "$(cat "$1")" = "$(cat "$2")" ]
fi
}
# Compare two files.
# If different, replace first with second otherwise remove second.
change_file()
{
if [ -e "$1" ]; then
if comp_file "$1" "$2"; then
rm -f "$2"
return 1
fi
fi
cat "$2" > "$1"
rm -f "$2"
return 0
}
# Compare two files.
# If different, copy or link depending on target type
copy_file()
{
if [ -h "$2" ]; then
[ "$(readlink "$2")" = "$1" ] && return 1
ln -sf "$1" "$2"
else
comp_file "$1" "$2" && return 1
cat "$1" >"$2"
fi
}
# Save a config file
save_conf()
{
if [ -f "$1" ]; then
rm -f "$1-pre.$interface"
cat "$1" > "$1-pre.$interface"
fi
}
# Restore a config file
restore_conf()
{
[ -f "$1-pre.$interface" ] || return 1
cat "$1-pre.$interface" > "$1"
rm -f "$1-pre.$interface"
}
# Write a syslog entry
syslog()
{
lvl="$1"
if [ "$lvl" = debug ]; then
${syslog_debug} || return 0
fi
[ -n "$lvl" ] && shift
[ -n "$*" ] || return 0
case "$lvl" in
err|error) echo "$interface: $*" >&2;;
*) echo "$interface: $*";;
esac
if type logger >/dev/null 2>&1; then
logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*"
fi
}
# Check for a valid name as per RFC952 and RFC1123 section 2.1
valid_domainname()
{
name="$1"
[ -z "$name" ] || [ ${#name} -gt 255 ] && return 1
while [ -n "$name" ]; do
label="${name%%.*}"
[ -z "$label" ] || [ ${#label} -gt 63 ] && return 1
case "$label" in
-*|_*|*-|*_) return 1;;
*[![:alnum:]_-]*) return 1;;
"$name") return 0;;
esac
name="${name#*.}"
done
return 0
}
valid_domainname_list()
{
for name do
valid_domainname "$name" || return $?
done
return 0
}
# With the advent of alternative init systems, it's possible to have
# more than one installed. So we need to try to guess what one we're
# using unless overridden by configure.
detect_init()
{
_service_exists="@SERVICEEXISTS@"
_service_cmd="@SERVICECMD@"
_service_status="@SERVICESTATUS@"
[ -n "$_service_cmd" ] && return 0
if $_detected_init; then
[ -n "$_service_cmd" ]
return $?
fi
# Detect the running init system.
# As systemd and OpenRC can be installed on top of legacy init
# systems we try to detect them first.
status="@STATUSARG@"
: ${status:=status}
if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then
_service_exists="/bin/systemctl --quiet is-enabled \$1.service"
_service_status="/bin/systemctl --quiet is-active \$1.service"
_service_cmd="/bin/systemctl \$2 \$1.service"
elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then
_service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service"
_service_status="/usr/bin/systemctl --quiet is-active \$1.service"
_service_cmd="/usr/bin/systemctl \$2 \$1.service"
elif [ -x /sbin/rc-service ] &&
{ [ -s /libexec/rc/init.d/softlevel ] ||
[ -s /run/openrc/softlevel ]; }
then
_service_exists="/sbin/rc-service -e \$1"
_service_cmd="/sbin/rc-service \$1 -- -D \$2"
elif [ -x /usr/sbin/invoke-rc.d ]; then
_service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]"
_service_cmd="/usr/sbin/invoke-rc.d \$1 \$2"
elif [ -x /sbin/service ]; then
_service_exists="/sbin/service \$1 >/dev/null 2>&1"
_service_cmd="/sbin/service \$1 \$2"
elif [ -x /usr/sbin/service ]; then
_service_exists="/usr/sbin/service \$1 $status >/dev/null 2>&1"
_service_cmd="/usr/sbin/service \$1 \$2"
elif [ -x /bin/sv ]; then
_service_exists="/bin/sv status \$1 >/dev/null 2>&1"
_service_cmd="/bin/sv \$2 \$1"
elif [ -x /usr/bin/sv ]; then
_service_exists="/usr/bin/sv status \$1 >/dev/null 2>&1"
_service_cmd="/usr/bin/sv \$2 \$1"
elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then
_service_exists="[ -x /etc/rc.d/rc.\$1 ]"
_service_cmd="/etc/rc.d/rc.\$1 \$2"
_service_status="/etc/rc.d/rc.\$1 status >/dev/null 2>&1"
else
for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
if [ -d $x ]; then
_service_exists="[ -x $x/\$1 ]"
_service_cmd="$x/\$1 \$2"
_service_status="$x/\$1 $status >/dev/null 2>&1"
break
fi
done
if [ -e /etc/arch-release ]; then
_service_status="[ -e /var/run/daemons/\$1 ]"
elif [ "$x" = "/etc/rc.d" ] && [ -e /etc/rc.d/rc.subr ]; then
_service_status="$x/\$1 check >/dev/null 2>&1"
fi
fi
_detected_init=true
if [ -z "$_service_cmd" ]; then
syslog err "could not detect a useable init system"
return 1
fi
return 0
}
# Check a system service exists
service_exists()
{
if [ -z "$_service_exists" ]; then
detect_init || return 1
fi
eval $_service_exists
}
# Send a command to a system service
service_cmd()
{
if [ -z "$_service_cmd" ]; then
detect_init || return 1
fi
eval $_service_cmd
}
# Send a command to a system service if it is running
service_status()
{
if [ -z "$_service_cmd" ]; then
detect_init || return 1
fi
if [ -n "$_service_status" ]; then
eval $_service_status
else
service_command $1 status >/dev/null 2>&1
fi
}
# Handy macros for our hooks
service_command()
{
service_exists $1 && service_cmd $1 $2
}
service_condcommand()
{
service_exists $1 && service_status $1 && service_cmd $1 $2
}
# We source each script into this one so that scripts run earlier can
# remove variables from the environment so later scripts don't see them.
# Thus, the user can create their dhcpcd.enter/exit-hook script to configure
# /etc/resolv.conf how they want and stop the system scripts ever updating it.
for hook in \
@SYSCONFDIR@/dhcpcd.enter-hook \
@HOOKDIR@/* \
@SYSCONFDIR@/dhcpcd.exit-hook
do
for skip in $skip_hooks; do
case "$hook" in
*/*~) continue 2;;
*/"$skip") continue 2;;
*/[0-9][0-9]"-$skip") continue 2;;
*/[0-9][0-9]"-$skip.sh") continue 2;;
esac
done
if [ -f "$hook" ]; then
. "$hook"
fi
done

670
external/bsd/dhcpcd/dist/src/arp.c vendored Normal file
View File

@ -0,0 +1,670 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - ARP handler
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define ELOOP_QUEUE ELOOP_ARP
#include "config.h"
#include "arp.h"
#include "bpf.h"
#include "ipv4.h"
#include "common.h"
#include "dhcpcd.h"
#include "eloop.h"
#include "if.h"
#include "if-options.h"
#include "ipv4ll.h"
#include "logerr.h"
#include "privsep.h"
#if defined(ARP)
#define ARP_LEN \
(FRAMEHDRLEN_MAX + \
sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
/* ARP debugging can be quite noisy. Enable this for more noise! */
//#define ARP_DEBUG
/* Assert the correct structure size for on wire */
__CTASSERT(sizeof(struct arphdr) == 8);
static ssize_t
arp_request(const struct arp_state *astate,
const struct in_addr *sip)
{
const struct interface *ifp = astate->iface;
const struct in_addr *tip = &astate->addr;
uint8_t arp_buffer[ARP_LEN];
struct arphdr ar;
size_t len;
uint8_t *p;
ar.ar_hrd = htons(ifp->hwtype);
ar.ar_pro = htons(ETHERTYPE_IP);
ar.ar_hln = ifp->hwlen;
ar.ar_pln = sizeof(tip->s_addr);
ar.ar_op = htons(ARPOP_REQUEST);
p = arp_buffer;
len = 0;
#define CHECK(fun, b, l) \
do { \
if (len + (l) > sizeof(arp_buffer)) \
goto eexit; \
fun(p, (b), (l)); \
p += (l); \
len += (l); \
} while (/* CONSTCOND */ 0)
#define APPEND(b, l) CHECK(memcpy, b, l)
#define ZERO(l) CHECK(memset, 0, l)
APPEND(&ar, sizeof(ar));
APPEND(ifp->hwaddr, ifp->hwlen);
if (sip != NULL)
APPEND(&sip->s_addr, sizeof(sip->s_addr));
else
ZERO(sizeof(tip->s_addr));
ZERO(ifp->hwlen);
APPEND(&tip->s_addr, sizeof(tip->s_addr));
#ifdef PRIVSEP
if (ifp->ctx->options & DHCPCD_PRIVSEP)
return ps_bpf_sendarp(ifp, tip, arp_buffer, len);
#endif
/* Note that well formed ethernet will add extra padding
* to ensure that the packet is at least 60 bytes (64 including FCS). */
return bpf_send(astate->bpf, ETHERTYPE_ARP, arp_buffer, len);
eexit:
errno = ENOBUFS;
return -1;
}
static void
arp_report_conflicted(const struct arp_state *astate,
const struct arp_msg *amsg)
{
char abuf[HWADDR_LEN * 3];
char fbuf[HWADDR_LEN * 3];
if (amsg == NULL) {
logerrx("%s: DAD detected %s",
astate->iface->name, inet_ntoa(astate->addr));
return;
}
hwaddr_ntoa(amsg->sha, astate->iface->hwlen, abuf, sizeof(abuf));
if (bpf_frame_header_len(astate->iface) == 0) {
logwarnx("%s: %s claims %s",
astate->iface->name, abuf, inet_ntoa(astate->addr));
return;
}
logwarnx("%s: %s(%s) claims %s",
astate->iface->name, abuf,
hwaddr_ntoa(amsg->fsha, astate->iface->hwlen, fbuf, sizeof(fbuf)),
inet_ntoa(astate->addr));
}
static void
arp_found(struct arp_state *astate, const struct arp_msg *amsg)
{
struct interface *ifp;
struct ipv4_addr *ia;
#ifndef KERNEL_RFC5227
struct timespec now;
#endif
arp_report_conflicted(astate, amsg);
ifp = astate->iface;
/* If we haven't added the address we're doing a probe. */
ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
if (ia == NULL) {
if (astate->found_cb != NULL)
astate->found_cb(astate, amsg);
return;
}
#ifndef KERNEL_RFC5227
/* RFC 3927 Section 2.5 says a defence should
* broadcast an ARP announcement.
* Because the kernel will also unicast a reply to the
* hardware address which requested the IP address
* the other IPv4LL client will receieve two ARP
* messages.
* If another conflict happens within DEFEND_INTERVAL
* then we must drop our address and negotiate a new one.
* If DHCPCD_ARP_PERSISTDEFENCE is set, that enables
* RFC5227 section 2.4.c behaviour. Upon conflict
* detection, the host records the time that the
* conflicting ARP packet was received, and then
* broadcasts one single ARP Announcement. The host then
* continues to use the address normally. All further
* conflict notifications within the DEFEND_INTERVAL are
* ignored. */
clock_gettime(CLOCK_MONOTONIC, &now);
if (timespecisset(&astate->defend) &&
eloop_timespec_diff(&now, &astate->defend, NULL) < DEFEND_INTERVAL)
{
logwarnx("%s: %d second defence failed for %s",
ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr));
if (ifp->options->options & DHCPCD_ARP_PERSISTDEFENCE)
return;
}
else if (arp_request(astate, &astate->addr) == -1)
logerr(__func__);
else {
logdebugx("%s: defended address %s",
ifp->name, inet_ntoa(astate->addr));
astate->defend = now;
return;
}
#endif
if (astate->defend_failed_cb != NULL)
astate->defend_failed_cb(astate);
}
static bool
arp_validate(const struct interface *ifp, struct arphdr *arp)
{
/* Address type must match */
if (arp->ar_hrd != htons(ifp->hwtype))
return false;
/* Protocol must be IP. */
if (arp->ar_pro != htons(ETHERTYPE_IP))
return false;
/* lladdr length matches */
if (arp->ar_hln != ifp->hwlen)
return false;
/* Protocol length must match in_addr_t */
if (arp->ar_pln != sizeof(in_addr_t))
return false;
/* Only these types are recognised */
if (arp->ar_op != htons(ARPOP_REPLY) &&
arp->ar_op != htons(ARPOP_REQUEST))
return false;
return true;
}
void
arp_packet(struct interface *ifp, uint8_t *data, size_t len,
unsigned int bpf_flags)
{
size_t fl = bpf_frame_header_len(ifp), falen;
const struct interface *ifn;
struct arphdr ar;
struct arp_msg arm;
const struct iarp_state *state;
struct arp_state *astate, *astaten;
uint8_t *hw_s, *hw_t;
#ifndef KERNEL_RFC5227
bool is_probe;
#endif /* KERNEL_RFC5227 */
/* Copy the frame header source and destination out */
memset(&arm, 0, sizeof(arm));
if (fl != 0) {
hw_s = bpf_frame_header_src(ifp, data, &falen);
if (hw_s != NULL && falen <= sizeof(arm.fsha))
memcpy(arm.fsha, hw_s, falen);
hw_t = bpf_frame_header_dst(ifp, data, &falen);
if (hw_t != NULL && falen <= sizeof(arm.ftha))
memcpy(arm.ftha, hw_t, falen);
/* Skip past the frame header */
data += fl;
len -= fl;
}
/* We must have a full ARP header */
if (len < sizeof(ar))
return;
memcpy(&ar, data, sizeof(ar));
if (!arp_validate(ifp, &ar)) {
#ifdef BPF_DEBUG
logerrx("%s: ARP BPF validation failure", ifp->name);
#endif
return;
}
/* Get pointers to the hardware addresses */
hw_s = data + sizeof(ar);
hw_t = hw_s + ar.ar_hln + ar.ar_pln;
/* Ensure we got all the data */
if ((size_t)((hw_t + ar.ar_hln + ar.ar_pln) - data) > len)
return;
/* Ignore messages from ourself */
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ar.ar_hln == ifn->hwlen &&
memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
break;
}
if (ifn) {
#ifdef ARP_DEBUG
logdebugx("%s: ignoring ARP from self", ifp->name);
#endif
return;
}
/* Copy out the HW and IP addresses */
memcpy(&arm.sha, hw_s, ar.ar_hln);
memcpy(&arm.sip.s_addr, hw_s + ar.ar_hln, ar.ar_pln);
memcpy(&arm.tha, hw_t, ar.ar_hln);
memcpy(&arm.tip.s_addr, hw_t + ar.ar_hln, ar.ar_pln);
#ifndef KERNEL_RFC5227
/* During ARP probe the 'sender hardware address' MUST contain the hardware
* address of the interface sending the packet. RFC5227, 1.1 */
is_probe = ar.ar_op == htons(ARPOP_REQUEST) && IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
bpf_flags & BPF_BCAST;
if (is_probe && falen > 0 && (falen != ar.ar_hln ||
memcmp(&arm.sha, &arm.fsha, ar.ar_hln))) {
char abuf[HWADDR_LEN * 3];
char fbuf[HWADDR_LEN * 3];
hwaddr_ntoa(&arm.sha, ar.ar_hln, abuf, sizeof(abuf));
hwaddr_ntoa(&arm.fsha, falen, fbuf, sizeof(fbuf));
logwarnx("%s: invalid ARP probe, sender hw address mismatch (%s, %s)",
ifp->name, abuf, fbuf);
return;
}
#endif /* KERNEL_RFC5227 */
/* Match the ARP probe to our states.
* Ignore Unicast Poll, RFC1122. */
state = ARP_CSTATE(ifp);
if (state == NULL)
return;
TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) {
if (IN_ARE_ADDR_EQUAL(&arm.sip, &astate->addr) ||
(IN_IS_ADDR_UNSPECIFIED(&arm.sip) &&
IN_ARE_ADDR_EQUAL(&arm.tip, &astate->addr) &&
bpf_flags & BPF_BCAST))
arp_found(astate, &arm);
}
}
static void
arp_read(void *arg, unsigned short events)
{
struct arp_state *astate = arg;
struct bpf *bpf = astate->bpf;
struct interface *ifp = astate->iface;
uint8_t buf[ARP_LEN];
ssize_t bytes;
struct in_addr addr = astate->addr;
if (events != ELE_READ)
logerrx("%s: unexpected event 0x%04x", __func__, events);
/* Some RAW mechanisms are generic file descriptors, not sockets.
* This means we have no kernel call to just get one packet,
* so we have to process the entire buffer. */
bpf->bpf_flags &= ~BPF_EOF;
while (!(bpf->bpf_flags & BPF_EOF)) {
bytes = bpf_read(bpf, buf, sizeof(buf));
if (bytes == -1) {
logerr("%s: %s", __func__, ifp->name);
arp_free(astate);
return;
}
arp_packet(ifp, buf, (size_t)bytes, bpf->bpf_flags);
/* Check we still have a state after processing. */
if ((astate = arp_find(ifp, &addr)) == NULL)
break;
if ((bpf = astate->bpf) == NULL)
break;
}
}
static void
arp_probed(void *arg)
{
struct arp_state *astate = arg;
timespecclear(&astate->defend);
astate->not_found_cb(astate);
}
static void
arp_probe1(void *arg)
{
struct arp_state *astate = arg;
struct interface *ifp = astate->iface;
unsigned int delay;
if (++astate->probes < PROBE_NUM) {
delay = (PROBE_MIN * MSEC_PER_SEC) +
(arc4random_uniform(
(PROBE_MAX - PROBE_MIN) * MSEC_PER_SEC));
eloop_timeout_add_msec(ifp->ctx->eloop, delay, arp_probe1, astate);
} else {
delay = ANNOUNCE_WAIT * MSEC_PER_SEC;
eloop_timeout_add_msec(ifp->ctx->eloop, delay, arp_probed, astate);
}
logdebugx("%s: ARP probing %s (%d of %d), next in %0.1f seconds",
ifp->name, inet_ntoa(astate->addr),
astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
(float)delay / MSEC_PER_SEC);
if (arp_request(astate, NULL) == -1)
logerr(__func__);
}
void
arp_probe(struct arp_state *astate)
{
astate->probes = 0;
logdebugx("%s: probing for %s",
astate->iface->name, inet_ntoa(astate->addr));
arp_probe1(astate);
}
#endif /* ARP */
struct arp_state *
arp_find(struct interface *ifp, const struct in_addr *addr)
{
struct iarp_state *state;
struct arp_state *astate;
if ((state = ARP_STATE(ifp)) == NULL)
goto out;
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
return astate;
}
out:
errno = ESRCH;
return NULL;
}
static void
arp_announced(void *arg)
{
struct arp_state *astate = arg;
if (astate->announced_cb) {
astate->announced_cb(astate);
return;
}
/* Keep the ARP state open to handle ongoing ACD. */
}
static void
arp_announce1(void *arg)
{
struct arp_state *astate = arg;
struct interface *ifp = astate->iface;
struct ipv4_addr *ia;
if (++astate->claims < ANNOUNCE_NUM)
logdebugx("%s: ARP announcing %s (%d of %d), "
"next in %d.0 seconds",
ifp->name, inet_ntoa(astate->addr),
astate->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
else
logdebugx("%s: ARP announcing %s (%d of %d)",
ifp->name, inet_ntoa(astate->addr),
astate->claims, ANNOUNCE_NUM);
/* The kernel will send a Gratuitous ARP for newly added addresses.
* So we can avoid sending the same.
* Linux is special and doesn't send one. */
ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
#ifndef __linux__
if (astate->claims == 1 && ia != NULL && ia->flags & IPV4_AF_NEW)
goto skip_request;
#endif
if (arp_request(astate, &astate->addr) == -1)
logerr(__func__);
#ifndef __linux__
skip_request:
#endif
/* No longer a new address. */
if (ia != NULL)
ia->flags |= ~IPV4_AF_NEW;
eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
astate);
}
static void
arp_announce(struct arp_state *astate)
{
struct iarp_state *state;
struct interface *ifp;
struct arp_state *a2;
int r;
/* Cancel any other ARP announcements for this address. */
TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
state = ARP_STATE(ifp);
if (state == NULL)
continue;
TAILQ_FOREACH(a2, &state->arp_states, next) {
if (astate == a2 ||
a2->addr.s_addr != astate->addr.s_addr)
continue;
r = eloop_timeout_delete(a2->iface->ctx->eloop,
a2->claims < ANNOUNCE_NUM
? arp_announce1 : arp_announced,
a2);
if (r == -1)
logerr(__func__);
else if (r != 0) {
logdebugx("%s: ARP announcement "
"of %s cancelled",
a2->iface->name,
inet_ntoa(a2->addr));
arp_announced(a2);
}
}
}
astate->claims = 0;
arp_announce1(astate);
}
struct arp_state *
arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
{
struct arp_state *astate;
if (ifp->flags & IFF_NOARP || !(ifp->options->options & DHCPCD_ARP))
return NULL;
astate = arp_find(ifp, ia);
if (astate == NULL) {
astate = arp_new(ifp, ia);
if (astate == NULL)
return NULL;
astate->announced_cb = arp_free;
}
arp_announce(astate);
return astate;
}
struct arp_state *
arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
{
struct interface *ifp, *iff = NULL;
struct ipv4_addr *iap;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (!ifp->active || !if_is_link_up(ifp))
continue;
iap = ipv4_iffindaddr(ifp, ia, NULL);
if (iap == NULL)
continue;
#ifdef IN_IFF_NOTUSEABLE
if (iap->addr_flags & IN_IFF_NOTUSEABLE)
continue;
#endif
if (iff != NULL && iff->metric < ifp->metric)
continue;
iff = ifp;
}
if (iff == NULL)
return NULL;
return arp_ifannounceaddr(iff, ia);
}
struct arp_state *
arp_new(struct interface *ifp, const struct in_addr *addr)
{
struct iarp_state *state;
struct arp_state *astate;
if ((state = ARP_STATE(ifp)) == NULL) {
ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state));
state = ARP_STATE(ifp);
if (state == NULL) {
logerr(__func__);
return NULL;
}
TAILQ_INIT(&state->arp_states);
} else {
if ((astate = arp_find(ifp, addr)) != NULL)
return astate;
}
if ((astate = calloc(1, sizeof(*astate))) == NULL) {
logerr(__func__);
return NULL;
}
astate->iface = ifp;
astate->addr = *addr;
#ifdef PRIVSEP
if (IN_PRIVSEP(ifp->ctx)) {
if (ps_bpf_openarp(ifp, addr) == -1) {
logerr(__func__);
free(astate);
return NULL;
}
} else
#endif
{
astate->bpf = bpf_open(ifp, bpf_arp, addr);
if (astate->bpf == NULL) {
logerr(__func__);
free(astate);
return NULL;
}
if (eloop_event_add(ifp->ctx->eloop, astate->bpf->bpf_fd, ELE_READ,
arp_read, astate) == -1)
logerr("%s: eloop_event_add", __func__);
}
state = ARP_STATE(ifp);
TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
return astate;
}
void
arp_free(struct arp_state *astate)
{
struct interface *ifp;
struct dhcpcd_ctx *ctx;
struct iarp_state *state;
if (astate == NULL)
return;
ifp = astate->iface;
ctx = ifp->ctx;
eloop_timeout_delete(ctx->eloop, NULL, astate);
state = ARP_STATE(ifp);
TAILQ_REMOVE(&state->arp_states, astate, next);
if (astate->free_cb)
astate->free_cb(astate);
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx) && ps_bpf_closearp(ifp, &astate->addr) == -1)
logerr(__func__);
#endif
if (astate->bpf != NULL) {
eloop_event_delete(ctx->eloop, astate->bpf->bpf_fd);
bpf_close(astate->bpf);
}
free(astate);
if (TAILQ_FIRST(&state->arp_states) == NULL) {
free(state);
ifp->if_data[IF_DATA_ARP] = NULL;
}
}
void
arp_freeaddr(struct interface *ifp, const struct in_addr *ia)
{
struct arp_state *astate;
astate = arp_find(ifp, ia);
arp_free(astate);
}
void
arp_drop(struct interface *ifp)
{
struct iarp_state *state;
struct arp_state *astate;
while ((state = ARP_STATE(ifp)) != NULL &&
(astate = TAILQ_FIRST(&state->arp_states)) != NULL)
arp_free(astate);
}

106
external/bsd/dhcpcd/dist/src/arp.h vendored Normal file
View File

@ -0,0 +1,106 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef ARP_H
#define ARP_H
/* ARP timings from RFC5227 */
#define PROBE_WAIT 1
#define PROBE_NUM 3
#define PROBE_MIN 1
#define PROBE_MAX 2
#define ANNOUNCE_WAIT 2
#define ANNOUNCE_NUM 2
#define ANNOUNCE_INTERVAL 2
#define MAX_CONFLICTS 10
#define RATE_LIMIT_INTERVAL 60
#define DEFEND_INTERVAL 10
#include "bpf.h"
#include "dhcpcd.h"
#include "if.h"
#ifdef IN_IFF_DUPLICATED
/* NetBSD gained RFC 5227 support in the kernel.
* This means dhcpcd doesn't need ARP except for ARPing support
* and ARP announcing an address. */
#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 799003900
#define KERNEL_RFC5227
#endif
#endif
struct arp_msg {
uint16_t op;
uint8_t sha[HWADDR_LEN];
struct in_addr sip;
uint8_t tha[HWADDR_LEN];
struct in_addr tip;
/* Frame header and sender to diagnose failures */
uint8_t fsha[HWADDR_LEN];
uint8_t ftha[HWADDR_LEN];
};
struct arp_state {
TAILQ_ENTRY(arp_state) next;
struct interface *iface;
struct in_addr addr;
struct bpf *bpf;
int probes;
int claims;
struct timespec defend;
void (*found_cb)(struct arp_state *, const struct arp_msg *);
void (*not_found_cb)(struct arp_state *);
void (*announced_cb)(struct arp_state *);
void (*defend_failed_cb)(struct arp_state *);
void (*free_cb)(struct arp_state *);
};
TAILQ_HEAD(arp_statehead, arp_state);
struct iarp_state {
struct arp_statehead arp_states;
};
#define ARP_STATE(ifp) \
((struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
#define ARP_CSTATE(ifp) \
((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
#ifdef ARP
void arp_packet(struct interface *, uint8_t *, size_t, unsigned int);
struct arp_state *arp_new(struct interface *, const struct in_addr *);
void arp_probe(struct arp_state *);
struct arp_state *arp_announceaddr(struct dhcpcd_ctx *, const struct in_addr *);
struct arp_state *arp_ifannounceaddr(struct interface *, const struct in_addr *);
struct arp_state * arp_find(struct interface *, const struct in_addr *);
void arp_free(struct arp_state *);
void arp_freeaddr(struct interface *, const struct in_addr *);
void arp_drop(struct interface *);
#endif /* ARP */
#endif /* ARP_H */

738
external/bsd/dhcpcd/dist/src/auth.c vendored Normal file
View File

@ -0,0 +1,738 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/file.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "config.h"
#include "auth.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "dhcpcd.h"
#include "privsep-root.h"
#ifdef HAVE_HMAC_H
#include <hmac.h>
#endif
#ifdef __sun
#define htonll
#define ntohll
#endif
#ifndef htonll
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define htonll(x) ((uint64_t)htonl((uint32_t)((x) >> 32)) | \
(uint64_t)htonl((uint32_t)((x) & 0x00000000ffffffffULL)) << 32)
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
#define htonll(x) (x)
#endif
#endif /* htonll */
#ifndef ntohll
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define ntohll(x) ((uint64_t)ntohl((uint32_t)((x) >> 32)) | \
(uint64_t)ntohl((uint32_t)((x) & 0x00000000ffffffffULL)) << 32)
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
#define ntohll(x) (x)
#endif
#endif /* ntohll */
#define HMAC_LENGTH 16
void
dhcp_auth_reset(struct authstate *state)
{
state->replay = 0;
if (state->token) {
free(state->token->key);
free(state->token->realm);
free(state->token);
state->token = NULL;
}
if (state->reconf) {
free(state->reconf->key);
free(state->reconf->realm);
free(state->reconf);
state->reconf = NULL;
}
}
/*
* Authenticate a DHCP message.
* m and mlen refer to the whole message.
* t is the DHCP type, pass it 4 or 6.
* data and dlen refer to the authentication option within the message.
*/
const struct token *
dhcp_auth_validate(struct authstate *state, const struct auth *auth,
const void *vm, size_t mlen, int mp, int mt,
const void *vdata, size_t dlen)
{
const uint8_t *m, *data;
uint8_t protocol, algorithm, rdm, *mm, type;
uint64_t replay;
uint32_t secretid;
const uint8_t *d, *realm;
size_t realm_len;
const struct token *t;
time_t now;
uint8_t hmac_code[HMAC_LENGTH];
if (dlen < 3 + sizeof(replay)) {
errno = EINVAL;
return NULL;
}
m = vm;
data = vdata;
/* Ensure that d is inside m which *may* not be the case for DHCPv4.
* This can occur if the authentication option is split using
* DHCP long option from RFC 3399. Section 9 which does infact note that
* implementations should take this into account.
* Fixing this would be problematic, patches welcome. */
if (data < m || data > m + mlen || data + dlen > m + mlen) {
errno = ERANGE;
return NULL;
}
d = data;
protocol = *d++;
algorithm = *d++;
rdm = *d++;
if (!(auth->options & DHCPCD_AUTH_SEND)) {
/* If we didn't send any authorisation, it can only be a
* reconfigure key */
if (protocol != AUTH_PROTO_RECONFKEY) {
errno = EINVAL;
return NULL;
}
} else if (protocol != auth->protocol ||
algorithm != auth->algorithm ||
rdm != auth->rdm)
{
/* As we don't require authentication, we should still
* accept a reconfigure key */
if (protocol != AUTH_PROTO_RECONFKEY ||
auth->options & DHCPCD_AUTH_REQUIRE)
{
errno = EPERM;
return NULL;
}
}
dlen -= 3;
memcpy(&replay, d, sizeof(replay));
replay = ntohll(replay);
/*
* Test for a replay attack.
*
* NOTE: Some servers always send a replay data value of zero.
* This is strictly compliant with RFC 3315 and 3318 which say:
* "If the RDM field contains 0x00, the replay detection field MUST be
* set to the value of a monotonically increasing counter."
* An example of a monotonically increasing sequence is:
* 1, 2, 2, 2, 2, 2, 2
* Errata 3474 updates RFC 3318 to say:
* "If the RDM field contains 0x00, the replay detection field MUST be
* set to the value of a strictly increasing counter."
*
* Taking the above into account, dhcpcd will only test for
* strictly speaking replay attacks if it receives any non zero
* replay data to validate against.
*/
if (state->token && state->replay != 0) {
if (state->replay == (replay ^ 0x8000000000000000ULL)) {
/* We don't know if the singular point is increasing
* or decreasing. */
errno = EPERM;
return NULL;
}
if ((uint64_t)(replay - state->replay) <= 0) {
/* Replay attack detected */
errno = EPERM;
return NULL;
}
}
d+= sizeof(replay);
dlen -= sizeof(replay);
realm = NULL;
realm_len = 0;
/* Extract realm and secret.
* Rest of data is MAC. */
switch (protocol) {
case AUTH_PROTO_TOKEN:
secretid = auth->token_rcv_secretid;
break;
case AUTH_PROTO_DELAYED:
if (dlen < sizeof(secretid) + sizeof(hmac_code)) {
errno = EINVAL;
return NULL;
}
memcpy(&secretid, d, sizeof(secretid));
secretid = ntohl(secretid);
d += sizeof(secretid);
dlen -= sizeof(secretid);
break;
case AUTH_PROTO_DELAYEDREALM:
if (dlen < sizeof(secretid) + sizeof(hmac_code)) {
errno = EINVAL;
return NULL;
}
realm_len = dlen - (sizeof(secretid) + sizeof(hmac_code));
if (realm_len) {
realm = d;
d += realm_len;
dlen -= realm_len;
}
memcpy(&secretid, d, sizeof(secretid));
secretid = ntohl(secretid);
d += sizeof(secretid);
dlen -= sizeof(secretid);
break;
case AUTH_PROTO_RECONFKEY:
if (dlen != 1 + 16) {
errno = EINVAL;
return NULL;
}
type = *d++;
dlen--;
switch (type) {
case 1:
if ((mp == 4 && mt == DHCP_ACK) ||
(mp == 6 && mt == DHCP6_REPLY))
{
if (state->reconf == NULL) {
state->reconf =
malloc(sizeof(*state->reconf));
if (state->reconf == NULL)
return NULL;
state->reconf->key = malloc(16);
if (state->reconf->key == NULL) {
free(state->reconf);
state->reconf = NULL;
return NULL;
}
state->reconf->secretid = 0;
state->reconf->expire = 0;
state->reconf->realm = NULL;
state->reconf->realm_len = 0;
state->reconf->key_len = 16;
}
memcpy(state->reconf->key, d, 16);
} else {
errno = EINVAL;
return NULL;
}
if (state->reconf == NULL)
errno = ENOENT;
/* Free the old token so we log acceptance */
if (state->token) {
free(state->token);
state->token = NULL;
}
/* Nothing to validate, just accepting the key */
return state->reconf;
case 2:
if (!((mp == 4 && mt == DHCP_FORCERENEW) ||
(mp == 6 && mt == DHCP6_RECONFIGURE)))
{
errno = EINVAL;
return NULL;
}
if (state->reconf == NULL) {
errno = ENOENT;
return NULL;
}
t = state->reconf;
goto gottoken;
default:
errno = EINVAL;
return NULL;
}
default:
errno = ENOTSUP;
return NULL;
}
/* Find a token for the realm and secret */
TAILQ_FOREACH(t, &auth->tokens, next) {
if (t->secretid == secretid &&
t->realm_len == realm_len &&
(t->realm_len == 0 ||
memcmp(t->realm, realm, t->realm_len) == 0))
break;
}
if (t == NULL) {
errno = ESRCH;
return NULL;
}
if (t->expire) {
if (time(&now) == -1)
return NULL;
if (t->expire < now) {
errno = EFAULT;
return NULL;
}
}
gottoken:
/* First message from the server */
if (state->token &&
(state->token->secretid != t->secretid ||
state->token->realm_len != t->realm_len ||
memcmp(state->token->realm, t->realm, t->realm_len)))
{
errno = EPERM;
return NULL;
}
/* Special case as no hashing needs to be done. */
if (protocol == AUTH_PROTO_TOKEN) {
if (dlen != t->key_len || memcmp(d, t->key, dlen)) {
errno = EPERM;
return NULL;
}
goto finish;
}
/* Make a duplicate of the message, but zero out the MAC part */
mm = malloc(mlen);
if (mm == NULL)
return NULL;
memcpy(mm, m, mlen);
memset(mm + (d - m), 0, dlen);
/* RFC3318, section 5.2 - zero giaddr and hops */
if (mp == 4) {
/* Assert the bootp structure is correct size. */
__CTASSERT(sizeof(struct bootp) == 300);
*(mm + offsetof(struct bootp, hops)) = '\0';
memset(mm + offsetof(struct bootp, giaddr), 0, 4);
}
memset(hmac_code, 0, sizeof(hmac_code));
switch (algorithm) {
case AUTH_ALG_HMAC_MD5:
hmac("md5", t->key, t->key_len, mm, mlen,
hmac_code, sizeof(hmac_code));
break;
default:
errno = ENOSYS;
free(mm);
return NULL;
}
free(mm);
if (!consttime_memequal(d, &hmac_code, dlen)) {
errno = EPERM;
return NULL;
}
finish:
/* If we got here then authentication passed */
state->replay = replay;
if (state->token == NULL) {
/* We cannot just save a pointer because a reconfigure will
* recreate the token list. So we duplicate it. */
state->token = malloc(sizeof(*state->token));
if (state->token) {
state->token->secretid = t->secretid;
state->token->key = malloc(t->key_len);
if (state->token->key) {
state->token->key_len = t->key_len;
memcpy(state->token->key, t->key, t->key_len);
} else {
free(state->token);
state->token = NULL;
return NULL;
}
if (t->realm_len) {
state->token->realm = malloc(t->realm_len);
if (state->token->realm) {
state->token->realm_len = t->realm_len;
memcpy(state->token->realm, t->realm,
t->realm_len);
} else {
free(state->token->key);
free(state->token);
state->token = NULL;
return NULL;
}
} else {
state->token->realm = NULL;
state->token->realm_len = 0;
}
}
/* If we cannot save the token, we must invalidate */
if (state->token == NULL)
return NULL;
}
return t;
}
int
auth_get_rdm_monotonic(uint64_t *rdm)
{
FILE *fp;
int err;
#ifdef LOCK_EX
int flocked;
#endif
fp = fopen(RDM_MONOFILE, "r+");
if (fp == NULL) {
if (errno != ENOENT)
return -1;
fp = fopen(RDM_MONOFILE, "w");
if (fp == NULL)
return -1;
if (chmod(RDM_MONOFILE, 0400) == -1) {
fclose(fp);
unlink(RDM_MONOFILE);
return -1;
}
#ifdef LOCK_EX
flocked = flock(fileno(fp), LOCK_EX);
#endif
*rdm = 0;
} else {
#ifdef LOCK_EX
flocked = flock(fileno(fp), LOCK_EX);
#endif
if (fscanf(fp, "0x%016" PRIu64, rdm) != 1) {
fclose(fp);
return -1;
}
}
(*rdm)++;
if (fseek(fp, 0, SEEK_SET) == -1 ||
ftruncate(fileno(fp), 0) == -1 ||
fprintf(fp, "0x%016" PRIu64 "\n", *rdm) != 19 ||
fflush(fp) == EOF)
err = -1;
else
err = 0;
#ifdef LOCK_EX
if (flocked == 0)
flock(fileno(fp), LOCK_UN);
#endif
fclose(fp);
return err;
}
#define NTP_EPOCH 2208988800U /* 1970 - 1900 in seconds */
#define NTP_SCALE_FRAC 4294967295.0 /* max value of the fractional part */
static uint64_t
get_next_rdm_monotonic_clock(struct auth *auth)
{
struct timespec ts;
uint64_t secs, rdm;
double frac;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
return ++auth->last_replay; /* report error? */
secs = (uint64_t)ts.tv_sec + NTP_EPOCH;
frac = ((double)ts.tv_nsec / 1e9 * NTP_SCALE_FRAC);
rdm = (secs << 32) | (uint64_t)frac;
return rdm;
}
static uint64_t
get_next_rdm_monotonic(struct dhcpcd_ctx *ctx, struct auth *auth)
{
#ifndef PRIVSEP
UNUSED(ctx);
#endif
if (auth->options & DHCPCD_AUTH_RDM_COUNTER) {
uint64_t rdm;
int err;
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx)) {
err = ps_root_getauthrdm(ctx, &rdm);
} else
#endif
err = auth_get_rdm_monotonic(&rdm);
if (err == -1)
return ++auth->last_replay;
auth->last_replay = rdm;
return rdm;
}
return get_next_rdm_monotonic_clock(auth);
}
/*
* Encode a DHCP message.
* Either we know which token to use from the server response
* or we are using a basic configuration token.
* token is the token to encrypt with.
* m and mlen refer to the whole message.
* mp is the DHCP type, pass it 4 or 6.
* mt is the DHCP message type.
* data and dlen refer to the authentication option within the message.
*/
ssize_t
dhcp_auth_encode(struct dhcpcd_ctx *ctx, struct auth *auth,
const struct token *t,
void *vm, size_t mlen, int mp, int mt,
void *vdata, size_t dlen)
{
uint64_t rdm;
uint8_t hmac_code[HMAC_LENGTH];
time_t now;
uint8_t hops, *p, *m, *data;
uint32_t giaddr, secretid;
bool auth_info;
/* Ignore the token argument given to us - always send using the
* configured token. */
if (auth->protocol == AUTH_PROTO_TOKEN) {
TAILQ_FOREACH(t, &auth->tokens, next) {
if (t->secretid == auth->token_snd_secretid)
break;
}
if (t == NULL) {
errno = EINVAL;
return -1;
}
if (t->expire) {
if (time(&now) == -1)
return -1;
if (t->expire < now) {
errno = EPERM;
return -1;
}
}
}
switch(auth->protocol) {
case AUTH_PROTO_TOKEN:
case AUTH_PROTO_DELAYED:
case AUTH_PROTO_DELAYEDREALM:
/* We don't ever send a reconf key */
break;
default:
errno = ENOTSUP;
return -1;
}
switch(auth->algorithm) {
case AUTH_ALG_NONE:
case AUTH_ALG_HMAC_MD5:
break;
default:
errno = ENOTSUP;
return -1;
}
switch(auth->rdm) {
case AUTH_RDM_MONOTONIC:
break;
default:
errno = ENOTSUP;
return -1;
}
/* DISCOVER or INFORM messages don't write auth info */
if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) ||
(mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ)))
auth_info = false;
else
auth_info = true;
/* Work out the auth area size.
* We only need to do this for DISCOVER messages */
if (vdata == NULL) {
dlen = 1 + 1 + 1 + 8;
switch(auth->protocol) {
case AUTH_PROTO_TOKEN:
dlen += t->key_len;
break;
case AUTH_PROTO_DELAYEDREALM:
if (auth_info && t)
dlen += t->realm_len;
/* FALLTHROUGH */
case AUTH_PROTO_DELAYED:
if (auth_info && t)
dlen += sizeof(t->secretid) + sizeof(hmac_code);
break;
}
return (ssize_t)dlen;
}
if (dlen < 1 + 1 + 1 + 8) {
errno = ENOBUFS;
return -1;
}
/* Ensure that d is inside m which *may* not be the case for DHPCPv4 */
m = vm;
data = vdata;
if (data < m || data > m + mlen || data + dlen > m + mlen) {
errno = ERANGE;
return -1;
}
/* Write out our option */
*data++ = auth->protocol;
*data++ = auth->algorithm;
/*
* RFC 3315 21.4.4.1 says that SOLICIT in DELAYED authentication
* should not set RDM or it's data.
* An expired draft draft-ietf-dhc-dhcpv6-clarify-auth-01 suggets
* this should not be set for INFORMATION REQ messages as well,
* which is probably a good idea because both states start from zero.
*/
if (auth_info ||
!(auth->protocol & (AUTH_PROTO_DELAYED | AUTH_PROTO_DELAYEDREALM)))
{
*data++ = auth->rdm;
switch (auth->rdm) {
case AUTH_RDM_MONOTONIC:
rdm = get_next_rdm_monotonic(ctx, auth);
break;
default:
/* This block appeases gcc, clang doesn't need it */
rdm = get_next_rdm_monotonic(ctx, auth);
break;
}
rdm = htonll(rdm);
memcpy(data, &rdm, 8);
} else {
*data++ = 0; /* rdm */
memset(data, 0, 8); /* replay detection data */
}
data += 8;
dlen -= 1 + 1 + 1 + 8;
/* Special case as no hashing needs to be done. */
if (auth->protocol == AUTH_PROTO_TOKEN) {
/* Should be impossible, but still */
if (t == NULL) {
errno = EINVAL;
return -1;
}
if (dlen < t->key_len) {
errno = ENOBUFS;
return -1;
}
memcpy(data, t->key, t->key_len);
return (ssize_t)(dlen - t->key_len);
}
/* DISCOVER or INFORM messages don't write auth info */
if (!auth_info)
return (ssize_t)dlen;
/* Loading a saved lease without an authentication option */
if (t == NULL)
return 0;
/* Write out the Realm */
if (auth->protocol == AUTH_PROTO_DELAYEDREALM) {
if (dlen < t->realm_len) {
errno = ENOBUFS;
return -1;
}
memcpy(data, t->realm, t->realm_len);
data += t->realm_len;
dlen -= t->realm_len;
}
/* Write out the SecretID */
if (auth->protocol == AUTH_PROTO_DELAYED ||
auth->protocol == AUTH_PROTO_DELAYEDREALM)
{
if (dlen < sizeof(t->secretid)) {
errno = ENOBUFS;
return -1;
}
secretid = htonl(t->secretid);
memcpy(data, &secretid, sizeof(secretid));
data += sizeof(secretid);
dlen -= sizeof(secretid);
}
/* Zero what's left, the MAC */
memset(data, 0, dlen);
/* RFC3318, section 5.2 - zero giaddr and hops */
if (mp == 4) {
p = m + offsetof(struct bootp, hops);
hops = *p;
*p = '\0';
p = m + offsetof(struct bootp, giaddr);
memcpy(&giaddr, p, sizeof(giaddr));
memset(p, 0, sizeof(giaddr));
} else {
/* appease GCC again */
hops = 0;
giaddr = 0;
}
/* Create our hash and write it out */
switch(auth->algorithm) {
case AUTH_ALG_HMAC_MD5:
hmac("md5", t->key, t->key_len, m, mlen,
hmac_code, sizeof(hmac_code));
memcpy(data, hmac_code, sizeof(hmac_code));
break;
}
/* RFC3318, section 5.2 - restore giaddr and hops */
if (mp == 4) {
p = m + offsetof(struct bootp, hops);
*p = hops;
p = m + offsetof(struct bootp, giaddr);
memcpy(p, &giaddr, sizeof(giaddr));
}
/* Done! */
return (int)(dlen - sizeof(hmac_code)); /* should be zero */
}

100
external/bsd/dhcpcd/dist/src/auth.h vendored Normal file
View File

@ -0,0 +1,100 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef AUTH_H
#define AUTH_H
#include "config.h"
#ifdef HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#define DHCPCD_AUTH_SEND (1 << 0)
#define DHCPCD_AUTH_REQUIRE (1 << 1)
#define DHCPCD_AUTH_RDM_COUNTER (1 << 2)
#define DHCPCD_AUTH_SENDREQUIRE (DHCPCD_AUTH_SEND | DHCPCD_AUTH_REQUIRE)
#define AUTH_PROTO_TOKEN 0
#define AUTH_PROTO_DELAYED 1
#define AUTH_PROTO_DELAYEDREALM 2
#define AUTH_PROTO_RECONFKEY 3
#define AUTH_ALG_NONE 0
#define AUTH_ALG_HMAC_MD5 1
#define AUTH_RDM_MONOTONIC 0
struct token {
TAILQ_ENTRY(token) next;
uint32_t secretid;
size_t realm_len;
unsigned char *realm;
size_t key_len;
unsigned char *key;
time_t expire;
};
TAILQ_HEAD(token_head, token);
struct auth {
int options;
#ifdef AUTH
uint8_t protocol;
uint8_t algorithm;
uint8_t rdm;
uint64_t last_replay;
uint8_t last_replay_set;
struct token_head tokens;
uint32_t token_snd_secretid;
uint32_t token_rcv_secretid;
#endif
};
struct authstate {
uint64_t replay;
struct token *token;
struct token *reconf;
};
void dhcp_auth_reset(struct authstate *);
const struct token * dhcp_auth_validate(struct authstate *,
const struct auth *,
const void *, size_t, int, int,
const void *, size_t);
struct dhcpcd_ctx;
ssize_t dhcp_auth_encode(struct dhcpcd_ctx *, struct auth *,
const struct token *,
void *, size_t, int, int,
void *, size_t);
int auth_get_rdm_monotonic(uint64_t *rdm);
#endif

714
external/bsd/dhcpcd/dist/src/bpf.c vendored Normal file
View File

@ -0,0 +1,714 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd: BPF arp and bootp filtering
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#ifdef __linux__
/* Special BPF snowflake. */
#include <linux/filter.h>
#define bpf_insn sock_filter
#else
#include <net/bpf.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "arp.h"
#include "bpf.h"
#include "dhcp.h"
#include "if.h"
#include "logerr.h"
/* BPF helper macros */
#ifdef __linux__
#define BPF_WHOLEPACKET 0x7fffffff /* work around buggy LPF filters */
#else
#define BPF_WHOLEPACKET ~0U
#endif
/* Macros to update the BPF structure */
#define BPF_SET_STMT(insn, c, v) { \
(insn)->code = (c); \
(insn)->jt = 0; \
(insn)->jf = 0; \
(insn)->k = (uint32_t)(v); \
}
#define BPF_SET_JUMP(insn, c, v, t, f) { \
(insn)->code = (c); \
(insn)->jt = (t); \
(insn)->jf = (f); \
(insn)->k = (uint32_t)(v); \
}
size_t
bpf_frame_header_len(const struct interface *ifp)
{
switch (ifp->hwtype) {
case ARPHRD_ETHER:
return sizeof(struct ether_header);
default:
return 0;
}
}
void *
bpf_frame_header_src(const struct interface *ifp, void *fh, size_t *len)
{
uint8_t *f = fh;
switch (ifp->hwtype) {
case ARPHRD_ETHER:
*len = sizeof(((struct ether_header *)0)->ether_shost);
return f + offsetof(struct ether_header, ether_shost);
default:
*len = 0;
errno = ENOTSUP;
return NULL;
}
}
void *
bpf_frame_header_dst(const struct interface *ifp, void *fh, size_t *len)
{
uint8_t *f = fh;
switch (ifp->hwtype) {
case ARPHRD_ETHER:
*len = sizeof(((struct ether_header *)0)->ether_dhost);
return f + offsetof(struct ether_header, ether_dhost);
default:
*len = 0;
errno = ENOTSUP;
return NULL;
}
}
static const uint8_t etherbcastaddr[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int
bpf_frame_bcast(const struct interface *ifp, const void *frame)
{
switch (ifp->hwtype) {
case ARPHRD_ETHER:
return memcmp((const char *)frame +
offsetof(struct ether_header, ether_dhost),
etherbcastaddr, sizeof(etherbcastaddr));
default:
return -1;
}
}
#ifndef __linux__
/* Linux is a special snowflake for opening, attaching and reading BPF.
* See if-linux.c for the Linux specific BPF functions. */
const char *bpf_name = "Berkley Packet Filter";
struct bpf *
bpf_open(const struct interface *ifp,
int (*filter)(const struct bpf *, const struct in_addr *),
const struct in_addr *ia)
{
struct bpf *bpf;
struct bpf_version pv = { .bv_major = 0, .bv_minor = 0 };
struct ifreq ifr = { .ifr_flags = 0 };
int ibuf_len = 0;
#ifdef O_CLOEXEC
#define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK | O_CLOEXEC
#else
#define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK
#endif
#ifdef BIOCIMMEDIATE
unsigned int flags;
#endif
#ifndef O_CLOEXEC
int fd_opts;
#endif
bpf = calloc(1, sizeof(*bpf));
if (bpf == NULL)
return NULL;
bpf->bpf_ifp = ifp;
/* /dev/bpf is a cloner on modern kernels */
bpf->bpf_fd = open("/dev/bpf", BPF_OPEN_FLAGS);
/* Support older kernels where /dev/bpf is not a cloner */
if (bpf->bpf_fd == -1) {
char device[32];
int n = 0;
do {
snprintf(device, sizeof(device), "/dev/bpf%d", n++);
bpf->bpf_fd = open(device, BPF_OPEN_FLAGS);
} while (bpf->bpf_fd == -1 && errno == EBUSY);
}
if (bpf->bpf_fd == -1)
goto eexit;
#ifndef O_CLOEXEC
if ((fd_opts = fcntl(bpf->bpf_fd, F_GETFD)) == -1 ||
fcntl(bpf->bpf_fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1)
goto eexit;
#endif
if (ioctl(bpf->bpf_fd, BIOCVERSION, &pv) == -1)
goto eexit;
if (pv.bv_major != BPF_MAJOR_VERSION ||
pv.bv_minor < BPF_MINOR_VERSION) {
logerrx("BPF version mismatch - recompile");
goto eexit;
}
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(bpf->bpf_fd, BIOCSETIF, &ifr) == -1)
goto eexit;
#ifdef BIOCIMMEDIATE
flags = 1;
if (ioctl(bpf->bpf_fd, BIOCIMMEDIATE, &flags) == -1)
goto eexit;
#endif
if (filter(bpf, ia) != 0)
goto eexit;
/* Get the required BPF buffer length from the kernel. */
if (ioctl(bpf->bpf_fd, BIOCGBLEN, &ibuf_len) == -1)
goto eexit;
bpf->bpf_size = (size_t)ibuf_len;
bpf->bpf_buffer = malloc(bpf->bpf_size);
if (bpf->bpf_buffer == NULL)
goto eexit;
return bpf;
eexit:
if (bpf->bpf_fd != -1)
close(bpf->bpf_fd);
free(bpf);
return NULL;
}
/* BPF requires that we read the entire buffer.
* So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
bpf_read(struct bpf *bpf, void *data, size_t len)
{
ssize_t bytes;
struct bpf_hdr packet;
const char *payload;
bpf->bpf_flags &= ~BPF_EOF;
for (;;) {
if (bpf->bpf_len == 0) {
bytes = read(bpf->bpf_fd, bpf->bpf_buffer,
bpf->bpf_size);
#if defined(__sun)
/* After 2^31 bytes, the kernel offset overflows.
* To work around this bug, lseek 0. */
if (bytes == -1 && errno == EINVAL) {
lseek(bpf->bpf_fd, 0, SEEK_SET);
continue;
}
#endif
if (bytes == -1 || bytes == 0)
return bytes;
bpf->bpf_len = (size_t)bytes;
bpf->bpf_pos = 0;
}
bytes = -1;
payload = (const char *)bpf->bpf_buffer + bpf->bpf_pos;
memcpy(&packet, payload, sizeof(packet));
if (bpf->bpf_pos + packet.bh_caplen + packet.bh_hdrlen >
bpf->bpf_len)
goto next; /* Packet beyond buffer, drop. */
payload += packet.bh_hdrlen;
if (packet.bh_caplen > len)
bytes = (ssize_t)len;
else
bytes = (ssize_t)packet.bh_caplen;
if (bpf_frame_bcast(bpf->bpf_ifp, payload) == 0)
bpf->bpf_flags |= BPF_BCAST;
else
bpf->bpf_flags &= ~BPF_BCAST;
memcpy(data, payload, (size_t)bytes);
next:
bpf->bpf_pos += BPF_WORDALIGN(packet.bh_hdrlen +
packet.bh_caplen);
if (bpf->bpf_pos >= bpf->bpf_len) {
bpf->bpf_len = bpf->bpf_pos = 0;
bpf->bpf_flags |= BPF_EOF;
}
if (bytes != -1)
return bytes;
}
/* NOTREACHED */
}
int
bpf_attach(int fd, void *filter, unsigned int filter_len)
{
struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
/* Install the filter. */
return ioctl(fd, BIOCSETF, &pf);
}
#ifdef BIOCSETWF
static int
bpf_wattach(int fd, void *filter, unsigned int filter_len)
{
struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
/* Install the filter. */
return ioctl(fd, BIOCSETWF, &pf);
}
#endif
#endif
#ifndef __sun
/* SunOS is special too - sending via BPF goes nowhere. */
ssize_t
bpf_send(const struct bpf *bpf, uint16_t protocol,
const void *data, size_t len)
{
struct iovec iov[2];
struct ether_header eh;
switch(bpf->bpf_ifp->hwtype) {
case ARPHRD_ETHER:
memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
memcpy(&eh.ether_shost, bpf->bpf_ifp->hwaddr,
sizeof(eh.ether_shost));
eh.ether_type = htons(protocol);
iov[0].iov_base = &eh;
iov[0].iov_len = sizeof(eh);
break;
default:
iov[0].iov_base = NULL;
iov[0].iov_len = 0;
break;
}
iov[1].iov_base = UNCONST(data);
iov[1].iov_len = len;
return writev(bpf->bpf_fd, iov, 2);
}
#endif
void
bpf_close(struct bpf *bpf)
{
close(bpf->bpf_fd);
free(bpf->bpf_buffer);
free(bpf);
}
#ifdef ARP
#define BPF_CMP_HWADDR_LEN ((((HWADDR_LEN / 4) + 2) * 2) + 1)
static unsigned int
bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off,
bool equal, const uint8_t *hwaddr, size_t hwaddr_len)
{
struct bpf_insn *bp;
size_t maclen, nlft, njmps;
uint32_t mac32;
uint16_t mac16;
uint8_t jt, jf;
/* Calc the number of jumps */
if ((hwaddr_len / 4) >= 128) {
errno = EINVAL;
return 0;
}
njmps = (hwaddr_len / 4) * 2; /* 2 instructions per check */
/* We jump after the 1st check. */
if (njmps)
njmps -= 2;
nlft = hwaddr_len % 4;
if (nlft) {
njmps += (nlft / 2) * 2;
nlft = nlft % 2;
if (nlft)
njmps += 2;
}
/* Skip to positive finish. */
njmps++;
if (equal) {
jt = (uint8_t)njmps;
jf = 0;
} else {
jt = 0;
jf = (uint8_t)njmps;
}
bp = bpf;
for (; hwaddr_len > 0;
hwaddr += maclen, hwaddr_len -= maclen, off += maclen)
{
if (bpf_len < 3) {
errno = ENOBUFS;
return 0;
}
bpf_len -= 3;
if (hwaddr_len >= 4) {
maclen = sizeof(mac32);
memcpy(&mac32, hwaddr, maclen);
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off);
bp++;
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
htonl(mac32), jt, jf);
} else if (hwaddr_len >= 2) {
maclen = sizeof(mac16);
memcpy(&mac16, hwaddr, maclen);
BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off);
bp++;
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
htons(mac16), jt, jf);
} else {
maclen = sizeof(*hwaddr);
BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off);
bp++;
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
*hwaddr, jt, jf);
}
if (jt)
jt = (uint8_t)(jt - 2);
if (jf)
jf = (uint8_t)(jf - 2);
bp++;
}
/* Last step is always return failure.
* Next step is a positive finish. */
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
return (unsigned int)(bp - bpf);
}
#endif
#ifdef ARP
static const struct bpf_insn bpf_arp_ether [] = {
/* Check this is an ARP packet. */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
offsetof(struct ether_header, ether_type)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Load frame header length into X */
BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)),
/* Make sure the hardware type matches. */
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Make sure the hardware length matches. */
BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_hln)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
sizeof(((struct ether_arp *)0)->arp_sha), 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
};
#define BPF_ARP_ETHER_LEN __arraycount(bpf_arp_ether)
static const struct bpf_insn bpf_arp_filter [] = {
/* Make sure this is for IP. */
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_pro)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Make sure this is an ARP REQUEST. */
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
/* or ARP REPLY. */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Make sure the protocol length matches. */
BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
};
#define BPF_ARP_FILTER_LEN __arraycount(bpf_arp_filter)
/* One address is two checks of two statements. */
#define BPF_NADDRS 1
#define BPF_ARP_ADDRS_LEN 5 + ((BPF_NADDRS * 2) * 2)
#define BPF_ARP_LEN BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + \
BPF_CMP_HWADDR_LEN + BPF_ARP_ADDRS_LEN
static int
bpf_arp_rw(const struct bpf *bpf, const struct in_addr *ia, bool recv)
{
const struct interface *ifp = bpf->bpf_ifp;
struct bpf_insn buf[BPF_ARP_LEN + 1];
struct bpf_insn *bp;
uint16_t arp_len;
bp = buf;
/* Check frame header. */
switch(ifp->hwtype) {
case ARPHRD_ETHER:
memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether));
bp += BPF_ARP_ETHER_LEN;
arp_len = sizeof(struct ether_header)+sizeof(struct ether_arp);
break;
default:
errno = EINVAL;
return -1;
}
/* Copy in the main filter. */
memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter));
bp += BPF_ARP_FILTER_LEN;
/* Ensure it's not from us. */
bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr),
!recv, ifp->hwaddr, ifp->hwlen);
/* Match sender protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
sizeof(struct arphdr) + ifp->hwlen);
bp++;
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
/* If we didn't match sender, then we're only interested in
* ARP probes to us, so check the null host sender. */
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
/* Match target protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, (sizeof(struct arphdr) +
(size_t)(ifp->hwlen * 2) + sizeof(in_addr_t)));
bp++;
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
/* No match, drop it */
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
#ifdef BIOCSETWF
if (!recv)
return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
#endif
return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
}
int
bpf_arp(const struct bpf *bpf, const struct in_addr *ia)
{
#ifdef BIOCSETWF
if (bpf_arp_rw(bpf, ia, true) == -1 ||
bpf_arp_rw(bpf, ia, false) == -1 ||
ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
return -1;
return 0;
#else
return bpf_arp_rw(bpf, ia, true);
#endif
}
#endif
#ifdef ARPHRD_NONE
static const struct bpf_insn bpf_bootp_none[] = {
};
#define BPF_BOOTP_NONE_LEN __arraycount(bpf_bootp_none)
#endif
static const struct bpf_insn bpf_bootp_ether[] = {
/* Make sure this is an IP packet. */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
offsetof(struct ether_header, ether_type)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Advance to the IP header. */
BPF_STMT(BPF_LDX + BPF_K, sizeof(struct ether_header)),
};
#define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether)
static const struct bpf_insn bpf_bootp_base[] = {
/* Make sure it's an IPv4 packet. */
BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x40, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Make sure it's a UDP packet. */
BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Make sure this isn't a fragment. */
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_off)),
BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1),
BPF_STMT(BPF_RET + BPF_K, 0),
/* Advance to the UDP header. */
BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f),
BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4),
BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),
BPF_STMT(BPF_MISC + BPF_TAX, 0),
};
#define BPF_BOOTP_BASE_LEN __arraycount(bpf_bootp_base)
static const struct bpf_insn bpf_bootp_read[] = {
/* Make sure it's to the right port.
* RFC2131 makes no mention of enforcing a source port. */
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, uh_dport)),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTPC, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
};
#define BPF_BOOTP_READ_LEN __arraycount(bpf_bootp_read)
#ifdef BIOCSETWF
static const struct bpf_insn bpf_bootp_write[] = {
/* Make sure it's from and to the right port.
* RFC2131 makes no mention of encforcing a source port,
* but dhcpcd does enforce it for sending. */
BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPC << 16) + BOOTPS, 1, 0),
BPF_STMT(BPF_RET + BPF_K, 0),
};
#define BPF_BOOTP_WRITE_LEN __arraycount(bpf_bootp_write)
#endif
#define BPF_BOOTP_CHADDR_LEN ((BOOTP_CHADDR_LEN / 4) * 3)
#define BPF_BOOTP_XID_LEN 4 /* BOUND check is 4 instructions */
#define BPF_BOOTP_LEN BPF_BOOTP_ETHER_LEN + \
BPF_BOOTP_BASE_LEN + BPF_BOOTP_READ_LEN + \
BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4
static int
bpf_bootp_rw(const struct bpf *bpf, bool read)
{
struct bpf_insn buf[BPF_BOOTP_LEN + 1];
struct bpf_insn *bp;
bp = buf;
/* Check frame header. */
switch(bpf->bpf_ifp->hwtype) {
#ifdef ARPHRD_NONE
case ARPHRD_NONE:
memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none));
bp += BPF_BOOTP_NONE_LEN;
break;
#endif
case ARPHRD_ETHER:
memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether));
bp += BPF_BOOTP_ETHER_LEN;
break;
default:
errno = EINVAL;
return -1;
}
/* Copy in the main filter. */
memcpy(bp, bpf_bootp_base, sizeof(bpf_bootp_base));
bp += BPF_BOOTP_BASE_LEN;
#ifdef BIOCSETWF
if (!read) {
memcpy(bp, bpf_bootp_write, sizeof(bpf_bootp_write));
bp += BPF_BOOTP_WRITE_LEN;
/* All passed, return the packet. */
BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
bp++;
return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
}
#else
UNUSED(read);
#endif
memcpy(bp, bpf_bootp_read, sizeof(bpf_bootp_read));
bp += BPF_BOOTP_READ_LEN;
/* All passed, return the packet. */
BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
bp++;
return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
}
int
bpf_bootp(const struct bpf *bpf, __unused const struct in_addr *ia)
{
#ifdef BIOCSETWF
if (bpf_bootp_rw(bpf, true) == -1 ||
bpf_bootp_rw(bpf, false) == -1 ||
ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
return -1;
return 0;
#else
#ifdef PRIVSEP
#if defined(__sun) /* Solaris cannot send via BPF. */
#elif defined(BIOCSETF)
#warning No BIOCSETWF support - a compromised BPF can be used as a raw socket
#else
#warning A compromised PF_PACKET socket can be used as a raw socket
#endif
#endif
return bpf_bootp_rw(bpf, true);
#endif
}

81
external/bsd/dhcpcd/dist/src/bpf.h vendored Normal file
View File

@ -0,0 +1,81 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd: BPF arp and bootp filtering
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef BPF_HEADER
#define BPF_HEADER
#define BPF_EOF 0x01U
#define BPF_PARTIALCSUM 0x02U
#define BPF_BCAST 0x04U
/*
* Even though we program the BPF filter should we trust it?
* On Linux at least there is a window between opening the socket,
* binding the interface and setting the filter where we receive data.
* This data is NOT checked OR flushed and IS returned when reading.
* We have no way of flushing it other than reading these packets!
* But we don't know if they passed the filter or not ..... so we need
* to validate each and every packet that comes through ourselves as well.
* Even if Linux does fix this sorry state, who is to say other kernels
* don't have bugs causing a similar effect?
*
* As such, let's strive to keep the filters just for pattern matching
* to avoid waking dhcpcd up.
*
* If you want to be notified of any packet failing the BPF filter,
* define BPF_DEBUG below.
*/
//#define BPF_DEBUG
#include "dhcpcd.h"
struct bpf {
const struct interface *bpf_ifp;
int bpf_fd;
unsigned int bpf_flags;
void *bpf_buffer;
size_t bpf_size;
size_t bpf_len;
size_t bpf_pos;
};
extern const char *bpf_name;
size_t bpf_frame_header_len(const struct interface *);
void *bpf_frame_header_src(const struct interface *, void *, size_t *);
void *bpf_frame_header_dst(const struct interface *, void *, size_t *);
int bpf_frame_bcast(const struct interface *, const void *);
struct bpf * bpf_open(const struct interface *,
int (*)(const struct bpf *, const struct in_addr *),
const struct in_addr *);
void bpf_close(struct bpf *);
int bpf_attach(int, void *, unsigned int);
ssize_t bpf_send(const struct bpf *, uint16_t, const void *, size_t);
ssize_t bpf_read(struct bpf *, void *, size_t);
int bpf_arp(const struct bpf *, const struct in_addr *);
int bpf_bootp(const struct bpf *, const struct in_addr *);
#endif

216
external/bsd/dhcpcd/dist/src/common.c vendored Normal file
View File

@ -0,0 +1,216 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/stat.h>
#include <sys/statvfs.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "dhcpcd.h"
#include "if-options.h"
const char *
hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
{
const unsigned char *hp, *ep;
char *p;
/* Allow a hwlen of 0 to be an empty string. */
if (buf == NULL || buflen == 0) {
errno = ENOBUFS;
return NULL;
}
if (hwlen * 3 > buflen) {
/* We should still terminate the string just in case. */
buf[0] = '\0';
errno = ENOBUFS;
return NULL;
}
hp = hwaddr;
ep = hp + hwlen;
p = buf;
while (hp < ep) {
if (hp != hwaddr)
*p ++= ':';
p += snprintf(p, 3, "%.2x", *hp++);
}
*p ++= '\0';
return buf;
}
size_t
hwaddr_aton(uint8_t *buffer, const char *addr)
{
char c[3];
const char *p = addr;
uint8_t *bp = buffer;
size_t len = 0;
c[2] = '\0';
while (*p != '\0') {
/* Skip separators */
c[0] = *p++;
switch (c[0]) {
case '\n': /* long duid split on lines */
case ':': /* typical mac address */
case '-': /* uuid */
continue;
}
c[1] = *p++;
/* Ensure that digits are hex */
if (isxdigit((unsigned char)c[0]) == 0 ||
isxdigit((unsigned char)c[1]) == 0)
{
errno = EINVAL;
return 0;
}
/* We should have at least two entries 00:01 */
if (len == 0 && *p == '\0') {
errno = EINVAL;
return 0;
}
if (bp)
*bp++ = (uint8_t)strtol(c, NULL, 16);
len++;
}
return len;
}
ssize_t
readfile(const char *file, void *data, size_t len)
{
int fd;
ssize_t bytes;
fd = open(file, O_RDONLY);
if (fd == -1)
return -1;
bytes = read(fd, data, len);
close(fd);
if ((size_t)bytes == len) {
errno = ENOBUFS;
return -1;
}
return bytes;
}
ssize_t
writefile(const char *file, mode_t mode, const void *data, size_t len)
{
int fd;
ssize_t bytes;
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (fd == -1)
return -1;
bytes = write(fd, data, len);
close(fd);
return bytes;
}
int
filemtime(const char *file, time_t *time)
{
struct stat st;
if (stat(file, &st) == -1)
return -1;
*time = st.st_mtime;
return 0;
}
/* Handy routine to read very long lines in text files.
* This means we read the whole line and avoid any nasty buffer overflows.
* We strip leading space and avoid comment lines, making the code that calls
* us smaller. */
char *
get_line(char ** __restrict buf, ssize_t * __restrict buflen)
{
char *p, *c;
bool quoted;
do {
p = *buf;
if (*buf == NULL)
return NULL;
c = memchr(*buf, '\n', (size_t)*buflen);
if (c == NULL) {
c = memchr(*buf, '\0', (size_t)*buflen);
if (c == NULL)
return NULL;
*buflen = c - *buf;
*buf = NULL;
} else {
*c++ = '\0';
*buflen -= c - *buf;
*buf = c;
}
for (; *p == ' ' || *p == '\t'; p++)
;
} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
/* Strip embedded comments unless in a quoted string or escaped */
quoted = false;
for (c = p; *c != '\0'; c++) {
if (*c == '\\') {
c++; /* escaped */
continue;
}
if (*c == '"')
quoted = !quoted;
else if (*c == '#' && !quoted) {
*c = '\0';
break;
}
}
return p;
}
int
is_root_local(void)
{
#ifdef ST_LOCAL
struct statvfs vfs;
if (statvfs("/", &vfs) == -1)
return -1;
return vfs.f_flag & ST_LOCAL ? 1 : 0;
#else
errno = ENOTSUP;
return -1;
#endif
}

157
external/bsd/dhcpcd/dist/src/common.h vendored Normal file
View File

@ -0,0 +1,157 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef COMMON_H
#define COMMON_H
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
/* Define eloop queues here, as other apps share eloop.h */
#define ELOOP_DHCPCD 1 /* default queue */
#define ELOOP_DHCP 2
#define ELOOP_ARP 3
#define ELOOP_IPV4LL 4
#define ELOOP_IPV6 5
#define ELOOP_IPV6ND 6
#define ELOOP_IPV6RA_EXPIRE 7
#define ELOOP_DHCP6 8
#define ELOOP_IF 9
#ifndef HOSTNAME_MAX_LEN
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
#endif
#ifndef MIN
#define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
#define MAX(a,b) ((/*CONSTCOND*/(a)>(b))?(a):(b))
#endif
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#define STRINGIFY(a) #a
#define TOSTRING(a) STRINGIFY(a)
#define UNUSED(a) (void)(a)
#define ROUNDUP4(a) (1 + (((a) - 1) | 3))
#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
/* Some systems don't define timespec macros */
#ifndef timespecclear
#define timespecclear(tsp) (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
#endif
#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
# ifndef __packed
# define __packed __attribute__((__packed__))
# endif
# ifndef __unused
# define __unused __attribute__((__unused__))
# endif
#else
# ifndef __packed
# define __packed
# endif
# ifndef __unused
# define __unused
# endif
#endif
/* Needed for rbtree(3) compat */
#ifndef __RCSID
#define __RCSID(a)
#endif
#ifndef __predict_false
# if __GNUC__ > 2
# define __predict_true(exp) __builtin_expect((exp) != 0, 1)
# define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#else
# define __predict_true(exp) (exp)
# define __predict_false(exp) (exp)
# endif
#endif
#ifndef __BEGIN_DECLS
# if defined(__cplusplus)
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS };
# else /* __BEGIN_DECLS */
# define __BEGIN_DECLS
# define __END_DECLS
# endif /* __BEGIN_DECLS */
#endif /* __BEGIN_DECLS */
#ifndef __fallthrough
# if __GNUC__ >= 7
# define __fallthrough __attribute__((fallthrough))
# else
# define __fallthrough
# endif
#endif
/*
* Compile Time Assertion.
*/
#ifndef __CTASSERT
# ifdef __COUNTER__
# define __CTASSERT(x) __CTASSERT0(x, __ctassert, __COUNTER__)
# else
# define __CTASSERT(x) __CTASSERT99(x, __INCLUDE_LEVEL__, __LINE__)
# define __CTASSERT99(x, a, b) __CTASSERT0(x, __CONCAT(__ctassert,a), \
__CONCAT(_,b))
# endif
# define __CTASSERT0(x, y, z) __CTASSERT1(x, y, z)
# define __CTASSERT1(x, y, z) typedef char y ## z[/*CONSTCOND*/(x) ? 1 : -1] __unused
#endif
#ifndef __arraycount
# define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
#endif
/* We don't really need this as our supported systems define __restrict
* automatically for us, but it is here for completeness. */
#ifndef __restrict
# if defined(__lint__)
# define __restrict
# elif __STDC_VERSION__ >= 199901L
# define __restrict restrict
# elif !(2 < __GNUC__ || (2 == __GNU_C && 95 <= __GNUC_VERSION__))
# define __restrict
# endif
#endif
const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
size_t hwaddr_aton(uint8_t *, const char *);
ssize_t readfile(const char *, void *, size_t);
ssize_t writefile(const char *, mode_t, const void *, size_t);
int filemtime(const char *, time_t *);
char *get_line(char ** __restrict, ssize_t * __restrict);
int is_root_local(void);
#endif

634
external/bsd/dhcpcd/dist/src/control.c vendored Normal file
View File

@ -0,0 +1,634 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/socket.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "dhcpcd.h"
#include "control.h"
#include "eloop.h"
#include "if.h"
#include "logerr.h"
#include "privsep.h"
#ifndef SUN_LEN
#define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
static void control_handle_data(void *, unsigned short);
static void
control_queue_free(struct fd_list *fd)
{
struct fd_data *fdp;
while ((fdp = TAILQ_FIRST(&fd->queue))) {
TAILQ_REMOVE(&fd->queue, fdp, next);
if (fdp->data_size != 0)
free(fdp->data);
free(fdp);
}
#ifdef CTL_FREE_LIST
while ((fdp = TAILQ_FIRST(&fd->free_queue))) {
TAILQ_REMOVE(&fd->free_queue, fdp, next);
if (fdp->data_size != 0)
free(fdp->data);
free(fdp);
}
#endif
}
void
control_free(struct fd_list *fd)
{
#ifdef PRIVSEP
if (fd->ctx->ps_control_client == fd)
fd->ctx->ps_control_client = NULL;
#endif
eloop_event_delete(fd->ctx->eloop, fd->fd);
close(fd->fd);
TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
control_queue_free(fd);
free(fd);
}
static void
control_hangup(struct fd_list *fd)
{
#ifdef PRIVSEP
if (IN_PRIVSEP(fd->ctx)) {
if (ps_ctl_sendeof(fd) == -1)
logerr(__func__);
}
#endif
control_free(fd);
}
static int
control_handle_read(struct fd_list *fd)
{
char buffer[1024];
ssize_t bytes;
bytes = read(fd->fd, buffer, sizeof(buffer) - 1);
if (bytes == -1)
logerr(__func__);
if (bytes == -1 || bytes == 0) {
control_hangup(fd);
return -1;
}
#ifdef PRIVSEP
if (IN_PRIVSEP(fd->ctx)) {
ssize_t err;
fd->flags |= FD_SENDLEN;
err = ps_ctl_handleargs(fd, buffer, (size_t)bytes);
fd->flags &= ~FD_SENDLEN;
if (err == -1) {
logerr(__func__);
return 0;
}
if (err == 1 &&
ps_ctl_sendargs(fd, buffer, (size_t)bytes) == -1) {
logerr(__func__);
control_free(fd);
return -1;
}
return 0;
}
#endif
control_recvdata(fd, buffer, (size_t)bytes);
return 0;
}
static int
control_handle_write(struct fd_list *fd)
{
struct iovec iov[2];
int iov_len;
struct fd_data *data;
data = TAILQ_FIRST(&fd->queue);
if (data->data_flags & FD_SENDLEN) {
iov[0].iov_base = &data->data_len;
iov[0].iov_len = sizeof(size_t);
iov[1].iov_base = data->data;
iov[1].iov_len = data->data_len;
iov_len = 2;
} else {
iov[0].iov_base = data->data;
iov[0].iov_len = data->data_len;
iov_len = 1;
}
if (writev(fd->fd, iov, iov_len) == -1) {
if (errno != EPIPE && errno != ENOTCONN) {
// We don't get ELE_HANGUP for some reason
logerr("%s: write", __func__);
}
control_hangup(fd);
return -1;
}
TAILQ_REMOVE(&fd->queue, data, next);
#ifdef CTL_FREE_LIST
TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
#else
if (data->data_size != 0)
free(data->data);
free(data);
#endif
if (TAILQ_FIRST(&fd->queue) != NULL)
return 0;
#ifdef PRIVSEP
if (IN_PRIVSEP_SE(fd->ctx) && !(fd->flags & FD_LISTEN)) {
if (ps_ctl_sendeof(fd) == -1)
logerr(__func__);
}
#endif
/* Done sending data, stop watching write to fd */
if (eloop_event_add(fd->ctx->eloop, fd->fd, ELE_READ,
control_handle_data, fd) == -1)
logerr("%s: eloop_event_add", __func__);
return 0;
}
static void
control_handle_data(void *arg, unsigned short events)
{
struct fd_list *fd = arg;
if (!(events & (ELE_READ | ELE_WRITE | ELE_HANGUP)))
logerrx("%s: unexpected event 0x%04x", __func__, events);
if (events & ELE_WRITE && !(events & ELE_HANGUP)) {
if (control_handle_write(fd) == -1)
return;
}
if (events & ELE_READ) {
if (control_handle_read(fd) == -1)
return;
}
if (events & ELE_HANGUP)
control_hangup(fd);
}
void
control_recvdata(struct fd_list *fd, char *data, size_t len)
{
char *p = data, *e;
char *argvp[255], **ap;
int argc;
/* Each command is \n terminated
* Each argument is NULL separated */
while (len != 0) {
argc = 0;
ap = argvp;
while (len != 0) {
if (*p == '\0') {
p++;
len--;
continue;
}
e = memchr(p, '\0', len);
if (e == NULL) {
errno = EINVAL;
logerrx("%s: no terminator", __func__);
return;
}
if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) {
errno = ENOBUFS;
logerrx("%s: no arg buffer", __func__);
return;
}
*ap++ = p;
argc++;
e++;
len -= (size_t)(e - p);
p = e;
e--;
if (*(--e) == '\n') {
*e = '\0';
break;
}
}
if (argc == 0) {
logerrx("%s: no args", __func__);
continue;
}
*ap = NULL;
if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) {
logerr(__func__);
if (errno != EINTR && errno != EAGAIN) {
control_free(fd);
return;
}
}
}
}
struct fd_list *
control_new(struct dhcpcd_ctx *ctx, int fd, unsigned int flags)
{
struct fd_list *l;
l = malloc(sizeof(*l));
if (l == NULL)
return NULL;
l->ctx = ctx;
l->fd = fd;
l->flags = flags;
TAILQ_INIT(&l->queue);
#ifdef CTL_FREE_LIST
TAILQ_INIT(&l->free_queue);
#endif
TAILQ_INSERT_TAIL(&ctx->control_fds, l, next);
return l;
}
static void
control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags,
unsigned short events)
{
struct sockaddr_un run;
socklen_t len;
struct fd_list *l;
int fd, flags;
if (events != ELE_READ)
logerrx("%s: unexpected event 0x%04x", __func__, events);
len = sizeof(run);
if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
goto error;
if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto error;
if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
goto error;
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx) && !IN_PRIVSEP_SE(ctx))
;
else
#endif
fd_flags |= FD_SENDLEN;
l = control_new(ctx, fd, fd_flags);
if (l == NULL)
goto error;
if (eloop_event_add(ctx->eloop, l->fd, ELE_READ,
control_handle_data, l) == -1)
logerr("%s: eloop_event_add", __func__);
return;
error:
logerr(__func__);
if (fd != -1)
close(fd);
}
static void
control_handle(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
control_handle1(ctx, ctx->control_fd, 0, events);
}
static void
control_handle_unpriv(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV, events);
}
static int
make_path(char *path, size_t len, const char *ifname, sa_family_t family,
bool unpriv)
{
const char *per;
const char *sunpriv;
switch(family) {
case AF_INET:
per = "-4";
break;
case AF_INET6:
per = "-6";
break;
default:
per = "";
break;
}
if (unpriv)
sunpriv = ifname ? ".unpriv" : "unpriv.";
else
sunpriv = "";
return snprintf(path, len, CONTROLSOCKET,
ifname ? ifname : "", ifname ? per : "",
sunpriv, ifname ? "." : "");
}
static int
make_sock(struct sockaddr_un *sa, const char *ifname, sa_family_t family,
bool unpriv)
{
int fd;
if ((fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0)) == -1)
return -1;
memset(sa, 0, sizeof(*sa));
sa->sun_family = AF_UNIX;
make_path(sa->sun_path, sizeof(sa->sun_path), ifname, family, unpriv);
return fd;
}
#define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
#define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
static int
control_start1(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family,
mode_t fmode)
{
struct sockaddr_un sa;
int fd;
socklen_t len;
fd = make_sock(&sa, ifname, family, (fmode & S_UNPRIV) == S_UNPRIV);
if (fd == -1)
return -1;
len = (socklen_t)SUN_LEN(&sa);
unlink(sa.sun_path);
if (bind(fd, (struct sockaddr *)&sa, len) == -1 ||
chmod(sa.sun_path, fmode) == -1 ||
(ctx->control_group &&
chown(sa.sun_path, geteuid(), ctx->control_group) == -1) ||
listen(fd, sizeof(ctx->control_fds)) == -1)
{
close(fd);
unlink(sa.sun_path);
return -1;
}
#ifdef PRIVSEP_RIGHTS
if (IN_PRIVSEP(ctx) && ps_rights_limit_fd_fctnl(fd) == -1) {
close(fd);
unlink(sa.sun_path);
return -1;
}
#endif
if ((fmode & S_UNPRIV) == S_UNPRIV)
strlcpy(ctx->control_sock_unpriv, sa.sun_path,
sizeof(ctx->control_sock_unpriv));
else
strlcpy(ctx->control_sock, sa.sun_path,
sizeof(ctx->control_sock));
return fd;
}
int
control_start(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family)
{
int fd;
#ifdef PRIVSEP
if (IN_PRIVSEP_SE(ctx)) {
make_path(ctx->control_sock, sizeof(ctx->control_sock),
ifname, family, false);
make_path(ctx->control_sock_unpriv,
sizeof(ctx->control_sock_unpriv),
ifname, family, true);
return 0;
}
#endif
if ((fd = control_start1(ctx, ifname, family, S_PRIV)) == -1)
return -1;
ctx->control_fd = fd;
if (eloop_event_add(ctx->eloop, fd, ELE_READ,
control_handle, ctx) == -1)
logerr("%s: eloop_event_add", __func__);
if ((fd = control_start1(ctx, ifname, family, S_UNPRIV)) != -1) {
ctx->control_unpriv_fd = fd;
if (eloop_event_add(ctx->eloop, fd, ELE_READ,
control_handle_unpriv, ctx) == -1)
logerr("%s: eloop_event_add", __func__);
}
return ctx->control_fd;
}
static int
control_unlink(struct dhcpcd_ctx *ctx, const char *file)
{
int retval = 0;
errno = 0;
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx))
retval = (int)ps_root_unlink(ctx, file);
else
#else
UNUSED(ctx);
#endif
retval = unlink(file);
return retval == -1 && errno != ENOENT ? -1 : 0;
}
int
control_stop(struct dhcpcd_ctx *ctx)
{
int retval = 0;
struct fd_list *l;
while ((l = TAILQ_FIRST(&ctx->control_fds)) != NULL) {
control_free(l);
}
#ifdef PRIVSEP
if (IN_PRIVSEP_SE(ctx)) {
if (ctx->control_sock[0] != '\0' &&
ps_root_unlink(ctx, ctx->control_sock) == -1)
retval = -1;
if (ctx->control_sock_unpriv[0] != '\0' &&
ps_root_unlink(ctx, ctx->control_sock_unpriv) == -1)
retval = -1;
return retval;
} else if (ctx->options & DHCPCD_FORKED)
return retval;
#endif
if (ctx->control_fd != -1) {
eloop_event_delete(ctx->eloop, ctx->control_fd);
close(ctx->control_fd);
ctx->control_fd = -1;
if (control_unlink(ctx, ctx->control_sock) == -1)
retval = -1;
}
if (ctx->control_unpriv_fd != -1) {
eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd);
close(ctx->control_unpriv_fd);
ctx->control_unpriv_fd = -1;
if (control_unlink(ctx, ctx->control_sock_unpriv) == -1)
retval = -1;
}
return retval;
}
int
control_open(const char *ifname, sa_family_t family, bool unpriv)
{
struct sockaddr_un sa;
int fd;
if ((fd = make_sock(&sa, ifname, family, unpriv)) != -1) {
socklen_t len;
len = (socklen_t)SUN_LEN(&sa);
if (connect(fd, (struct sockaddr *)&sa, len) == -1) {
close(fd);
fd = -1;
}
}
return fd;
}
ssize_t
control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
{
char buffer[1024];
int i;
size_t len, l;
if (argc > 255) {
errno = ENOBUFS;
return -1;
}
len = 0;
for (i = 0; i < argc; i++) {
l = strlen(argv[i]) + 1;
if (len + l > sizeof(buffer)) {
errno = ENOBUFS;
return -1;
}
memcpy(buffer + len, argv[i], l);
len += l;
}
return write(ctx->control_fd, buffer, len);
}
int
control_queue(struct fd_list *fd, void *data, size_t data_len)
{
struct fd_data *d;
unsigned short events;
if (data_len == 0) {
errno = EINVAL;
return -1;
}
#ifdef CTL_FREE_LIST
struct fd_data *df;
d = NULL;
TAILQ_FOREACH(df, &fd->free_queue, next) {
if (d == NULL || d->data_size < df->data_size) {
d = df;
if (d->data_size <= data_len)
break;
}
}
if (d != NULL)
TAILQ_REMOVE(&fd->free_queue, d, next);
else
#endif
{
d = calloc(1, sizeof(*d));
if (d == NULL)
return -1;
}
if (d->data_size == 0)
d->data = NULL;
if (d->data_size < data_len) {
void *nbuf = realloc(d->data, data_len);
if (nbuf == NULL) {
free(d->data);
free(d);
return -1;
}
d->data = nbuf;
d->data_size = data_len;
}
memcpy(d->data, data, data_len);
d->data_len = data_len;
d->data_flags = fd->flags & FD_SENDLEN;
TAILQ_INSERT_TAIL(&fd->queue, d, next);
events = ELE_WRITE;
if (fd->flags & FD_LISTEN)
events |= ELE_READ;
return eloop_event_add(fd->ctx->eloop, fd->fd, events,
control_handle_data, fd);
}

79
external/bsd/dhcpcd/dist/src/control.h vendored Normal file
View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef CONTROL_H
#define CONTROL_H
#include <stdbool.h>
#include "dhcpcd.h"
#if !defined(CTL_FREE_LIST)
#define CTL_FREE_LIST 1
#elif CTL_FREE_LIST == 0
#undef CTL_FREE_LIST
#endif
/* Limit queue size per fd */
#define CONTROL_QUEUE_MAX 100
struct fd_data {
TAILQ_ENTRY(fd_data) next;
void *data;
size_t data_size;
size_t data_len;
unsigned int data_flags;
};
TAILQ_HEAD(fd_data_head, fd_data);
struct fd_list {
TAILQ_ENTRY(fd_list) next;
struct dhcpcd_ctx *ctx;
int fd;
unsigned int flags;
struct fd_data_head queue;
#ifdef CTL_FREE_LIST
struct fd_data_head free_queue;
#endif
};
TAILQ_HEAD(fd_list_head, fd_list);
#define FD_LISTEN 0x01U
#define FD_UNPRIV 0x02U
#define FD_SENDLEN 0x04U
int control_start(struct dhcpcd_ctx *, const char *, sa_family_t);
int control_stop(struct dhcpcd_ctx *);
int control_open(const char *, sa_family_t, bool);
ssize_t control_send(struct dhcpcd_ctx *, int, char * const *);
struct fd_list *control_new(struct dhcpcd_ctx *, int, unsigned int);
void control_free(struct fd_list *);
void control_delete(struct fd_list *);
int control_queue(struct fd_list *, void *, size_t);
void control_recvdata(struct fd_list *fd, char *, size_t);
#endif

78
external/bsd/dhcpcd/dist/src/defs.h vendored Normal file
View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
*
* 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.
*/
#ifndef DEFS_H
#define DEFS_H
#define PACKAGE "dhcpcd"
#define VERSION "10.0.8"
#ifndef PRIVSEP_USER
# define PRIVSEP_USER "_" PACKAGE
#endif
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
#endif
#ifndef SCRIPT
# define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
#endif
#ifndef DEVDIR
# define DEVDIR LIBDIR "/" PACKAGE "/dev"
#endif
#ifndef DUID
# define DUID DBDIR "/duid"
#endif
#ifndef SECRET
# define SECRET DBDIR "/secret"
#endif
#ifndef LEASEFILE
# define LEASEFILE DBDIR "/%s%s.lease"
#endif
#ifndef LEASEFILE6
# define LEASEFILE6 LEASEFILE "6"
#endif
#ifndef PIDFILE
# define PIDFILE RUNDIR "/%s%s%spid"
#endif
#ifndef CONTROLSOCKET
# define CONTROLSOCKET RUNDIR "/%s%s%s%ssock"
#endif
#ifndef RDM_MONOFILE
# define RDM_MONOFILE DBDIR "/rdm_monotonic"
#endif
#ifndef NO_SIGNALS
# define USE_SIGNALS
#endif
#ifndef USE_SIGNALS
# ifndef THERE_IS_NO_FORK
# define THERE_IS_NO_FORK
# endif
#endif
#endif

56
external/bsd/dhcpcd/dist/src/dev.h vendored Normal file
View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
*
* 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.
*/
#ifndef DEV_H
#define DEV_H
// dev plugin setup
struct dev {
const char *name;
int (*initialised)(const char *);
int (*listening)(void);
int (*handle_device)(void *);
int (*start)(void);
void (*stop)(void);
};
struct dev_dhcpcd {
int (*handle_interface)(void *, int, const char *);
};
int dev_init(struct dev *, const struct dev_dhcpcd *);
// hooks for dhcpcd
#ifdef PLUGIN_DEV
#include "dhcpcd.h"
int dev_initialised(struct dhcpcd_ctx *, const char *);
int dev_listening(struct dhcpcd_ctx *);
int dev_start(struct dhcpcd_ctx *, int (*)(void *, int, const char *));
void dev_stop(struct dhcpcd_ctx *);
#endif
#endif

1083
external/bsd/dhcpcd/dist/src/dhcp-common.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef DHCPCOMMON_H
#define DHCPCOMMON_H
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdint.h>
#include <arpa/nameser.h> /* after normal includes for sunos */
#include "common.h"
#include "dhcpcd.h"
/* Support very old arpa/nameser.h as found in OpenBSD */
#ifndef NS_MAXDNAME
#define NS_MAXCDNAME MAXCDNAME
#define NS_MAXDNAME MAXDNAME
#define NS_MAXLABEL MAXLABEL
#endif
/* Max MTU - defines dhcp option length */
#define IP_UDP_SIZE 28
#define MTU_MAX 1500 - IP_UDP_SIZE
#define MTU_MIN 576 + IP_UDP_SIZE
#define OT_REQUEST (1 << 0)
#define OT_UINT8 (1 << 1)
#define OT_INT8 (1 << 2)
#define OT_UINT16 (1 << 3)
#define OT_INT16 (1 << 4)
#define OT_UINT32 (1 << 5)
#define OT_INT32 (1 << 6)
#define OT_ADDRIPV4 (1 << 7)
#define OT_STRING (1 << 8)
#define OT_ARRAY (1 << 9)
#define OT_RFC3361 (1 << 10)
#define OT_RFC1035 (1 << 11)
#define OT_RFC3442 (1 << 12)
#define OT_OPTIONAL (1 << 13)
#define OT_ADDRIPV6 (1 << 14)
#define OT_BINHEX (1 << 15)
#define OT_FLAG (1 << 16)
#define OT_NOREQ (1 << 17)
#define OT_EMBED (1 << 18)
#define OT_ENCAP (1 << 19)
#define OT_INDEX (1 << 20)
#define OT_OPTION (1 << 21)
#define OT_DOMAIN (1 << 22)
#define OT_ASCII (1 << 23)
#define OT_RAW (1 << 24)
#define OT_ESCSTRING (1 << 25)
#define OT_ESCFILE (1 << 26)
#define OT_BITFLAG (1 << 27)
#define OT_RESERVED (1 << 28)
#define OT_URI (1 << 29)
#define DHC_REQ(r, n, o) \
(has_option_mask((r), (o)) && !has_option_mask((n), (o)))
#define DHC_REQOPT(o, r, n) \
(!((o)->type & OT_NOREQ) && \
((o)->type & OT_REQUEST || has_option_mask((r), (o)->option)) && \
!has_option_mask((n), (o)->option))
struct dhcp_opt {
uint32_t option; /* Also used for IANA Enterpise Number */
int type;
size_t len;
char *var;
int index; /* Index counter for many instances of the same option */
char bitflags[8];
/* Embedded options.
* The option code is irrelevant here. */
struct dhcp_opt *embopts;
size_t embopts_len;
/* Encapsulated options */
struct dhcp_opt *encopts;
size_t encopts_len;
};
const char *dhcp_get_hostname(char *, size_t, const struct if_options *);
struct dhcp_opt *vivso_find(uint32_t, const void *);
ssize_t dhcp_vendor(char *, size_t);
void dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols);
#define add_option_mask(var, val) \
((var)[(val) >> 3] = (uint8_t)((var)[(val) >> 3] | 1 << ((val) & 7)))
#define del_option_mask(var, val) \
((var)[(val) >> 3] = (uint8_t)((var)[(val) >> 3] & ~(1 << ((val) & 7))))
#define has_option_mask(var, val) \
((var)[(val) >> 3] & (uint8_t)(1 << ((val) & 7)))
int make_option_mask(const struct dhcp_opt *, size_t,
const struct dhcp_opt *, size_t,
uint8_t *, const char *, int);
size_t encode_rfc1035(const char *src, uint8_t *dst);
ssize_t decode_rfc1035(char *, size_t, const uint8_t *, size_t);
ssize_t print_string(char *, size_t, int, const uint8_t *, size_t);
int dhcp_set_leasefile(char *, size_t, int, const struct interface *);
void dhcp_envoption(struct dhcpcd_ctx *,
FILE *, const char *, const char *, struct dhcp_opt *,
const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
size_t *, unsigned int *, size_t *,
const uint8_t *, size_t, struct dhcp_opt **),
const uint8_t *od, size_t ol);
void dhcp_zero_index(struct dhcp_opt *);
ssize_t dhcp_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
ssize_t dhcp_writefile(struct dhcpcd_ctx *, const char *, mode_t,
const void *, size_t);
int dhcp_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
int dhcp_unlink(struct dhcpcd_ctx *, const char *);
size_t dhcp_read_hwaddr_aton(struct dhcpcd_ctx *, uint8_t **, const char *);
#endif

4332
external/bsd/dhcpcd/dist/src/dhcp.c vendored Normal file

File diff suppressed because it is too large Load Diff

285
external/bsd/dhcpcd/dist/src/dhcp.h vendored Normal file
View File

@ -0,0 +1,285 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef DHCP_H
#define DHCP_H
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
#include <netinet/udp.h>
#undef __FAVOR_BSD
#include <limits.h>
#include <stdint.h>
#include "arp.h"
#include "bpf.h"
#include "auth.h"
#include "dhcp-common.h"
/* UDP port numbers for BOOTP */
#define BOOTPS 67
#define BOOTPC 68
#define MAGIC_COOKIE 0x63825363
#define BROADCAST_FLAG 0x8000
/* BOOTP message OP code */
#define BOOTREQUEST 1
#define BOOTREPLY 2
/* DHCP message type */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
#define DHCP_FORCERENEW 9
/* Constants taken from RFC 2131. */
#define T1 0.5
#define T2 0.875
#define DHCP_BASE 4
#define DHCP_MAX 64
#define DHCP_RAND_MIN -1
#define DHCP_RAND_MAX 1
#ifdef RFC2131_STRICT
/* Be strictly conformant for section 4.1.1 */
# define DHCP_MIN_DELAY 1
# define DHCP_MAX_DELAY 10
#else
/* or mirror the more modern IPv6RS and DHCPv6 delays */
# define DHCP_MIN_DELAY 0
# define DHCP_MAX_DELAY 1
#endif
/* DHCP options */
enum DHO {
DHO_PAD = 0,
DHO_SUBNETMASK = 1,
DHO_ROUTER = 3,
DHO_DNSSERVER = 6,
DHO_HOSTNAME = 12,
DHO_DNSDOMAIN = 15,
DHO_MTU = 26,
DHO_BROADCAST = 28,
DHO_STATICROUTE = 33,
DHO_NISDOMAIN = 40,
DHO_NISSERVER = 41,
DHO_NTPSERVER = 42,
DHO_VENDOR = 43,
DHO_IPADDRESS = 50,
DHO_LEASETIME = 51,
DHO_OPTSOVERLOADED = 52,
DHO_MESSAGETYPE = 53,
DHO_SERVERID = 54,
DHO_PARAMETERREQUESTLIST = 55,
DHO_MESSAGE = 56,
DHO_MAXMESSAGESIZE = 57,
DHO_RENEWALTIME = 58,
DHO_REBINDTIME = 59,
DHO_VENDORCLASSID = 60,
DHO_CLIENTID = 61,
DHO_USERCLASS = 77, /* RFC 3004 */
DHO_RAPIDCOMMIT = 80, /* RFC 4039 */
DHO_FQDN = 81,
DHO_AUTHENTICATION = 90, /* RFC 3118 */
DHO_IPV6_PREFERRED_ONLY = 108, /* RFC 8925 */
DHO_AUTOCONFIGURE = 116, /* RFC 2563 */
DHO_DNSSEARCH = 119, /* RFC 3397 */
DHO_CSR = 121, /* RFC 3442 */
DHO_VIVCO = 124, /* RFC 3925 */
DHO_VIVSO = 125, /* RFC 3925 */
DHO_FORCERENEW_NONCE = 145, /* RFC 6704 */
DHO_MUDURL = 161, /* draft-ietf-opsawg-mud */
DHO_SIXRD = 212, /* RFC 5969 */
DHO_MSCSR = 249, /* MS code for RFC 3442 */
DHO_END = 255
};
/* FQDN values - lsnybble used in flags
* hsnybble to create order
* and to allow 0x00 to mean disable
*/
enum FQDN {
FQDN_DISABLE = 0x00,
FQDN_NONE = 0x18,
FQDN_PTR = 0x20,
FQDN_BOTH = 0x31
};
#define MIN_V6ONLY_WAIT 300 /* seconds, RFC 8925 */
/* Sizes for BOOTP options */
#define BOOTP_CHADDR_LEN 16
#define BOOTP_SNAME_LEN 64
#define BOOTP_FILE_LEN 128
#define BOOTP_VEND_LEN 64
/* DHCP is basically an extension to BOOTP */
struct bootp {
uint8_t op; /* message type */
uint8_t htype; /* hardware address type */
uint8_t hlen; /* hardware address length */
uint8_t hops; /* should be zero in client message */
uint32_t xid; /* transaction id */
uint16_t secs; /* elapsed time in sec. from boot */
uint16_t flags; /* such as broadcast flag */
uint32_t ciaddr; /* (previously allocated) client IP */
uint32_t yiaddr; /* 'your' client IP address */
uint32_t siaddr; /* should be zero in client's messages */
uint32_t giaddr; /* should be zero in client's messages */
uint8_t chaddr[BOOTP_CHADDR_LEN]; /* client's hardware address */
uint8_t sname[BOOTP_SNAME_LEN]; /* server host name */
uint8_t file[BOOTP_FILE_LEN]; /* boot file name */
uint8_t vend[BOOTP_VEND_LEN]; /* vendor specific area */
/* DHCP allows a variable length vendor area */
};
#define DHCP_MIN_LEN (offsetof(struct bootp, vend) + 4)
struct bootp_pkt
{
struct ip ip;
struct udphdr udp;
struct bootp bootp;
};
struct dhcp_lease {
struct in_addr addr;
struct in_addr mask;
struct in_addr brd;
uint32_t leasetime;
uint32_t renewaltime;
uint32_t rebindtime;
struct in_addr server;
uint8_t frominfo;
uint32_t cookie;
};
#ifndef DHCP_INFINITE_LIFETIME
# define DHCP_INFINITE_LIFETIME (~0U)
#endif
enum DHS {
DHS_NONE,
DHS_INIT,
DHS_DISCOVER,
DHS_REQUEST,
DHS_PROBE,
DHS_BOUND,
DHS_RENEW,
DHS_REBIND,
DHS_REBOOT,
DHS_INFORM,
DHS_RENEW_REQUESTED,
DHS_RELEASE
};
struct dhcp_state {
enum DHS state;
struct bootp *sent;
size_t sent_len;
struct bootp *offer;
size_t offer_len;
struct bootp *new;
size_t new_len;
struct bootp *old;
size_t old_len;
struct dhcp_lease lease;
const char *reason;
unsigned int interval;
unsigned int nakoff;
uint32_t xid;
int socket;
struct bpf *bpf;
int udp_rfd;
struct ipv4_addr *addr;
uint8_t added;
char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDLEN * 4)];
struct timespec started;
unsigned char *clientid;
struct authstate auth;
#ifdef ARPING
ssize_t arping_index;
#endif
};
#ifdef INET
#define D_STATE(ifp) \
((struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
#define D_CSTATE(ifp) \
((const struct dhcp_state *)(ifp)->if_data[IF_DATA_DHCP])
#define D_STATE_RUNNING(ifp) \
(D_CSTATE((ifp)) && D_CSTATE((ifp))->new && D_CSTATE((ifp))->reason)
#define IS_DHCP(b) ((b)->vend[0] == 0x63 && \
(b)->vend[1] == 0x82 && \
(b)->vend[2] == 0x53 && \
(b)->vend[3] == 0x63)
#include "dhcpcd.h"
#include "if-options.h"
ssize_t print_rfc3361(FILE *, const uint8_t *, size_t);
ssize_t print_rfc3442(FILE *, const uint8_t *, size_t);
int dhcp_openudp(struct in_addr *);
void dhcp_packet(struct interface *, uint8_t *, size_t, unsigned int);
void dhcp_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
void dhcp_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
uint16_t dhcp_get_mtu(const struct interface *);
int dhcp_get_routes(rb_tree_t *, struct interface *);
ssize_t dhcp_env(FILE *, const char *, const struct interface *,
const struct bootp *, size_t);
struct ipv4_addr *dhcp_handleifa(int, struct ipv4_addr *, pid_t pid);
void dhcp_drop(struct interface *, const char *);
void dhcp_start(struct interface *);
void dhcp_abort(struct interface *);
void dhcp_discover(void *);
void dhcp_inform(struct interface *);
void dhcp_renew(struct interface *);
void dhcp_bind(struct interface *);
void dhcp_reboot_newopts(struct interface *, unsigned long long);
void dhcp_close(struct interface *);
void dhcp_free(struct interface *);
int dhcp_dump(struct interface *);
#endif /* INET */
#endif /* DHCP_H */

4432
external/bsd/dhcpcd/dist/src/dhcp6.c vendored Normal file

File diff suppressed because it is too large Load Diff

254
external/bsd/dhcpcd/dist/src/dhcp6.h vendored Normal file
View File

@ -0,0 +1,254 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef DHCP6_H
#define DHCP6_H
#include "dhcpcd.h"
#define IN6ADDR_LINKLOCAL_ALLDHCP_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 }}}
/* UDP port numbers for DHCP */
#define DHCP6_CLIENT_PORT 546
#define DHCP6_SERVER_PORT 547
/* DHCP message type */
#define DHCP6_SOLICIT 1
#define DHCP6_ADVERTISE 2
#define DHCP6_REQUEST 3
#define DHCP6_CONFIRM 4
#define DHCP6_RENEW 5
#define DHCP6_REBIND 6
#define DHCP6_REPLY 7
#define DHCP6_RELEASE 8
#define DHCP6_DECLINE 9
#define DHCP6_RECONFIGURE 10
#define DHCP6_INFORMATION_REQ 11
#define DHCP6_RELAY_FLOW 12
#define DHCP6_RELAY_REPL 13
#define DHCP6_RECONFIGURE_REQ 18
#define DHCP6_RECONFIGURE_REPLY 19
#ifdef DHCP6
#define D6_OPTION_CLIENTID 1
#define D6_OPTION_SERVERID 2
#define D6_OPTION_IA_NA 3
#define D6_OPTION_IA_TA 4
#define D6_OPTION_ORO 6
#define D6_OPTION_IA_ADDR 5
#define D6_OPTION_PREFERENCE 7
#define D6_OPTION_ELAPSED 8
#define D6_OPTION_AUTH 11
#define D6_OPTION_UNICAST 12
#define D6_OPTION_STATUS_CODE 13
#define D6_OPTION_RAPID_COMMIT 14
#define D6_OPTION_USER_CLASS 15
#define D6_OPTION_VENDOR_CLASS 16
#define D6_OPTION_VENDOR_OPTS 17
#define D6_OPTION_INTERFACE_ID 18
#define D6_OPTION_RECONF_MSG 19
#define D6_OPTION_RECONF_ACCEPT 20
#define D6_OPTION_SIP_SERVERS_NAME 21
#define D6_OPTION_SIP_SERVERS_ADDRESS 22
#define D6_OPTION_DNS_SERVERS 23
#define D6_OPTION_DOMAIN_LIST 24
#define D6_OPTION_IA_PD 25
#define D6_OPTION_IAPREFIX 26
#define D6_OPTION_NIS_SERVERS 27
#define D6_OPTION_NISP_SERVERS 28
#define D6_OPTION_NIS_DOMAIN_NAME 29
#define D6_OPTION_NISP_DOMAIN_NAME 30
#define D6_OPTION_SNTP_SERVERS 31
#define D6_OPTION_INFO_REFRESH_TIME 32
#define D6_OPTION_BCMS_SERVER_D 33
#define D6_OPTION_BCMS_SERVER_A 34
#define D6_OPTION_FQDN 39
#define D6_OPTION_POSIX_TIMEZONE 41
#define D6_OPTION_TZDB_TIMEZONE 42
#define D6_OPTION_NTP_SERVER 56
#define D6_OPTION_PD_EXCLUDE 67
#define D6_OPTION_SOL_MAX_RT 82
#define D6_OPTION_INF_MAX_RT 83
#define D6_OPTION_MUDURL 112
#define D6_FQDN_PTR 0x00
#define D6_FQDN_BOTH 0x01
#define D6_FQDN_NONE 0x04
#include "dhcp.h"
#include "ipv6.h"
#define D6_STATUS_OK 0
#define D6_STATUS_FAIL 1
#define D6_STATUS_NOADDR 2
#define D6_STATUS_NOBINDING 3
#define D6_STATUS_NOTONLINK 4
#define D6_STATUS_USEMULTICAST 5
#define SOL_MAX_DELAY 1
#define SOL_TIMEOUT 1
#define SOL_MAX_RT 3600 /* RFC7083 */
#define SOL_MAX_RC 0
#define REQ_MAX_DELAY 0
#define REQ_TIMEOUT 1
#define REQ_MAX_RT 30
#define REQ_MAX_RC 10
#define CNF_MAX_DELAY 1
#define CNF_TIMEOUT 1
#define CNF_MAX_RT 4
#define CNF_MAX_RC 0
#define CNF_MAX_RD 10
#define REN_MAX_DELAY 0
#define REN_TIMEOUT 10
#define REN_MAX_RT 600
#define REB_MAX_DELAY 0
#define REB_TIMEOUT 10
#define REB_MAX_RT 600
#define INF_MAX_DELAY 1
#define INF_TIMEOUT 1
#define INF_MAX_RD CNF_MAX_RD /* NOT RFC defined */
#define INF_MAX_RT 3600 /* RFC7083 */
#define REL_MAX_DELAY 0
#define REL_TIMEOUT 1
#define REL_MAX_RT 0
#define REL_MAX_RC 5
#define DEC_MAX_DELAY 0
#define DEC_TIMEOUT 1
#define DEC_MAX_RC 5
#define REC_MAX_DELAY 0
#define REC_TIMEOUT 2
#define REC_MAX_RC 8
#define HOP_COUNT_LIMIT 32
/* RFC4242 3.1 */
#define IRT_DEFAULT 86400
#define IRT_MINIMUM 600
/* These should give -.1 to .1 randomness */
#define DHCP6_RAND_MIN -100
#define DHCP6_RAND_MAX 100
#define DHCP6_RAND_DIV 1000.0f
enum DH6S {
DH6S_INIT,
DH6S_DISCOVER,
DH6S_REQUEST,
DH6S_BOUND,
DH6S_RENEW,
DH6S_REBIND,
DH6S_CONFIRM,
DH6S_INFORM,
DH6S_INFORMED,
DH6S_RENEW_REQUESTED,
DH6S_PROBE,
DH6S_DECLINE,
DH6S_DELEGATED,
DH6S_RELEASE,
DH6S_RELEASED,
};
struct dhcp6_state {
enum DH6S state;
struct timespec started;
/* Message retransmission timings in seconds */
unsigned int IMD;
unsigned int RTC;
unsigned int IRT;
unsigned int MRC;
unsigned int MRT;
void (*MRCcallback)(void *);
unsigned int sol_max_rt;
unsigned int inf_max_rt;
unsigned int RT; /* retransmission timer in milliseconds
* maximal RT is 1 day + RAND,
* so should be enough */
struct dhcp6_message *send;
size_t send_len;
struct dhcp6_message *recv;
size_t recv_len;
struct dhcp6_message *new;
size_t new_len;
struct dhcp6_message *old;
size_t old_len;
struct timespec acquired;
uint32_t renew;
uint32_t rebind;
uint32_t expire;
struct in6_addr unicast;
struct ipv6_addrhead addrs;
uint32_t lowpl;
/* The +3 is for the possible .pd extension for prefix delegation */
char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) +3];
const char *reason;
uint16_t lerror; /* Last error received from DHCPv6 reply. */
bool has_no_binding;
bool failed; /* Entered the failed state - used to rate limit log. */
bool new_start; /* New external start, to determine log type. */
#ifdef AUTH
struct authstate auth;
#endif
};
#define D6_STATE(ifp) \
((struct dhcp6_state *)(ifp)->if_data[IF_DATA_DHCP6])
#define D6_CSTATE(ifp) \
((const struct dhcp6_state *)(ifp)->if_data[IF_DATA_DHCP6])
#define D6_STATE_RUNNING(ifp) \
(D6_CSTATE((ifp)) && \
D6_CSTATE((ifp))->reason && dhcp6_dadcompleted((ifp)))
int dhcp6_openraw(void);
int dhcp6_openudp(unsigned int, struct in6_addr *);
void dhcp6_recvmsg(struct dhcpcd_ctx *, struct msghdr *, struct ipv6_addr *);
void dhcp6_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
const struct ipv6_addr *dhcp6_iffindaddr(const struct interface *ifp,
const struct in6_addr *addr, unsigned int flags);
struct ipv6_addr *dhcp6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *,
unsigned int);
size_t dhcp6_find_delegates(struct interface *);
int dhcp6_start(struct interface *, enum DH6S);
void dhcp6_reboot(struct interface *);
void dhcp6_renew(struct interface *);
ssize_t dhcp6_env(FILE *, const char *, const struct interface *,
const struct dhcp6_message *, size_t);
void dhcp6_free(struct interface *);
void dhcp6_handleifa(int, struct ipv6_addr *, pid_t);
bool dhcp6_dadcompleted(const struct interface *);
void dhcp6_abort(struct interface *);
void dhcp6_drop(struct interface *, const char *);
int dhcp6_dump(struct interface *);
#endif /* DHCP6 */
#endif /* DHCP6_H */

View File

@ -0,0 +1,532 @@
/*
* DO NOT EDIT!
* Automatically generated from dhcpcd-embedded.conf
* Ths allows us to simply generate DHCP structure without any C programming.
*/
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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 <unistd.h>
const char dhcpcd_embedded_conf[] =
#ifdef SMALL
"define 1 request ipaddress subnet_mask\n"
"define 121 rfc3442 classless_static_routes\n"
"define 3 request array ipaddress routers\n"
"define 6 array ipaddress domain_name_servers\n"
"define 12 dname host_name\n"
"define 15 array dname domain_name\n"
"define 26 uint16 interface_mtu\n"
"define 28 request ipaddress broadcast_address\n"
"define 33 request array ipaddress static_routes\n"
"define 50 ipaddress dhcp_requested_address\n"
"define 51 request uint32 dhcp_lease_time\n"
"define 52 byte dhcp_option_overload\n"
"define 53 byte dhcp_message_type\n"
"define 54 ipaddress dhcp_server_identifier\n"
"define 55 array byte dhcp_parameter_request_list\n"
"define 56 string dhcp_message\n"
"define 57 uint16 dhcp_max_message_size\n"
"define 58 request uint32 dhcp_renewal_time\n"
"define 59 request uint32 dhcp_rebinding_time\n"
"define 60 string vendor_class_identifier\n"
"define 61 binhex dhcp_client_identifier\n"
"define 80 norequest flag rapid_commit\n"
"define 81 embed fqdn\n"
"embed bitflags=0000NEOS flags\n"
"embed byte rcode1\n"
"embed byte rcode2\n"
"embed optional domain fqdn\n"
"define 119 array domain domain_search\n"
"define 249 rfc3442 ms_classless_static_routes\n"
"definend 1 binhex source_address\n"
"definend 2 binhex target_address\n"
"definend 3 index embed prefix_information\n"
"embed byte length\n"
"embed bitflags=LAH flags\n"
"embed uint32 vltime\n"
"embed uint32 pltime\n"
"embed uint32 reserved\n"
"embed array ip6address prefix\n"
"definend 5 embed mtu\n"
"embed uint16 reserved\n"
"embed uint32 mtu\n"
"definend 25 index embed rdnss\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed array ip6address servers\n"
"definend 31 index embed dnssl\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed domain search\n"
"define6 1 binhex client_id\n"
"define6 2 binhex server_id\n"
"define6 3 norequest index embed ia_na\n"
"embed binhex:4 iaid\n"
"embed uint32 t1\n"
"embed uint32 t2\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 4 norequest index embed ia_ta\n"
"embed uint32 iaid\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 5 norequest index embed ia_addr\n"
"embed ip6address ia_addr\n"
"embed uint32 pltime\n"
"embed uint32 vltime\n"
"encap 13 option\n"
"define6 12 ip6address unicast\n"
"define6 13 norequest embed status_code\n"
"embed uint16 status_code\n"
"embed optional string message\n"
"define6 18 binhex interface_id\n"
"define6 19 byte reconfigure_msg\n"
"define6 20 flag reconfigure_accept\n"
"define6 23 array ip6address name_servers\n"
"define6 24 array domain domain_search\n"
"define6 39 embed fqdn\n"
"embed bitflags=00000NOS flags\n"
"embed optional domain fqdn\n"
"define6 82 request uint32 sol_max_rt\n"
"define6 83 request uint32 inf_max_rt\n"
#else
"define 1 request ipaddress subnet_mask\n"
"define 121 rfc3442 classless_static_routes\n"
"define 2 int32 time_offset\n"
"define 3 request array ipaddress routers\n"
"define 4 array ipaddress time_servers\n"
"define 5 array ipaddress ien116_name_servers\n"
"define 6 array ipaddress domain_name_servers\n"
"define 7 array ipaddress log_servers\n"
"define 8 array ipaddress cookie_servers\n"
"define 9 array ipaddress lpr_servers\n"
"define 10 array ipaddress impress_servers\n"
"define 11 array ipaddress resource_location_servers\n"
"define 12 dname host_name\n"
"define 13 uint16 boot_size\n"
"define 14 string merit_dump\n"
"define 15 array dname domain_name\n"
"define 16 ipaddress swap_server\n"
"define 17 string root_path\n"
"define 18 string extensions_path\n"
"define 19 byte ip_forwarding\n"
"define 20 byte non_local_source_routing\n"
"define 21 array ipaddress policy_filter\n"
"define 22 uint16 max_dgram_reassembly\n"
"define 23 byte default_ip_ttl\n"
"define 24 uint32 path_mtu_aging_timeout\n"
"define 25 array uint16 path_mtu_plateau_table\n"
"define 26 uint16 interface_mtu\n"
"define 27 byte all_subnets_local\n"
"define 28 request ipaddress broadcast_address\n"
"define 29 byte perform_mask_discovery\n"
"define 30 byte mask_supplier\n"
"define 31 byte router_discovery\n"
"define 32 ipaddress router_solicitation_address\n"
"define 33 request array ipaddress static_routes\n"
"define 34 byte trailer_encapsulation\n"
"define 35 uint32 arp_cache_timeout\n"
"define 36 uint16 ieee802_3_encapsulation\n"
"define 37 byte default_tcp_ttl\n"
"define 38 uint32 tcp_keepalive_interval\n"
"define 39 byte tcp_keepalive_garbage\n"
"define 40 string nis_domain\n"
"define 41 array ipaddress nis_servers\n"
"define 42 array ipaddress ntp_servers\n"
"define 43 binhex vendor_encapsulated_options\n"
"define 44 array ipaddress netbios_name_servers\n"
"define 45 ipaddress netbios_dd_server\n"
"define 46 byte netbios_node_type\n"
"define 47 string netbios_scope\n"
"define 48 array ipaddress font_servers\n"
"define 49 array ipaddress x_display_manager\n"
"define 50 ipaddress dhcp_requested_address\n"
"define 51 request uint32 dhcp_lease_time\n"
"define 52 byte dhcp_option_overload\n"
"define 53 byte dhcp_message_type\n"
"define 54 ipaddress dhcp_server_identifier\n"
"define 55 array byte dhcp_parameter_request_list\n"
"define 56 string dhcp_message\n"
"define 57 uint16 dhcp_max_message_size\n"
"define 58 request uint32 dhcp_renewal_time\n"
"define 59 request uint32 dhcp_rebinding_time\n"
"define 60 string vendor_class_identifier\n"
"define 61 binhex dhcp_client_identifier\n"
"define 64 string nisplus_domain\n"
"define 65 array ipaddress nisplus_servers\n"
"define 66 dname tftp_server_name\n"
"define 67 string bootfile_name\n"
"define 68 array ipaddress mobile_ip_home_agent\n"
"define 69 array ipaddress smtp_server\n"
"define 70 array ipaddress pop_server\n"
"define 71 array ipaddress nntp_server\n"
"define 72 array ipaddress www_server\n"
"define 73 array ipaddress finger_server\n"
"define 74 array ipaddress irc_server\n"
"define 75 array ipaddress streettalk_server\n"
"define 76 array ipaddress streettalk_directory_assistance_server\n"
"define 77 binhex user_class\n"
"define 78 embed slp_agent\n"
"embed byte mandatory\n"
"embed array ipaddress address\n"
"define 79 embed slp_service\n"
"embed byte mandatory\n"
"embed ascii scope_list\n"
"define 80 norequest flag rapid_commit\n"
"define 81 embed fqdn\n"
"embed bitflags=0000NEOS flags\n"
"embed byte rcode1\n"
"embed byte rcode2\n"
"embed optional domain fqdn\n"
"define 83 embed isns\n"
"embed byte reserved1\n"
"embed bitflags=00000SAE functions\n"
"embed byte reserved2\n"
"embed bitflags=00fFsSCE dd\n"
"embed byte reserved3\n"
"embed bitflags=0000DMHE admin\n"
"embed uint16 reserved4\n"
"embed byte reserved5\n"
"embed bitflags=0TXPAMSE server_security\n"
"embed array ipaddress servers\n"
"define 85 array ipaddress nds_servers\n"
"define 86 raw nds_tree_name\n"
"define 87 raw nds_context\n"
"define 88 array domain bcms_controller_names\n"
"define 89 array ipaddress bcms_controller_address\n"
"define 90 embed auth\n"
"embed byte protocol\n"
"embed byte algorithm\n"
"embed byte rdm\n"
"embed binhex:8 replay\n"
"embed binhex information\n"
"define 91 uint32 client_last_transaction_time\n"
"define 92 array ipaddress associated_ip\n"
"define 98 string uap_servers\n"
"define 99 encap geoconf_civic\n"
"embed byte what\n"
"embed uint16 country_code\n"
"define 100 string posix_timezone\n"
"define 101 string tzdb_timezone\n"
"define 108 uint32 ipv6_only_preferred\n"
"define 114 string captive_portal_uri\n"
"define 116 byte auto_configure\n"
"define 117 array uint16 name_service_search\n"
"define 118 ipaddress subnet_selection\n"
"define 119 array domain domain_search\n"
"define 120 rfc3361 sip_server\n"
"define 122 encap tsp\n"
"encap 1 ipaddress dhcp_server\n"
"encap 2 ipaddress dhcp_secondary_server\n"
"encap 3 rfc3361 provisioning_server\n"
"encap 4 embed as_req_as_rep_backoff\n"
"embed uint32 nominal\n"
"embed uint32 maximum\n"
"embed uint32 retry\n"
"encap 5 embed ap_req_ap_rep_backoff\n"
"embed uint32 nominal\n"
"embed uint32 maximum\n"
"embed uint32 retry\n"
"encap 6 domain kerberos_realm\n"
"encap 7 byte ticket_granting_server_utilization\n"
"encap 8 byte provisioning_timer\n"
"define 123 binhex geoconf\n"
"define 124 binhex vivco\n"
"define 125 embed vivso\n"
"embed uint32 enterprise_number\n"
"define 136 array ipaddress pana_agent\n"
"define 137 domain lost_server\n"
"define 138 array ipaddress capwap_ac\n"
"define 139 encap mos_ip\n"
"encap 1 array ipaddress is\n"
"encap 2 array ipaddress cs\n"
"encap 3 array ipaddress es\n"
"define 140 encap mos_domain\n"
"encap 1 domain is\n"
"encap 2 domain cs\n"
"encap 3 domain es\n"
"define 141 array domain sip_ua_cs_list\n"
"define 142 array ipaddress andsf\n"
"define 143 array uri sztp_redirect\n"
"define 144 binhex geoloc\n"
"define 145 array byte forcerenew_nonce_capable\n"
"define 146 embed rdnss_selection\n"
"embed byte prf\n"
"embed ipaddress primary\n"
"embed ipaddress secondary\n"
"embed array domain domains\n"
"define 147 domain dots_ri\n"
"define 148 array ipaddress dots_address\n"
"define 150 array ipaddress tftp_servers\n"
"define 161 string mudurl\n"
"define 208 binhex pxelinux_magic\n"
"define 209 string config_file\n"
"define 210 string path_prefix\n"
"define 211 uint32 reboot_time\n"
"define 212 embed sixrd\n"
"embed byte mask_len\n"
"embed byte prefix_len\n"
"embed ip6address prefix\n"
"embed array ipaddress brip_address\n"
"define 213 domain access_domain\n"
"define 221 encap vss\n"
"encap 0 string nvt\n"
"encap 1 binhex vpn_id\n"
"encap 255 flag global\n"
"define 245 ipaddress azureendpoint\n"
"define 249 rfc3442 ms_classless_static_routes\n"
"define 252 uri wpad_url\n"
"define 224 binhex site_specific_224\n"
"define 225 binhex site_specific_225\n"
"define 226 binhex site_specific_226\n"
"define 227 binhex site_specific_227\n"
"define 228 binhex site_specific_228\n"
"define 229 binhex site_specific_229\n"
"define 230 binhex site_specific_230\n"
"define 231 binhex site_specific_231\n"
"define 232 binhex site_specific_232\n"
"define 233 binhex site_specific_233\n"
"define 234 binhex site_specific_234\n"
"define 235 binhex site_specific_235\n"
"define 236 binhex site_specific_236\n"
"define 237 binhex site_specific_237\n"
"define 238 binhex site_specific_238\n"
"define 239 binhex site_specific_239\n"
"define 240 binhex site_specific_240\n"
"define 241 binhex site_specific_241\n"
"define 242 binhex site_specific_242\n"
"define 243 binhex site_specific_243\n"
"define 244 binhex site_specific_244\n"
"define 246 binhex site_specific_246\n"
"define 247 binhex site_specific_247\n"
"define 248 binhex site_specific_248\n"
"define 250 binhex site_specific_250\n"
"define 251 binhex site_specific_251\n"
"define 253 binhex site_specific_253\n"
"define 254 binhex site_specific_254\n"
"definend 1 binhex source_address\n"
"definend 2 binhex target_address\n"
"definend 3 index embed prefix_information\n"
"embed byte length\n"
"embed bitflags=LAH flags\n"
"embed uint32 vltime\n"
"embed uint32 pltime\n"
"embed uint32 reserved\n"
"embed array ip6address prefix\n"
"definend 5 embed mtu\n"
"embed uint16 reserved\n"
"embed uint32 mtu\n"
"definend 8 embed homeagent_information\n"
"embed uint16 reserved\n"
"embed uint16 preference\n"
"embed uint16 lifetime\n"
"definend 25 index embed rdnss\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed array ip6address servers\n"
"definend 31 index embed dnssl\n"
"embed uint16 reserved\n"
"embed uint32 lifetime\n"
"embed domain search\n"
"define6 1 binhex client_id\n"
"define6 2 binhex server_id\n"
"define6 3 norequest index embed ia_na\n"
"embed binhex:4 iaid\n"
"embed uint32 t1\n"
"embed uint32 t2\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 4 norequest index embed ia_ta\n"
"embed uint32 iaid\n"
"encap 5 option\n"
"encap 13 option\n"
"define6 5 norequest index embed ia_addr\n"
"embed ip6address ia_addr\n"
"embed uint32 pltime\n"
"embed uint32 vltime\n"
"encap 13 option\n"
"define6 6 array uint16 option_request\n"
"define6 7 byte preference\n"
"define6 8 uint16 elased_time\n"
"define6 9 binhex dhcp_relay_msg\n"
"define6 11 embed auth\n"
"embed byte protocol\n"
"embed byte algorithm\n"
"embed byte rdm\n"
"embed binhex:8 replay\n"
"embed binhex information\n"
"define6 12 ip6address unicast\n"
"define6 13 norequest embed status_code\n"
"embed uint16 status_code\n"
"embed optional string message\n"
"define6 14 norequest flag rapid_commit\n"
"define6 15 binhex user_class\n"
"define6 16 binhex vivco\n"
"define6 17 embed vivso\n"
"embed uint32 enterprise_number\n"
"define6 18 binhex interface_id\n"
"define6 19 byte reconfigure_msg\n"
"define6 20 flag reconfigure_accept\n"
"define6 21 array domain sip_servers_names\n"
"define6 22 array ip6address sip_servers_addresses\n"
"define6 23 array ip6address name_servers\n"
"define6 24 array domain domain_search\n"
"define6 25 norequest index embed ia_pd\n"
"embed binhex:4 iaid\n"
"embed uint32 t1\n"
"embed uint32 t2\n"
"encap 26 option\n"
"define6 26 index embed prefix\n"
"embed uint32 pltime\n"
"embed uint32 vltime\n"
"embed byte length\n"
"embed ip6address prefix\n"
"encap 13 option\n"
"encap 67 option\n"
"define6 27 array ip6address nis_servers\n"
"define6 28 array ip6address nisp_servers\n"
"define6 29 string nis_domain_name\n"
"define6 30 string nisp_domain_name\n"
"define6 31 array ip6address sntp_servers\n"
"define6 32 uint32 info_refresh_time\n"
"define6 33 array domain bcms_server_d\n"
"define6 34 array ip6address bcms_server_a\n"
"define6 36 encap geoconf_civic\n"
"embed byte what\n"
"embed uint16 country_code\n"
"define6 37 embed remote_id\n"
"embed uint32 enterprise_number\n"
"embed binhex remote_id\n"
"define6 38 binhex subscriber_id\n"
"define6 39 embed fqdn\n"
"embed bitflags=00000NOS flags\n"
"embed optional domain fqdn\n"
"define6 40 array ip6address pana_agent\n"
"define6 41 string posix_timezone\n"
"define6 42 string tzdb_timezone\n"
"define6 43 array uint16 ero\n"
"define6 49 domain mip6_hnidf\n"
"define6 50 encap mip6_vdinf\n"
"encap 71 option\n"
"encap 72 option\n"
"encap 73 option\n"
"define6 51 domain lost_server\n"
"define6 52 array ip6address capwap_ac\n"
"define6 53 binhex relay_id\n"
"define6 54 encap mos_ip\n"
"encap 1 array ip6address is\n"
"encap 2 array ip6address cs\n"
"encap 3 array ip6address es\n"
"define6 55 encap mos_domain\n"
"encap 1 domain is\n"
"encap 2 domain cs\n"
"encap 3 domain es\n"
"define6 56 encap ntp_server\n"
"encap 1 ip6address addr\n"
"encap 2 ip6address mcast_addr\n"
"encap 3 domain fqdn\n"
"define6 57 domain access_domain\n"
"define6 58 array domain sip_ua_cs_list\n"
"define6 59 uri bootfile_url\n"
"define6 60 binhex bootfile_param\n"
"define6 61 array uint16 architecture_types\n"
"define6 62 embed nii\n"
"embed byte type\n"
"embed byte major\n"
"embed byte minor\n"
"define6 63 binhex geoloc\n"
"define6 64 domain aftr_name\n"
"define6 67 embed pd_exclude\n"
"embed byte prefix_len\n"
"embed binhex subnetID\n"
"define6 69 encap mip6_idinf\n"
"encap 71 option\n"
"encap 72 option\n"
"encap 73 option\n"
"define6 70 encap mip6_udinf\n"
"encap 71 option\n"
"encap 72 option\n"
"encap 73 option\n"
"define6 71 embed mip6_hnp\n"
"embed byte prefix_len\n"
"embed ip6address prefix\n"
"define6 72 ip6address mip6_haa\n"
"define6 73 domain mip6_haf\n"
"define6 74 embed rdnss_selection\n"
"embed ip6address server\n"
"embed byte prf\n"
"embed array domain domains\n"
"define6 75 string krb_principal_name\n"
"define6 76 string krb_realm_name\n"
"define6 78 embed krb_kdc\n"
"embed uint16 priority\n"
"embed uint16 weight\n"
"embed byte transport_type\n"
"embed uint16 port\n"
"embed ip6address address\n"
"embed string realm_name\n"
"define6 80 ip6address link_address\n"
"define6 82 request uint32 sol_max_rt\n"
"define6 83 request uint32 inf_max_rt\n"
"define6 89 embed s46_rule\n"
"embed bitflags=0000000F flags\n"
"embed byte ea_len\n"
"embed byte prefix4_len\n"
"embed ipaddress ipv4_prefix\n"
"embed ip6address ipv6_prefix\n"
"define6 90 ip6address s64_br\n"
"define6 91 embed s46_dmr\n"
"embed byte prefix_len\n"
"embed binhex prefix\n"
"define6 92 embed s46_v4v6bind\n"
"embed ipaddress ipv4_address\n"
"embed byte ipv6_prefix_len\n"
"embed binhex ipv6_prefix_and_options\n"
"define6 93 embed s46_portparams\n"
"embed byte offset\n"
"embed byte psid_len\n"
"embed uint16 psid\n"
"define6 94 embed s46_cont_mape\n"
"encap 89 option\n"
"encap 90 option\n"
"define6 95 embed s46_cont_mapt\n"
"encap 89 option\n"
"encap 91 option\n"
"define6 96 embed s46_cont_lw\n"
"encap 90 option\n"
"encap 92 option\n"
"define6 112 string mudurl\n"
"define6 103 uri captive_portal_uri\n"
"define6 136 array uri sztp_redirect\n"
"define6 141 domain dots_ri\n"
"define6 142 array ip6address dots_address\n"
"define6 143 array ip6address andsf6\n"
#endif
"\0";

View File

@ -0,0 +1,38 @@
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifdef SMALL
#define INITDEFINES 25
#define INITDEFINENDS 6
#define INITDEFINE6S 14
#else
#define INITDEFINES 157
#define INITDEFINENDS 7
#define INITDEFINE6S 74
#endif
extern const char dhcpcd_embedded_conf[];

888
external/bsd/dhcpcd/dist/src/dhcpcd.8 vendored Normal file
View File

@ -0,0 +1,888 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2006-2023 Roy Marples
.\" 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.
.\"
.Dd December 10, 2023
.Dt DHCPCD 8
.Os
.Sh NAME
.Nm dhcpcd
.Nd a DHCP client
.Sh SYNOPSIS
.Nm
.Op Fl 146ABbDdEGgHJKLMNPpqTV
.Op Fl C , Fl Fl nohook Ar hook
.Op Fl c , Fl Fl script Ar script
.Op Fl e , Fl Fl env Ar value
.Op Fl F , Fl Fl fqdn Ar FQDN
.Op Fl f , Fl Fl config Ar file
.Op Fl h , Fl Fl hostname Ar hostname
.Op Fl I , Fl Fl clientid Ar clientid
.Op Fl i , Fl Fl vendorclassid Ar vendorclassid
.Op Fl j , Fl Fl logfile Ar logfile
.Op Fl l , Fl Fl leasetime Ar seconds
.Op Fl m , Fl Fl metric Ar metric
.Op Fl O , Fl Fl nooption Ar option
.Op Fl o , Fl Fl option Ar option
.Op Fl Q , Fl Fl require Ar option
.Op Fl r , Fl Fl request Ar address
.Op Fl S , Fl Fl static Ar value
.Op Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address
.Op Fl Fl inform6
.Op Fl t , Fl Fl timeout Ar seconds
.Op Fl u , Fl Fl userclass Ar class
.Op Fl v , Fl Fl vendor Ar code , Ar value
.Op Fl W , Fl Fl whitelist Ar address Ns Op Ar /cidr
.Op Fl w
.Op Fl Fl waitip Ns = Ns Op 4 | 6
.Op Fl y , Fl Fl reboot Ar seconds
.Op Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
.Op Fl Z , Fl Fl denyinterfaces Ar pattern
.Op Fl z , Fl Fl allowinterfaces Ar pattern
.Op Fl Fl inactive
.Op Fl Fl configure
.Op Fl Fl noconfigure
.Op interface
.Op ...
.Nm
.Fl n , Fl Fl rebind
.Op interface
.Nm
.Fl k , Fl Fl release
.Op interface
.Nm
.Fl U , Fl Fl dumplease
.Op Ar interface
.Nm
.Fl Fl version
.Nm
.Fl x , Fl Fl exit
.Op interface
.Sh DESCRIPTION
.Nm
is an implementation of the DHCP client specified in
.Li RFC 2131 .
.Nm
gets the host information
.Po
IP address, routes, etc
.Pc
from a DHCP server and configures the network
.Ar interface
of the
machine on which it is running.
.Nm
then runs the configuration script which writes DNS information to
.Xr resolvconf 8 ,
if available, otherwise directly to
.Pa /etc/resolv.conf .
If the hostname is currently blank, (null) or localhost, or
.Va force_hostname
is YES or TRUE or 1 then
.Nm
sets the hostname to the one supplied by the DHCP server.
.Nm
then daemonises and waits for the lease renewal time to lapse.
It will then attempt to renew its lease and reconfigure if the new lease
changes when the lease begins to expire or the DHCP server sends a message
to renew early.
.Pp
If any interface reports a working carrier then
.Nm
will try to obtain a lease before forking to the background,
otherwise it will fork right away.
This behaviour can be modified with the
.Fl b , Fl Fl background
and
.Fl w , Fl Fl waitip
options.
.Pp
.Nm
is also an implementation of the BOOTP client specified in
.Li RFC 951 .
.Pp
.Nm
is also an implementation of the IPv6 Router Solicitor as specified in
.Li RFC 4861
and
.Li RFC 6106 .
.Pp
.Nm
is also an implementation of the IPv6 Privacy Extensions to AutoConf as
specified in
.Li RFC 4941 .
This feature needs to be enabled in the kernel and
.Nm
will start using it.
.Pp
.Nm
is also an implementation of the DHCPv6 client as specified in
.Li RFC 3315 .
By default,
.Nm
only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement.
If no Identity Association is configured,
then a Non-temporary Address is requested.
.Ss Local Link configuration
If
.Nm
failed to obtain a lease, it probes for a valid IPv4LL address
.Po
aka ZeroConf, aka APIPA
.Pc .
Once obtained it restarts the process of looking for a DHCP server to get a
proper address.
.Pp
When using IPv4LL,
.Nm
nearly always succeeds and returns an exit code of 0.
In the rare case it fails, it normally means that there is a reverse ARP proxy
installed which always defeats IPv4LL probing.
To disable this behaviour, you can use the
.Fl L , Fl Fl noipv4ll
option.
.Ss Multiple interfaces
If a list of interfaces are given on the command line, then
.Nm
only works with those interfaces, otherwise
.Nm
discovers available Ethernet interfaces that can be configured.
When
.Nm
is not limited to one interface on the command line,
it is running in Manager mode.
The
.Nm dhcpcd-ui
project expects dhcpcd to be running this way.
.Pp
If a single interface is given then
.Nm
only works for that interface and runs as a separate instance to other
.Nm
processes.
The
.Fl w , Fl Fl waitip
option is enabled in this instance to maintain compatibility with older
versions.
Using a single interface,
optionally further limited to an address protocol,
also affects the
.Fl k ,
.Fl N ,
.Fl n
and
.Fl x
options, where the same interface and any address protocol
will need to be specified, as a lack of an
interface will imply Manager mode which this is not.
To force starting in Manager mode with only one interface, the
.Fl M , Fl Fl manager
option can be used.
.Pp
Interfaces are preferred by carrier, DHCP lease/IPv4LL and then lowest metric.
For systems that support route metrics, each route will be tagged with the
metric, otherwise
.Nm
changes the routes to use the interface with the same route and the lowest
metric.
See options below for controlling which interfaces we allow and deny through
the use of patterns.
.Pp
Non-ethernet interfaces and some virtual ethernet interfaces
such as TAP and bridge are ignored by default,
as is the FireWire interface.
To work with these devices they either need to be specified on the command line,
be listed in
.Fl Fl allowinterfaces
or have an interface directive in
.Pa /etc/dhcpcd.conf .
.Ss Hooking into events
.Nm
runs
.Pa /libexec/dhcpcd-run-hooks ,
or the script specified by the
.Fl c , Fl Fl script
option.
This script runs each script found in
.Pa /libexec/dhcpcd-hooks
in a lexical order.
The default installation supplies the scripts
.Pa 01-test ,
.Pa 20-resolv.conf
and
.Pa 30-hostname .
You can disable each script by using the
.Fl C , Fl Fl nohook
option.
See
.Xr dhcpcd-run-hooks 8
for details on how these scripts work.
.Nm
currently ignores the exit code of the script.
.Pp
More scripts are supplied in
.Pa /usr/share/dhcpcd/hooks
and need to be copied to
.Pa /libexec/dhcpcd-hooks
if you intend to use them.
For example, you could install
.Pa 29-lookup-hostname
so that
.Nm
can lookup the hostname of the IP address in DNS if no hostname
is given by the lease and one is not already set.
.Ss Fine tuning
You can fine-tune the behaviour of
.Nm
with the following options:
.Bl -tag -width indent
.It Fl b , Fl Fl background
Background immediately.
This is useful for startup scripts which don't disable link messages for
carrier status.
.It Fl c , Fl Fl script Ar script
Use this
.Ar script
instead of the default
.Pa /libexec/dhcpcd-run-hooks .
.It Fl D , Fl Fl duid Op Ar ll | lt | uuid | value
Use a DHCP Unique Identifier.
If a system UUID is available, that will be used to create a DUID-UUID,
otherwise if persistent storage is available then a DUID-LLT
(link local address + time) is generated,
otherwise DUID-LL is generated (link local address).
The DUID type can be hinted as an optional parameter if the file
.Pa /var/db/dhcpcd/duid
does not exist.
If not
.Va ll ,
.Va lt
or
.Va uuid
then
.Va value
will be converted from 00:11:22:33 format.
This, plus the IAID will be used as the
.Fl I , Fl Fl clientid .
The DUID generated will be held in
.Pa /var/db/dhcpcd/duid
and should not be copied to other hosts.
This file also takes precedence over the above rules except for setting a value.
.It Fl d , Fl Fl debug
Echo debug messages to the stderr and syslog.
.It Fl E , Fl Fl lastlease
If
.Nm
cannot obtain a lease, then try to use the last lease acquired for the
interface.
.It Fl Fl lastleaseextend
Same as the above, but the lease will be retained even if it expires.
.Nm
will give it up if any other host tries to claim it for their own via ARP.
This violates RFC 2131, section 3.7, which states the lease should be
dropped once it has expired.
.It Fl e , Fl Fl env Ar value
Push
.Ar value
to the environment for use in
.Xr dhcpcd-run-hooks 8 .
For example, you can force the hostname hook to always set the hostname with
.Fl e
.Va force_hostname=YES .
.It Fl g , Fl Fl reconfigure
.Nm
will re-apply IP address, routing and run
.Xr dhcpcd-run-hooks 8
for each interface.
This is useful so that a 3rd party such as PPP or VPN can change the routing
table and / or DNS, etc and then instruct
.Nm
to put things back afterwards.
.Nm
does not read a new configuration when this happens - you should rebind if you
need that functionality.
.It Fl F , Fl Fl fqdn Ar fqdn
Requests that the DHCP server update DNS using FQDN instead of just a
hostname.
Valid values for
.Ar fqdn
are disable, none, ptr and both.
.Nm
itself never does any DNS updates.
.Nm
encodes the FQDN hostname as specified in
.Li RFC 1035 .
.It Fl f , Fl Fl config Ar file
Specify a config to load instead of
.Pa /etc/dhcpcd.conf .
.Nm
always processes the config file before any command line options.
.It Fl h , Fl Fl hostname Ar hostname
Sends
.Ar hostname
to the DHCP server so it can be registered in DNS.
If
.Ar hostname
is an empty string then the current system hostname is sent.
If
.Ar hostname
is a FQDN (i.e., contains a .) then it will be encoded as such.
.It Fl I , Fl Fl clientid Ar clientid
Send the
.Ar clientid .
If the string is of the format 01:02:03 then it is encoded as hex.
For interfaces whose hardware address is longer than 8 bytes, or if the
.Ar clientid
is an empty string then
.Nm
sends a default
.Ar clientid
of the hardware family and the hardware address.
.It Fl i , Fl Fl vendorclassid Ar vendorclassid
Override the DHCPv4
.Ar vendorclassid
field sent.
The default is
dhcpcd-<version>:<os>:<machine>:<platform>.
For example
.D1 dhcpcd-5.5.6:NetBSD-6.99.5:i386:i386
If not set then none is sent.
Some badly configured DHCP servers reject unknown vendorclassids.
To work around it, try and impersonate Windows by using the MSFT vendorclassid.
.It Fl j , Fl Fl logfile Ar logfile
Writes to the specified
.Ar logfile .
.Nm
still writes to
.Xr syslog 3 .
The
.Ar logfile
is reopened when
.Nm
receives the
.Dv SIGUSR2
signal.
.It Fl k , Fl Fl release Op Ar interface
This causes an existing
.Nm
process running on the
.Ar interface
to release its lease and de-configure the
.Ar interface
regardless of the
.Fl p , Fl Fl persistent
option.
If no
.Ar interface
is specified then this applies to all interfaces in Manager mode.
If no interfaces are left running,
.Nm
will exit.
.It Fl l , Fl Fl leasetime Ar seconds
Request a lease time of
.Ar seconds .
.Ar -1
represents an infinite lease time.
By default
.Nm
does not request any lease time and leaves it in the hands of the
DHCP server.
.It Fl M , Fl Fl manager
Start
.Nm
in Manager mode even if only one interface specified on the command line.
See the Multiple Interfaces section above.
.It Fl m , Fl Fl metric Ar metric
Metrics are used to prefer an interface over another one, lowest wins.
.Nm
will supply a default metric of 1000 +
.Xr if_nametoindex 3 .
This will be offset by 2000 for wireless interfaces, with additional offsets
of 1000000 for IPv4LL and 2000000 for roaming interfaces.
.It Fl n , Fl Fl rebind Op Ar interface
Notifies
.Nm
to reload its configuration and rebind the specified
.Ar interface .
If no
.Ar interface
is specified then this applies to all interfaces in Manager mode.
If
.Nm
is not running, then it starts up as normal.
.It Fl N , Fl Fl renew Op Ar interface
Notifies
.Nm
to renew existing addresses on the specified
.Ar interface .
If no
.Ar interface
is specified then this applies to all interfaces in Manager mode.
If
.Nm
is not running, then it starts up as normal.
Unlike the
.Fl n , Fl Fl rebind
option above, the configuration for
.Nm
is not reloaded.
.It Fl o , Fl Fl option Ar option
Request the DHCP
.Ar option
variable for use in
.Pa /libexec/dhcpcd-run-hooks .
.It Fl p , Fl Fl persistent
.Nm
de-configures the
.Ar interface
when it exits unless this option is enabled.
Sometimes, this isn't desirable if, for example, you have root mounted over
NFS or SSH clients connect to this host and they need to be notified of
the host shutting down.
You can use this option to stop this from happening.
.It Fl r , Fl Fl request Ar address
Request the
.Ar address
in the DHCP DISCOVER message.
There is no guarantee this is the address the DHCP server will actually give.
If no
.Ar address
is given then the first address currently assigned to the
.Ar interface
is used.
.It Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address
Behaves like
.Fl r , Fl Fl request
as above, but sends a DHCP INFORM instead of DISCOVER/REQUEST.
This does not get a lease as such, just notifies the DHCP server of the
.Ar address
in use.
You should also include the optional
.Ar cidr
network number in case the address is not already configured on the interface.
.Nm
remains running and pretends it has an infinite lease.
.Nm
will not de-configure the interface when it exits.
If
.Nm
fails to contact a DHCP server then it returns a failure instead of falling
back on IPv4LL.
.It Fl Fl inform6
Performs a DHCPv6 Information Request.
No address is requested or specified, but all other DHCPv6 options are allowed.
This is normally performed automatically when the IPv6 Router Advertises
that the client should perform this operation.
This option is only needed when
.Nm
is not processing IPv6RA messages and the need for DHCPv6 Information Request
exists.
.It Fl S , Fl Fl static Ar value
Configures a static DHCP
.Ar value .
If you set
.Ic ip_address
then
.Nm
will not attempt to obtain a lease and just use the value for the address with
an infinite lease time.
.Pp
Here is an example which configures a static address, routes and DNS.
.D1 dhcpcd -S ip_address=192.168.0.10/24 \e
.D1 -S routers=192.168.0.1 \e
.D1 -S domain_name_servers=192.168.0.1 \e
.D1 eth0
.Pp
You cannot presently set static DHCPv6 values.
Use the
.Fl e , Fl Fl env
option instead.
.It Fl t , Fl Fl timeout Ar seconds
Timeout after
.Ar seconds ,
instead of the default 30.
A setting of 0
.Ar seconds
causes
.Nm
to wait forever to get a lease.
If
.Nm
is working on a single interface then
.Nm
will exit when a timeout occurs, otherwise
.Nm
will fork into the background.
.It Fl u , Fl Fl userclass Ar class
Tags the DHCPv4 message with the userclass
.Ar class .
DHCP servers use this to give members of the class DHCP options other than the
default, without having to know things like hardware address or hostname.
.It Fl v , Fl Fl vendor Ar code , Ns Ar value
Add an encapsulated vendor option.
.Ar code
should be between 1 and 254 inclusive.
To add a raw vendor string, omit
.Ar code
but keep the comma.
Examples.
.Pp
Set the vendor option 01 with an IP address.
.D1 dhcpcd \-v 01,192.168.0.2 eth0
Set the vendor option 02 with a hex code.
.D1 dhcpcd \-v 02,01:02:03:04:05 eth0
Set the vendor option 03 with an IP address as a string.
.D1 dhcpcd \-v 03,\e"192.168.0.2\e" eth0
Set un-encapsulated vendor option to hello world.
.D1 dhcpcd \-v ,"hello world" eth0
.It Fl Fl version
Display both program version and copyright information.
.Nm
then exits before doing any configuration.
.It Fl w
Wait for an address to be assigned before forking to the background.
Does not take an argument, unlike the below option.
.It Fl Fl waitip Ns = Ns Op 4 | 6
Wait for an address to be assigned before forking to the background.
4 means wait for an IPv4 address to be assigned.
6 means wait for an IPv6 address to be assigned.
If no argument is given,
.Nm
will wait for any address protocol to be assigned.
It is possible to wait for more than one address protocol and
.Nm
will only fork to the background when all waiting conditions are satisfied.
.It Fl x , Fl Fl exit Op Ar interface
This will signal an existing
.Nm
process running on the
.Ar interface
to exit.
If no
.Ar interface
is specified, then the above is applied to all interfaces in Manager mode.
See the
.Fl p , Fl Fl persistent
option to control configuration persistence on exit,
which is enabled by default in
.Xr dhcpcd.conf 5 .
.Nm
then waits until this process has exited.
.It Fl y , Fl Fl reboot Ar seconds
Allow
.Ar reboot
seconds before moving to the discover phase if we have an old lease to use.
Allow
.Ar reboot
seconds before starting fallback states from the discover phase.
IPv4LL is started when the first
.Ar reboot
timeout is reached.
The default is 5 seconds.
A setting of 0 seconds causes
.Nm
to skip the reboot phase and go straight into discover.
This has no effect on DHCPv6 other than skipping the reboot phase.
.El
.Ss Restricting behaviour
.Nm
will try to do as much as it can by default.
However, there are sometimes situations where you don't want the things to be
configured exactly how the DHCP server wants.
Here are some options that deal with turning these bits off.
.Pp
Note that when
.Nm
is restricted to a single interface then the interface also needs to be
specified when asking
.Nm
to exit using the commandline.
If the protocol is restricted as well then the protocol needs to be included
with the exit instruction.
.Bl -tag -width indent
.It Fl 1 , Fl Fl oneshot
Exit after configuring an interface.
Use the
.Fl w , Fl Fl waitip
option to specify which protocol(s) to configure before exiting.
.It Fl 4 , Fl Fl ipv4only
Configure IPv4 only.
.It Fl 6 , Fl Fl ipv6only
Configure IPv6 only.
.It Fl A , Fl Fl noarp
Don't request or claim the address by ARP.
This also disables IPv4LL.
.It Fl B , Fl Fl nobackground
Don't run in the background when we acquire a lease.
This is mainly useful for running under the control of another process, such
as a debugger or a network manager.
.It Fl C , Fl Fl nohook Ar script
Don't run this hook script.
Matches full name, or prefixed with 2 numbers optionally ending with
.Pa .sh .
.Pp
So to stop
.Nm
from touching your DNS settings you would do:-
.D1 dhcpcd -C resolv.conf eth0
.It Fl G , Fl Fl nogateway
Don't set any default routes.
.It Fl H , Fl Fl xidhwaddr
Use the last four bytes of the hardware address as the DHCP xid instead
of a randomly generated number.
.It Fl J , Fl Fl broadcast
Instructs the DHCP server to broadcast replies back to the client.
Normally this is only set for non-Ethernet interfaces,
such as FireWire and InfiniBand.
In most instances,
.Nm
will set this automatically.
.It Fl K , Fl Fl nolink
Don't receive link messages for carrier status.
You should only have to use this with buggy device drivers or running
.Nm
through a network manager.
.It Fl L , Fl Fl noipv4ll
Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf).
.It Fl O , Fl Fl nooption Ar option
Removes the
.Ar option
from the DHCP message before processing.
.It Fl P , Fl Fl printpidfile
Print the
.Pa pidfile
.Nm
will use based on command-line arguments to stdout.
.It Fl Q , Fl Fl require Ar option
Requires the
.Ar option
to be present in all DHCP messages, otherwise the message is ignored.
To enforce that
.Nm
only responds to DHCP servers and not BOOTP servers, you can
.Fl Q
.Ar dhcp_message_type .
.It Fl q , Fl Fl quiet
Quiet
.Nm
on the command line, only warnings and errors will be displayed.
If this option is used another time then all console output is disabled.
These messages are still logged via
.Xr syslog 3 .
.It Fl T , Fl Fl test
On receipt of DHCP messages just call
.Pa /libexec/dhcpcd-run-hooks
with the reason of TEST which echos the DHCP variables found in the message
to the console.
The interface configuration isn't touched and neither are any configuration
files.
The
.Ar rapid_commit
option is not sent in TEST mode so that the server does not lease an address.
To test INFORM the interface needs to be configured with the desired address
before starting
.Nm .
.It Fl U , Fl Fl dumplease Op Ar interface
Dumps the current lease for the
.Ar interface
to stdout.
If no
.Ar interface
is given then all interfaces are dumped.
Use the
.Fl 4
or
.Fl 6
flags to specify an address family.
If a lease is piped in via standard input then that is dumped.
In this case, specifying an address family is mandatory.
.It Fl V , Fl Fl variables
Display a list of option codes, the associated variable and encoding for use in
.Xr dhcpcd-run-hooks 8 .
Variables are prefixed with new_ and old_ unless the option number is -.
Variables without an option are part of the DHCP message and cannot be
directly requested.
.It Fl W , Fl Fl whitelist Ar address Ns Op /cidr
Only accept packets from
.Ar address Ns Op /cidr .
.Fl X , Fl Fl blacklist
is ignored if
.Fl W , Fl Fl whitelist
is set.
.It Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
Ignore all packets from
.Ar address Ns Op Ar /cidr .
.It Fl Z , Fl Fl denyinterfaces Ar pattern
When discovering interfaces, the interface name must not match
.Ar pattern
which is a space or comma separated list of patterns passed to
.Xr fnmatch 3 .
.It Fl z , Fl Fl allowinterfaces Ar pattern
When discovering interfaces, the interface name must match
.Ar pattern
which is a space or comma separated list of patterns passed to
.Xr fnmatch 3 .
If the same interface is matched in
.Fl Z , Fl Fl denyinterfaces
then it is still denied.
.It Fl Fl inactive
Don't start any interfaces other than those specified on the command line.
This allows
.Nm
to be started in Manager mode and then wait for subsequent
.Nm
commands to start each interface as required.
.It Fl Fl configure
Allows
.Nm
to configure the system.
This is the default behaviour and sets
.Ev if_configured=true .
.It Fl Fl noconfigure
.Nm
will not configure the system at all.
This is only of use if the
.Fl Fl script
that
.Nm
calls at each network event configures the system instead.
This is different from
.Fl T , Fl Fl test
mode in that it's not one shot and the only change to the environment is the
addition of
.Ev if_configured=false .
.It Fl Fl nodev
Don't load any
.Pa /dev
management modules.
.El
.Sh 3RDPARTY LINK MANAGEMENT
Some interfaces require configuration by 3rd parties, such as PPP or VPN.
When an interface configuration in
.Nm
is marked as STATIC or INFORM without an address then
.Nm
will monitor the interface until an address is added or removed from it and
act accordingly.
For point to point interfaces (like PPP), a default route to its
destination is automatically added to the configuration.
If the point to point interface is configured for INFORM, then
.Nm
unicasts INFORM to the destination, otherwise it defaults to STATIC.
.Sh NOTES
.Nm
requires a Berkeley Packet Filter, or BPF device on BSD based systems and a
Linux Socket Filter, or LPF device on Linux based systems for all IPv4
configuration.
.Pp
If restricting
.Nm
to a single interface and optionally address family via the command-line
then all further calls to
.Nm
to rebind, reconfigure or exit need to include the same restrictive flags
so that
.Nm
knows which process to signal.
.Pp
Some DHCP servers implement ClientID filtering.
If
.Nm
is replacing an in-use DHCP client then you might need to adjust the clientid
option
.Nm
sends to match.
If using a DUID in place of the ClientID, edit
.Pa /var/db/dhcpcd/duid
accordingly.
.Sh FILES
.Bl -ohang
.It Pa /etc/dhcpcd.conf
Configuration file for dhcpcd.
If you always use the same options, put them here.
.It Pa /libexec/dhcpcd-run-hooks
Bourne shell script that is run to configure or de-configure an interface.
.It Pa /lib/dhcpcd/dev
Linux
.Pa /dev
management modules.
.It Pa /libexec/dhcpcd-hooks
A directory containing Bourne shell scripts that are run by the above script.
Each script can be disabled by using the
.Fl C , Fl Fl nohook
option described above.
.It Pa /var/db/dhcpcd/duid
Text file that holds the DUID used to identify the host.
.It Pa /var/db/dhcpcd/secret
Text file that holds a secret key known only to the host.
.It Pa /var/db/dhcpcd/ Ns Ar interface Ns Ar -ssid Ns .lease
The actual DHCP message sent by the server.
We use this when reading the last
lease and use the file's mtime as when it was issued.
.It Pa /var/db/dhcpcd/ Ns Ar interface Ns Ar -ssid Ns .lease6
The actual DHCPv6 message sent by the server.
We use this when reading the last
lease and use the file's mtime as when it was issued.
.It Pa /var/db/dhcpcd/rdm_monotonic
Stores the monotonic counter used in the
.Ar replay
field in Authentication Options.
.It Pa /var/run/dhcpcd/pid
Stores the PID of
.Nm
running on all interfaces.
.It Pa /var/run/dhcpcd/ Ns Ar interface Ns .pid
Stores the PID of
.Nm
running on the
.Ar interface .
.It Pa /var/run/dhcpcd/sock
Control socket to the manager daemon.
.It Pa /var/run/dhcpcd/unpriv.sock
Unprivileged socket to the manager daemon, only allows state retrieval.
.It Pa /var/run/dhcpcd/ Ns Ar interface Ns .sock
Control socket to per interface daemon.
.It Pa /var/run/dhcpcd/ Ns Ar interface Ns .unpriv.sock
Unprivileged socket to per interface daemon, only allows state retrieval.
.El
.Sh SEE ALSO
.Xr fnmatch 3 ,
.Xr if_nametoindex 3 ,
.Xr dhcpcd.conf 5 ,
.Xr resolv.conf 5 ,
.Xr dhcpcd-run-hooks 8 ,
.Xr resolvconf 8
.Sh STANDARDS
RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855,
RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6355,
RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Please report them to
.Lk https://roy.marples.name/projects/dhcpcd

882
external/bsd/dhcpcd/dist/src/dhcpcd.8.in vendored Normal file
View File

@ -0,0 +1,882 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2006-2020 Roy Marples
.\" 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.
.\"
.Dd November 25, 2020
.Dt DHCPCD 8
.Os
.Sh NAME
.Nm dhcpcd
.Nd a DHCP client
.Sh SYNOPSIS
.Nm
.Op Fl 146ABbDdEGgHJKLMNPpqTV
.Op Fl C , Fl Fl nohook Ar hook
.Op Fl c , Fl Fl script Ar script
.Op Fl e , Fl Fl env Ar value
.Op Fl F , Fl Fl fqdn Ar FQDN
.Op Fl f , Fl Fl config Ar file
.Op Fl h , Fl Fl hostname Ar hostname
.Op Fl I , Fl Fl clientid Ar clientid
.Op Fl i , Fl Fl vendorclassid Ar vendorclassid
.Op Fl j , Fl Fl logfile Ar logfile
.Op Fl l , Fl Fl leasetime Ar seconds
.Op Fl m , Fl Fl metric Ar metric
.Op Fl O , Fl Fl nooption Ar option
.Op Fl o , Fl Fl option Ar option
.Op Fl Q , Fl Fl require Ar option
.Op Fl r , Fl Fl request Ar address
.Op Fl S , Fl Fl static Ar value
.Op Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address
.Op Fl Fl inform6
.Op Fl t , Fl Fl timeout Ar seconds
.Op Fl u , Fl Fl userclass Ar class
.Op Fl v , Fl Fl vendor Ar code , Ar value
.Op Fl W , Fl Fl whitelist Ar address Ns Op Ar /cidr
.Op Fl w
.Op Fl Fl waitip Ns = Ns Op 4 | 6
.Op Fl y , Fl Fl reboot Ar seconds
.Op Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
.Op Fl Z , Fl Fl denyinterfaces Ar pattern
.Op Fl z , Fl Fl allowinterfaces Ar pattern
.Op Fl Fl inactive
.Op Fl Fl configure
.Op Fl Fl noconfigure
.Op interface
.Op ...
.Nm
.Fl n , Fl Fl rebind
.Op interface
.Nm
.Fl k , Fl Fl release
.Op interface
.Nm
.Fl U , Fl Fl dumplease
.Op Ar interface
.Nm
.Fl Fl version
.Nm
.Fl x , Fl Fl exit
.Op interface
.Sh DESCRIPTION
.Nm
is an implementation of the DHCP client specified in
.Li RFC 2131 .
.Nm
gets the host information
.Po
IP address, routes, etc
.Pc
from a DHCP server and configures the network
.Ar interface
of the
machine on which it is running.
.Nm
then runs the configuration script which writes DNS information to
.Xr resolvconf 8 ,
if available, otherwise directly to
.Pa /etc/resolv.conf .
If the hostname is currently blank, (null) or localhost, or
.Va force_hostname
is YES or TRUE or 1 then
.Nm
sets the hostname to the one supplied by the DHCP server.
.Nm
then daemonises and waits for the lease renewal time to lapse.
It will then attempt to renew its lease and reconfigure if the new lease
changes when the lease begins to expire or the DHCP server sends a message
to renew early.
.Pp
If any interface reports a working carrier then
.Nm
will try to obtain a lease before forking to the background,
otherwise it will fork right away.
This behaviour can be modified with the
.Fl b , Fl Fl background
and
.Fl w , Fl Fl waitip
options.
.Pp
.Nm
is also an implementation of the BOOTP client specified in
.Li RFC 951 .
.Pp
.Nm
is also an implementation of the IPv6 Router Solicitor as specified in
.Li RFC 4861
and
.Li RFC 6106 .
.Pp
.Nm
is also an implementation of the IPv6 Privacy Extensions to AutoConf as
specified in
.Li RFC 4941 .
This feature needs to be enabled in the kernel and
.Nm
will start using it.
.Pp
.Nm
is also an implementation of the DHCPv6 client as specified in
.Li RFC 3315 .
By default,
.Nm
only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement.
If no Identity Association is configured,
then a Non-temporary Address is requested.
.Ss Local Link configuration
If
.Nm
failed to obtain a lease, it probes for a valid IPv4LL address
.Po
aka ZeroConf, aka APIPA
.Pc .
Once obtained it restarts the process of looking for a DHCP server to get a
proper address.
.Pp
When using IPv4LL,
.Nm
nearly always succeeds and returns an exit code of 0.
In the rare case it fails, it normally means that there is a reverse ARP proxy
installed which always defeats IPv4LL probing.
To disable this behaviour, you can use the
.Fl L , Fl Fl noipv4ll
option.
.Ss Multiple interfaces
If a list of interfaces are given on the command line, then
.Nm
only works with those interfaces, otherwise
.Nm
discovers available Ethernet interfaces that can be configured.
When
.Nm
not limited to one interface on the command line,
it is running in Master mode.
The
.Nm dhcpcd-ui
project expects dhcpcd to be running this way.
.Pp
If a single interface is given then
.Nm
only works for that interface and runs as a separate instance to other
.Nm
processes.
.Fl w , Fl Fl waitip
option is enabled in this instance to maintain compatibility with older
versions.
Using a single interface also affects the
.Fl k ,
.Fl N ,
.Fl n
and
.Fl x
options, where the same interface will need to be specified, as a lack of an
interface will imply Master mode which this is not.
To force starting in Master mode with only one interface, the
.Fl M , Fl Fl master
option can be used.
.Pp
Interfaces are preferred by carrier, DHCP lease/IPv4LL and then lowest metric.
For systems that support route metrics, each route will be tagged with the
metric, otherwise
.Nm
changes the routes to use the interface with the same route and the lowest
metric.
See options below for controlling which interfaces we allow and deny through
the use of patterns.
.Pp
Non-ethernet interfaces and some virtual ethernet interfaces
such as TAP and bridge are ignored by default,
as is the FireWire interface.
To work with these devices they either need to be specified on the command line,
be listed in
.Fl Fl allowinterfaces
or have an interface directive in
.Pa @SYSCONFDIR@/dhcpcd.conf .
.Ss Hooking into events
.Nm
runs
.Pa @SCRIPT@ ,
or the script specified by the
.Fl c , Fl Fl script
option.
This script runs each script found in
.Pa @HOOKDIR@
in a lexical order.
The default installation supplies the scripts
.Pa 01-test ,
.Pa 02-dump ,
.Pa 20-resolv.conf
and
.Pa 30-hostname .
You can disable each script by using the
.Fl C , Fl Fl nohook
option.
See
.Xr dhcpcd-run-hooks 8
for details on how these scripts work.
.Nm
currently ignores the exit code of the script.
.Pp
More scripts are supplied in
.Pa @DATADIR@/dhcpcd/hooks
and need to be copied to
.Pa @HOOKDIR@
if you intend to use them.
For example, you could install
.Pa 29-lookup-hostname
so that
.Nm
can lookup the hostname of the IP address in DNS if no hostname
is given by the lease and one is not already set.
.Ss Fine tuning
You can fine-tune the behaviour of
.Nm
with the following options:
.Bl -tag -width indent
.It Fl b , Fl Fl background
Background immediately.
This is useful for startup scripts which don't disable link messages for
carrier status.
.It Fl c , Fl Fl script Ar script
Use this
.Ar script
instead of the default
.Pa @SCRIPT@ .
.It Fl D , Fl Fl duid Op Ar ll | lt | uuid | value
Use a DHCP Unique Identifier.
If a system UUID is available, that will be used to create a DUID-UUID,
otheriwse if persistent storage is available then a DUID-LLT
(link local address + time) is generated,
otherwise DUID-LL is generated (link local address).
The DUID type can be hinted as an optional parameter if the file
.Pa @DBDIR@/duid
does not exist.
If not
.Va ll ,
.Va lt
or
.Va uuid
then
.Va value
will be converted from 00:11:22:33 format.
This, plus the IAID will be used as the
.Fl I , Fl Fl clientid .
The DUID generated will be held in
.Pa @DBDIR@/duid
and should not be copied to other hosts.
This file also takes precedence over the above rules except for setting a value.
.It Fl d , Fl Fl debug
Echo debug messages to the stderr and syslog.
.It Fl E , Fl Fl lastlease
If
.Nm
cannot obtain a lease, then try to use the last lease acquired for the
interface.
.It Fl Fl lastleaseextend
Same as the above, but the lease will be retained even if it expires.
.Nm
will give it up if any other host tries to claim it for their own via ARP.
This violates RFC 2131, section 3.7, which states the lease should be
dropped once it has expired.
.It Fl e , Fl Fl env Ar value
Push
.Ar value
to the environment for use in
.Xr dhcpcd-run-hooks 8 .
For example, you can force the hostname hook to always set the hostname with
.Fl e
.Va force_hostname=YES .
.It Fl g , Fl Fl reconfigure
.Nm
will re-apply IP address, routing and run
.Xr dhcpcd-run-hooks 8
for each interface.
This is useful so that a 3rd party such as PPP or VPN can change the routing
table and / or DNS, etc and then instruct
.Nm
to put things back afterwards.
.Nm
does not read a new configuration when this happens - you should rebind if you
need that functionality.
.It Fl F , Fl Fl fqdn Ar fqdn
Requests that the DHCP server updates DNS using FQDN instead of just a
hostname.
Valid values for
.Ar fqdn
are disable, none, ptr and both.
.Nm
itself never does any DNS updates.
.Nm
encodes the FQDN hostname as specified in
.Li RFC 1035 .
.It Fl f , Fl Fl config Ar file
Specify a config to load instead of
.Pa @SYSCONFDIR@/dhcpcd.conf .
.Nm
always processes the config file before any command line options.
.It Fl h , Fl Fl hostname Ar hostname
Sends
.Ar hostname
to the DHCP server so it can be registered in DNS.
If
.Ar hostname
is an empty string then the current system hostname is sent.
If
.Ar hostname
is a FQDN (i.e., contains a .) then it will be encoded as such.
.It Fl I , Fl Fl clientid Ar clientid
Send the
.Ar clientid .
If the string is of the format 01:02:03 then it is encoded as hex.
For interfaces whose hardware address is longer than 8 bytes, or if the
.Ar clientid
is an empty string then
.Nm
sends a default
.Ar clientid
of the hardware family and the hardware address.
.It Fl i , Fl Fl vendorclassid Ar vendorclassid
Override the DHCPv4
.Ar vendorclassid
field sent.
The default is
dhcpcd-<version>:<os>:<machine>:<platform>.
For example
.D1 dhcpcd-5.5.6:NetBSD-6.99.5:i386:i386
If not set then none is sent.
Some badly configured DHCP servers reject unknown vendorclassids.
To work around it, try and impersonate Windows by using the MSFT vendorclassid.
.It Fl j , Fl Fl logfile Ar logfile
Writes to the specified
.Ar logfile .
.Nm
still writes to
.Xr syslog 3 .
The
.Ar logfile
is reopened when
.Nm
receives the
.Dv SIGUSR2
signal.
.It Fl k , Fl Fl release Op Ar interface
This causes an existing
.Nm
process running on the
.Ar interface
to release its lease and de-configure the
.Ar interface
regardless of the
.Fl p , Fl Fl persistent
option.
If no
.Ar interface
is specified then this applies to all interfaces in Master mode.
If no interfaces are left running,
.Nm
will exit.
.It Fl l , Fl Fl leasetime Ar seconds
Request a lease time of
.Ar seconds .
.Ar -1
represents an infinite lease time.
By default
.Nm
does not request any lease time and leaves it in the hands of the
DHCP server.
.It Fl M , Fl Fl master
Start
.Nm
in Master mode even if only one interface specified on the command line.
See the Multiple Interfaces section above.
.It Fl m , Fl Fl metric Ar metric
Metrics are used to prefer an interface over another one, lowest wins.
.Nm
will supply a default metic of 200 +
.Xr if_nametoindex 3 .
An extra 100 will be added for wireless interfaces.
.It Fl n , Fl Fl rebind Op Ar interface
Notifies
.Nm
to reload its configuration and rebind the specified
.Ar interface .
If no
.Ar interface
is specified then this applies to all interfaces in Master mode.
If
.Nm
is not running, then it starts up as normal.
.It Fl N , Fl Fl renew Op Ar interface
Notifies
.Nm
to renew existing addresses on the specified
.Ar interface .
If no
.Ar interface
is specified then this applies to all interfaces in Master mode.
If
.Nm
is not running, then it starts up as normal.
Unlike the
.Fl n , Fl Fl rebind
option above, the configuration for
.Nm
is not reloaded.
.It Fl o , Fl Fl option Ar option
Request the DHCP
.Ar option
variable for use in
.Pa @SCRIPT@ .
.It Fl p , Fl Fl persistent
.Nm
normally de-configures the
.Ar interface
and configuration when it exits.
Sometimes, this isn't desirable if, for example, you have root mounted over
NFS or SSH clients connect to this host and they need to be notified of
the host shutting down.
You can use this option to stop this from happening.
.It Fl r , Fl Fl request Ar address
Request the
.Ar address
in the DHCP DISCOVER message.
There is no guarantee this is the address the DHCP server will actually give.
If no
.Ar address
is given then the first address currently assigned to the
.Ar interface
is used.
.It Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address
Behaves like
.Fl r , Fl Fl request
as above, but sends a DHCP INFORM instead of DISCOVER/REQUEST.
This does not get a lease as such, just notifies the DHCP server of the
.Ar address
in use.
You should also include the optional
.Ar cidr
network number in case the address is not already configured on the interface.
.Nm
remains running and pretends it has an infinite lease.
.Nm
will not de-configure the interface when it exits.
If
.Nm
fails to contact a DHCP server then it returns a failure instead of falling
back on IPv4LL.
.It Fl Fl inform6
Performs a DHCPv6 Information Request.
No address is requested or specified, but all other DHCPv6 options are allowed.
This is normally performed automatically when the IPv6 Router Advertises
that the client should perform this operation.
This option is only needed when
.Nm
is not processing IPv6RA messages and the need for DHCPv6 Information Request
exists.
.It Fl S , Fl Fl static Ar value
Configures a static DHCP
.Ar value .
If you set
.Ic ip_address
then
.Nm
will not attempt to obtain a lease and just use the value for the address with
an infinite lease time.
.Pp
Here is an example which configures a static address, routes and DNS.
.D1 dhcpcd -S ip_address=192.168.0.10/24 \e
.D1 -S routers=192.168.0.1 \e
.D1 -S domain_name_servers=192.168.0.1 \e
.D1 eth0
.Pp
You cannot presently set static DHCPv6 values.
Use the
.Fl e , Fl Fl env
option instead.
.It Fl t , Fl Fl timeout Ar seconds
Timeout after
.Ar seconds ,
instead of the default 30.
A setting of 0
.Ar seconds
causes
.Nm
to wait forever to get a lease.
If
.Nm
is working on a single interface then
.Nm
will exit when a timeout occurs, otherwise
.Nm
will fork into the background.
.It Fl u , Fl Fl userclass Ar class
Tags the DHCPv4 message with the userclass
.Ar class .
DHCP servers use this to give members of the class DHCP options other than the
default, without having to know things like hardware address or hostname.
.It Fl v , Fl Fl vendor Ar code , Ns Ar value
Add an encapsulated vendor option.
.Ar code
should be between 1 and 254 inclusive.
To add a raw vendor string, omit
.Ar code
but keep the comma.
Examples.
.Pp
Set the vendor option 01 with an IP address.
.D1 dhcpcd \-v 01,192.168.0.2 eth0
Set the vendor option 02 with a hex code.
.D1 dhcpcd \-v 02,01:02:03:04:05 eth0
Set the vendor option 03 with an IP address as a string.
.D1 dhcpcd \-v 03,\e"192.168.0.2\e" eth0
Set un-encapsulated vendor option to hello world.
.D1 dhcpcd \-v ,"hello world" eth0
.It Fl Fl version
Display both program version and copyright information.
.Nm
then exits before doing any configuration.
.It Fl w
Wait for an address to be assigned before forking to the background.
Does not take an argument, unlike the below option.
.It Fl Fl waitip Ns = Ns Op 4 | 6
Wait for an address to be assigned before forking to the background.
4 means wait for an IPv4 address to be assigned.
6 means wait for an IPv6 address to be assigned.
If no argument is given,
.Nm
will wait for any address protocol to be assigned.
It is possible to wait for more than one address protocol and
.Nm
will only fork to the background when all waiting conditions are satisfied.
.It Fl x , Fl Fl exit Op Ar interface
This will signal an existing
.Nm
process running on the
.Ar interface
to exit.
If no
.Ar interface
is specified, then the above is applied to all interfaces in Master mode.
See the
.Fl p , Fl Fl persistent
option to control configuration persistence on exit,
which is enabled by default in
.Xr dhcpcd.conf 5 .
.Nm
then waits until this process has exited.
.It Fl y , Fl Fl reboot Ar seconds
Allow
.Ar reboot
seconds before moving to the discover phase if we have an old lease to use.
Allow
.Ar reboot
seconds before starting fallback states from the discover phase.
IPv4LL is started when the first
.Ar reboot
timeout is reached.
The default is 5 seconds.
A setting of 0 seconds causes
.Nm
to skip the reboot phase and go straight into discover.
This has no effect on DHCPv6 other than skipping the reboot phase.
.El
.Ss Restricting behaviour
.Nm
will try to do as much as it can by default.
However, there are sometimes situations where you don't want the things to be
configured exactly how the DHCP server wants.
Here are some options that deal with turning these bits off.
.Pp
Note that when
.Nm
is restricted to a single interface then the interface also needs to be
specified when asking
.Nm
to exit using the commandline.
If the protocol is restricted as well then the protocol needs to be included
with the exit instruction.
.Bl -tag -width indent
.It Fl 1 , Fl Fl oneshot
Exit after configuring an interface.
Use the
.Fl w , Fl Fl waitip
option to specify which protocol(s) to configure before exiting.
.It Fl 4 , Fl Fl ipv4only
Configure IPv4 only.
.It Fl 6 , Fl Fl ipv6only
Configure IPv6 only.
.It Fl A , Fl Fl noarp
Don't request or claim the address by ARP.
This also disables IPv4LL.
.It Fl B , Fl Fl nobackground
Don't run in the background when we acquire a lease.
This is mainly useful for running under the control of another process, such
as a debugger or a network manager.
.It Fl C , Fl Fl nohook Ar script
Don't run this hook script.
Matches full name, or prefixed with 2 numbers optionally ending with
.Pa .sh .
.Pp
So to stop
.Nm
from touching your DNS settings you would do:-
.D1 dhcpcd -C resolv.conf eth0
.It Fl G , Fl Fl nogateway
Don't set any default routes.
.It Fl H , Fl Fl xidhwaddr
Use the last four bytes of the hardware address as the DHCP xid instead
of a randomly generated number.
.It Fl J , Fl Fl broadcast
Instructs the DHCP server to broadcast replies back to the client.
Normally this is only set for non-Ethernet interfaces,
such as FireWire and InfiniBand.
In most instances,
.Nm
will set this automatically.
.It Fl K , Fl Fl nolink
Don't receive link messages for carrier status.
You should only have to use this with buggy device drivers or running
.Nm
through a network manager.
.It Fl L , Fl Fl noipv4ll
Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf).
.It Fl O , Fl Fl nooption Ar option
Removes the
.Ar option
from the DHCP message before processing.
.It Fl P , Fl Fl printpidfile
Print the
.Pa pidfile
.Nm
will use based on commmand-line arguments to stdout.
.It Fl Q , Fl Fl require Ar option
Requires the
.Ar option
to be present in all DHCP messages, otherwise the message is ignored.
To enforce that
.Nm
only responds to DHCP servers and not BOOTP servers, you can
.Fl Q
.Ar dhcp_message_type .
.It Fl q , Fl Fl quiet
Quiet
.Nm
on the command line, only warnings and errors will be displayed.
If this option is used another time then all console output is disabled.
These messages are still logged via
.Xr syslog 3 .
.It Fl T , Fl Fl test
On receipt of DHCP messages just call
.Pa @SCRIPT@
with the reason of TEST which echos the DHCP variables found in the message
to the console.
The interface configuration isn't touched and neither are any configuration
files.
The
.Ar rapid_commit
option is not sent in TEST mode so that the server does not lease an address.
To test INFORM the interface needs to be configured with the desired address
before starting
.Nm .
.It Fl U , Fl Fl dumplease Op Ar interface
Dumps the current lease for the
.Ar interface
to stdout.
If no
.Ar interface
is given then all interfaces are dumped.
Use the
.Fl 4
or
.Fl 6
flags to specify an address family.
If a lease is piped in via standard input then that is dumped.
In this case, specifying an address family is mandatory.
.It Fl V , Fl Fl variables
Display a list of option codes, the associated variable and encoding for use in
.Xr dhcpcd-run-hooks 8 .
Variables are prefixed with new_ and old_ unless the option number is -.
Variables without an option are part of the DHCP message and cannot be
directly requested.
.It Fl W , Fl Fl whitelist Ar address Ns Op /cidr
Only accept packets from
.Ar address Ns Op /cidr .
.Fl X , Fl Fl blacklist
is ignored if
.Fl W , Fl Fl whitelist
is set.
.It Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr
Ignore all packets from
.Ar address Ns Op Ar /cidr .
.It Fl Z , Fl Fl denyinterfaces Ar pattern
When discovering interfaces, the interface name must not match
.Ar pattern
which is a space or comma separated list of patterns passed to
.Xr fnmatch 3 .
.It Fl z , Fl Fl allowinterfaces Ar pattern
When discovering interfaces, the interface name must match
.Ar pattern
which is a space or comma separated list of patterns passed to
.Xr fnmatch 3 .
If the same interface is matched in
.Fl Z , Fl Fl denyinterfaces
then it is still denied.
.It Fl Fl inactive
Don't start any interfaces other than those specified on the command line.
This allows
.Nm
to be started in Master mode and then wait for subsequent
.Nm
commands to start each interface as required.
.It Fl Fl configure
Allows
.Nm
to configure the system.
This is the default behaviour and sets
.Ev if_configured=true .
.It Fl Fl noconfigure
.Nm
will not configure the system at all.
This is only of use if the
.Fl Fl script
that
.Nm
calls at each network event configures the system instead.
This is different from
.Fl T , Fl Fl test
mode in that it's not one shot and the only change to the environment is the
addition of
.Ev if_configured=false .
.It Fl Fl nodev
Don't load any
.Pa /dev
management modules.
.El
.Sh 3RDPARTY LINK MANAGEMENT
Some interfaces require configuration by 3rd parties, such as PPP or VPN.
When an interface configuration in
.Nm
is marked as STATIC or INFORM without an address then
.Nm
will monitor the interface until an address is added or removed from it and
act accordingly.
For point to point interfaces (like PPP), a default route to its
destination is automatically added to the configuration.
If the point to point interface is configured for INFORM, then
.Nm
unicasts INFORM to the destination, otherwise it defaults to STATIC.
.Sh NOTES
.Nm
requires a Berkley Packet Filter, or BPF device on BSD based systems and a
Linux Socket Filter, or LPF device on Linux based systems for all IPv4
configuration.
.Pp
If restricting
.Nm
to a single interface and optionally address family via the command-line
then all further calls to
.Nm
to rebind, reconfigure or exit need to include the same restrictive flags
so that
.Nm
knows which process to signal.
.Pp
Some DHCP servers implement ClientID filtering.
If
.Nm
is replacing an in-use DHCP client then you might need to adjust the clientid
option
.Nm
sends to match.
If using a DUID in place of the ClientID, edit
.Pa @DBDIR@/duid
accordingly.
.Sh FILES
.Bl -ohang
.It Pa @SYSCONFDIR@/dhcpcd.conf
Configuration file for dhcpcd.
If you always use the same options, put them here.
.It Pa @SCRIPT@
Bourne shell script that is run to configure or de-configure an interface.
.It Pa @LIBDIR@/dhcpcd/dev
Linux
.Pa /dev
management modules.
.It Pa @HOOKDIR@
A directory containing bourne shell scripts that are run by the above script.
Each script can be disabled by using the
.Fl C , Fl Fl nohook
option described above.
.It Pa @DBDIR@/duid
Text file that holds the DUID used to identify the host.
.It Pa @DBDIR@/secret
Text file that holds a secret key known only to the host.
.It Pa @DBDIR@/ Ns Ar interface Ns Ar -ssid Ns .lease
The actual DHCP message sent by the server.
We use this when reading the last
lease and use the file's mtime as when it was issued.
.It Pa @DBDIR@/ Ns Ar interface Ns Ar -ssid Ns .lease6
The actual DHCPv6 message sent by the server.
We use this when reading the last
lease and use the file's mtime as when it was issued.
.It Pa @DBDIR@/rdm_monotonic
Stores the monotonic counter used in the
.Ar replay
field in Authentication Options.
.It Pa @RUNDIR@/pid
Stores the PID of
.Nm
running on all interfaces.
.It Pa @RUNDIR@/ Ns Ar interface Ns .pid
Stores the PID of
.Nm
running on the
.Ar interface .
.It Pa @RUNDIR@/sock
Control socket to the master daemon.
.It Pa @RUNDIR@/unpriv.sock
Unprivileged socket to the master daemon, only allows state retrieval.
.It Pa @RUNDIR@/ Ns Ar interface Ns .sock
Control socket to per interface daemon.
.El
.Sh SEE ALSO
.Xr fnmatch 3 ,
.Xr if_nametoindex 3 ,
.Xr dhcpcd.conf 5 ,
.Xr resolv.conf 5 ,
.Xr dhcpcd-run-hooks 8 ,
.Xr resolvconf 8
.Sh STANDARDS
RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855,
RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6355,
RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd

2733
external/bsd/dhcpcd/dist/src/dhcpcd.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
# A sample configuration for dhcpcd.
# See dhcpcd.conf(5) for details.
# Allow users of this group to interact with dhcpcd via the control socket.
#controlgroup wheel
# Inform the DHCP server of our hostname for DDNS.
#hostname
# Use the hardware address of the interface for the Client ID.
#clientid
# or
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
# Some non-RFC compliant DHCP servers do not reply with this set.
# In this case, comment out duid and enable clientid above.
duid
# Persist interface configuration when dhcpcd exits.
persistent
# vendorclassid is set to blank to avoid sending the default of
# dhcpcd-<version>:<os>:<machine>:<platform>
vendorclassid
# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search
option classless_static_routes
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
# Request a hostname from the network
option host_name
# Most distributions have NTP support.
#option ntp_servers
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
option rapid_commit
# A ServerID is required by RFC2131.
require dhcp_server_identifier
# Generate SLAAC address using the Hardware Address of the interface
#slaac hwaddr
# OR generate Stable Private IPv6 Addresses based from the DUID
slaac private

1038
external/bsd/dhcpcd/dist/src/dhcpcd.conf.5 vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

280
external/bsd/dhcpcd/dist/src/dhcpcd.h vendored Normal file
View File

@ -0,0 +1,280 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef DHCPCD_H
#define DHCPCD_H
#include <sys/socket.h>
#include <net/if.h>
#include <stdio.h>
#include "config.h"
#ifdef HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#include "defs.h"
#include "control.h"
#include "if-options.h"
#define HWADDR_LEN 20
#define IF_SSIDLEN 32
#define PROFILE_LEN 64
#define SECRET_LEN 64
#define IF_INACTIVE 0
#define IF_ACTIVE 1
#define IF_ACTIVE_USER 2
#define LINK_UP 1
#define LINK_UNKNOWN 0
#define LINK_DOWN -1
#define IF_DATA_IPV4 0
#define IF_DATA_ARP 1
#define IF_DATA_IPV4LL 2
#define IF_DATA_DHCP 3
#define IF_DATA_IPV6 4
#define IF_DATA_IPV6ND 5
#define IF_DATA_DHCP6 6
#define IF_DATA_MAX 7
#ifdef __QNX__
/* QNX carries defines for, but does not actually support PF_LINK */
#undef IFLR_ACTIVE
#endif
struct interface {
struct dhcpcd_ctx *ctx;
TAILQ_ENTRY(interface) next;
char name[IF_NAMESIZE];
unsigned int index;
unsigned int active;
unsigned int flags;
uint16_t hwtype; /* ARPHRD_ETHER for example */
unsigned char hwaddr[HWADDR_LEN];
uint8_t hwlen;
unsigned short vlanid;
unsigned int metric;
int carrier;
bool wireless;
uint8_t ssid[IF_SSIDLEN];
unsigned int ssid_len;
char profile[PROFILE_LEN];
struct if_options *options;
void *if_data[IF_DATA_MAX];
};
TAILQ_HEAD(if_head, interface);
#include "privsep.h"
/* dhcpcd requires CMSG_SPACE to evaluate to a compile time constant. */
#if defined(__QNX) || \
(defined(__NetBSD_Version__) && __NetBSD_Version__ < 600000000)
#undef CMSG_SPACE
#endif
#ifndef ALIGNBYTES
#define ALIGNBYTES (sizeof(int) - 1)
#endif
#ifndef ALIGN
#define ALIGN(p) (((unsigned int)(p) + ALIGNBYTES) & ~ALIGNBYTES)
#endif
#ifndef CMSG_SPACE
#define CMSG_SPACE(len) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(len))
#endif
struct passwd;
struct dhcpcd_ctx {
char pidfile[sizeof(PIDFILE) + IF_NAMESIZE + 1];
char vendor[256];
int fork_fd; /* FD for the fork init signal pipe */
const char *cffile;
unsigned long long options;
char *logfile;
int argc;
char **argv;
int ifac; /* allowed interfaces */
char **ifav; /* allowed interfaces */
int ifdc; /* denied interfaces */
char **ifdv; /* denied interfaces */
int ifc; /* listed interfaces */
char **ifv; /* listed interfaces */
int ifcc; /* configured interfaces */
char **ifcv; /* configured interfaces */
uint8_t duid_type;
unsigned char *duid;
size_t duid_len;
struct if_head *ifaces;
char *ctl_buf;
size_t ctl_buflen;
size_t ctl_bufpos;
size_t ctl_extra;
rb_tree_t routes; /* our routes */
#ifdef RT_FREE_ROUTE_TABLE
rb_tree_t froutes; /* free routes for re-use */
#endif
size_t rt_order; /* route order storage */
int pf_inet_fd;
#ifdef PF_LINK
int pf_link_fd;
#endif
void *priv;
int link_fd;
#ifndef SMALL
int link_rcvbuf;
#endif
int seq; /* route message sequence no */
int sseq; /* successful seq no sent */
#ifdef USE_SIGNALS
sigset_t sigset;
#endif
struct eloop *eloop;
char *script;
#ifdef HAVE_OPEN_MEMSTREAM
FILE *script_fp;
#endif
char *script_buf;
size_t script_buflen;
char **script_env;
size_t script_envlen;
int control_fd;
int control_unpriv_fd;
struct fd_list_head control_fds;
char control_sock[sizeof(CONTROLSOCKET) + IF_NAMESIZE];
char control_sock_unpriv[sizeof(CONTROLSOCKET) + IF_NAMESIZE + 7];
gid_t control_group;
/* DHCP Enterprise options, RFC3925 */
struct dhcp_opt *vivso;
size_t vivso_len;
char *randomstate; /* original state */
/* For filtering RTM_MISS messages per router */
#ifdef BSD
uint8_t *rt_missfilter;
size_t rt_missfilterlen;
size_t rt_missfiltersize;
#endif
#ifdef PRIVSEP
struct passwd *ps_user; /* struct passwd for privsep user */
struct ps_process_head ps_processes; /* List of spawned processes */
struct ps_process *ps_root;
struct ps_process *ps_inet;
struct ps_process *ps_ctl;
int ps_data_fd; /* data returned from processes */
int ps_log_fd; /* chroot logging */
int ps_log_root_fd; /* outside chroot log reader */
struct eloop *ps_eloop; /* eloop for polling root data */
struct fd_list *ps_control; /* Queue for the above */
struct fd_list *ps_control_client; /* Queue for the above */
#endif
#ifdef INET
struct dhcp_opt *dhcp_opts;
size_t dhcp_opts_len;
int udp_rfd;
int udp_wfd;
/* Our aggregate option buffer.
* We ONLY use this when options are split, which for most purposes is
* practically never. See RFC3396 for details. */
uint8_t *opt_buffer;
size_t opt_buffer_len;
#endif
#ifdef INET6
uint8_t *secret;
size_t secret_len;
#ifndef __sun
int nd_fd;
#endif
struct ra_head *ra_routers;
struct dhcp_opt *nd_opts;
size_t nd_opts_len;
#ifdef DHCP6
int dhcp6_rfd;
int dhcp6_wfd;
struct dhcp_opt *dhcp6_opts;
size_t dhcp6_opts_len;
#endif
#ifndef __linux__
int ra_global;
#endif
#endif /* INET6 */
#ifdef PLUGIN_DEV
char *dev_load;
int dev_fd;
struct dev *dev;
void *dev_handle;
#endif
};
#ifdef USE_SIGNALS
extern const int dhcpcd_signals[];
extern const size_t dhcpcd_signals_len;
extern const int dhcpcd_signals_ignore[];
extern const size_t dhcpcd_signals_ignore_len;
#endif
extern const char *dhcpcd_default_script;
int dhcpcd_ifafwaiting(const struct interface *);
int dhcpcd_afwaiting(const struct dhcpcd_ctx *);
void dhcpcd_daemonised(struct dhcpcd_ctx *);
void dhcpcd_daemonise(struct dhcpcd_ctx *);
void dhcpcd_signal_cb(int, void *);
void dhcpcd_linkoverflow(struct dhcpcd_ctx *);
int dhcpcd_handleargs(struct dhcpcd_ctx *, struct fd_list *, int, char **);
void dhcpcd_handlecarrier(struct interface *, int, unsigned int);
int dhcpcd_handleinterface(void *, int, const char *);
void dhcpcd_handlehwaddr(struct interface *, uint16_t, const void *, uint8_t);
void dhcpcd_dropinterface(struct interface *, const char *);
int dhcpcd_selectprofile(struct interface *, const char *);
void dhcpcd_startinterface(void *);
void dhcpcd_activateinterface(struct interface *, unsigned long long);
#endif

247
external/bsd/dhcpcd/dist/src/duid.c vendored Normal file
View File

@ -0,0 +1,247 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#define UUID_LEN 36
#define DUID_TIME_EPOCH 946684800
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/types.h>
#ifdef BSD
# include <sys/sysctl.h>
#endif
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "common.h"
#include "dhcpcd.h"
#include "duid.h"
#include "logerr.h"
/*
* Machine, system or product UUIDs are not guaranteed unique.
* Let's not use them by default.
*/
#ifdef USE_MACHINE_UUID
static size_t
duid_machineuuid(char *uuid, size_t uuid_len)
{
int r;
size_t len = uuid_len;
#if defined(HW_UUID) /* OpenBSD */
int mib[] = { CTL_HW, HW_UUID };
r = sysctl(mib, sizeof(mib)/sizeof(mib[0]), uuid, &len, NULL, 0);
#elif defined(KERN_HOSTUUID) /* FreeBSD */
int mib[] = { CTL_KERN, KERN_HOSTUUID };
r = sysctl(mib, sizeof(mib)/sizeof(mib[0]), uuid, &len, NULL, 0);
#elif defined(__NetBSD__)
r = sysctlbyname("machdep.dmi.system-uuid", uuid, &len, NULL, 0);
#elif defined(__linux__)
FILE *fp;
fp = fopen("/sys/class/dmi/id/product_uuid", "r");
if (fp == NULL)
return 0;
if (fgets(uuid, (int)uuid_len, fp) == NULL) {
fclose(fp);
return 0;
}
len = strlen(uuid) + 1;
fclose(fp);
r = len == 1 ? -1 : 0;
#else
UNUSED(uuid);
r = -1;
errno = ENOSYS;
#endif
if (r == -1)
return 0;
return len;
}
static size_t
duid_make_uuid(uint8_t *d)
{
uint16_t type = htons(DUID_UUID);
char uuid[UUID_LEN + 1];
size_t l;
if (duid_machineuuid(uuid, sizeof(uuid)) != sizeof(uuid))
return 0;
/* All zeros UUID is not valid */
if (strcmp("00000000-0000-0000-0000-000000000000", uuid) == 0)
return 0;
memcpy(d, &type, sizeof(type));
l = sizeof(type);
d += sizeof(type);
l += hwaddr_aton(d, uuid);
return l;
}
#endif
size_t
duid_make(void *d, const struct interface *ifp, uint16_t type)
{
uint8_t *p;
uint16_t u16;
time_t t;
uint32_t u32;
if (ifp->hwlen == 0)
return 0;
p = d;
u16 = htons(type);
memcpy(p, &u16, sizeof(u16));
p += sizeof(u16);
u16 = htons(ifp->hwtype);
memcpy(p, &u16, sizeof(u16));
p += sizeof(u16);
if (type == DUID_LLT) {
/* time returns seconds from jan 1 1970, but DUID-LLT is
* seconds from jan 1 2000 modulo 2^32 */
t = time(NULL) - DUID_TIME_EPOCH;
u32 = htonl((uint32_t)t & 0xffffffff);
memcpy(p, &u32, sizeof(u32));
p += sizeof(u32);
}
/* Finally, add the MAC address of the interface */
memcpy(p, ifp->hwaddr, ifp->hwlen);
p += ifp->hwlen;
return (size_t)(p - (uint8_t *)d);
}
#define DUID_STRLEN DUID_LEN * 3
static size_t
duid_get(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
uint8_t *data;
size_t len, slen;
char line[DUID_STRLEN];
const struct interface *ifp2;
/* If we already have a DUID then use it as it's never supposed
* to change once we have one even if the interfaces do */
if ((len = dhcp_read_hwaddr_aton(ctx, &data, DUID)) != 0) {
if (len <= DUID_LEN) {
ctx->duid = data;
return len;
}
logerrx("DUID too big (max %u): %s", DUID_LEN, DUID);
/* Keep the buffer, will assign below. */
} else {
if (errno != ENOENT)
logerr("%s", DUID);
if ((data = malloc(DUID_LEN)) == NULL) {
logerr(__func__);
return 0;
}
}
/* No file? OK, lets make one based the machines UUID */
if (ifp == NULL) {
#ifdef USE_MACHINE_UUID
if (ctx->duid_type != DUID_DEFAULT &&
ctx->duid_type != DUID_UUID)
len = 0;
else
len = duid_make_uuid(data);
if (len == 0)
free(data);
else
ctx->duid = data;
return len;
#else
free(data);
return 0;
#endif
}
/* Regardless of what happens we will create a DUID to use. */
ctx->duid = data;
/* No UUID? OK, lets make one based on our interface */
if (ifp->hwlen == 0) {
logwarnx("%s: does not have hardware address", ifp->name);
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (ifp2->hwlen != 0)
break;
}
if (ifp2) {
ifp = ifp2;
logwarnx("picked interface %s to generate a DUID",
ifp->name);
} else {
if (ctx->duid_type != DUID_LL)
logwarnx("no interfaces have a fixed hardware "
"address");
return duid_make(data, ifp, DUID_LL);
}
}
len = duid_make(data, ifp,
ctx->duid_type == DUID_LL ? DUID_LL : DUID_LLT);
hwaddr_ntoa(data, len, line, sizeof(line));
slen = strlen(line);
if (slen < sizeof(line) - 2) {
line[slen++] = '\n';
line[slen] = '\0';
}
if (dhcp_writefile(ctx, DUID, 0640, line, slen) == -1) {
logerr("%s: cannot write duid", __func__);
if (ctx->duid_type != DUID_LL)
return duid_make(data, ifp, DUID_LL);
}
return len;
}
size_t
duid_init(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
if (ctx->duid == NULL)
ctx->duid_len = duid_get(ctx, ifp);
return ctx->duid_len;
}

41
external/bsd/dhcpcd/dist/src/duid.h vendored Normal file
View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef DUID_H
#define DUID_H
#define DUID_LEN 128 + 2
#define DUID_DEFAULT 0
#define DUID_LLT 1
#define DUID_LL 3
#define DUID_UUID 4
size_t duid_make(void *, const struct interface *, uint16_t);
size_t duid_init(struct dhcpcd_ctx *, const struct interface *);
#endif

1242
external/bsd/dhcpcd/dist/src/eloop.c vendored Normal file

File diff suppressed because it is too large Load Diff

97
external/bsd/dhcpcd/dist/src/eloop.h vendored Normal file
View File

@ -0,0 +1,97 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef ELOOP_H
#define ELOOP_H
#include <time.h>
/* Handy macros to create subsecond timeouts */
#define CSEC_PER_SEC 100
#define MSEC_PER_SEC 1000
#define NSEC_PER_CSEC 10000000
#define NSEC_PER_MSEC 1000000
#define NSEC_PER_SEC 1000000000
/* eloop queues are really only for deleting timeouts registered
* for a function or object.
* The idea being that one interface has different timeouts for
* say DHCP and DHCPv6. */
#ifndef ELOOP_QUEUE
#define ELOOP_QUEUE 1
#endif
/* Used for deleting a timeout for all queues. */
#define ELOOP_QUEUE_ALL 0
/* Forward declare eloop - the content should be invisible to the outside */
struct eloop;
#define ELE_READ 0x0001
#define ELE_WRITE 0x0002
#define ELE_ERROR 0x0100
#define ELE_HANGUP 0x0200
#define ELE_NVAL 0x0400
size_t eloop_event_count(const struct eloop *);
int eloop_event_add(struct eloop *, int, unsigned short,
void (*)(void *, unsigned short), void *);
int eloop_event_delete(struct eloop *, int);
unsigned long long eloop_timespec_diff(const struct timespec *tsp,
const struct timespec *usp, unsigned int *nsp);
#define eloop_timeout_add_tv(eloop, tv, cb, ctx) \
eloop_q_timeout_add_tv((eloop), ELOOP_QUEUE, (tv), (cb), (ctx))
#define eloop_timeout_add_sec(eloop, tv, cb, ctx) \
eloop_q_timeout_add_sec((eloop), ELOOP_QUEUE, (tv), (cb), (ctx))
#define eloop_timeout_add_msec(eloop, ms, cb, ctx) \
eloop_q_timeout_add_msec((eloop), ELOOP_QUEUE, (ms), (cb), (ctx))
#define eloop_timeout_delete(eloop, cb, ctx) \
eloop_q_timeout_delete((eloop), ELOOP_QUEUE, (cb), (ctx))
int eloop_q_timeout_add_tv(struct eloop *, int,
const struct timespec *, void (*)(void *), void *);
int eloop_q_timeout_add_sec(struct eloop *, int,
unsigned int, void (*)(void *), void *);
int eloop_q_timeout_add_msec(struct eloop *, int,
unsigned long, void (*)(void *), void *);
int eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *);
int eloop_signal_set_cb(struct eloop *, const int *, size_t,
void (*)(int, void *), void *);
int eloop_signal_mask(struct eloop *, sigset_t *oldset);
struct eloop * eloop_new(void);
void eloop_clear(struct eloop *, ...);
void eloop_free(struct eloop *);
void eloop_exit(struct eloop *, int);
void eloop_enter(struct eloop *);
int eloop_forked(struct eloop *);
int eloop_open(struct eloop *);
int eloop_start(struct eloop *, sigset_t *);
#endif

1946
external/bsd/dhcpcd/dist/src/if-bsd.c vendored Normal file

File diff suppressed because it is too large Load Diff

2881
external/bsd/dhcpcd/dist/src/if-options.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef IF_OPTIONS_H
#define IF_OPTIONS_H
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <getopt.h>
#include <limits.h>
#include <stdint.h>
#include "auth.h"
#include "route.h"
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
#define IF_OPTS "146bc:de:f:gh:i:j:kl:m:no:pqr:s:t:u:v:wxy:z:" \
"ABC:DEF:GHI:JKLMNO:PQ:S:TUVW:X:Z:"
#define NOERR_IF_OPTS ":" IF_OPTS
#define DEFAULT_TIMEOUT 30
#define DEFAULT_REBOOT 5
#define DEFAULT_REQUEST 180 /* secs to request, mirror DHCP6 */
#define DEFAULT_FALLBACK 5 /* secs until fallback */
#define DEFAULT_IPV4LL 5 /* secs until ipv4ll */
#ifndef HOSTNAME_MAX_LEN
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
#endif
#define VENDORCLASSID_MAX_LEN 255
#define CLIENTID_MAX_LEN 48
#define USERCLASS_MAX_LEN 255
#define VENDOR_MAX_LEN 255
#define MUDURL_MAX_LEN 255
#define DHCPCD_ARP (1ULL << 0)
#define DHCPCD_RELEASE (1ULL << 1)
#define DHCPCD_RTBUILD (1ULL << 2)
#define DHCPCD_GATEWAY (1ULL << 3)
#define DHCPCD_STATIC (1ULL << 4)
#define DHCPCD_DEBUG (1ULL << 5)
#define DHCPCD_ARP_PERSISTDEFENCE (1ULL << 6)
#define DHCPCD_LASTLEASE (1ULL << 7)
#define DHCPCD_INFORM (1ULL << 8)
#define DHCPCD_REQUEST (1ULL << 9)
#define DHCPCD_IPV4LL (1ULL << 10)
#define DHCPCD_DUID (1ULL << 11)
#define DHCPCD_PERSISTENT (1ULL << 12)
#define DHCPCD_DAEMONISE (1ULL << 14)
#define DHCPCD_DAEMONISED (1ULL << 15)
#define DHCPCD_TEST (1ULL << 16)
#define DHCPCD_MANAGER (1ULL << 17)
#define DHCPCD_HOSTNAME (1ULL << 18)
#define DHCPCD_CLIENTID (1ULL << 19)
#define DHCPCD_LINK (1ULL << 20)
#define DHCPCD_ANONYMOUS (1ULL << 21)
#define DHCPCD_BACKGROUND (1ULL << 22)
#define DHCPCD_VENDORRAW (1ULL << 23)
#define DHCPCD_NOWAITIP (1ULL << 24) /* To force daemonise */
#define DHCPCD_WAITIP (1ULL << 25)
#define DHCPCD_SLAACPRIVATE (1ULL << 26)
#define DHCPCD_CSR_WARNED (1ULL << 27)
#define DHCPCD_XID_HWADDR (1ULL << 28)
#define DHCPCD_BROADCAST (1ULL << 29)
#define DHCPCD_DUMPLEASE (1ULL << 30)
#define DHCPCD_IPV6RS (1ULL << 31)
#define DHCPCD_IPV6RA_REQRDNSS (1ULL << 32)
#define DHCPCD_PRIVSEP (1ULL << 33)
#define DHCPCD_CONFIGURE (1ULL << 34)
#define DHCPCD_IPV4 (1ULL << 35)
#define DHCPCD_FORKED (1ULL << 36)
#define DHCPCD_IPV6 (1ULL << 37)
#define DHCPCD_STARTED (1ULL << 38)
#define DHCPCD_NOALIAS (1ULL << 39)
#define DHCPCD_IA_FORCED (1ULL << 40)
#define DHCPCD_STOPPING (1ULL << 41)
#define DHCPCD_LAUNCHER (1ULL << 42)
#define DHCPCD_HOSTNAME_SHORT (1ULL << 43)
#define DHCPCD_EXITING (1ULL << 44)
#define DHCPCD_WAITIP4 (1ULL << 45)
#define DHCPCD_WAITIP6 (1ULL << 46)
#define DHCPCD_DEV (1ULL << 47)
#define DHCPCD_IAID (1ULL << 48)
#define DHCPCD_DHCP (1ULL << 49)
#define DHCPCD_DHCP6 (1ULL << 50)
#define DHCPCD_IF_UP (1ULL << 51)
#define DHCPCD_INFORM6 (1ULL << 52)
#define DHCPCD_WANTDHCP (1ULL << 53)
#define DHCPCD_IPV6RA_AUTOCONF (1ULL << 54)
#define DHCPCD_ROUTER_HOST_ROUTE_WARNED (1ULL << 55)
#define DHCPCD_LASTLEASE_EXTEND (1ULL << 56)
#define DHCPCD_BOOTP (1ULL << 57)
#define DHCPCD_INITIAL_DELAY (1ULL << 58)
#define DHCPCD_PRINT_PIDFILE (1ULL << 59)
#define DHCPCD_ONESHOT (1ULL << 60)
#define DHCPCD_INACTIVE (1ULL << 61)
#define DHCPCD_SLAACTEMP (1ULL << 62)
#define DHCPCD_PRIVSEPROOT (1ULL << 63)
#define DHCPCD_NODROP (DHCPCD_EXITING | DHCPCD_PERSISTENT)
#define DHCPCD_WAITOPTS (DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6)
#define DHCPCD_WARNINGS (DHCPCD_CSR_WARNED | \
DHCPCD_ROUTER_HOST_ROUTE_WARNED)
/* These options only make sense in the config file, so don't use any
valid short options for them */
#define O_BASE MAX('z', 'Z') + 1
#define O_ARPING O_BASE + 1
#define O_FALLBACK O_BASE + 2
#define O_DESTINATION O_BASE + 3
#define O_IPV6RS O_BASE + 4
#define O_NOIPV6RS O_BASE + 5
#define O_IPV6RA_FORK O_BASE + 6
#define O_LINK_RCVBUF O_BASE + 7
#define O_ANONYMOUS O_BASE + 8
#define O_NOALIAS O_BASE + 9
#define O_IA_NA O_BASE + 10
#define O_IA_TA O_BASE + 11
#define O_IA_PD O_BASE + 12
#define O_HOSTNAME_SHORT O_BASE + 13
#define O_DEV O_BASE + 14
#define O_NODEV O_BASE + 15
#define O_NOIPV4 O_BASE + 16
#define O_NOIPV6 O_BASE + 17
#define O_IAID O_BASE + 18
#define O_DEFINE O_BASE + 19
#define O_DEFINE6 O_BASE + 20
#define O_EMBED O_BASE + 21
#define O_ENCAP O_BASE + 22
#define O_VENDOPT O_BASE + 23
#define O_VENDCLASS O_BASE + 24
#define O_AUTHPROTOCOL O_BASE + 25
#define O_AUTHTOKEN O_BASE + 26
#define O_AUTHNOTREQUIRED O_BASE + 27
#define O_NODHCP O_BASE + 28
#define O_NODHCP6 O_BASE + 29
#define O_DHCP O_BASE + 30
#define O_DHCP6 O_BASE + 31
#define O_IPV4 O_BASE + 32
#define O_IPV6 O_BASE + 33
#define O_CONTROLGRP O_BASE + 34
#define O_SLAAC O_BASE + 35
#define O_GATEWAY O_BASE + 36
#define O_NOUP O_BASE + 37
#define O_IPV6RA_AUTOCONF O_BASE + 38
#define O_IPV6RA_NOAUTOCONF O_BASE + 39
#define O_REJECT O_BASE + 40
#define O_BOOTP O_BASE + 42
#define O_DEFINEND O_BASE + 43
#define O_NODELAY O_BASE + 44
#define O_INFORM6 O_BASE + 45
#define O_LASTLEASE_EXTEND O_BASE + 46
#define O_INACTIVE O_BASE + 47
#define O_MUDURL O_BASE + 48
#define O_MSUSERCLASS O_BASE + 49
#define O_CONFIGURE O_BASE + 50
#define O_NOCONFIGURE O_BASE + 51
#define O_RANDOMISE_HWADDR O_BASE + 52
#define O_ARP_PERSISTDEFENCE O_BASE + 53
#define O_REQUEST_TIME O_BASE + 54
#define O_FALLBACK_TIME O_BASE + 55
#define O_IPV4LL_TIME O_BASE + 56
extern const struct option cf_options[];
struct if_sla {
char ifname[IF_NAMESIZE];
uint32_t sla;
uint8_t prefix_len;
uint64_t suffix;
bool sla_set;
};
struct if_ia {
uint8_t iaid[4];
#ifdef INET6
uint16_t ia_type;
uint8_t iaid_set;
struct in6_addr addr;
uint8_t prefix_len;
#ifndef SMALL
uint32_t sla_max;
size_t sla_len;
struct if_sla *sla;
#endif
#endif
};
struct vivco {
size_t len;
uint8_t *data;
};
struct if_options {
time_t mtime;
uint8_t iaid[4];
int metric;
uint8_t requestmask[256 / NBBY];
uint8_t requiremask[256 / NBBY];
uint8_t nomask[256 / NBBY];
uint8_t rejectmask[256 / NBBY];
uint8_t dstmask[256 / NBBY];
uint8_t requestmasknd[(UINT16_MAX + 1) / NBBY];
uint8_t requiremasknd[(UINT16_MAX + 1) / NBBY];
uint8_t nomasknd[(UINT16_MAX + 1) / NBBY];
uint8_t rejectmasknd[(UINT16_MAX + 1) / NBBY];
uint8_t requestmask6[(UINT16_MAX + 1) / NBBY];
uint8_t requiremask6[(UINT16_MAX + 1) / NBBY];
uint8_t nomask6[(UINT16_MAX + 1) / NBBY];
uint8_t rejectmask6[(UINT16_MAX + 1) / NBBY];
uint32_t leasetime;
uint32_t timeout;
uint32_t reboot;
uint32_t request_time;
uint32_t fallback_time;
uint32_t ipv4ll_time;
unsigned long long options;
bool randomise_hwaddr;
struct in_addr req_addr;
struct in_addr req_mask;
struct in_addr req_brd;
rb_tree_t routes;
struct in6_addr req_addr6;
uint8_t req_prefix_len;
unsigned int mtu;
char **config;
char **environ;
char hostname[HOSTNAME_MAX_LEN + 1]; /* We don't store the length */
uint8_t fqdn;
uint8_t vendorclassid[VENDORCLASSID_MAX_LEN + 2];
uint8_t clientid[CLIENTID_MAX_LEN + 2];
uint8_t userclass[USERCLASS_MAX_LEN + 2];
uint8_t vendor[VENDOR_MAX_LEN + 2];
uint8_t mudurl[MUDURL_MAX_LEN + 2];
size_t blacklist_len;
in_addr_t *blacklist;
size_t whitelist_len;
in_addr_t *whitelist;
ssize_t arping_len;
in_addr_t *arping;
char *fallback;
struct if_ia *ia;
size_t ia_len;
#ifdef INET6
struct in6_addr token;
#endif
struct dhcp_opt *dhcp_override;
size_t dhcp_override_len;
struct dhcp_opt *nd_override;
size_t nd_override_len;
struct dhcp_opt *dhcp6_override;
size_t dhcp6_override_len;
uint32_t vivco_en;
struct vivco *vivco;
size_t vivco_len;
struct dhcp_opt *vivso_override;
size_t vivso_override_len;
struct auth auth;
};
struct if_options *read_config(struct dhcpcd_ctx *,
const char *, const char *, const char *);
int add_options(struct dhcpcd_ctx *, const char *,
struct if_options *, int, char **);
void free_dhcp_opt_embenc(struct dhcp_opt *);
void free_options(struct dhcpcd_ctx *, struct if_options *);
#endif

1060
external/bsd/dhcpcd/dist/src/if.c vendored Normal file

File diff suppressed because it is too large Load Diff

294
external/bsd/dhcpcd/dist/src/if.h vendored Normal file
View File

@ -0,0 +1,294 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef INTERFACE_H
#define INTERFACE_H
#include <net/if.h>
#include <net/route.h> /* for RTM_ADD et all */
#include <netinet/in.h>
#ifdef BSD
#include <netinet/in_var.h> /* for IN_IFF_TENTATIVE et all */
#endif
#include <ifaddrs.h>
/* If the interface does not support carrier status (ie PPP),
* dhcpcd can poll it for the relevant flags periodically */
#define IF_POLL_UP 100 /* milliseconds */
/*
* Systems which handle 1 address per alias.
* Currenly this is just Solaris.
* While Linux can do aliased addresses, it is only useful for their
* legacy ifconfig(8) tool which cannot display >1 IPv4 address
* (it can display many IPv6 addresses which makes the limitation odd).
* Linux has ip(8) which is a more feature rich tool, without the above
* restriction.
*/
#ifndef ALIAS_ADDR
# ifdef __sun
# define ALIAS_ADDR
# endif
#endif
#include "config.h"
/* POSIX defines ioctl request as an int, which Solaris and musl use.
* Everyone else use an unsigned long, which happens to be the bigger one
* so we use that in our on wire API. */
#ifdef IOCTL_REQUEST_TYPE
typedef IOCTL_REQUEST_TYPE ioctl_request_t;
#else
typedef unsigned long ioctl_request_t;
#endif
#include "dhcpcd.h"
#include "ipv4.h"
#include "ipv6.h"
#include "route.h"
#define EUI64_ADDR_LEN 8
#define INFINIBAND_ADDR_LEN 20
/* Linux 2.4 doesn't define this */
#ifndef ARPHRD_IEEE1394
# define ARPHRD_IEEE1394 24
#endif
/* The BSD's don't define this yet */
#ifndef ARPHRD_INFINIBAND
# define ARPHRD_INFINIBAND 32
#endif
/* Maximum frame length.
* Support jumbo frames and some extra. */
#define FRAMEHDRLEN_MAX 14 /* only ethernet support */
#define FRAMELEN_MAX (FRAMEHDRLEN_MAX + 9216)
#define UDPLEN_MAX 64 * 1024
/* Work out if we have a private address or not
* 10/8
* 172.16/12
* 192.168/16
*/
#ifndef IN_PRIVATE
# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \
((addr & 0xfff00000) == 0xac100000) || \
((addr & IN_CLASSB_NET) == 0xc0a80000))
#endif
#ifndef CLLADDR
#ifdef AF_LINK
# define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
#endif
#endif
#ifdef __sun
/* Solaris stupidly defines this for compat with BSD
* but then ignores it. */
#undef RTF_CLONING
/* This interface is busted on DilOS at least.
* It used to work, but lukily Solaris can fall back to
* IP_PKTINFO. */
#undef IP_RECVIF
#endif
/* Private structures specific to an OS */
#ifdef BSD
struct priv {
#ifdef INET6
int pf_inet6_fd;
#endif
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
int pf_link_fd;
#endif
};
#endif
#ifdef __linux__
struct priv {
int route_fd;
int generic_fd;
uint32_t route_pid;
};
#endif
#ifdef __sun
struct priv {
#ifdef INET6
int pf_inet6_fd;
#endif
};
#endif
#ifdef __sun
/* Solaris getifaddrs is very un-suitable for dhcpcd.
* See if-sun.c for details why. */
struct ifaddrs;
int if_getifaddrs(struct ifaddrs **);
#define getifaddrs if_getifaddrs
int if_getsubnet(struct dhcpcd_ctx *, const char *, int, void *, size_t);
#endif
int if_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
#ifdef HAVE_PLEDGE
#define pioctl(ctx, req, data, len) if_ioctl((ctx), (req), (data), (len))
#else
#define pioctl(ctx, req, data, len) ioctl((ctx)->pf_inet_fd, (req),(data),(len))
#endif
int if_getflags(struct interface *);
int if_setflag(struct interface *, short, short);
#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING), 0)
#define if_down(ifp) if_setflag((ifp), 0, IFF_UP);
bool if_is_link_up(const struct interface *);
bool if_valid_hwaddr(const uint8_t *, size_t);
struct if_head *if_discover(struct dhcpcd_ctx *, struct ifaddrs **,
int, char * const *);
void if_freeifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **);
void if_markaddrsstale(struct if_head *);
void if_learnaddrs(struct dhcpcd_ctx *, struct if_head *, struct ifaddrs **);
void if_deletestaleaddrs(struct if_head *);
struct interface *if_find(struct if_head *, const char *);
struct interface *if_findindex(struct if_head *, unsigned int);
struct interface *if_loopback(struct dhcpcd_ctx *);
void if_free(struct interface *);
int if_domtu(const struct interface *, short int);
#define if_getmtu(ifp) if_domtu((ifp), 0)
#define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
int if_carrier(struct interface *, const void *);
bool if_roaming(struct interface *);
#ifdef ALIAS_ADDR
int if_makealias(char *, size_t, const char *, int);
#endif
int if_mtu_os(const struct interface *);
/*
* Helper to decode an interface name of bge0:1 to
* devname = bge0, drvname = bge0, ppa = 0, lun = 1.
* If ppa or lun are invalid they are set to -1.
*/
struct if_spec {
char ifname[IF_NAMESIZE];
char devname[IF_NAMESIZE];
char drvname[IF_NAMESIZE];
int ppa;
int vlid;
int lun;
};
int if_nametospec(const char *, struct if_spec *);
/* The below functions are provided by if-KERNEL.c */
int os_init(void);
int if_conf(struct interface *);
int if_init(struct interface *);
int if_getssid(struct interface *);
int if_ignoregroup(int, const char *);
bool if_ignore(struct dhcpcd_ctx *, const char *);
int if_vimaster(struct dhcpcd_ctx *ctx, const char *);
unsigned short if_vlanid(const struct interface *);
char * if_getnetworknamespace(char *, size_t);
int if_opensockets(struct dhcpcd_ctx *);
int if_opensockets_os(struct dhcpcd_ctx *);
void if_closesockets(struct dhcpcd_ctx *);
void if_closesockets_os(struct dhcpcd_ctx *);
int if_handlelink(struct dhcpcd_ctx *);
int if_randomisemac(struct interface *);
int if_setmac(struct interface *ifp, void *, uint8_t);
/* dhcpcd uses the same routing flags as BSD.
* If the platform doesn't use these flags,
* map them in the platform interace file. */
#ifndef RTM_ADD
#define RTM_ADD 0x1 /* Add Route */
#define RTM_DELETE 0x2 /* Delete Route */
#define RTM_CHANGE 0x3 /* Change Metrics or flags */
#define RTM_GET 0x4 /* Report Metrics */
#endif
/* Define SOCK_CLOEXEC and SOCK_NONBLOCK for systems that lack it.
* xsocket() in if.c will map them to fctnl FD_CLOEXEC and O_NONBLOCK. */
#ifdef SOCK_CLOEXEC
# define HAVE_SOCK_CLOEXEC
#else
# define SOCK_CLOEXEC 0x10000000
#endif
#ifdef SOCK_NONBLOCK
# define HAVE_SOCK_NONBLOCK
#else
# define SOCK_NONBLOCK 0x20000000
#endif
#ifndef SOCK_CXNB
#define SOCK_CXNB SOCK_CLOEXEC | SOCK_NONBLOCK
#endif
int xsocket(int, int, int);
int xsocketpair(int, int, int, int[2]);
int if_route(unsigned char, const struct rt *rt);
int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int);
int if_missfilter(struct interface *, struct sockaddr *);
int if_missfilter_apply(struct dhcpcd_ctx *);
#ifdef INET
int if_address(unsigned char, const struct ipv4_addr *);
int if_addrflags(const struct interface *, const struct in_addr *,
const char *);
#endif
#ifdef INET6
void if_disable_rtadv(void);
void if_setup_inet6(const struct interface *);
int ip6_forwarding(const char *ifname);
struct ra;
struct ipv6_addr;
int if_applyra(const struct ra *);
int if_address6(unsigned char, const struct ipv6_addr *);
int if_addrflags6(const struct interface *, const struct in6_addr *,
const char *);
int if_getlifetime6(struct ipv6_addr *);
#else
#define if_checkipv6(a, b, c) (-1)
#endif
int if_machinearch(char *, size_t);
struct interface *if_findifpfromcmsg(struct dhcpcd_ctx *,
struct msghdr *, int *);
#ifdef __linux__
int if_linksocket(struct sockaddr_nl *, int, int);
int if_getnetlink(struct dhcpcd_ctx *, struct iovec *, int, int,
int (*)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *);
#endif
#endif

1002
external/bsd/dhcpcd/dist/src/ipv4.c vendored Normal file

File diff suppressed because it is too large Load Diff

157
external/bsd/dhcpcd/dist/src/ipv4.h vendored Normal file
View File

@ -0,0 +1,157 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef IPV4_H
#define IPV4_H
#include "dhcpcd.h"
/* Prefer our macro */
#ifdef HTONL
#undef HTONL
#endif
#ifndef BYTE_ORDER
#define BIG_ENDIAN 1234
#define LITTLE_ENDIAN 4321
#if defined(_BIG_ENDIAN)
#define BYTE_ORDER BIG_ENDIAN
#elif defined(_LITTLE_ENDIAN)
#define BYTE_ORDER LITTLE_ENDIAN
#else
#error Endian unknown
#endif
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define HTONL(A) (A)
#elif BYTE_ORDER == LITTLE_ENDIAN
#define HTONL(A) \
((((uint32_t)(A) & 0xff000000) >> 24) | \
(((uint32_t)(A) & 0x00ff0000) >> 8) | \
(((uint32_t)(A) & 0x0000ff00) << 8) | \
(((uint32_t)(A) & 0x000000ff) << 24))
#endif /* BYTE_ORDER */
#ifdef __sun
/* Solaris lacks these defines.
* While it supports DaD, to seems to only expose IFF_DUPLICATE
* so we have no way of knowing if it's tentative or not.
* I don't even know if Solaris has any special treatment for tentative. */
# define IN_IFF_TENTATIVE 0x01
# define IN_IFF_DUPLICATED 0x02
# define IN_IFF_DETACHED 0x00
#endif
#ifdef IN_IFF_TENTATIVE
#define IN_IFF_NOTUSEABLE \
(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED | IN_IFF_DETACHED)
#endif
#define IN_ARE_ADDR_EQUAL(a, b) ((a)->s_addr == (b)->s_addr)
#define IN_IS_ADDR_UNSPECIFIED(a) ((a)->s_addr == INADDR_ANY)
#ifdef __linux__
#define IP_LIFETIME
#endif
struct ipv4_addr {
TAILQ_ENTRY(ipv4_addr) next;
struct in_addr addr;
struct in_addr mask;
struct in_addr brd;
struct interface *iface;
int addr_flags;
unsigned int flags;
#ifdef IP_LIFETIME
uint32_t vltime;
uint32_t pltime;
#endif
char saddr[INET_ADDRSTRLEN + 3];
#ifdef ALIAS_ADDR
char alias[IF_NAMESIZE];
#endif
};
TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
#define IPV4_AF_STALE (1U << 0)
#define IPV4_AF_NEW (1U << 1)
#define IPV4_ADDR_EQ(a1, a2) ((a1) && (a1)->addr.s_addr == (a2)->addr.s_addr)
#define IPV4_MASK1_EQ(a1, a2) ((a1) && (a1)->mask.s_addr == (a2)->mask.s_addr)
#define IPV4_MASK_EQ(a1, a2) (IPV4_ADDR_EQ(a1, a2) && IPV4_MASK1_EQ(a1, a2))
#define IPV4_BRD1_EQ(a1, a2) ((a1) && (a1)->brd.s_addr == (a2)->brd.s_addr)
#define IPV4_BRD_EQ(a1, a2) (IPV4_MASK_EQ(a1, a2) && IPV4_BRD1_EQ(a1, a2))
struct ipv4_state {
struct ipv4_addrhead addrs;
};
#define IPV4_STATE(ifp) \
((struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
#define IPV4_CSTATE(ifp) \
((const struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
#ifdef INET
struct ipv4_state *ipv4_getstate(struct interface *);
int ipv4_ifcmp(const struct interface *, const struct interface *);
uint8_t inet_ntocidr(struct in_addr);
int inet_cidrtoaddr(int, struct in_addr *);
uint32_t ipv4_getnetmask(uint32_t);
int ipv4_hasaddr(const struct interface *);
bool inet_getroutes(struct dhcpcd_ctx *, rb_tree_t *);
#define STATE_ADDED 0x01
#define STATE_FAKE 0x02
#define STATE_EXPIRED 0x04
int ipv4_deladdr(struct ipv4_addr *, int);
struct ipv4_addr *ipv4_addaddr(struct interface *,
const struct in_addr *, const struct in_addr *, const struct in_addr *,
uint32_t, uint32_t);
struct ipv4_addr *ipv4_applyaddr(void *);
struct ipv4_addr *ipv4_iffindaddr(struct interface *,
const struct in_addr *, const struct in_addr *);
struct ipv4_addr *ipv4_iffindlladdr(struct interface *);
struct ipv4_addr *ipv4_findaddr(struct dhcpcd_ctx *, const struct in_addr *);
struct ipv4_addr *ipv4_findmaskaddr(struct dhcpcd_ctx *,
const struct in_addr *);
struct ipv4_addr *ipv4_findmaskbrd(struct dhcpcd_ctx *,
const struct in_addr *);
void ipv4_markaddrsstale(struct interface *);
void ipv4_deletestaleaddrs(struct interface *);
void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *,
const struct in_addr *, const struct in_addr *, const struct in_addr *,
int, pid_t);
void ipv4_free(struct interface *);
#endif /* INET */
#endif /* IPV4_H */

561
external/bsd/dhcpcd/dist/src/ipv4ll.c vendored Normal file
View File

@ -0,0 +1,561 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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 <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define ELOOP_QUEUE IPV4LL
#include "config.h"
#include "arp.h"
#include "common.h"
#include "dhcp.h"
#include "eloop.h"
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "logerr.h"
#include "sa.h"
#include "script.h"
static const struct in_addr inaddr_llmask = {
.s_addr = HTONL(LINKLOCAL_MASK)
};
static const struct in_addr inaddr_llbcast = {
.s_addr = HTONL(LINKLOCAL_BCAST)
};
static void
ipv4ll_pickaddr(struct interface *ifp)
{
struct in_addr addr = { .s_addr = 0 };
struct ipv4ll_state *state;
state = IPV4LL_STATE(ifp);
setstate(state->randomstate);
do {
long r;
again:
/* RFC 3927 Section 2.1 states that the first 256 and
* last 256 addresses are reserved for future use.
* See ipv4ll_start for why we don't use arc4random. */
/* coverity[dont_call] */
r = random();
addr.s_addr = ntohl(LINKLOCAL_ADDR |
((uint32_t)(r % 0xFD00) + 0x0100));
/* No point using a failed address */
if (IN_ARE_ADDR_EQUAL(&addr, &state->pickedaddr))
goto again;
/* Ensure we don't have the address on another interface */
} while (ipv4_findaddr(ifp->ctx, &addr) != NULL);
/* Restore the original random state */
setstate(ifp->ctx->randomstate);
state->pickedaddr = addr;
}
int
ipv4ll_subnetroute(rb_tree_t *routes, struct interface *ifp)
{
struct ipv4ll_state *state;
struct rt *rt;
struct in_addr in;
assert(ifp != NULL);
if ((state = IPV4LL_STATE(ifp)) == NULL ||
state->addr == NULL)
return 0;
if ((rt = rt_new(ifp)) == NULL)
return -1;
in.s_addr = state->addr->addr.s_addr & state->addr->mask.s_addr;
sa_in_init(&rt->rt_dest, &in);
in.s_addr = state->addr->mask.s_addr;
sa_in_init(&rt->rt_netmask, &in);
in.s_addr = INADDR_ANY;
sa_in_init(&rt->rt_gateway, &in);
sa_in_init(&rt->rt_ifa, &state->addr->addr);
rt->rt_dflags |= RTDF_IPV4LL;
return rt_proto_add(routes, rt) ? 1 : 0;
}
int
ipv4ll_defaultroute(rb_tree_t *routes, struct interface *ifp)
{
struct ipv4ll_state *state;
struct rt *rt;
struct in_addr in;
assert(ifp != NULL);
if ((state = IPV4LL_STATE(ifp)) == NULL ||
state->addr == NULL)
return 0;
if ((rt = rt_new(ifp)) == NULL)
return -1;
in.s_addr = INADDR_ANY;
sa_in_init(&rt->rt_dest, &in);
sa_in_init(&rt->rt_netmask, &in);
sa_in_init(&rt->rt_gateway, &in);
sa_in_init(&rt->rt_ifa, &state->addr->addr);
rt->rt_dflags |= RTDF_IPV4LL;
#ifdef HAVE_ROUTE_METRIC
rt->rt_metric += RTMETRIC_IPV4LL;
#endif
return rt_proto_add(routes, rt) ? 1 : 0;
}
ssize_t
ipv4ll_env(FILE *fp, const char *prefix, const struct interface *ifp)
{
const struct ipv4ll_state *state;
const char *pf = prefix == NULL ? "" : "_";
struct in_addr netnum;
assert(ifp != NULL);
if ((state = IPV4LL_CSTATE(ifp)) == NULL || state->addr == NULL)
return 0;
/* Emulate a DHCP environment */
if (efprintf(fp, "%s%sip_address=%s",
prefix, pf, inet_ntoa(state->addr->addr)) == -1)
return -1;
if (efprintf(fp, "%s%ssubnet_mask=%s",
prefix, pf, inet_ntoa(state->addr->mask)) == -1)
return -1;
if (efprintf(fp, "%s%ssubnet_cidr=%d",
prefix, pf, inet_ntocidr(state->addr->mask)) == -1)
return -1;
if (efprintf(fp, "%s%sbroadcast_address=%s",
prefix, pf, inet_ntoa(state->addr->brd)) == -1)
return -1;
netnum.s_addr = state->addr->addr.s_addr & state->addr->mask.s_addr;
if (efprintf(fp, "%s%snetwork_number=%s",
prefix, pf, inet_ntoa(netnum)) == -1)
return -1;
return 5;
}
static void
ipv4ll_announced_arp(struct arp_state *astate)
{
struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
state->conflicts = 0;
#ifdef KERNEL_RFC5227
arp_free(astate);
#endif
}
#ifndef KERNEL_RFC5227
/* This is the callback by ARP freeing */
static void
ipv4ll_free_arp(struct arp_state *astate)
{
struct ipv4ll_state *state;
state = IPV4LL_STATE(astate->iface);
if (state != NULL && state->arp == astate)
state->arp = NULL;
}
/* This is us freeing any ARP state */
static void
ipv4ll_freearp(struct interface *ifp)
{
struct ipv4ll_state *state;
state = IPV4LL_STATE(ifp);
if (state == NULL || state->arp == NULL)
return;
eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
arp_free(state->arp);
state->arp = NULL;
}
#else
#define ipv4ll_freearp(ifp)
#endif
static void
ipv4ll_not_found(struct interface *ifp)
{
struct ipv4ll_state *state;
struct ipv4_addr *ia;
struct arp_state *astate;
state = IPV4LL_STATE(ifp);
ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
#ifdef IN_IFF_NOTREADY
if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
#endif
loginfox("%s: using IPv4LL address %s",
ifp->name, inet_ntoa(state->pickedaddr));
if (!(ifp->options->options & DHCPCD_CONFIGURE))
goto run;
if (ia == NULL) {
if (ifp->ctx->options & DHCPCD_TEST)
goto test;
ia = ipv4_addaddr(ifp, &state->pickedaddr,
&inaddr_llmask, &inaddr_llbcast,
DHCP_INFINITE_LIFETIME, DHCP_INFINITE_LIFETIME);
}
if (ia == NULL)
return;
#ifdef IN_IFF_NOTREADY
if (ia->addr_flags & IN_IFF_NOTREADY)
return;
logdebugx("%s: DAD completed for %s", ifp->name, ia->saddr);
#endif
test:
state->addr = ia;
state->down = false;
if (ifp->ctx->options & DHCPCD_TEST) {
script_runreason(ifp, "TEST");
eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
return;
}
rt_build(ifp->ctx, AF_INET);
run:
astate = arp_announceaddr(ifp->ctx, &ia->addr);
if (astate != NULL)
astate->announced_cb = ipv4ll_announced_arp;
script_runreason(ifp, "IPV4LL");
dhcpcd_daemonise(ifp->ctx);
}
static void
ipv4ll_found(struct interface *ifp)
{
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
ipv4ll_freearp(ifp);
if (++state->conflicts == MAX_CONFLICTS)
logerrx("%s: failed to acquire an IPv4LL address",
ifp->name);
ipv4ll_pickaddr(ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
state->conflicts >= MAX_CONFLICTS ?
RATE_LIMIT_INTERVAL : PROBE_WAIT,
ipv4ll_start, ifp);
}
static void
ipv4ll_defend_failed(struct interface *ifp)
{
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
ipv4ll_freearp(ifp);
if (ifp->options->options & DHCPCD_CONFIGURE)
ipv4_deladdr(state->addr, 1);
state->addr = NULL;
rt_build(ifp->ctx, AF_INET);
script_runreason(ifp, "IPV4LL");
ipv4ll_pickaddr(ifp);
ipv4ll_start(ifp);
}
#ifndef KERNEL_RFC5227
static void
ipv4ll_not_found_arp(struct arp_state *astate)
{
ipv4ll_not_found(astate->iface);
}
static void
ipv4ll_found_arp(struct arp_state *astate, __unused const struct arp_msg *amsg)
{
ipv4ll_found(astate->iface);
}
static void
ipv4ll_defend_failed_arp(struct arp_state *astate)
{
ipv4ll_defend_failed(astate->iface);
}
#endif
void
ipv4ll_start(void *arg)
{
struct interface *ifp = arg;
struct ipv4ll_state *state;
struct ipv4_addr *ia;
bool repick;
#ifndef KERNEL_RFC5227
struct arp_state *astate;
#endif
if ((state = IPV4LL_STATE(ifp)) == NULL) {
ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
if ((state = IPV4LL_STATE(ifp)) == NULL) {
logerr(__func__);
return;
}
}
if (state->running)
return;
state->running = true;
/* RFC 3927 Section 2.1 states that the random number generator
* SHOULD be seeded with a value derived from persistent information
* such as the IEEE 802 MAC address so that it usually picks
* the same address without persistent storage. */
if (!state->seeded) {
unsigned int seed;
char *orig;
if (sizeof(seed) > ifp->hwlen) {
seed = 0;
memcpy(&seed, ifp->hwaddr, ifp->hwlen);
} else
memcpy(&seed, ifp->hwaddr + ifp->hwlen - sizeof(seed),
sizeof(seed));
/* coverity[dont_call] */
orig = initstate(seed,
state->randomstate, sizeof(state->randomstate));
/* Save the original state. */
if (ifp->ctx->randomstate == NULL)
ifp->ctx->randomstate = orig;
/* Set back the original state until we need the seeded one. */
setstate(ifp->ctx->randomstate);
state->seeded = true;
}
/* Find the previosuly used address. */
if (state->pickedaddr.s_addr != INADDR_ANY)
ia = ipv4_iffindaddr(ifp, &state->pickedaddr, NULL);
else
ia = NULL;
/* Find an existing IPv4LL address and ensure we can work with it. */
if (ia == NULL)
ia = ipv4_iffindlladdr(ifp);
repick = false;
#ifdef IN_IFF_DUPLICATED
if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
state->pickedaddr = ia->addr; /* So it's not picked again. */
repick = true;
if (ifp->options->options & DHCPCD_CONFIGURE)
ipv4_deladdr(ia, 0);
ia = NULL;
}
#endif
state->addr = ia;
state->down = true;
if (ia != NULL) {
state->pickedaddr = ia->addr;
#ifdef IN_IFF_TENTATIVE
if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
loginfox("%s: waiting for DAD to complete on %s",
ifp->name, inet_ntoa(ia->addr));
return;
}
#endif
#ifdef IN_IFF_DUPLICATED
loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr);
#endif
} else {
loginfox("%s: probing for an IPv4LL address", ifp->name);
if (repick || state->pickedaddr.s_addr == INADDR_ANY)
ipv4ll_pickaddr(ifp);
}
#ifdef KERNEL_RFC5227
ipv4ll_not_found(ifp);
#else
ipv4ll_freearp(ifp);
state->arp = astate = arp_new(ifp, &state->pickedaddr);
if (state->arp == NULL)
return;
astate->found_cb = ipv4ll_found_arp;
astate->not_found_cb = ipv4ll_not_found_arp;
astate->announced_cb = ipv4ll_announced_arp;
astate->defend_failed_cb = ipv4ll_defend_failed_arp;
astate->free_cb = ipv4ll_free_arp;
arp_probe(astate);
#endif
}
void
ipv4ll_drop(struct interface *ifp)
{
struct ipv4ll_state *state;
bool dropped = false;
struct ipv4_state *istate;
assert(ifp != NULL);
ipv4ll_freearp(ifp);
if ((ifp->options->options & DHCPCD_NODROP) == DHCPCD_NODROP)
return;
state = IPV4LL_STATE(ifp);
if (state) {
state->running = false;
if (state->addr != NULL) {
if (ifp->options->options & DHCPCD_CONFIGURE)
ipv4_deladdr(state->addr, 1);
state->addr = NULL;
dropped = true;
}
}
/* Free any other link local addresses that might exist. */
if ((istate = IPV4_STATE(ifp)) != NULL) {
struct ipv4_addr *ia, *ian;
TAILQ_FOREACH_SAFE(ia, &istate->addrs, next, ian) {
if (IN_LINKLOCAL(ntohl(ia->addr.s_addr))) {
if (ifp->options->options & DHCPCD_CONFIGURE)
ipv4_deladdr(ia, 0);
dropped = true;
}
}
}
if (dropped) {
rt_build(ifp->ctx, AF_INET);
script_runreason(ifp, "IPV4LL");
}
}
void
ipv4ll_reset(struct interface *ifp)
{
struct ipv4ll_state *state = IPV4LL_STATE(ifp);
if (state == NULL)
return;
ipv4ll_freearp(ifp);
state->pickedaddr.s_addr = INADDR_ANY;
state->seeded = false;
}
void
ipv4ll_free(struct interface *ifp)
{
assert(ifp != NULL);
ipv4ll_freearp(ifp);
free(IPV4LL_STATE(ifp));
ifp->if_data[IF_DATA_IPV4LL] = NULL;
}
/* This may cause issues in BSD systems, where running as a single dhcpcd
* daemon would solve this issue easily. */
#ifdef HAVE_ROUTE_METRIC
int
ipv4ll_recvrt(__unused int cmd, const struct rt *rt)
{
struct dhcpcd_ctx *ctx;
struct interface *ifp;
/* Only interested in default route changes. */
if (sa_is_unspecified(&rt->rt_dest))
return 0;
/* If any interface is running IPv4LL, rebuild our routing table. */
ctx = rt->rt_ifp->ctx;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (IPV4LL_STATE_RUNNING(ifp)) {
rt_build(ctx, AF_INET);
break;
}
}
return 0;
}
#endif
struct ipv4_addr *
ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid)
{
struct interface *ifp;
struct ipv4ll_state *state;
ifp = ia->iface;
state = IPV4LL_STATE(ifp);
if (state == NULL)
return ia;
if (cmd == RTM_DELADDR &&
state->addr != NULL &&
IN_ARE_ADDR_EQUAL(&state->addr->addr, &ia->addr))
{
loginfox("%s: pid %d deleted IP address %s",
ifp->name, pid, ia->saddr);
ipv4ll_defend_failed(ifp);
return ia;
}
#ifdef IN_IFF_DUPLICATED
if (cmd != RTM_NEWADDR)
return ia;
if (!IN_ARE_ADDR_EQUAL(&state->pickedaddr, &ia->addr))
return ia;
if (!(ia->addr_flags & IN_IFF_NOTUSEABLE))
ipv4ll_not_found(ifp);
else if (ia->addr_flags & IN_IFF_DUPLICATED) {
logerrx("%s: DAD detected %s", ifp->name, ia->saddr);
ipv4ll_freearp(ifp);
if (ifp->options->options & DHCPCD_CONFIGURE)
ipv4_deladdr(ia, 1);
state->addr = NULL;
rt_build(ifp->ctx, AF_INET);
ipv4ll_found(ifp);
return NULL;
}
#endif
return ia;
}

80
external/bsd/dhcpcd/dist/src/ipv4ll.h vendored Normal file
View File

@ -0,0 +1,80 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef IPV4LL_H
#define IPV4LL_H
#define LINKLOCAL_ADDR 0xa9fe0000
#define LINKLOCAL_MASK IN_CLASSB_NET
#define LINKLOCAL_BCAST (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
#ifndef IN_LINKLOCAL
# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
#endif
#ifdef IPV4LL
#include "arp.h"
struct ipv4ll_state {
struct in_addr pickedaddr;
struct ipv4_addr *addr;
char randomstate[128];
bool running;
bool seeded;
bool down;
size_t conflicts;
#ifndef KERNEL_RFC5227
struct arp_state *arp;
#endif
};
#define IPV4LL_STATE(ifp) \
((struct ipv4ll_state *)(ifp)->if_data[IF_DATA_IPV4LL])
#define IPV4LL_CSTATE(ifp) \
((const struct ipv4ll_state *)(ifp)->if_data[IF_DATA_IPV4LL])
#define IPV4LL_STATE_RUNNING(ifp) \
(IPV4LL_CSTATE((ifp)) && !IPV4LL_CSTATE((ifp))->down && \
(IPV4LL_CSTATE((ifp))->addr != NULL))
int ipv4ll_subnetroute(rb_tree_t *, struct interface *);
int ipv4ll_defaultroute(rb_tree_t *,struct interface *);
ssize_t ipv4ll_env(FILE *, const char *, const struct interface *);
void ipv4ll_start(void *);
void ipv4ll_claimed(void *);
void ipv4ll_handle_failure(void *);
struct ipv4_addr *ipv4ll_handleifa(int, struct ipv4_addr *, pid_t pid);
#ifdef HAVE_ROUTE_METRIC
int ipv4ll_recvrt(int, const struct rt *);
#endif
void ipv4ll_reset(struct interface *);
void ipv4ll_drop(struct interface *);
void ipv4ll_free(struct interface *);
#endif
#endif

2431
external/bsd/dhcpcd/dist/src/ipv6.c vendored Normal file

File diff suppressed because it is too large Load Diff

316
external/bsd/dhcpcd/dist/src/ipv6.h vendored Normal file
View File

@ -0,0 +1,316 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef IPV6_H
#define IPV6_H
#include <sys/uio.h>
#include <netinet/in.h>
#include "config.h"
#include "if.h"
#ifndef __linux__
# if !defined(__QNX__) && !defined(__sun)
# include <sys/endian.h>
# endif
# include <net/if.h>
# ifndef __sun
# include <netinet6/in6_var.h>
# endif
#endif
#define EUI64_GBIT 0x01
#define EUI64_UBIT 0x02
#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
#ifndef ND6_INFINITE_LIFETIME
# define ND6_INFINITE_LIFETIME ((uint32_t)~0)
#endif
/* RFC4941 constants */
#define TEMP_VALID_LIFETIME 604800 /* 1 week */
#define TEMP_PREFERRED_LIFETIME 86400 /* 1 day */
#define REGEN_ADVANCE 5 /* seconds */
#define MAX_DESYNC_FACTOR 600 /* 10 minutes */
#define TEMP_IDGEN_RETRIES 3
/* RFC7217 constants */
#define IDGEN_RETRIES 3
#define IDGEN_DELAY 1 /* second */
/* Interface identifier length. Prefix + this == 128 for autoconf */
#define ipv6_ifidlen(ifp) 64
#define IA6_CANAUTOCONF(ia) \
((ia)->prefix_len + ipv6_ifidlen((ia)->iface) == 128)
#ifndef IN6_ARE_MASKED_ADDR_EQUAL
#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
(((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
(((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \
(((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \
(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
#endif
#ifndef IN6ADDR_LINKLOCAL_ALLNODES_INIT
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
#endif
#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
#endif
/*
* BSD kernels don't inform userland of DAD results.
* See the discussion here:
* http://mail-index.netbsd.org/tech-net/2013/03/15/msg004019.html
*/
#ifndef __linux__
/* We guard here to avoid breaking a compile on linux ppc-64 headers */
# include <sys/param.h>
#endif
#ifdef BSD
# define IPV6_POLLADDRFLAG
#endif
/* This was fixed in NetBSD */
#if (defined(__DragonFly_version) && __DragonFly_version >= 500704) || \
(defined(__NetBSD_Version__) && __NetBSD_Version__ >= 699002000)
# undef IPV6_POLLADDRFLAG
#endif
/* Of course OpenBSD has their own special name. */
#if !defined(IN6_IFF_TEMPORARY) && defined(IN6_IFF_PRIVACY)
#define IN6_IFF_TEMPORARY IN6_IFF_PRIVACY
#endif
#ifdef __sun
/* Solaris lacks these defines.
* While it supports DaD, to seems to only expose IFF_DUPLICATE
* so we have no way of knowing if it's tentative or not.
* I don't even know if Solaris has any special treatment for tentative. */
# define IN6_IFF_TENTATIVE 0x02
# define IN6_IFF_DUPLICATED 0x04
# define IN6_IFF_DETACHED 0x00
#endif
#define IN6_IFF_NOTUSEABLE \
(IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED)
/*
* If dhcpcd handles RA processing instead of the kernel, the kernel needs
* to either allow userland to set temporary addresses or mark an address
* for the kernel to manage temporary addresses from.
* If the kernel allows the former, a global #define is needed, otherwise
* the address marking will be handled in the platform specific address handler.
*
* Some BSDs do not allow userland to set temporary addresses.
* Linux-3.18 allows the marking of addresses from which to manage temp addrs.
*/
#if defined(IN6_IFF_TEMPORARY) && !defined(__linux__)
#define IPV6_MANAGETEMPADDR
#endif
#ifdef __linux__
/* Match Linux defines to BSD */
# ifdef IFA_F_TEMPORARY
# define IN6_IFF_TEMPORARY IFA_F_TEMPORARY
# endif
# ifdef IFA_F_OPTIMISTIC
# define IN6_IFF_TENTATIVE (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)
# else
# define IN6_IFF_TENTATIVE (IFA_F_TENTATIVE | 0x04)
# endif
# ifdef IF_F_DADFAILED
# define IN6_IFF_DUPLICATED IFA_F_DADFAILED
# else
# define IN6_IFF_DUPLICATED 0x08
# endif
# define IN6_IFF_DETACHED 0
#endif
/*
* ND6 Advertising is only used for IP address sharing to prefer
* the address on a specific interface.
* This just fails to work on OpenBSD and causes erroneous duplicate
* address messages on BSD's other then DragonFly and NetBSD.
*/
#if !defined(SMALL) && \
((defined(__DragonFly_version) && __DragonFly_version >= 500703) || \
(defined(__NetBSD_Version__) && __NetBSD_Version__ >= 899002800) || \
defined(__linux__) || defined(__sun))
# define ND6_ADVERTISE
#endif
#ifdef INET6
TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
struct ipv6_addr {
TAILQ_ENTRY(ipv6_addr) next;
struct interface *iface;
struct in6_addr prefix;
uint8_t prefix_len;
uint32_t prefix_vltime;
uint32_t prefix_pltime;
struct timespec created;
struct timespec acquired;
struct in6_addr addr;
int addr_flags;
unsigned int flags;
char saddr[INET6_ADDRSTRLEN];
uint8_t iaid[4];
uint16_t ia_type;
int dhcp6_fd;
#ifndef SMALL
struct ipv6_addr *delegating_prefix;
struct ipv6_addrhead pd_pfxs;
TAILQ_ENTRY(ipv6_addr) pd_next;
uint8_t prefix_exclude_len;
struct in6_addr prefix_exclude;
#endif
void (*dadcallback)(void *);
int dadcounter;
struct nd_neighbor_advert *na;
size_t na_len;
int na_count;
#ifdef ALIAS_ADDR
char alias[IF_NAMESIZE];
#endif
};
#define IPV6_AF_ONLINK (1U << 0)
#define IPV6_AF_NEW (1U << 1)
#define IPV6_AF_STALE (1U << 2)
#define IPV6_AF_ADDED (1U << 3)
#define IPV6_AF_AUTOCONF (1U << 4)
#define IPV6_AF_DADCOMPLETED (1U << 5)
#define IPV6_AF_DELEGATED (1U << 6)
#define IPV6_AF_DELEGATEDPFX (1U << 7)
#define IPV6_AF_NOREJECT (1U << 8)
#define IPV6_AF_REQUEST (1U << 9)
#define IPV6_AF_STATIC (1U << 10)
#define IPV6_AF_DELEGATEDLOG (1U << 11)
#define IPV6_AF_RAPFX (1U << 12)
#define IPV6_AF_EXTENDED (1U << 13)
#define IPV6_AF_REGEN (1U << 14)
#define IPV6_AF_ROUTER (1U << 15)
#ifdef IPV6_MANAGETEMPADDR
#define IPV6_AF_TEMPORARY (1U << 16)
#endif
struct ll_callback {
TAILQ_ENTRY(ll_callback) next;
void (*callback)(void *);
void *arg;
};
TAILQ_HEAD(ll_callback_head, ll_callback);
struct ipv6_state {
struct ipv6_addrhead addrs;
struct ll_callback_head ll_callbacks;
#ifdef IPV6_MANAGETEMPADDR
uint32_t desync_factor;
#endif
};
#define IPV6_STATE(ifp) \
((struct ipv6_state *)(ifp)->if_data[IF_DATA_IPV6])
#define IPV6_CSTATE(ifp) \
((const struct ipv6_state *)(ifp)->if_data[IF_DATA_IPV6])
#define IPV6_STATE_RUNNING(ifp) ipv6_staticdadcompleted((ifp))
int ipv6_init(struct dhcpcd_ctx *);
int ipv6_makestableprivate(struct in6_addr *,
const struct in6_addr *, int, const struct interface *, int *);
int ipv6_makeaddr(struct in6_addr *, struct interface *,
const struct in6_addr *, int, unsigned int);
int ipv6_mask(struct in6_addr *, int);
uint8_t ipv6_prefixlen(const struct in6_addr *);
int ipv6_userprefix( const struct in6_addr *, short prefix_len,
uint64_t user_number, struct in6_addr *result, short result_len);
void ipv6_checkaddrflags(void *);
void ipv6_markaddrsstale(struct interface *, unsigned int);
void ipv6_deletestaleaddrs(struct interface *);
int ipv6_addaddr(struct ipv6_addr *, const struct timespec *);
int ipv6_doaddr(struct ipv6_addr *, struct timespec *);
ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs);
void ipv6_deleteaddr(struct ipv6_addr *);
void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,
const struct interface *);
void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
const char *, const struct in6_addr *, uint8_t, int, pid_t);
int ipv6_handleifa_addrs(int, struct ipv6_addrhead *, const struct ipv6_addr *,
pid_t);
struct ipv6_addr *ipv6_iffindaddr(struct interface *,
const struct in6_addr *, int);
int ipv6_hasaddr(const struct interface *);
struct ipv6_addr *ipv6_anyglobal(struct interface *);
int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
unsigned int);
struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, unsigned int);
struct ipv6_addr *ipv6_findmaskaddr(struct dhcpcd_ctx *,
const struct in6_addr *);
#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL, IN6_IFF_NOTUSEABLE)
int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
void ipv6_setscope(struct sockaddr_in6 *, unsigned int);
unsigned int ipv6_getscope(const struct sockaddr_in6 *);
struct ipv6_addr *ipv6_newaddr(struct interface *, const struct in6_addr *,
uint8_t, unsigned int);
void ipv6_freeaddr(struct ipv6_addr *);
void ipv6_freedrop(struct interface *, int);
#define ipv6_free(ifp) ipv6_freedrop((ifp), 0)
#define ipv6_drop(ifp) ipv6_freedrop((ifp), 2)
#ifdef IPV6_MANAGETEMPADDR
struct ipv6_addr *ipv6_createtempaddr(struct ipv6_addr *,
const struct timespec *);
struct ipv6_addr *ipv6_settemptime(struct ipv6_addr *, int);
void ipv6_addtempaddrs(struct interface *, const struct timespec *);
void ipv6_regentempaddrs(void *);
#endif
int ipv6_start(struct interface *);
int ipv6_staticdadcompleted(const struct interface *);
int ipv6_startstatic(struct interface *);
ssize_t ipv6_env(FILE *, const char *, const struct interface *);
void ipv6_ctxfree(struct dhcpcd_ctx *);
bool inet6_getroutes(struct dhcpcd_ctx *, rb_tree_t *);
#endif /* INET6 */
#endif /* INET6_H */

2254
external/bsd/dhcpcd/dist/src/ipv6nd.c vendored Normal file

File diff suppressed because it is too large Load Diff

147
external/bsd/dhcpcd/dist/src/ipv6nd.h vendored Normal file
View File

@ -0,0 +1,147 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - IPv6 ND handling
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef IPV6ND_H
#define IPV6ND_H
#ifdef INET6
#include <time.h>
#include "config.h"
#include "dhcpcd.h"
#include "ipv6.h"
/* rfc4191 */
struct routeinfo {
TAILQ_ENTRY(routeinfo) next;
struct in6_addr prefix;
uint8_t prefix_len;
uint32_t lifetime;
uint8_t flags;
struct timespec acquired;
char sprefix[INET6_ADDRSTRLEN];
};
TAILQ_HEAD(routeinfohead, routeinfo);
struct ra {
TAILQ_ENTRY(ra) next;
struct interface *iface;
struct in6_addr from;
char sfrom[INET6_ADDRSTRLEN];
uint8_t *data;
size_t data_len;
struct timespec acquired;
uint8_t flags;
uint32_t lifetime;
uint32_t reachable;
uint32_t retrans;
uint32_t mtu;
uint8_t hoplimit;
struct ipv6_addrhead addrs;
struct routeinfohead rinfos;
bool hasdns;
bool expired;
bool willexpire;
bool doexpire;
bool isreachable;
};
TAILQ_HEAD(ra_head, ra);
struct rs_state {
struct nd_router_solicit *rs;
size_t rslen;
int rsprobes;
uint32_t retrans;
#ifdef __sun
int nd_fd;
#endif
};
#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
#define RS_CSTATE(a) ((const struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
#define RS_STATE_RUNNING(a) (ipv6nd_hasra((a)) && ipv6nd_dadcompleted((a)))
#ifndef MAX_RTR_SOLICITATION_DELAY
#define MAX_RTR_SOLICITATION_DELAY 1 /* seconds */
#define MAX_UNICAST_SOLICIT 3 /* 3 transmissions */
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
#define MAX_RTR_SOLICITATIONS 3 /* times */
#define MAX_NEIGHBOR_ADVERTISEMENT 3 /* 3 transmissions */
#ifndef IPV6_DEFHLIM
#define IPV6_DEFHLIM 64
#endif
#endif
/* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */
#define RTR_CARRIER_EXPIRE \
(MAX_RTR_SOLICITATION_DELAY + \
(MAX_RTR_SOLICITATIONS + 1) * \
RTR_SOLICITATION_INTERVAL)
#define MAX_REACHABLE_TIME 3600000 /* milliseconds */
#define REACHABLE_TIME 30000 /* milliseconds */
#define RETRANS_TIMER 1000 /* milliseconds */
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
#define MIN_EXTENDED_VLTIME 7200 /* seconds */
int ipv6nd_open(bool);
#ifdef __sun
int ipv6nd_openif(struct interface *);
#endif
void ipv6nd_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
int ipv6nd_rtpref(uint8_t);
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
void ipv6nd_startrs(struct interface *);
ssize_t ipv6nd_env(FILE *, const struct interface *);
const struct ipv6_addr *ipv6nd_iffindaddr(const struct interface *ifp,
const struct in6_addr *addr, unsigned int flags);
struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, unsigned int);
struct ipv6_addr *ipv6nd_iffindprefix(struct interface *,
const struct in6_addr *, uint8_t);
ssize_t ipv6nd_free(struct interface *);
void ipv6nd_expirera(void *arg);
bool ipv6nd_hasralifetime(const struct interface *, bool);
#define ipv6nd_hasra(i) ipv6nd_hasralifetime((i), false)
bool ipv6nd_hasradhcp(const struct interface *, bool);
void ipv6nd_handleifa(int, struct ipv6_addr *, pid_t);
int ipv6nd_dadcompleted(const struct interface *);
void ipv6nd_advertise(struct ipv6_addr *);
void ipv6nd_startexpire(struct interface *);
void ipv6nd_drop(struct interface *);
void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, bool);
#endif /* INET6 */
#endif /* IPV6ND_H */

499
external/bsd/dhcpcd/dist/src/logerr.c vendored Normal file
View File

@ -0,0 +1,499 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* logerr: errx with logging
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/time.h>
#include <errno.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include "logerr.h"
#ifndef LOGERR_SYSLOG_FACILITY
#define LOGERR_SYSLOG_FACILITY LOG_DAEMON
#endif
#ifdef SMALL
#undef LOGERR_TAG
#endif
/* syslog protocol is 1k message max, RFC 3164 section 4.1 */
#define LOGERR_SYSLOGBUF 1024 + sizeof(int) + sizeof(pid_t)
#define UNUSED(a) (void)(a)
struct logctx {
char log_buf[BUFSIZ];
unsigned int log_opts;
int log_fd;
pid_t log_pid;
#ifndef SMALL
FILE *log_file;
#ifdef LOGERR_TAG
const char *log_tag;
#endif
#endif
};
static struct logctx _logctx = {
/* syslog style, but without the hostname or tag. */
.log_opts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID,
.log_fd = -1,
.log_pid = 0,
};
#if defined(__linux__)
/* Poor man's getprogname(3). */
static char *_logprog;
static const char *
getprogname(void)
{
const char *p;
/* Use PATH_MAX + 1 to avoid truncation. */
if (_logprog == NULL) {
/* readlink(2) does not append a NULL byte,
* so zero the buffer. */
if ((_logprog = calloc(1, PATH_MAX + 1)) == NULL)
return NULL;
if (readlink("/proc/self/exe", _logprog, PATH_MAX + 1) == -1) {
free(_logprog);
_logprog = NULL;
return NULL;
}
}
if (_logprog[0] == '[')
return NULL;
p = strrchr(_logprog, '/');
if (p == NULL)
return _logprog;
return p + 1;
}
#endif
#ifndef SMALL
/* Write the time, syslog style. month day time - */
static int
logprintdate(FILE *stream)
{
struct timeval tv;
time_t now;
struct tm tmnow;
char buf[32];
if (gettimeofday(&tv, NULL) == -1)
return -1;
now = tv.tv_sec;
if (localtime_r(&now, &tmnow) == NULL)
return -1;
if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0)
return -1;
return fprintf(stream, "%s", buf);
}
#endif
__printflike(3, 0) static int
vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
{
int len = 0, e;
va_list a;
#ifndef SMALL
bool log_pid;
#ifdef LOGERR_TAG
bool log_tag;
#endif
if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) ||
(stream != stderr && ctx->log_opts & LOGERR_LOG_DATE))
{
if ((e = logprintdate(stream)) == -1)
return -1;
len += e;
}
#ifdef LOGERR_TAG
log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) ||
(stream != stderr && ctx->log_opts & LOGERR_LOG_TAG));
if (log_tag) {
if (ctx->log_tag == NULL)
ctx->log_tag = getprogname();
if ((e = fprintf(stream, "%s", ctx->log_tag)) == -1)
return -1;
len += e;
}
#endif
log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) ||
(stream != stderr && ctx->log_opts & LOGERR_LOG_PID));
if (log_pid) {
pid_t pid;
if (ctx->log_pid == 0)
pid = getpid();
else
pid = ctx->log_pid;
if ((e = fprintf(stream, "[%d]", pid)) == -1)
return -1;
len += e;
}
#ifdef LOGERR_TAG
if (log_tag || log_pid)
#else
if (log_pid)
#endif
{
if ((e = fprintf(stream, ": ")) == -1)
return -1;
len += e;
}
#else
UNUSED(ctx);
#endif
va_copy(a, args);
e = vfprintf(stream, fmt, a);
if (fputc('\n', stream) == EOF)
e = -1;
else if (e != -1)
e++;
va_end(a);
return e == -1 ? -1 : len + e;
}
/*
* NetBSD's gcc has been modified to check for the non standard %m in printf
* like functions and warn noisily about it that they should be marked as
* syslog like instead.
* This is all well and good, but our logger also goes via vfprintf and
* when marked as a sysloglike funcion, gcc will then warn us that the
* function should be printflike instead!
* This creates an infinte loop of gcc warnings.
* Until NetBSD solves this issue, we have to disable a gcc diagnostic
* for our fully standards compliant code in the logger function.
*/
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
#endif
__printflike(2, 0) static int
vlogmessage(int pri, const char *fmt, va_list args)
{
struct logctx *ctx = &_logctx;
int len = 0;
if (ctx->log_fd != -1) {
char buf[LOGERR_SYSLOGBUF];
pid_t pid;
memcpy(buf, &pri, sizeof(pri));
pid = getpid();
memcpy(buf + sizeof(pri), &pid, sizeof(pid));
len = vsnprintf(buf + sizeof(pri) + sizeof(pid),
sizeof(buf) - sizeof(pri) - sizeof(pid),
fmt, args);
if (len != -1)
len = (int)write(ctx->log_fd, buf,
((size_t)++len) + sizeof(pri) + sizeof(pid));
return len;
}
if (ctx->log_opts & LOGERR_ERR &&
(pri <= LOG_ERR ||
(!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) ||
(ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG)))
len = vlogprintf_r(ctx, stderr, fmt, args);
#ifndef SMALL
if (ctx->log_file != NULL &&
(pri != LOG_DEBUG || (ctx->log_opts & LOGERR_DEBUG)))
len = vlogprintf_r(ctx, ctx->log_file, fmt, args);
#endif
if (ctx->log_opts & LOGERR_LOG)
vsyslog(pri, fmt, args);
return len;
}
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
#pragma GCC diagnostic pop
#endif
__printflike(2, 3) void
logmessage(int pri, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogmessage(pri, fmt, args);
va_end(args);
}
__printflike(2, 0) static void
vlogerrmessage(int pri, const char *fmt, va_list args)
{
int _errno = errno;
char buf[1024];
vsnprintf(buf, sizeof(buf), fmt, args);
logmessage(pri, "%s: %s", buf, strerror(_errno));
errno = _errno;
}
__printflike(2, 3) void
logerrmessage(int pri, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogerrmessage(pri, fmt, args);
va_end(args);
}
void
log_debug(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogerrmessage(LOG_DEBUG, fmt, args);
va_end(args);
}
void
log_debugx(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogmessage(LOG_DEBUG, fmt, args);
va_end(args);
}
void
log_info(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogerrmessage(LOG_INFO, fmt, args);
va_end(args);
}
void
log_infox(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogmessage(LOG_INFO, fmt, args);
va_end(args);
}
void
log_warn(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogerrmessage(LOG_WARNING, fmt, args);
va_end(args);
}
void
log_warnx(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogmessage(LOG_WARNING, fmt, args);
va_end(args);
}
void
log_err(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogerrmessage(LOG_ERR, fmt, args);
va_end(args);
}
void
log_errx(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogmessage(LOG_ERR, fmt, args);
va_end(args);
}
int
loggetfd(void)
{
struct logctx *ctx = &_logctx;
return ctx->log_fd;
}
void
logsetfd(int fd)
{
struct logctx *ctx = &_logctx;
ctx->log_fd = fd;
if (fd != -1)
closelog();
#ifndef SMALL
if (fd != -1 && ctx->log_file != NULL) {
fclose(ctx->log_file);
ctx->log_file = NULL;
}
#endif
}
int
logreadfd(int fd)
{
struct logctx *ctx = &_logctx;
char buf[LOGERR_SYSLOGBUF];
int len, pri;
len = (int)read(fd, buf, sizeof(buf));
if (len == -1)
return -1;
/* Ensure we have pri, pid and a terminator */
if (len < (int)(sizeof(pri) + sizeof(pid_t) + 1) ||
buf[len - 1] != '\0')
{
errno = EINVAL;
return -1;
}
memcpy(&pri, buf, sizeof(pri));
memcpy(&ctx->log_pid, buf + sizeof(pri), sizeof(ctx->log_pid));
logmessage(pri, "%s", buf + sizeof(pri) + sizeof(ctx->log_pid));
ctx->log_pid = 0;
return len;
}
unsigned int
loggetopts(void)
{
struct logctx *ctx = &_logctx;
return ctx->log_opts;
}
void
logsetopts(unsigned int opts)
{
struct logctx *ctx = &_logctx;
ctx->log_opts = opts;
setlogmask(LOG_UPTO(opts & LOGERR_DEBUG ? LOG_DEBUG : LOG_INFO));
}
#ifdef LOGERR_TAG
void
logsettag(const char *tag)
{
#if !defined(SMALL)
struct logctx *ctx = &_logctx;
ctx->log_tag = tag;
#else
UNUSED(tag);
#endif
}
#endif
int
logopen(const char *path)
{
struct logctx *ctx = &_logctx;
int opts = 0;
/* Cache timezone */
tzset();
(void)setvbuf(stderr, ctx->log_buf, _IOLBF, sizeof(ctx->log_buf));
#ifndef SMALL
if (ctx->log_file != NULL) {
fclose(ctx->log_file);
ctx->log_file = NULL;
}
#endif
if (ctx->log_opts & LOGERR_LOG_PID)
opts |= LOG_PID;
openlog(getprogname(), opts, LOGERR_SYSLOG_FACILITY);
if (path == NULL)
return 1;
#ifndef SMALL
if ((ctx->log_file = fopen(path, "ae")) == NULL)
return -1;
setlinebuf(ctx->log_file);
return fileno(ctx->log_file);
#else
errno = ENOTSUP;
return -1;
#endif
}
void
logclose(void)
{
#ifndef SMALL
struct logctx *ctx = &_logctx;
#endif
closelog();
#if defined(__linux__)
free(_logprog);
_logprog = NULL;
#endif
#ifndef SMALL
if (ctx->log_file == NULL)
return;
fclose(ctx->log_file);
ctx->log_file = NULL;
#endif
}

111
external/bsd/dhcpcd/dist/src/logerr.h vendored Normal file
View File

@ -0,0 +1,111 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* logerr: errx with logging
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef LOGERR_H
#define LOGERR_H
#include <sys/param.h>
#ifndef __printflike
#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
#define __printflike(a, b) __attribute__((format(printf, a, b)))
#else
#define __printflike(a, b)
#endif
#endif /* !__printflike */
/* Please do not call log_* functions directly, use macros below */
__printflike(1, 2) void log_debug(const char *, ...);
__printflike(1, 2) void log_debugx(const char *, ...);
__printflike(1, 2) void log_info(const char *, ...);
__printflike(1, 2) void log_infox(const char *, ...);
__printflike(1, 2) void log_warn(const char *, ...);
__printflike(1, 2) void log_warnx(const char *, ...);
__printflike(1, 2) void log_err(const char *, ...);
__printflike(1, 2) void log_errx(const char *, ...);
#define LOGERROR logerr("%s: %d", __FILE__, __LINE__)
__printflike(2, 3) void logmessage(int pri, const char *fmt, ...);
__printflike(2, 3) void logerrmessage(int pri, const char *fmt, ...);
/*
* These are macros to prevent taking address of them so
* __FILE__, __LINE__, etc can easily be added.
*
* We should be using
* #define loginfox(fmt, __VA_OPT__(,) __VA_ARGS__)
* but that requires gcc-8 or clang-6 and we still have a need to support
* old OS's without modern compilers.
*
* Likewise, ##__VA_ARGS__ can't be used as that's a gcc only extension.
*
* The solution is to put fmt into __VA_ARGS__.
* It's not pretty but it's 100% portable.
*/
#define logdebug(...) log_debug(__VA_ARGS__)
#define logdebugx(...) log_debugx(__VA_ARGS__)
#define loginfo(...) log_info(__VA_ARGS__)
#define loginfox(...) log_infox(__VA_ARGS__)
#define logwarn(...) log_warn(__VA_ARGS__)
#define logwarnx(...) log_warnx(__VA_ARGS__)
#define logerr(...) log_err(__VA_ARGS__)
#define logerrx(...) log_errx(__VA_ARGS__)
/* For logging in a chroot */
int loggetfd(void);
void logsetfd(int);
int logreadfd(int);
unsigned int loggetopts(void);
void logsetopts(unsigned int);
#define LOGERR_DEBUG (1U << 6)
#define LOGERR_QUIET (1U << 7)
#define LOGERR_LOG (1U << 11)
#define LOGERR_LOG_DATE (1U << 12)
#define LOGERR_LOG_HOST (1U << 13)
#define LOGERR_LOG_TAG (1U << 14)
#define LOGERR_LOG_PID (1U << 15)
#define LOGERR_ERR (1U << 21)
#define LOGERR_ERR_DATE (1U << 22)
#define LOGERR_ERR_HOST (1U << 23)
#define LOGERR_ERR_TAG (1U << 24)
#define LOGERR_ERR_PID (1U << 25)
/* To build tag support or not. */
//#define LOGERR_TAG
#if defined(LOGERR_TAG)
void logsettag(const char *);
#endif
/* Can be called more than once. */
int logopen(const char *);
/* Should only be called at program exit. */
void logclose(void);
#endif

View File

@ -0,0 +1,386 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation BPF Initiator
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/socket.h>
#include <sys/types.h>
/* Need these headers just for if_ether on some OS. */
#ifndef __NetBSD__
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#endif
#include <netinet/if_ether.h>
#include <assert.h>
#include <pwd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arp.h"
#include "bpf.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "eloop.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 3 SEQPACKET and one RAW fd */
static void
ps_bpf_recvbpf(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
struct bpf *bpf = psp->psp_bpf;
uint8_t buf[FRAMELEN_MAX];
ssize_t len;
struct ps_msghdr psm = {
.ps_id = psp->psp_id,
.ps_cmd = psp->psp_id.psi_cmd,
};
if (events != ELE_READ)
logerrx("%s: unexpected event 0x%04x", __func__, events);
bpf->bpf_flags &= ~BPF_EOF;
/* A BPF read can read more than one filtered packet at time.
* This mechanism allows us to read each packet from the buffer. */
while (!(bpf->bpf_flags & BPF_EOF)) {
len = bpf_read(bpf, buf, sizeof(buf));
if (len == -1) {
int error = errno;
if (errno != ENETDOWN)
logerr("%s: %s", psp->psp_ifname, __func__);
if (error != ENXIO)
break;
/* If the interface has departed, close the BPF
* socket. This stops log spam if RTM_IFANNOUNCE is
* delayed in announcing the departing interface. */
eloop_event_delete(psp->psp_ctx->eloop, bpf->bpf_fd);
bpf_close(bpf);
psp->psp_bpf = NULL;
break;
}
if (len == 0)
break;
psm.ps_flags = bpf->bpf_flags;
len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd,
&psm, buf, (size_t)len);
if (len == -1)
logerr(__func__);
if (len == -1 || len == 0)
break;
}
}
static ssize_t
ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct ps_process *psp = arg;
struct iovec *iov = msg->msg_iov;
#ifdef PRIVSEP_DEBUG
logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
#endif
switch(psm->ps_cmd) {
#ifdef ARP
case PS_BPF_ARP: /* FALLTHROUGH */
#endif
case PS_BPF_BOOTP:
break;
default:
/* IPC failure, we should not be processing any commands
* at this point!/ */
errno = EINVAL;
return -1;
}
/* We might have had an earlier ENXIO error. */
if (psp->psp_bpf == NULL) {
errno = ENXIO;
return -1;
}
return bpf_send(psp->psp_bpf, psp->psp_proto,
iov->iov_base, iov->iov_len);
}
static void
ps_bpf_recvmsg(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
ps_bpf_recvmsgcb, arg) == -1)
logerr(__func__);
}
static int
ps_bpf_start_bpf(struct ps_process *psp)
{
struct dhcpcd_ctx *ctx = psp->psp_ctx;
char *addr;
struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
if (ia->s_addr == INADDR_ANY) {
ia = NULL;
addr = NULL;
} else
addr = inet_ntoa(*ia);
setproctitle("[BPF %s] %s%s%s", psp->psp_protostr, psp->psp_ifname,
addr != NULL ? " " : "", addr != NULL ? addr : "");
ps_freeprocesses(ctx, psp);
psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
#ifdef DEBUG_FD
logdebugx("pid %d bpf_fd=%d", getpid(), psp->psp_bpf->bpf_fd);
#endif
if (psp->psp_bpf == NULL)
logerr("%s: bpf_open",__func__);
#ifdef PRIVSEP_RIGHTS
else if (ps_rights_limit_fd(psp->psp_bpf->bpf_fd) == -1)
logerr("%s: ps_rights_limit_fd", __func__);
#endif
else if (eloop_event_add(ctx->eloop, psp->psp_bpf->bpf_fd, ELE_READ,
ps_bpf_recvbpf, psp) == -1)
logerr("%s: eloop_event_add", __func__);
else {
psp->psp_work_fd = psp->psp_bpf->bpf_fd;
return 0;
}
eloop_exit(ctx->eloop, EXIT_FAILURE);
return -1;
}
ssize_t
ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
{
uint16_t cmd;
struct ps_process *psp;
pid_t start;
struct iovec *iov = msg->msg_iov;
struct interface *ifp;
struct in_addr *ia = &psm->ps_id.psi_addr.psa_in_addr;
const char *addr;
cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
#endif
switch (cmd) {
#ifdef ARP
case PS_BPF_ARP: /* FALLTHROUGH */
#endif
case PS_BPF_BOOTP:
break;
default:
logerrx("%s: unknown command %x", __func__, psm->ps_cmd);
errno = ENOTSUP;
return -1;
}
if (!(psm->ps_cmd & PS_START)) {
errno = EINVAL;
return -1;
}
if (psp != NULL)
return 1;
psp = ps_newprocess(ctx, &psm->ps_id);
if (psp == NULL)
return -1;
ifp = &psp->psp_ifp;
assert(msg->msg_iovlen == 1);
assert(iov->iov_len == sizeof(*ifp));
memcpy(ifp, iov->iov_base, sizeof(*ifp));
ifp->ctx = psp->psp_ctx;
ifp->options = NULL;
memset(ifp->if_data, 0, sizeof(ifp->if_data));
memcpy(psp->psp_ifname, ifp->name, sizeof(psp->psp_ifname));
switch (cmd) {
#ifdef ARP
case PS_BPF_ARP:
psp->psp_proto = ETHERTYPE_ARP;
psp->psp_protostr = "ARP";
psp->psp_filter = bpf_arp;
break;
#endif
case PS_BPF_BOOTP:
psp->psp_proto = ETHERTYPE_IP;
psp->psp_protostr = "BOOTP";
psp->psp_filter = bpf_bootp;
break;
}
if (ia->s_addr == INADDR_ANY)
addr = NULL;
else
addr = inet_ntoa(*ia);
snprintf(psp->psp_name, sizeof(psp->psp_name), "BPF %s%s%s",
psp->psp_protostr,
addr != NULL ? " " : "", addr != NULL ? addr : "");
start = ps_startprocess(psp, ps_bpf_recvmsg, NULL,
ps_bpf_start_bpf, NULL, PSF_DROPPRIVS);
switch (start) {
case -1:
ps_freeprocess(psp);
return -1;
case 0:
ps_entersandbox("stdio", NULL);
break;
default:
logdebugx("%s: spawned %s on PID %d",
psp->psp_ifname, psp->psp_name, psp->psp_pid);
break;
}
return start;
}
ssize_t
ps_bpf_dispatch(struct dhcpcd_ctx *ctx,
struct ps_msghdr *psm, struct msghdr *msg)
{
struct iovec *iov = msg->msg_iov;
struct interface *ifp;
uint8_t *bpf;
size_t bpf_len;
switch (psm->ps_cmd) {
#ifdef ARP
case PS_BPF_ARP:
#endif
case PS_BPF_BOOTP:
break;
default:
errno = ENOTSUP;
return -1;
}
ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex);
/* interface may have departed .... */
if (ifp == NULL)
return -1;
bpf = iov->iov_base;
bpf_len = iov->iov_len;
switch (psm->ps_cmd) {
#ifdef ARP
case PS_BPF_ARP:
arp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
break;
#endif
case PS_BPF_BOOTP:
dhcp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
break;
}
return 1;
}
static ssize_t
ps_bpf_send(const struct interface *ifp, const struct in_addr *ia,
uint16_t cmd, const void *data, size_t len)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
struct ps_msghdr psm = {
.ps_cmd = cmd,
.ps_id = {
.psi_ifindex = ifp->index,
.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
},
};
if (ia != NULL)
psm.ps_id.psi_addr.psa_in_addr = *ia;
return ps_sendpsmdata(ctx, PS_ROOT_FD(ctx), &psm, data, len);
}
#ifdef ARP
ssize_t
ps_bpf_openarp(const struct interface *ifp, const struct in_addr *ia)
{
assert(ia != NULL);
return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_START,
ifp, sizeof(*ifp));
}
ssize_t
ps_bpf_closearp(const struct interface *ifp, const struct in_addr *ia)
{
return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_STOP, NULL, 0);
}
ssize_t
ps_bpf_sendarp(const struct interface *ifp, const struct in_addr *ia,
const void *data, size_t len)
{
assert(ia != NULL);
return ps_bpf_send(ifp, ia, PS_BPF_ARP, data, len);
}
#endif
ssize_t
ps_bpf_openbootp(const struct interface *ifp)
{
return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_START,
ifp, sizeof(*ifp));
}
ssize_t
ps_bpf_closebootp(const struct interface *ifp)
{
return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_STOP, NULL, 0);
}
ssize_t
ps_bpf_sendbootp(const struct interface *ifp, const void *data, size_t len)
{
return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP, data, len);
}

View File

@ -0,0 +1,50 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef PRIVSEP_BPF_H
#define PRIVSEP_BPF_H
ssize_t ps_bpf_cmd(struct dhcpcd_ctx *,
struct ps_msghdr *, struct msghdr *);
ssize_t ps_bpf_dispatch(struct dhcpcd_ctx *,
struct ps_msghdr *, struct msghdr *);
#ifdef ARP
ssize_t ps_bpf_openarp(const struct interface *, const struct in_addr *);
ssize_t ps_bpf_closearp(const struct interface *, const struct in_addr *);
ssize_t ps_bpf_sendarp(const struct interface *, const struct in_addr *,
const void *, size_t);
#endif
ssize_t ps_bpf_openbootp(const struct interface *);
ssize_t ps_bpf_closebootp(const struct interface *);
ssize_t ps_bpf_sendbootp(const struct interface *, const void *, size_t);
ssize_t ps_bpf_openbootpudp(const struct interface *);
ssize_t ps_bpf_closebootpudp(const struct interface *);
ssize_t ps_bpf_sendbootpudp(const struct interface *, const void *, size_t);
#endif

View File

@ -0,0 +1,421 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd, BSD driver
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/ioctl.h>
#include <sys/types.h>
#include <sys/sysctl.h>
/* Need these for filtering the ioctls */
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#ifdef __NetBSD__
#include <netinet/if_ether.h>
#include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
#elif defined(__DragonFly__)
#include <net/vlan/if_vlan_var.h>
#else
#include <net/if_vlan_var.h>
#endif
#ifdef __DragonFly__
# include <netproto/802_11/ieee80211_ioctl.h>
#else
# include <net80211/ieee80211.h>
# include <net80211/ieee80211_ioctl.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dhcpcd.h"
#include "if.h"
#include "logerr.h"
#include "privsep.h"
static ssize_t
ps_root_doioctldom(struct dhcpcd_ctx *ctx, int domain, unsigned long req, void *data, size_t len)
{
#if defined(INET6) || (defined(SIOCALIFADDR) && defined(IFLR_ACTIVE))
struct priv *priv = (struct priv *)ctx->priv;
#endif
int s;
switch(domain) {
#ifdef INET
case PF_INET:
s = ctx->pf_inet_fd;
break;
#endif
#ifdef INET6
case PF_INET6:
s = priv->pf_inet6_fd;
break;
#endif
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
case PF_LINK:
s = priv->pf_link_fd;
break;
#endif
default:
errno = EPFNOSUPPORT;
return -1;
}
/* Only allow these ioctls */
switch(req) {
#ifdef SIOCGIFDATA
case SIOCGIFDATA: /* FALLTHROUGH */
#endif
#ifdef SIOCG80211NWID
case SIOCG80211NWID: /* FALLTHROUGH */
#endif
#ifdef SIOCGETVLAN
case SIOCGETVLAN: /* FALLTHROUGH */
#endif
#ifdef SIOCIFAFATTACH
case SIOCIFAFATTACH: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFXFLAGS
case SIOCSIFXFLAGS: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFINFO_FLAGS
case SIOCSIFINFO_FLAGS: /* FALLTHROUGH */
#endif
#ifdef SIOCSRTRFLUSH_IN6
case SIOCSRTRFLUSH_IN6: /* FALLTHROUGH */
case SIOCSPFXFLUSH_IN6: /* FALLTHROUGH */
#endif
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE)
case SIOCALIFADDR: /* FALLTHROUGH */
case SIOCDLIFADDR: /* FALLTHROUGH */
#else
case SIOCSIFLLADDR: /* FALLTHROUGH */
#endif
#ifdef SIOCSIFINFO_IN6
case SIOCSIFINFO_IN6: /* FALLTHROUGH */
#endif
case SIOCAIFADDR_IN6: /* FALLTHROUGH */
case SIOCDIFADDR_IN6:
break;
default:
errno = EPERM;
return -1;
}
return ioctl(s, req, data, len);
}
static ssize_t
ps_root_doroute(struct dhcpcd_ctx *ctx, void *data, size_t len)
{
return write(ctx->link_fd, data, len);
}
#if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
static ssize_t
ps_root_doindirectioctl(struct dhcpcd_ctx *ctx,
unsigned long req, void *data, size_t len)
{
char *p = data;
struct ifreq ifr = { .ifr_flags = 0 };
/* ioctl filtering is done in ps_root_doioctldom */
if (len < IFNAMSIZ + 1) {
errno = EINVAL;
return -1;
}
strlcpy(ifr.ifr_name, p, IFNAMSIZ);
len -= IFNAMSIZ;
memmove(data, p + IFNAMSIZ, len);
ifr.ifr_data = data;
return ps_root_doioctldom(ctx, PF_INET, req, &ifr, sizeof(ifr));
}
#endif
#ifdef HAVE_PLEDGE
static ssize_t
ps_root_doifignoregroup(struct dhcpcd_ctx *ctx, void *data, size_t len)
{
if (len == 0 || ((const char *)data)[len - 1] != '\0') {
errno = EINVAL;
return -1;
}
return if_ignoregroup(ctx->pf_inet_fd, data);
}
#endif
#ifdef HAVE_CAPSICUM
static ssize_t
ps_root_dosysctl(unsigned long flags,
void *data, size_t len, void **rdata, size_t *rlen)
{
char *p = data, *e = p + len;
int name[10];
unsigned int namelen;
void *oldp;
size_t *oldlenp, oldlen, nlen;
void *newp;
size_t newlen;
int err;
if (sizeof(namelen) >= len) {
errno = EINVAL;
return -1;
}
memcpy(&namelen, p, sizeof(namelen));
p += sizeof(namelen);
nlen = sizeof(*name) * namelen;
if (namelen > __arraycount(name)) {
errno = ENOBUFS;
return -1;
}
if (p + nlen > e) {
errno = EINVAL;
return -1;
}
memcpy(name, p, nlen);
p += nlen;
if (p + sizeof(oldlen) > e) {
errno = EINVAL;
return -1;
}
memcpy(&oldlen, p, sizeof(oldlen));
p += sizeof(oldlen);
if (p + sizeof(newlen) > e) {
errno = EINVAL;
return -1;
}
memcpy(&newlen, p, sizeof(newlen));
p += sizeof(newlen);
if (p + newlen > e) {
errno = EINVAL;
return -1;
}
newp = newlen ? p : NULL;
if (flags & PS_SYSCTL_OLEN) {
*rlen = sizeof(oldlen) + oldlen;
*rdata = malloc(*rlen);
if (*rdata == NULL)
return -1;
oldlenp = (size_t *)*rdata;
*oldlenp = oldlen;
if (flags & PS_SYSCTL_ODATA)
oldp = (char *)*rdata + sizeof(oldlen);
else
oldp = NULL;
} else {
oldlenp = NULL;
oldp = NULL;
}
err = sysctl(name, namelen, oldp, oldlenp, newp, newlen);
return err;
}
#endif
ssize_t
ps_root_os(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg,
void **rdata, size_t *rlen, bool *free_rdata)
{
struct iovec *iov = msg->msg_iov;
void *data = iov->iov_base;
size_t len = iov->iov_len;
ssize_t err;
switch (psm->ps_cmd) {
case PS_IOCTLLINK:
err = ps_root_doioctldom(ctx, PF_LINK, psm->ps_flags, data, len);
break;
case PS_IOCTL6:
err = ps_root_doioctldom(ctx, PF_INET6, psm->ps_flags, data, len);
break;
case PS_ROUTE:
return ps_root_doroute(ctx, data, len);
#if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
case PS_IOCTLINDIRECT:
err = ps_root_doindirectioctl(ctx, psm->ps_flags, data, len);
break;
#endif
#ifdef HAVE_PLEDGE
case PS_IFIGNOREGRP:
return ps_root_doifignoregroup(ctx, data, len);
#endif
#ifdef HAVE_CAPSICUM
case PS_SYSCTL:
*free_rdata = true;
return ps_root_dosysctl(psm->ps_flags, data, len, rdata, rlen);
#else
UNUSED(free_rdata);
#endif
default:
errno = ENOTSUP;
return -1;
}
if (err != -1) {
*rdata = data;
*rlen = len;
}
return err;
}
static ssize_t
ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint16_t domain, unsigned long request,
void *data, size_t len)
{
if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), domain,
request, data, len) == -1)
return -1;
return ps_root_readerror(ctx, data, len);
}
ssize_t
ps_root_ioctllink(struct dhcpcd_ctx *ctx, unsigned long request,
void *data, size_t len)
{
return ps_root_ioctldom(ctx, PS_IOCTLLINK, request, data, len);
}
ssize_t
ps_root_ioctl6(struct dhcpcd_ctx *ctx, unsigned long request,
void *data, size_t len)
{
return ps_root_ioctldom(ctx, PS_IOCTL6, request, data, len);
}
ssize_t
ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len)
{
if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_ROUTE, 0, data, len) == -1)
return -1;
return ps_root_readerror(ctx, data, len);
}
#if defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)
ssize_t
ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
const char *ifname, void *data, size_t len)
{
char buf[PS_BUFLEN];
if (IFNAMSIZ + len > sizeof(buf)) {
errno = ENOBUFS;
return -1;
}
strlcpy(buf, ifname, IFNAMSIZ);
memcpy(buf + IFNAMSIZ, data, len);
if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IOCTLINDIRECT,
request, buf, IFNAMSIZ + len) == -1)
return -1;
return ps_root_readerror(ctx, data, len);
}
#endif
#ifdef HAVE_PLEDGE
ssize_t
ps_root_ifignoregroup(struct dhcpcd_ctx *ctx, const char *ifname)
{
if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IFIGNOREGRP, 0,
ifname, strlen(ifname) + 1) == -1)
return -1;
return ps_root_readerror(ctx, NULL, 0);
}
#endif
#ifdef HAVE_CAPSICUM
ssize_t
ps_root_sysctl(struct dhcpcd_ctx *ctx,
const int *name, unsigned int namelen,
void *oldp, size_t *oldlenp, const void *newp, size_t newlen)
{
char buf[PS_BUFLEN], *p = buf;
unsigned long flags = 0;
size_t olen = (oldp && oldlenp) ? *oldlenp : 0, nolen;
if (sizeof(namelen) + (sizeof(*name) * namelen) +
sizeof(oldlenp) +
sizeof(newlen) + newlen > sizeof(buf))
{
errno = ENOBUFS;
return -1;
}
if (oldlenp)
flags |= PS_SYSCTL_OLEN;
if (oldp)
flags |= PS_SYSCTL_ODATA;
memcpy(p, &namelen, sizeof(namelen));
p += sizeof(namelen);
memcpy(p, name, sizeof(*name) * namelen);
p += sizeof(*name) * namelen;
memcpy(p, &olen, sizeof(olen));
p += sizeof(olen);
memcpy(p, &newlen, sizeof(newlen));
p += sizeof(newlen);
if (newlen) {
memcpy(p, newp, newlen);
p += newlen;
}
if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_SYSCTL,
flags, buf, (size_t)(p - buf)) == -1)
return -1;
if (ps_root_readerror(ctx, buf, sizeof(buf)) == -1)
return -1;
p = buf;
memcpy(&nolen, p, sizeof(nolen));
p += sizeof(nolen);
if (oldlenp) {
*oldlenp = nolen;
if (oldp && nolen <= olen)
memcpy(oldp, p, nolen);
}
return 0;
}
#endif

View File

@ -0,0 +1,299 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd, control proxy
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include "dhcpcd.h"
#include "control.h"
#include "eloop.h"
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 2 SEQPACKET, 2 STREAM and 2 file STREAM fds */
static int
ps_ctl_startcb(struct ps_process *psp)
{
struct dhcpcd_ctx *ctx = psp->psp_ctx;
sa_family_t af;
if (ctx->options & DHCPCD_MANAGER) {
setproctitle("[control proxy]");
af = AF_UNSPEC;
} else {
setproctitle("[control proxy] %s%s%s",
ctx->ifv[0],
ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
if ((ctx->options &
(DHCPCD_IPV4 | DHCPCD_IPV6)) == DHCPCD_IPV4)
af = AF_INET;
else if ((ctx->options &
(DHCPCD_IPV4 | DHCPCD_IPV6)) == DHCPCD_IPV6)
af = AF_INET6;
else
af = AF_UNSPEC;
}
return control_start(ctx,
ctx->options & DHCPCD_MANAGER ? NULL : *ctx->ifv, af);
}
static void
ps_ctl_recvmsg(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1)
logerr(__func__);
}
ssize_t
ps_ctl_handleargs(struct fd_list *fd, char *data, size_t len)
{
/* Make any change here in dhcpcd.c as well. */
if (strncmp(data, "--version",
MIN(strlen("--version"), len)) == 0) {
return control_queue(fd, UNCONST(VERSION),
strlen(VERSION) + 1);
} else if (strncmp(data, "--getconfigfile",
MIN(strlen("--getconfigfile"), len)) == 0) {
return control_queue(fd, UNCONST(fd->ctx->cffile),
strlen(fd->ctx->cffile) + 1);
} else if (strncmp(data, "--listen",
MIN(strlen("--listen"), len)) == 0) {
fd->flags |= FD_LISTEN;
return 0;
}
if (fd->ctx->ps_control_client != NULL &&
fd->ctx->ps_control_client != fd)
{
logerrx("%s: cannot handle another client", __func__);
return 0;
}
return 1;
}
static ssize_t
ps_ctl_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = arg;
struct iovec *iov = msg->msg_iov;
struct fd_list *fd;
unsigned int fd_flags = FD_SENDLEN;
switch (psm->ps_flags) {
case PS_CTL_PRIV:
break;
case PS_CTL_UNPRIV:
fd_flags |= FD_UNPRIV;
break;
}
switch (psm->ps_cmd) {
case PS_CTL:
if (msg->msg_iovlen != 1) {
errno = EINVAL;
return -1;
}
if (ctx->ps_control_client != NULL) {
logerrx("%s: cannot handle another client", __func__);
return 0;
}
fd = control_new(ctx, ctx->ps_ctl->psp_work_fd, fd_flags);
if (fd == NULL)
return -1;
ctx->ps_control_client = fd;
control_recvdata(fd, iov->iov_base, iov->iov_len);
break;
case PS_CTL_EOF:
ctx->ps_control_client = NULL;
break;
default:
errno = ENOTSUP;
return -1;
}
return 0;
}
static void
ps_ctl_dodispatch(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
ps_ctl_dispatch, psp->psp_ctx) == -1)
logerr(__func__);
}
static void
ps_ctl_recv(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
char buf[BUFSIZ];
ssize_t len;
if (!(events & (ELE_READ | ELE_HANGUP)))
logerrx("%s: unexpected event 0x%04x", __func__, events);
if (events & ELE_READ) {
len = read(ctx->ps_ctl->psp_work_fd, buf, sizeof(buf));
if (len == -1)
logerr("%s: read", __func__);
else if (len == 0)
// FIXME: Why does this happen?
;
else if (ctx->ps_control_client == NULL)
logerrx("%s: clientfd #%d disconnected (len=%zd)",
__func__, ctx->ps_ctl->psp_work_fd, len);
else {
errno = 0;
if (control_queue(ctx->ps_control_client,
buf, (size_t)len) == -1)
logerr("%s: control_queue", __func__);
}
}
}
static void
ps_ctl_listen(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
char buf[BUFSIZ];
ssize_t len;
struct fd_list *fd;
if (!(events & ELE_READ))
logerrx("%s: unexpected event 0x%04x", __func__, events);
len = read(ctx->ps_control->fd, buf, sizeof(buf));
if (len == -1) {
logerr("%s: read", __func__);
eloop_exit(ctx->eloop, EXIT_FAILURE);
return;
}
/* Send to our listeners */
TAILQ_FOREACH(fd, &ctx->control_fds, next) {
if (!(fd->flags & FD_LISTEN))
continue;
if (control_queue(fd, buf, (size_t)len)== -1)
logerr("%s: control_queue", __func__);
}
}
pid_t
ps_ctl_start(struct dhcpcd_ctx *ctx)
{
struct ps_id id = {
.psi_ifindex = 0,
.psi_cmd = PS_CTL,
};
struct ps_process *psp;
int work_fd[2], listen_fd[2];
pid_t pid;
if_closesockets(ctx);
if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, work_fd) == -1 ||
xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1)
return -1;
#ifdef PRIVSEP_RIGHTS
if (ps_rights_limit_fdpair(work_fd) == -1 ||
ps_rights_limit_fdpair(listen_fd) == -1)
return -1;
#endif
psp = ctx->ps_ctl = ps_newprocess(ctx, &id);
strlcpy(psp->psp_name, "control proxy", sizeof(psp->psp_name));
pid = ps_startprocess(psp, ps_ctl_recvmsg, ps_ctl_dodispatch,
ps_ctl_startcb, NULL, PSF_DROPPRIVS);
if (pid == -1)
return -1;
else if (pid != 0) {
psp->psp_work_fd = work_fd[0];
close(work_fd[1]);
close(listen_fd[1]);
ctx->ps_control = control_new(ctx,
listen_fd[0], FD_SENDLEN | FD_LISTEN);
if (ctx->ps_control == NULL)
return -1;
return pid;
}
close(work_fd[0]);
close(listen_fd[0]);
psp->psp_work_fd = work_fd[1];
if (eloop_event_add(ctx->eloop, psp->psp_work_fd, ELE_READ,
ps_ctl_recv, ctx) == -1)
return -1;
ctx->ps_control = control_new(ctx, listen_fd[1], 0);
if (ctx->ps_control == NULL)
return -1;
if (eloop_event_add(ctx->eloop, ctx->ps_control->fd, ELE_READ,
ps_ctl_listen, ctx) == -1)
return -1;
ps_entersandbox("stdio inet", NULL);
return 0;
}
int
ps_ctl_stop(struct dhcpcd_ctx *ctx)
{
return ps_stopprocess(ctx->ps_ctl);
}
ssize_t
ps_ctl_sendargs(struct fd_list *fd, void *data, size_t len)
{
struct dhcpcd_ctx *ctx = fd->ctx;
if (ctx->ps_control_client != NULL && ctx->ps_control_client != fd)
logerrx("%s: cannot deal with another client", __func__);
ctx->ps_control_client = fd;
return ps_sendcmd(ctx, ctx->ps_ctl->psp_fd, PS_CTL,
fd->flags & FD_UNPRIV ? PS_CTL_UNPRIV : PS_CTL_PRIV,
data, len);
}
ssize_t
ps_ctl_sendeof(struct fd_list *fd)
{
struct dhcpcd_ctx *ctx = fd->ctx;
return ps_sendcmd(ctx, ctx->ps_ctl->psp_fd, PS_CTL_EOF, 0, NULL, 0);
}

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef PRIVSEP_CTL_H
#define PRIVSEP_CTL_H
#define IN_PRIVSEP_CONTROLLER(ctx) \
(IN_PRIVSEP((ctx)) && (ctx)->ps_control_pid == getpid())
pid_t ps_ctl_start(struct dhcpcd_ctx *);
int ps_ctl_stop(struct dhcpcd_ctx *);
ssize_t ps_ctl_handleargs(struct fd_list *, char *, size_t);
ssize_t ps_ctl_sendargs(struct fd_list *, void *, size_t);
ssize_t ps_ctl_sendeof(struct fd_list *fd);
#endif

View File

@ -0,0 +1,741 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd, network proxy
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arp.h"
#include "bpf.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "eloop.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 2 SEQPACKET, 1 udp, 1 udp6 and 1 raw6 fds */
#ifdef INET
static void
ps_inet_recvbootp(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
if (ps_recvmsg(ctx->udp_rfd, events,
PS_BOOTP, ctx->ps_inet->psp_fd) == -1)
logerr(__func__);
}
#endif
#ifdef INET6
static void
ps_inet_recvra(void *arg, unsigned short events)
{
#ifdef __sun
struct interface *ifp = arg;
struct rs_state *state = RS_STATE(ifp);
struct dhcpcd_ctx *ctx = ifp->ctx;
if (ps_recvmsg(state->nd_fd, events,
PS_ND, ctx->ps_inet->psp_fd) == -1)
logerr(__func__);
#else
struct dhcpcd_ctx *ctx = arg;
if (ps_recvmsg(ctx->nd_fd, events,
PS_ND, ctx->ps_inet->psp_fd) == -1)
logerr(__func__);
#endif
}
#endif
#ifdef DHCP6
static void
ps_inet_recvdhcp6(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
if (ps_recvmsg(ctx->dhcp6_rfd, events,
PS_DHCP6, ctx->ps_inet->psp_fd) == -1)
logerr(__func__);
}
#endif
bool
ps_inet_canstart(const struct dhcpcd_ctx *ctx)
{
#ifdef INET
if ((ctx->options & (DHCPCD_IPV4 | DHCPCD_MANAGER)) ==
(DHCPCD_IPV4 | DHCPCD_MANAGER))
return true;
#endif
#if defined(INET6) && !defined(__sun)
if (ctx->options & DHCPCD_IPV6)
return true;
#endif
#ifdef DHCP6
if ((ctx->options & (DHCPCD_IPV6 | DHCPCD_MANAGER)) ==
(DHCPCD_IPV6 | DHCPCD_MANAGER))
return true;
#endif
return false;
}
static int
ps_inet_startcb(struct ps_process *psp)
{
struct dhcpcd_ctx *ctx = psp->psp_ctx;
int ret = 0;
if (ctx->options & DHCPCD_MANAGER)
setproctitle("[network proxy]");
else
setproctitle("[network proxy] %s%s%s",
ctx->ifc != 0 ? ctx->ifv[0] : "",
ctx->options & DHCPCD_IPV4 ? " [ip4]" : "",
ctx->options & DHCPCD_IPV6 ? " [ip6]" : "");
/* This end is the main engine, so it's useless for us. */
close(ctx->ps_data_fd);
ctx->ps_data_fd = -1;
errno = 0;
#ifdef INET
if ((ctx->options & (DHCPCD_IPV4 | DHCPCD_MANAGER)) ==
(DHCPCD_IPV4 | DHCPCD_MANAGER))
{
ctx->udp_rfd = dhcp_openudp(NULL);
if (ctx->udp_rfd == -1)
logerr("%s: dhcp_open", __func__);
#ifdef PRIVSEP_RIGHTS
else if (ps_rights_limit_fd_rdonly(ctx->udp_rfd) == -1) {
logerr("%s: ps_rights_limit_fd_rdonly", __func__);
close(ctx->udp_rfd);
ctx->udp_rfd = -1;
}
#endif
else if (eloop_event_add(ctx->eloop, ctx->udp_rfd, ELE_READ,
ps_inet_recvbootp, ctx) == -1)
{
logerr("%s: eloop_event_add DHCP", __func__);
close(ctx->udp_rfd);
ctx->udp_rfd = -1;
} else
ret++;
}
#endif
#if defined(INET6) && !defined(__sun)
if (ctx->options & DHCPCD_IPV6) {
ctx->nd_fd = ipv6nd_open(true);
if (ctx->nd_fd == -1)
logerr("%s: ipv6nd_open", __func__);
#ifdef PRIVSEP_RIGHTS
else if (ps_rights_limit_fd_rdonly(ctx->nd_fd) == -1) {
logerr("%s: ps_rights_limit_fd_rdonly", __func__);
close(ctx->nd_fd);
ctx->nd_fd = -1;
}
#endif
else if (eloop_event_add(ctx->eloop, ctx->nd_fd, ELE_READ,
ps_inet_recvra, ctx) == -1)
{
logerr("%s: eloop_event_add RA", __func__);
close(ctx->nd_fd);
ctx->nd_fd = -1;
} else
ret++;
}
#endif
#ifdef DHCP6
if ((ctx->options & (DHCPCD_IPV6 | DHCPCD_MANAGER)) ==
(DHCPCD_IPV6 | DHCPCD_MANAGER))
{
ctx->dhcp6_rfd = dhcp6_openudp(0, NULL);
if (ctx->dhcp6_rfd == -1)
logerr("%s: dhcp6_open", __func__);
#ifdef PRIVSEP_RIGHTS
else if (ps_rights_limit_fd_rdonly(ctx->dhcp6_rfd) == -1) {
logerr("%s: ps_rights_limit_fd_rdonly", __func__);
close(ctx->dhcp6_rfd);
ctx->dhcp6_rfd = -1;
}
#endif
else if (eloop_event_add(ctx->eloop, ctx->dhcp6_rfd, ELE_READ,
ps_inet_recvdhcp6, ctx) == -1)
{
logerr("%s: eloop_event_add DHCP6", __func__);
close(ctx->dhcp6_rfd);
ctx->dhcp6_rfd = -1;
} else
ret++;
}
#endif
if (ret == 0 && errno == 0) {
errno = ENXIO;
return -1;
}
return ret;
}
static bool
ps_inet_validudp(struct msghdr *msg, uint16_t sport, uint16_t dport)
{
struct udphdr udp;
struct iovec *iov = msg->msg_iov;
if (msg->msg_iovlen == 0 || iov->iov_len < sizeof(udp)) {
errno = EINVAL;
return false;
}
memcpy(&udp, iov->iov_base, sizeof(udp));
if (udp.uh_sport != htons(sport) || udp.uh_dport != htons(dport)) {
errno = EPERM;
return false;
}
return true;
}
#ifdef INET6
static bool
ps_inet_validnd(struct msghdr *msg)
{
struct icmp6_hdr icmp6;
struct iovec *iov = msg->msg_iov;
if (msg->msg_iovlen == 0 || iov->iov_len < sizeof(icmp6)) {
errno = EINVAL;
return false;
}
memcpy(&icmp6, iov->iov_base, sizeof(icmp6));
switch(icmp6.icmp6_type) {
case ND_ROUTER_SOLICIT:
case ND_NEIGHBOR_ADVERT:
break;
default:
errno = EPERM;
return false;
}
return true;
}
#endif
static ssize_t
ps_inet_sendmsg(struct dhcpcd_ctx *ctx,
struct ps_msghdr *psm, struct msghdr *msg)
{
struct ps_process *psp;
int s;
psp = ps_findprocess(ctx, &psm->ps_id);
if (psp != NULL) {
s = psp->psp_work_fd;
goto dosend;
}
switch (psm->ps_cmd) {
#ifdef INET
case PS_BOOTP:
if (!ps_inet_validudp(msg, BOOTPC, BOOTPS))
return -1;
s = ctx->udp_wfd;
break;
#endif
#if defined(INET6) && !defined(__sun)
case PS_ND:
if (!ps_inet_validnd(msg))
return -1;
s = ctx->nd_fd;
break;
#endif
#ifdef DHCP6
case PS_DHCP6:
if (!ps_inet_validudp(msg, DHCP6_CLIENT_PORT,DHCP6_SERVER_PORT))
return -1;
s = ctx->dhcp6_wfd;
break;
#endif
default:
errno = EINVAL;
return -1;
}
dosend:
return sendmsg(s, msg, 0);
}
static void
ps_inet_recvmsg(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
/* Receive shutdown */
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1)
logerr(__func__);
}
ssize_t
ps_inet_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = arg;
switch (psm->ps_cmd) {
#ifdef INET
case PS_BOOTP:
dhcp_recvmsg(ctx, msg);
break;
#endif
#ifdef INET6
case PS_ND:
ipv6nd_recvmsg(ctx, msg);
break;
#endif
#ifdef DHCP6
case PS_DHCP6:
dhcp6_recvmsg(ctx, msg, NULL);
break;
#endif
default:
errno = ENOTSUP;
return -1;
}
return 1;
}
static void
ps_inet_dodispatch(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
ps_inet_dispatch, psp->psp_ctx) == -1)
logerr(__func__);
}
pid_t
ps_inet_start(struct dhcpcd_ctx *ctx)
{
struct ps_id id = {
.psi_ifindex = 0,
.psi_cmd = PS_INET,
};
struct ps_process *psp;
pid_t pid;
psp = ctx->ps_inet = ps_newprocess(ctx, &id);
if (psp == NULL)
return -1;
strlcpy(psp->psp_name, "network proxy", sizeof(psp->psp_name));
pid = ps_startprocess(psp, ps_inet_recvmsg, ps_inet_dodispatch,
ps_inet_startcb, NULL, PSF_DROPPRIVS);
if (pid == 0)
ps_entersandbox("stdio", NULL);
return pid;
}
int
ps_inet_stop(struct dhcpcd_ctx *ctx)
{
return ps_stopprocess(ctx->ps_inet);
}
#ifdef INET
static void
ps_inet_recvinbootp(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
if (ps_recvmsg(psp->psp_work_fd, events,
PS_BOOTP, psp->psp_ctx->ps_data_fd) == -1)
logerr(__func__);
}
static int
ps_inet_listenin(struct ps_process *psp)
{
struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, ia, buf, sizeof(buf));
setproctitle("[%s proxy] %s", psp->psp_protostr, buf);
psp->psp_work_fd = dhcp_openudp(ia);
if (psp->psp_work_fd == -1) {
logerr(__func__);
return -1;
}
#ifdef PRIVSEP_RIGHTS
if (ps_rights_limit_fd_rdonly(psp->psp_work_fd) == -1) {
logerr("%s: ps_rights_limit_fd_rdonly", __func__);
return -1;
}
#endif
if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, ELE_READ,
ps_inet_recvinbootp, psp) == -1)
{
logerr("%s: eloop_event_add DHCP", __func__);
return -1;
}
return 0;
}
#endif
#if defined(INET6) && defined(__sun)
static void
ps_inet_recvin6nd(void *arg)
{
struct ps_process *psp = arg;
if (ps_recvmsg(psp->psp_work_fd,
PS_ND, psp->psp_ctx->ps_data_fd) == -1)
logerr(__func__);
}
static int
ps_inet_listennd(struct ps_process *psp)
{
setproctitle("[ND network proxy]");
psp->psp_work_fd = ipv6nd_open(&psp->psp_ifp);
if (psp->psp_work_fd == -1) {
logerr(__func__);
return -1;
}
#ifdef PRIVSEP_RIGHTS
if (ps_rights_limit_fd_rdonly(psp->psp_work_fd) == -1) {
logerr("%s: ps_rights_limit_fd_rdonly", __func__);
return -1;
}
#endif
if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd,
ps_inet_recvin6nd, psp) == -1)
{
logerr(__func__);
return -1;
}
return 0;
}
#endif
#ifdef DHCP6
static void
ps_inet_recvin6dhcp6(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
if (ps_recvmsg(psp->psp_work_fd, events,
PS_DHCP6, psp->psp_ctx->ps_data_fd) == -1)
logerr(__func__);
}
static int
ps_inet_listenin6(struct ps_process *psp)
{
struct in6_addr *ia = &psp->psp_id.psi_addr.psa_in6_addr;
char buf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, ia, buf, sizeof(buf));
setproctitle("[%s proxy] %s", psp->psp_protostr, buf);
psp->psp_work_fd = dhcp6_openudp(psp->psp_id.psi_ifindex, ia);
if (psp->psp_work_fd == -1) {
logerr(__func__);
return -1;
}
#ifdef PRIVSEP_RIGHTS
if (ps_rights_limit_fd_rdonly(psp->psp_work_fd) == -1) {
logerr("%s: ps_rights_limit_fd_rdonly", __func__);
return -1;
}
#endif
if (eloop_event_add(psp->psp_ctx->eloop, psp->psp_work_fd, ELE_READ,
ps_inet_recvin6dhcp6, psp) == -1)
{
logerr("%s: eloop_event_add DHCP", __func__);
return -1;
}
return 0;
}
#endif
static void
ps_inet_recvmsgpsp(void *arg, unsigned short events)
{
struct ps_process *psp = arg;
/* Receive shutdown. */
if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1)
logerr(__func__);
}
ssize_t
ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
{
uint16_t cmd;
struct ps_process *psp;
int (*start_func)(struct ps_process *);
pid_t start;
struct ps_addr *psa = &psm->ps_id.psi_addr;
void *ia;
char buf[INET_MAX_ADDRSTRLEN];
cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
if (cmd == psm->ps_cmd)
return ps_inet_sendmsg(ctx, psm, msg);
psp = ps_findprocess(ctx, &psm->ps_id);
#ifdef PRIVSEP_DEBUG
logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
#endif
if (psm->ps_cmd & PS_STOP) {
assert(psp == NULL);
return 0;
}
if (!(psm->ps_cmd & PS_START)) {
errno = EINVAL;
return -1;
}
if (psp != NULL)
return 1;
psp = ps_newprocess(ctx, &psm->ps_id);
if (psp == NULL)
return -1;
switch (cmd) {
#ifdef INET
case PS_BOOTP:
start_func = ps_inet_listenin;
psp->psp_protostr = "BOOTP";
ia = &psa->psa_in_addr;
break;
#endif
#ifdef INET6
#ifdef __sun
case PS_ND:
start_func = ps_inet_listennd;
psp->psp_protostr = "ND";
ia = &psa->psa_in6_addr;
break;
#endif
#ifdef DHCP6
case PS_DHCP6:
start_func = ps_inet_listenin6;
psp->psp_protostr = "DHCP6";
ia = &psa->psa_in6_addr;
break;
#endif
#endif
default:
logerrx("%s: unknown command %x", __func__, psm->ps_cmd);
errno = ENOTSUP;
return -1;
}
snprintf(psp->psp_name, sizeof(psp->psp_name),
"%s proxy %s", psp->psp_protostr,
inet_ntop(psa->psa_family, ia, buf, sizeof(buf)));
start = ps_startprocess(psp, ps_inet_recvmsgpsp, NULL,
start_func, NULL, PSF_DROPPRIVS);
switch (start) {
case -1:
ps_freeprocess(psp);
return -1;
case 0:
ps_entersandbox("stdio", NULL);
break;
default:
logdebugx("%s: spawned %s on PID %d",
psp->psp_ifname, psp->psp_name, psp->psp_pid);
break;
}
return start;
}
#ifdef INET
static ssize_t
ps_inet_in_docmd(struct ipv4_addr *ia, uint16_t cmd, const struct msghdr *msg)
{
assert(ia != NULL);
struct dhcpcd_ctx *ctx = ia->iface->ctx;
struct ps_msghdr psm = {
.ps_cmd = cmd,
.ps_id = {
.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
.psi_ifindex = ia->iface->index,
.psi_addr.psa_family = AF_INET,
.psi_addr.psa_in_addr = ia->addr,
},
};
return ps_sendpsmmsg(ctx, PS_ROOT_FD(ctx), &psm, msg);
}
ssize_t
ps_inet_openbootp(struct ipv4_addr *ia)
{
return ps_inet_in_docmd(ia, PS_START | PS_BOOTP, NULL);
}
ssize_t
ps_inet_closebootp(struct ipv4_addr *ia)
{
return ps_inet_in_docmd(ia, PS_STOP | PS_BOOTP, NULL);
}
ssize_t
ps_inet_sendbootp(struct interface *ifp, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
return ps_sendmsg(ctx, PS_ROOT_FD(ctx), PS_BOOTP, 0, msg);
}
#endif /* INET */
#ifdef INET6
#ifdef __sun
static ssize_t
ps_inet_ifp_docmd(struct interface *ifp, uint16_t cmd, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
struct ps_msghdr psm = {
.ps_cmd = cmd,
.ps_id = {
.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
.psi_ifindex = ifp->index,
.psi_addr.psa_family = AF_INET6,
},
};
return ps_sendpsmmsg(ctx, PS_ROOT_FD(ctx), &psm, msg);
}
ssize_t
ps_inet_opennd(struct interface *ifp)
{
return ps_inet_ifp_docmd(ifp, PS_ND | PS_START, NULL);
}
ssize_t
ps_inet_closend(struct interface *ifp)
{
return ps_inet_ifp_docmd(ifp, PS_ND | PS_STOP, NULL);
}
ssize_t
ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
{
return ps_inet_ifp_docmd(ifp, PS_ND, msg);
}
#else
ssize_t
ps_inet_sendnd(struct interface *ifp, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
return ps_sendmsg(ctx, PS_ROOT_FD(ctx), PS_ND, 0, msg);
}
#endif
#ifdef DHCP6
static ssize_t
ps_inet_in6_docmd(struct ipv6_addr *ia, uint16_t cmd, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ia->iface->ctx;
struct ps_msghdr psm = {
.ps_cmd = cmd,
.ps_id = {
.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
.psi_ifindex = ia->iface->index,
.psi_addr.psa_family = AF_INET6,
.psi_addr.psa_in6_addr = ia->addr,
},
};
return ps_sendpsmmsg(ctx, PS_ROOT_FD(ctx), &psm, msg);
}
ssize_t
ps_inet_opendhcp6(struct ipv6_addr *ia)
{
return ps_inet_in6_docmd(ia, PS_DHCP6 | PS_START, NULL);
}
ssize_t
ps_inet_closedhcp6(struct ipv6_addr *ia)
{
return ps_inet_in6_docmd(ia, PS_DHCP6 | PS_STOP, NULL);
}
ssize_t
ps_inet_senddhcp6(struct interface *ifp, const struct msghdr *msg)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
return ps_sendmsg(ctx, PS_ROOT_FD(ctx), PS_DHCP6, 0, msg);
}
#endif /* DHCP6 */
#endif /* INET6 */

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef PRIVSEP_INET_H
#define PRIVSEP_INET_H
bool ps_inet_canstart(const struct dhcpcd_ctx *);
pid_t ps_inet_start(struct dhcpcd_ctx *);
int ps_inet_stop(struct dhcpcd_ctx *);
ssize_t ps_inet_cmd(struct dhcpcd_ctx *, struct ps_msghdr *, struct msghdr *);
ssize_t ps_inet_dispatch(void *, struct ps_msghdr *, struct msghdr *);
#ifdef INET
struct ipv4_addr;
ssize_t ps_inet_openbootp(struct ipv4_addr *);
ssize_t ps_inet_closebootp(struct ipv4_addr *);
ssize_t ps_inet_sendbootp(struct interface *, const struct msghdr *);
#endif
#ifdef INET6
struct ipv6_addr;
#ifdef __sun
ssize_t ps_inet_opennd(struct interface *);
ssize_t ps_inet_closend(struct interface *);
#endif
ssize_t ps_inet_sendnd(struct interface *, const struct msghdr *);
#ifdef DHCP6
ssize_t ps_inet_opendhcp6(struct ipv6_addr *);
ssize_t ps_inet_closedhcp6(struct ipv6_addr *);
ssize_t ps_inet_senddhcp6(struct interface *, const struct msghdr *);
#endif /* DHCP6 */
#endif /* INET6 */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef PRIVSEP_ROOT_H
#define PRIVSEP_ROOT_H
#include "if.h"
#if defined(PRIVSEP) && (defined(HAVE_CAPSICUM) || defined(__linux__))
#define PRIVSEP_GETIFADDRS
#endif
pid_t ps_root_start(struct dhcpcd_ctx *ctx);
void ps_root_close(struct dhcpcd_ctx *ctx);
int ps_root_stop(struct dhcpcd_ctx *ctx);
void ps_root_signalcb(int, void *);
ssize_t ps_root_readerror(struct dhcpcd_ctx *, void *, size_t);
ssize_t ps_root_mreaderror(struct dhcpcd_ctx *, void **, size_t *);
ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
ssize_t ps_root_ip6forwarding(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_unlink(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
const void *, size_t);
ssize_t ps_root_logreopen(struct dhcpcd_ctx *);
ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
ssize_t ps_root_stopprocesses(struct dhcpcd_ctx *);
int ps_root_getauthrdm(struct dhcpcd_ctx *, uint64_t *);
#ifdef PRIVSEP_GETIFADDRS
int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **);
#endif
ssize_t ps_root_os(struct dhcpcd_ctx *, struct ps_msghdr *, struct msghdr *,
void **, size_t *, bool *);
#if defined(BSD) || defined(__sun)
ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);
ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t);
ssize_t ps_root_ioctl6(struct dhcpcd_ctx *, unsigned long, void *, size_t);
ssize_t ps_root_indirectioctl(struct dhcpcd_ctx *, unsigned long, const char *,
void *, size_t);
ssize_t ps_root_ifignoregroup(struct dhcpcd_ctx *, const char *);
ssize_t ps_root_sysctl(struct dhcpcd_ctx *, const int *, unsigned int,
void *, size_t *, const void *, size_t);
#endif
#ifdef __linux__
ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
#endif
#ifdef PLUGIN_DEV
int ps_root_dev_initialised(struct dhcpcd_ctx *, const char *);
int ps_root_dev_listening(struct dhcpcd_ctx *);
#endif
#endif

1236
external/bsd/dhcpcd/dist/src/privsep.c vendored Normal file

File diff suppressed because it is too large Load Diff

251
external/bsd/dhcpcd/dist/src/privsep.h vendored Normal file
View File

@ -0,0 +1,251 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Privilege Separation for dhcpcd
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef PRIVSEP_H
#define PRIVSEP_H
//#define PRIVSEP_DEBUG
/* Start flags */
#define PSF_DROPPRIVS 0x01
#define PSF_ELOOP 0x02
/* Protocols */
#define PS_BOOTP 0x0001
#define PS_ND 0x0002
#define PS_DHCP6 0x0003
#define PS_BPF_BOOTP 0x0004
#define PS_BPF_ARP 0x0005
/* Generic commands */
#define PS_IOCTL 0x0010
#define PS_ROUTE 0x0011 /* Also used for NETLINK */
#define PS_SCRIPT 0x0012
#define PS_UNLINK 0x0013
#define PS_READFILE 0x0014
#define PS_WRITEFILE 0x0015
#define PS_FILEMTIME 0x0016
#define PS_AUTH_MONORDM 0x0017
#define PS_CTL 0x0018
#define PS_CTL_EOF 0x0019
#define PS_LOGREOPEN 0x0020
#define PS_STOPPROCS 0x0021
#define PS_DAEMONISED 0x0022
/* Domains */
#define PS_ROOT 0x0101
#define PS_INET 0x0102
#define PS_CONTROL 0x0103
/* BSD Commands */
#define PS_IOCTLLINK 0x0201
#define PS_IOCTL6 0x0202
#define PS_IOCTLINDIRECT 0x0203
#define PS_IP6FORWARDING 0x0204
#define PS_GETIFADDRS 0x0205
#define PS_IFIGNOREGRP 0x0206
#define PS_SYSCTL 0x0207
/* Dev Commands */
#define PS_DEV_LISTENING 0x1001
#define PS_DEV_INITTED 0x1002
#define PS_DEV_IFCMD 0x1003
/* Dev Interface Commands (via flags) */
#define PS_DEV_IFADDED 0x0001
#define PS_DEV_IFREMOVED 0x0002
#define PS_DEV_IFUPDATED 0x0003
/* Control Type (via flags) */
#define PS_CTL_PRIV 0x0004
#define PS_CTL_UNPRIV 0x0005
/* Sysctl Needs (via flags) */
#define PS_SYSCTL_OLEN 0x0001
#define PS_SYSCTL_ODATA 0x0002
/* Process commands */
#define PS_START 0x4000
#define PS_STOP 0x8000
/* Max INET message size + meta data for IPC */
#define PS_BUFLEN ((64 * 1024) + \
sizeof(struct ps_msghdr) + \
sizeof(struct msghdr) + \
CMSG_SPACE(sizeof(struct in6_pktinfo) + \
sizeof(int)))
#define PSP_NAMESIZE 16 + INET_MAX_ADDRSTRLEN
/* Handy macro to work out if in the privsep engine or not. */
#define IN_PRIVSEP(ctx) \
((ctx)->options & DHCPCD_PRIVSEP)
#define IN_PRIVSEP_SE(ctx) \
(((ctx)->options & (DHCPCD_PRIVSEP | DHCPCD_FORKED)) == DHCPCD_PRIVSEP)
#define PS_PROCESS_TIMEOUT 5 /* seconds to stop all processes */
#if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
#define PRIVSEP_RIGHTS
#endif
#define PS_ROOT_FD(ctx) ((ctx)->ps_root ? (ctx)->ps_root->psp_fd : -1)
#if !defined(DISABLE_SECCOMP) && defined(__linux__)
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
# define HAVE_SECCOMP
# endif
#endif
#include "config.h"
#include "arp.h"
#include "dhcp.h"
#include "dhcpcd.h"
struct ps_addr {
sa_family_t psa_family;
uint8_t psa_pad[4 - sizeof(sa_family_t)];
union {
struct in_addr psau_in_addr;
struct in6_addr psau_in6_addr;
} psa_u;
#define psa_in_addr psa_u.psau_in_addr
#define psa_in6_addr psa_u.psau_in6_addr
};
/* Uniquely identify a process */
struct ps_id {
struct ps_addr psi_addr;
unsigned int psi_ifindex;
uint16_t psi_cmd;
uint8_t psi_pad[2];
};
struct ps_msghdr {
uint16_t ps_cmd;
uint8_t ps_pad[sizeof(unsigned long) - sizeof(uint16_t)];
unsigned long ps_flags;
struct ps_id ps_id;
socklen_t ps_namelen;
socklen_t ps_controllen;
uint8_t ps_pad2[sizeof(size_t) - sizeof(socklen_t)];
size_t ps_datalen;
};
struct ps_msg {
struct ps_msghdr psm_hdr;
uint8_t psm_data[PS_BUFLEN];
};
struct bpf;
struct ps_process {
TAILQ_ENTRY(ps_process) next;
struct dhcpcd_ctx *psp_ctx;
struct ps_id psp_id;
pid_t psp_pid;
int psp_fd;
int psp_work_fd;
unsigned int psp_ifindex;
char psp_ifname[IF_NAMESIZE];
char psp_name[PSP_NAMESIZE];
uint16_t psp_proto;
const char *psp_protostr;
bool psp_started;
#ifdef INET
int (*psp_filter)(const struct bpf *, const struct in_addr *);
struct interface psp_ifp; /* Move BPF gubbins elsewhere */
struct bpf *psp_bpf;
#endif
#ifdef HAVE_CAPSICUM
int psp_pfd;
#endif
};
TAILQ_HEAD(ps_process_head, ps_process);
#include "privsep-control.h"
#include "privsep-inet.h"
#include "privsep-root.h"
#ifdef INET
#include "privsep-bpf.h"
#endif
int ps_init(struct dhcpcd_ctx *);
int ps_start(struct dhcpcd_ctx *);
int ps_stop(struct dhcpcd_ctx *);
int ps_stopwait(struct dhcpcd_ctx *);
int ps_entersandbox(const char *, const char **);
int ps_managersandbox(struct dhcpcd_ctx *, const char *);
ssize_t ps_daemonised(struct dhcpcd_ctx *);
int ps_unrollmsg(struct msghdr *, struct ps_msghdr *, const void *, size_t);
ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,
struct ps_msghdr *, const struct msghdr *);
ssize_t ps_sendpsmdata(struct dhcpcd_ctx *, int,
struct ps_msghdr *, const void *, size_t);
ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
const struct msghdr *);
ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
const void *data, size_t len);
ssize_t ps_recvmsg(int, unsigned short, uint16_t, int);
ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int, unsigned short,
ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *);
/* Internal privsep functions. */
int ps_setbuf_fdpair(int []);
#ifdef PRIVSEP_RIGHTS
int ps_rights_limit_ioctl(int);
int ps_rights_limit_fd_fctnl(int);
int ps_rights_limit_fd_rdonly(int);
int ps_rights_limit_fd_sockopt(int);
int ps_rights_limit_fd(int);
int ps_rights_limit_fdpair(int []);
#endif
#ifdef HAVE_SECCOMP
int ps_seccomp_enter(void);
#endif
pid_t ps_startprocess(struct ps_process *,
void (*recv_msg)(void *, unsigned short),
void (*recv_unpriv_msg)(void *, unsigned short),
int (*callback)(struct ps_process *), void (*)(int, void *),
unsigned int);
int ps_stopprocess(struct ps_process *);
struct ps_process *ps_findprocess(struct dhcpcd_ctx *, struct ps_id *);
struct ps_process *ps_findprocesspid(struct dhcpcd_ctx *, pid_t);
struct ps_process *ps_newprocess(struct dhcpcd_ctx *, struct ps_id *);
bool ps_waitforprocs(struct dhcpcd_ctx *ctx);
void ps_process_timeout(void *);
void ps_freeprocess(struct ps_process *);
void ps_freeprocesses(struct dhcpcd_ctx *, struct ps_process *);
#endif

800
external/bsd/dhcpcd/dist/src/route.c vendored Normal file
View File

@ -0,0 +1,800 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - route management
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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 <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "dhcpcd.h"
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "ipv6.h"
#include "logerr.h"
#include "route.h"
#include "sa.h"
/* Needed for NetBSD-6, 7 and 8. */
#ifndef RB_TREE_FOREACH_SAFE
#ifndef RB_TREE_PREV
#define RB_TREE_NEXT(T, N) rb_tree_iterate((T), (N), RB_DIR_RIGHT)
#define RB_TREE_PREV(T, N) rb_tree_iterate((T), (N), RB_DIR_LEFT)
#endif
#define RB_TREE_FOREACH_SAFE(N, T, S) \
for ((N) = RB_TREE_MIN(T); \
(N) && ((S) = RB_TREE_NEXT((T), (N)), 1); \
(N) = (S))
#define RB_TREE_FOREACH_REVERSE_SAFE(N, T, S) \
for ((N) = RB_TREE_MAX(T); \
(N) && ((S) = RB_TREE_PREV((T), (N)), 1); \
(N) = (S))
#endif
#ifdef RT_FREE_ROUTE_TABLE_STATS
static size_t croutes;
static size_t nroutes;
static size_t froutes;
static size_t mroutes;
#endif
static void
rt_maskedaddr(struct sockaddr *dst,
const struct sockaddr *addr, const struct sockaddr *netmask)
{
const char *addrp = addr->sa_data, *netmaskp = netmask->sa_data;
char *dstp = dst->sa_data;
const char *addre = (char *)dst + sa_len(addr);
const char *netmaske = (char *)dst + MIN(sa_len(addr), sa_len(netmask));
dst->sa_family = addr->sa_family;
#ifdef HAVE_SA_LEN
dst->sa_len = addr->sa_len;
#endif
if (sa_is_unspecified(netmask)) {
if (addre > dstp)
memcpy(dstp, addrp, (size_t)(addre - dstp));
return;
}
while (dstp < netmaske)
*dstp++ = *addrp++ & *netmaskp++;
if (dstp < addre)
memset(dstp, 0, (size_t)(addre - dstp));
}
/*
* On some systems, host routes have no need for a netmask.
* However DHCP specifies host routes using an all-ones netmask.
* This handy function allows easy comparison when the two
* differ.
*/
static int
rt_cmp_netmask(const struct rt *rt1, const struct rt *rt2)
{
if (rt1->rt_flags & RTF_HOST && rt2->rt_flags & RTF_HOST)
return 0;
return sa_cmp(&rt1->rt_netmask, &rt2->rt_netmask);
}
int
rt_cmp_dest(const struct rt *rt1, const struct rt *rt2)
{
union sa_ss ma1 = { .sa.sa_family = AF_UNSPEC };
union sa_ss ma2 = { .sa.sa_family = AF_UNSPEC };
int c;
rt_maskedaddr(&ma1.sa, &rt1->rt_dest, &rt1->rt_netmask);
rt_maskedaddr(&ma2.sa, &rt2->rt_dest, &rt2->rt_netmask);
c = sa_cmp(&ma1.sa, &ma2.sa);
if (c != 0)
return c;
return rt_cmp_netmask(rt1, rt2);
}
static int
rt_compare_os(__unused void *context, const void *node1, const void *node2)
{
const struct rt *rt1 = node1, *rt2 = node2;
int c;
/* Sort by masked destination. */
c = rt_cmp_dest(rt1, rt2);
if (c != 0)
return c;
#ifdef HAVE_ROUTE_METRIC
c = (int)(rt1->rt_ifp->metric - rt2->rt_ifp->metric);
#endif
return c;
}
static int
rt_compare_list(__unused void *context, const void *node1, const void *node2)
{
const struct rt *rt1 = node1, *rt2 = node2;
if (rt1->rt_order > rt2->rt_order)
return 1;
if (rt1->rt_order < rt2->rt_order)
return -1;
return 0;
}
static int
rt_compare_proto(void *context, const void *node1, const void *node2)
{
const struct rt *rt1 = node1, *rt2 = node2;
int c;
struct interface *ifp1, *ifp2;
assert(rt1->rt_ifp != NULL);
assert(rt2->rt_ifp != NULL);
ifp1 = rt1->rt_ifp;
ifp2 = rt2->rt_ifp;
/* Prefer interfaces with a carrier. */
c = ifp1->carrier - ifp2->carrier;
if (c != 0)
return -c;
/* Prefer roaming over non roaming if both carriers are down. */
if (ifp1->carrier == LINK_DOWN && ifp2->carrier == LINK_DOWN) {
bool roam1 = if_roaming(ifp1);
bool roam2 = if_roaming(ifp2);
if (roam1 != roam2)
return roam1 ? 1 : -1;
}
#ifdef INET
/* IPv4LL routes always come last */
if (rt1->rt_dflags & RTDF_IPV4LL && !(rt2->rt_dflags & RTDF_IPV4LL))
return -1;
else if (!(rt1->rt_dflags & RTDF_IPV4LL) && rt2->rt_dflags & RTDF_IPV4LL)
return 1;
#endif
/* Lower metric interfaces come first. */
c = (int)(ifp1->metric - ifp2->metric);
if (c != 0)
return c;
/* Finally the order in which the route was given to us. */
return rt_compare_list(context, rt1, rt2);
}
static const rb_tree_ops_t rt_compare_os_ops = {
.rbto_compare_nodes = rt_compare_os,
.rbto_compare_key = rt_compare_os,
.rbto_node_offset = offsetof(struct rt, rt_tree),
.rbto_context = NULL
};
const rb_tree_ops_t rt_compare_list_ops = {
.rbto_compare_nodes = rt_compare_list,
.rbto_compare_key = rt_compare_list,
.rbto_node_offset = offsetof(struct rt, rt_tree),
.rbto_context = NULL
};
const rb_tree_ops_t rt_compare_proto_ops = {
.rbto_compare_nodes = rt_compare_proto,
.rbto_compare_key = rt_compare_proto,
.rbto_node_offset = offsetof(struct rt, rt_tree),
.rbto_context = NULL
};
#ifdef RT_FREE_ROUTE_TABLE
static int
rt_compare_free(__unused void *context, const void *node1, const void *node2)
{
return node1 == node2 ? 0 : node1 < node2 ? -1 : 1;
}
static const rb_tree_ops_t rt_compare_free_ops = {
.rbto_compare_nodes = rt_compare_free,
.rbto_compare_key = rt_compare_free,
.rbto_node_offset = offsetof(struct rt, rt_tree),
.rbto_context = NULL
};
#endif
void
rt_init(struct dhcpcd_ctx *ctx)
{
rb_tree_init(&ctx->routes, &rt_compare_os_ops);
#ifdef RT_FREE_ROUTE_TABLE
rb_tree_init(&ctx->froutes, &rt_compare_free_ops);
#endif
}
bool
rt_is_default(const struct rt *rt)
{
return sa_is_unspecified(&rt->rt_dest) &&
sa_is_unspecified(&rt->rt_netmask);
}
static void
rt_desc(const char *cmd, const struct rt *rt)
{
char dest[INET_MAX_ADDRSTRLEN], gateway[INET_MAX_ADDRSTRLEN];
int prefix;
const char *ifname;
bool gateway_unspec;
assert(cmd != NULL);
assert(rt != NULL);
sa_addrtop(&rt->rt_dest, dest, sizeof(dest));
prefix = sa_toprefix(&rt->rt_netmask);
sa_addrtop(&rt->rt_gateway, gateway, sizeof(gateway));
gateway_unspec = sa_is_unspecified(&rt->rt_gateway);
ifname = rt->rt_ifp == NULL ? "(null)" : rt->rt_ifp->name;
if (rt->rt_flags & RTF_HOST) {
if (gateway_unspec)
loginfox("%s: %s host route to %s",
ifname, cmd, dest);
else
loginfox("%s: %s host route to %s via %s",
ifname, cmd, dest, gateway);
} else if (rt_is_default(rt)) {
if (gateway_unspec)
loginfox("%s: %s default route",
ifname, cmd);
else
loginfox("%s: %s default route via %s",
ifname, cmd, gateway);
} else if (gateway_unspec)
loginfox("%s: %s%s route to %s/%d",
ifname, cmd,
rt->rt_flags & RTF_REJECT ? " reject" : "",
dest, prefix);
else
loginfox("%s: %s%s route to %s/%d via %s",
ifname, cmd,
rt->rt_flags & RTF_REJECT ? " reject" : "",
dest, prefix, gateway);
}
void
rt_headclear0(struct dhcpcd_ctx *ctx, rb_tree_t *rts, int af)
{
struct rt *rt, *rtn;
if (rts == NULL)
return;
assert(ctx != NULL);
#ifdef RT_FREE_ROUTE_TABLE
assert(&ctx->froutes != rts);
#endif
RB_TREE_FOREACH_SAFE(rt, rts, rtn) {
if (af != AF_UNSPEC &&
rt->rt_dest.sa_family != af &&
rt->rt_gateway.sa_family != af)
continue;
rb_tree_remove_node(rts, rt);
rt_free(rt);
}
}
void
rt_headclear(rb_tree_t *rts, int af)
{
struct rt *rt;
if (rts == NULL || (rt = RB_TREE_MIN(rts)) == NULL)
return;
rt_headclear0(rt->rt_ifp->ctx, rts, af);
}
static void
rt_headfree(rb_tree_t *rts)
{
struct rt *rt;
while ((rt = RB_TREE_MIN(rts)) != NULL) {
rb_tree_remove_node(rts, rt);
free(rt);
}
}
void
rt_dispose(struct dhcpcd_ctx *ctx)
{
assert(ctx != NULL);
rt_headfree(&ctx->routes);
#ifdef RT_FREE_ROUTE_TABLE
rt_headfree(&ctx->froutes);
#ifdef RT_FREE_ROUTE_TABLE_STATS
logdebugx("free route list used %zu times", froutes);
logdebugx("new routes from route free list %zu", nroutes);
logdebugx("maximum route free list size %zu", mroutes);
#endif
#endif
}
struct rt *
rt_new0(struct dhcpcd_ctx *ctx)
{
struct rt *rt;
assert(ctx != NULL);
#ifdef RT_FREE_ROUTE_TABLE
if ((rt = RB_TREE_MIN(&ctx->froutes)) != NULL) {
rb_tree_remove_node(&ctx->froutes, rt);
#ifdef RT_FREE_ROUTE_TABLE_STATS
croutes--;
nroutes++;
#endif
} else
#endif
if ((rt = malloc(sizeof(*rt))) == NULL) {
logerr(__func__);
return NULL;
}
memset(rt, 0, sizeof(*rt));
return rt;
}
void
rt_setif(struct rt *rt, struct interface *ifp)
{
assert(rt != NULL);
assert(ifp != NULL);
rt->rt_ifp = ifp;
#ifdef HAVE_ROUTE_METRIC
rt->rt_metric = ifp->metric;
if (if_roaming(ifp))
rt->rt_metric += RTMETRIC_ROAM;
#endif
}
struct rt *
rt_new(struct interface *ifp)
{
struct rt *rt;
assert(ifp != NULL);
if ((rt = rt_new0(ifp->ctx)) == NULL)
return NULL;
rt_setif(rt, ifp);
return rt;
}
struct rt *
rt_proto_add_ctx(rb_tree_t *tree, struct rt *rt, struct dhcpcd_ctx *ctx)
{
rt->rt_order = ctx->rt_order++;
if (rb_tree_insert_node(tree, rt) == rt)
return rt;
rt_free(rt);
errno = EEXIST;
return NULL;
}
struct rt *
rt_proto_add(rb_tree_t *tree, struct rt *rt)
{
assert (rt->rt_ifp != NULL);
return rt_proto_add_ctx(tree, rt, rt->rt_ifp->ctx);
}
void
rt_free(struct rt *rt)
{
#ifdef RT_FREE_ROUTE_TABLE
struct dhcpcd_ctx *ctx;
assert(rt != NULL);
if (rt->rt_ifp == NULL) {
free(rt);
return;
}
ctx = rt->rt_ifp->ctx;
rb_tree_insert_node(&ctx->froutes, rt);
#ifdef RT_FREE_ROUTE_TABLE_STATS
croutes++;
froutes++;
if (croutes > mroutes)
mroutes = croutes;
#endif
#else
free(rt);
#endif
}
void
rt_freeif(struct interface *ifp)
{
struct dhcpcd_ctx *ctx;
struct rt *rt, *rtn;
if (ifp == NULL)
return;
ctx = ifp->ctx;
RB_TREE_FOREACH_SAFE(rt, &ctx->routes, rtn) {
if (rt->rt_ifp == ifp) {
rb_tree_remove_node(&ctx->routes, rt);
rt_free(rt);
}
}
}
/* If something other than dhcpcd removes a route,
* we need to remove it from our internal table. */
void
rt_recvrt(int cmd, const struct rt *rt, pid_t pid)
{
struct dhcpcd_ctx *ctx;
struct rt *f;
assert(rt != NULL);
assert(rt->rt_ifp != NULL);
assert(rt->rt_ifp->ctx != NULL);
ctx = rt->rt_ifp->ctx;
switch(cmd) {
case RTM_DELETE:
f = rb_tree_find_node(&ctx->routes, rt);
if (f != NULL) {
char buf[32];
rb_tree_remove_node(&ctx->routes, f);
snprintf(buf, sizeof(buf), "pid %d deleted", pid);
rt_desc(buf, f);
rt_free(f);
}
break;
}
#if defined(IPV4LL) && defined(HAVE_ROUTE_METRIC)
if (rt->rt_dest.sa_family == AF_INET)
ipv4ll_recvrt(cmd, rt);
#endif
}
static bool
rt_add(rb_tree_t *kroutes, struct rt *nrt, struct rt *ort)
{
struct dhcpcd_ctx *ctx;
bool change, kroute, result;
assert(nrt != NULL);
ctx = nrt->rt_ifp->ctx;
/*
* Don't install a gateway if not asked to.
* This option is mainly for VPN users who want their VPN to be the
* default route.
* Because VPN's generally don't care about route management
* beyond their own, a longer term solution would be to remove this
* and get the VPN to inject the default route into dhcpcd somehow.
*/
if (((nrt->rt_ifp->active &&
!(nrt->rt_ifp->options->options & DHCPCD_GATEWAY)) ||
(!nrt->rt_ifp->active && !(ctx->options & DHCPCD_GATEWAY))) &&
sa_is_unspecified(&nrt->rt_dest) &&
sa_is_unspecified(&nrt->rt_netmask))
return false;
rt_desc(ort == NULL ? "adding" : "changing", nrt);
change = kroute = result = false;
if (ort == NULL) {
ort = rb_tree_find_node(kroutes, nrt);
if (ort != NULL &&
((ort->rt_flags & RTF_REJECT &&
nrt->rt_flags & RTF_REJECT) ||
(ort->rt_ifp == nrt->rt_ifp &&
#ifdef HAVE_ROUTE_METRIC
ort->rt_metric == nrt->rt_metric &&
#endif
sa_cmp(&ort->rt_gateway, &nrt->rt_gateway) == 0)))
{
if (ort->rt_mtu == nrt->rt_mtu)
return true;
change = true;
kroute = true;
}
} else if (ort->rt_dflags & RTDF_FAKE &&
!(nrt->rt_dflags & RTDF_FAKE) &&
ort->rt_ifp == nrt->rt_ifp &&
#ifdef HAVE_ROUTE_METRIC
ort->rt_metric == nrt->rt_metric &&
#endif
sa_cmp(&ort->rt_dest, &nrt->rt_dest) == 0 &&
rt_cmp_netmask(ort, nrt) == 0 &&
sa_cmp(&ort->rt_gateway, &nrt->rt_gateway) == 0)
{
if (ort->rt_mtu == nrt->rt_mtu)
return true;
change = true;
}
#ifdef RTF_CLONING
/* BSD can set routes to be cloning routes.
* Cloned routes inherit the parent flags.
* As such, we need to delete and re-add the route to flush children
* to correct the flags. */
if (change && ort != NULL && ort->rt_flags & RTF_CLONING)
change = false;
#endif
if (change) {
if (if_route(RTM_CHANGE, nrt) != -1) {
result = true;
goto out;
}
if (errno != ESRCH)
logerr("if_route (CHG)");
}
#ifdef HAVE_ROUTE_METRIC
/* With route metrics, we can safely add the new route before
* deleting the old route. */
if (if_route(RTM_ADD, nrt) != -1) {
if (ort != NULL) {
if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
logerr("if_route (DEL)");
}
result = true;
goto out;
}
/* If the kernel claims the route exists we need to rip out the
* old one first. */
if (errno != EEXIST || ort == NULL)
goto logerr;
#endif
/* No route metrics, we need to delete the old route before
* adding the new one. */
#ifdef ROUTE_PER_GATEWAY
errno = 0;
#endif
if (ort != NULL) {
if (if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
logerr("if_route (DEL)");
else
kroute = false;
}
#ifdef ROUTE_PER_GATEWAY
/* The OS allows many routes to the same dest with different gateways.
* dhcpcd does not support this yet, so for the time being just keep on
* deleting the route until there is an error. */
if (ort != NULL && errno == 0) {
for (;;) {
if (if_route(RTM_DELETE, ort) == -1)
break;
}
}
#endif
/* Shouldn't need to check for EEXIST, but some kernels don't
* dump the subnet route just after we added the address. */
if (if_route(RTM_ADD, nrt) != -1 || errno == EEXIST) {
result = true;
goto out;
}
#ifdef HAVE_ROUTE_METRIC
logerr:
#endif
logerr("if_route (ADD)");
out:
if (kroute) {
rb_tree_remove_node(kroutes, ort);
rt_free(ort);
}
return result;
}
static bool
rt_delete(struct rt *rt)
{
int retval;
rt_desc("deleting", rt);
retval = if_route(RTM_DELETE, rt) == -1 ? false : true;
if (!retval && errno != ENOENT && errno != ESRCH)
logerr(__func__);
return retval;
}
static bool
rt_cmp(const struct rt *r1, const struct rt *r2)
{
return (r1->rt_ifp == r2->rt_ifp &&
#ifdef HAVE_ROUTE_METRIC
r1->rt_metric == r2->rt_metric &&
#endif
sa_cmp(&r1->rt_gateway, &r2->rt_gateway) == 0);
}
static bool
rt_doroute(rb_tree_t *kroutes, struct rt *rt)
{
struct dhcpcd_ctx *ctx;
struct rt *or;
ctx = rt->rt_ifp->ctx;
/* Do we already manage it? */
or = rb_tree_find_node(&ctx->routes, rt);
if (or != NULL) {
if (rt->rt_dflags & RTDF_FAKE)
return true;
if (or->rt_dflags & RTDF_FAKE ||
!rt_cmp(rt, or) ||
(rt->rt_ifa.sa_family != AF_UNSPEC &&
sa_cmp(&or->rt_ifa, &rt->rt_ifa) != 0) ||
or->rt_mtu != rt->rt_mtu)
{
if (!rt_add(kroutes, rt, or))
return false;
}
rb_tree_remove_node(&ctx->routes, or);
rt_free(or);
} else {
if (rt->rt_dflags & RTDF_FAKE) {
or = rb_tree_find_node(kroutes, rt);
if (or == NULL)
return false;
if (!rt_cmp(rt, or))
return false;
} else {
if (!rt_add(kroutes, rt, NULL))
return false;
}
}
return true;
}
void
rt_build(struct dhcpcd_ctx *ctx, int af)
{
rb_tree_t routes, added, kroutes;
struct rt *rt, *rtn;
unsigned long long o;
rb_tree_init(&routes, &rt_compare_proto_ops);
rb_tree_init(&added, &rt_compare_os_ops);
rb_tree_init(&kroutes, &rt_compare_os_ops);
if (if_initrt(ctx, &kroutes, af) != 0)
logerr("%s: if_initrt", __func__);
ctx->rt_order = 0;
ctx->options |= DHCPCD_RTBUILD;
#ifdef INET
if (!inet_getroutes(ctx, &routes))
goto getfail;
#endif
#ifdef INET6
if (!inet6_getroutes(ctx, &routes))
goto getfail;
#endif
#ifdef BSD
/* Rewind the miss filter */
ctx->rt_missfilterlen = 0;
#endif
RB_TREE_FOREACH_SAFE(rt, &routes, rtn) {
if (rt->rt_ifp->active) {
if (!(rt->rt_ifp->options->options & DHCPCD_CONFIGURE))
continue;
} else if (!(ctx->options & DHCPCD_CONFIGURE))
continue;
#ifdef BSD
if (rt_is_default(rt) &&
if_missfilter(rt->rt_ifp, &rt->rt_gateway) == -1)
logerr("if_missfilter");
#endif
if ((rt->rt_dest.sa_family != af &&
rt->rt_dest.sa_family != AF_UNSPEC) ||
(rt->rt_gateway.sa_family != af &&
rt->rt_gateway.sa_family != AF_UNSPEC))
continue;
/* Is this route already in our table? */
if (rb_tree_find_node(&added, rt) != NULL)
continue;
if (rt_doroute(&kroutes, rt)) {
rb_tree_remove_node(&routes, rt);
if (rb_tree_insert_node(&added, rt) != rt) {
errno = EEXIST;
logerr(__func__);
rt_free(rt);
}
}
}
#ifdef BSD
if (if_missfilter_apply(ctx) == -1 && errno != ENOTSUP)
logerr("if_missfilter_apply");
#endif
/* Remove old routes we used to manage. */
RB_TREE_FOREACH_REVERSE_SAFE(rt, &ctx->routes, rtn) {
if ((rt->rt_dest.sa_family != af &&
rt->rt_dest.sa_family != AF_UNSPEC) ||
(rt->rt_gateway.sa_family != af &&
rt->rt_gateway.sa_family != AF_UNSPEC))
continue;
rb_tree_remove_node(&ctx->routes, rt);
if (rb_tree_find_node(&added, rt) == NULL) {
o = rt->rt_ifp->options ?
rt->rt_ifp->options->options :
ctx->options;
if ((o &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
rt_delete(rt);
}
rt_free(rt);
}
/* XXX This needs to be optimised. */
while ((rt = RB_TREE_MIN(&added)) != NULL) {
rb_tree_remove_node(&added, rt);
if (rb_tree_insert_node(&ctx->routes, rt) != rt) {
errno = EEXIST;
logerr(__func__);
rt_free(rt);
}
}
getfail:
rt_headclear(&routes, AF_UNSPEC);
rt_headclear(&kroutes, AF_UNSPEC);
}

145
external/bsd/dhcpcd/dist/src/route.h vendored Normal file
View File

@ -0,0 +1,145 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - route management
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef ROUTE_H
#define ROUTE_H
#ifdef HAVE_SYS_RBTREE_H
#include <sys/rbtree.h>
#endif
#include <sys/socket.h>
#include <net/route.h>
#include <stdbool.h>
#include "dhcpcd.h"
#include "sa.h"
/*
* Enable the route free list by default as
* memory usage is still reported as low/unchanged even
* when dealing with millions of routes.
*/
#if !defined(RT_FREE_ROUTE_TABLE)
#define RT_FREE_ROUTE_TABLE 1
#elif RT_FREE_ROUTE_TABLE == 0
#undef RT_FREE_ROUTE_TABLE
#endif
/* Some systems have route metrics.
* OpenBSD route priority is not this. */
#ifndef HAVE_ROUTE_METRIC
# if defined(__linux__)
# define HAVE_ROUTE_METRIC 1
# endif
#endif
#ifdef __linux__
# include <linux/version.h> /* RTA_PREF is only an enum.... */
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
# define HAVE_ROUTE_PREF
# endif
#endif
#if defined(__OpenBSD__) || defined (__sun)
# define ROUTE_PER_GATEWAY
/* XXX dhcpcd doesn't really support this yet.
* But that's generally OK if only dhcpcd is managing routes. */
#endif
/* OpenBSD defines this as a "convienience" ..... we work around it. */
#ifdef __OpenBSD__
#undef rt_mtu
#endif
struct rt {
union sa_ss rt_ss_dest;
#define rt_dest rt_ss_dest.sa
union sa_ss rt_ss_netmask;
#define rt_netmask rt_ss_netmask.sa
union sa_ss rt_ss_gateway;
#define rt_gateway rt_ss_gateway.sa
struct interface *rt_ifp;
union sa_ss rt_ss_ifa;
#define rt_ifa rt_ss_ifa.sa
unsigned int rt_flags;
unsigned int rt_mtu;
#ifdef HAVE_ROUTE_METRIC
unsigned int rt_metric;
#endif
/* Maximum interface index is generally USHORT_MAX or 65535.
* Add some padding for other stuff and we get offsets for the
* below that should work automatically.
* This is only an issue if the user defines higher metrics in
* their configuration, but then they might wish to override also. */
#define RTMETRIC_BASE 1000U
#define RTMETRIC_WIRELESS 2000U
#define RTMETRIC_IPV4LL 1000000U
#define RTMETRIC_ROAM 2000000U
#ifdef HAVE_ROUTE_PREF
int rt_pref;
#endif
#define RTPREF_HIGH 1
#define RTPREF_MEDIUM 0 /* has to be zero */
#define RTPREF_LOW (-1)
#define RTPREF_RESERVED (-2)
#define RTPREF_INVALID (-3) /* internal */
unsigned int rt_dflags;
#define RTDF_IFA_ROUTE 0x01 /* Address generated route */
#define RTDF_FAKE 0x02 /* Maybe us on lease reboot */
#define RTDF_IPV4LL 0x04 /* IPv4LL route */
#define RTDF_RA 0x08 /* Router Advertisement */
#define RTDF_DHCP 0x10 /* DHCP route */
#define RTDF_STATIC 0x20 /* Configured in dhcpcd */
#define RTDF_GATELINK 0x40 /* Gateway is on link */
size_t rt_order;
rb_node_t rt_tree;
};
extern const rb_tree_ops_t rt_compare_list_ops;
extern const rb_tree_ops_t rt_compare_proto_ops;
void rt_init(struct dhcpcd_ctx *);
void rt_dispose(struct dhcpcd_ctx *);
void rt_free(struct rt *);
void rt_freeif(struct interface *);
bool rt_is_default(const struct rt *);
void rt_headclear0(struct dhcpcd_ctx *, rb_tree_t *, int);
void rt_headclear(rb_tree_t *, int);
void rt_headfreeif(rb_tree_t *);
struct rt * rt_new0(struct dhcpcd_ctx *);
void rt_setif(struct rt *, struct interface *);
struct rt * rt_new(struct interface *);
struct rt * rt_proto_add_ctx(rb_tree_t *, struct rt *, struct dhcpcd_ctx *);
struct rt * rt_proto_add(rb_tree_t *, struct rt *);
int rt_cmp_dest(const struct rt *, const struct rt *);
void rt_recvrt(int, const struct rt *, pid_t);
void rt_build(struct dhcpcd_ctx *, int);
#endif

503
external/bsd/dhcpcd/dist/src/sa.c vendored Normal file
View File

@ -0,0 +1,503 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Socket Address handling for dhcpcd
* Copyright (c) 2015-2023 Roy Marples <roy@marples.name>
* 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/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#ifdef AF_LINK
#include <net/if_dl.h>
#elif defined(AF_PACKET)
#include <linux/if_packet.h>
#endif
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "common.h"
#include "sa.h"
#ifndef NDEBUG
static bool sa_inprefix;
#endif
socklen_t
sa_addroffset(const struct sockaddr *sa)
{
assert(sa != NULL);
switch(sa->sa_family) {
#ifdef INET
case AF_INET:
return offsetof(struct sockaddr_in, sin_addr) +
offsetof(struct in_addr, s_addr);
#endif /* INET */
#ifdef INET6
case AF_INET6:
return offsetof(struct sockaddr_in6, sin6_addr) +
offsetof(struct in6_addr, s6_addr);
#endif /* INET6 */
default:
errno = EAFNOSUPPORT;
return 0;
}
}
socklen_t
sa_addrlen(const struct sockaddr *sa)
{
#define membersize(type, member) sizeof(((type *)0)->member)
assert(sa != NULL);
switch(sa->sa_family) {
#ifdef INET
case AF_INET:
return membersize(struct in_addr, s_addr);
#endif /* INET */
#ifdef INET6
case AF_INET6:
return membersize(struct in6_addr, s6_addr);
#endif /* INET6 */
default:
errno = EAFNOSUPPORT;
return 0;
}
}
#ifndef HAVE_SA_LEN
socklen_t
sa_len(const struct sockaddr *sa)
{
switch (sa->sa_family) {
#ifdef AF_LINK
case AF_LINK:
return sizeof(struct sockaddr_dl);
#endif
#ifdef AF_PACKET
case AF_PACKET:
return sizeof(struct sockaddr_ll);
#endif
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
return sizeof(struct sockaddr);
}
}
#endif
bool
sa_is_unspecified(const struct sockaddr *sa)
{
assert(sa != NULL);
switch(sa->sa_family) {
case AF_UNSPEC:
return true;
#ifdef INET
case AF_INET:
return satocsin(sa)->sin_addr.s_addr == INADDR_ANY;
#endif /* INET */
#ifdef INET6
case AF_INET6:
return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr);
#endif /* INET6 */
default:
errno = EAFNOSUPPORT;
return false;
}
}
#ifdef INET6
#ifndef IN6MASK128
#define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
#endif
static const struct in6_addr in6allones = IN6MASK128;
#endif
bool
sa_is_allones(const struct sockaddr *sa)
{
assert(sa != NULL);
switch(sa->sa_family) {
case AF_UNSPEC:
return false;
#ifdef INET
case AF_INET:
{
const struct sockaddr_in *sin;
sin = satocsin(sa);
return sin->sin_addr.s_addr == INADDR_BROADCAST;
}
#endif /* INET */
#ifdef INET6
case AF_INET6:
{
const struct sockaddr_in6 *sin6;
sin6 = satocsin6(sa);
return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones);
}
#endif /* INET6 */
default:
errno = EAFNOSUPPORT;
return false;
}
}
bool
sa_is_loopback(const struct sockaddr *sa)
{
assert(sa != NULL);
switch(sa->sa_family) {
case AF_UNSPEC:
return false;
#ifdef INET
case AF_INET:
{
const struct sockaddr_in *sin;
sin = satocsin(sa);
return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
}
#endif /* INET */
#ifdef INET6
case AF_INET6:
{
const struct sockaddr_in6 *sin6;
sin6 = satocsin6(sa);
return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
}
#endif /* INET6 */
default:
errno = EAFNOSUPPORT;
return false;
}
}
int
sa_toprefix(const struct sockaddr *sa)
{
int prefix;
assert(sa != NULL);
switch(sa->sa_family) {
#ifdef INET
case AF_INET:
{
const struct sockaddr_in *sin;
uint32_t mask;
sin = satocsin(sa);
if (sin->sin_addr.s_addr == INADDR_ANY) {
prefix = 0;
break;
}
mask = ntohl(sin->sin_addr.s_addr);
prefix = 33 - ffs((int)mask); /* 33 - (1 .. 32) -> 32 .. 1 */
if (prefix < 32) { /* more than 1 bit in mask */
/* check for non-contig netmask */
if ((mask^(((1U << prefix)-1) << (32 - prefix))) != 0) {
errno = EINVAL;
return -1; /* noncontig, no pfxlen */
}
}
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
const struct sockaddr_in6 *sin6;
int x, y;
const uint8_t *lim, *p;
sin6 = satocsin6(sa);
p = (const uint8_t *)sin6->sin6_addr.s6_addr;
lim = p + sizeof(sin6->sin6_addr.s6_addr);
for (x = 0; p < lim; x++, p++) {
if (*p != 0xff)
break;
}
y = 0;
if (p < lim) {
for (y = 0; y < NBBY; y++) {
if ((*p & (0x80 >> y)) == 0)
break;
}
}
/*
* when the limit pointer is given, do a stricter check on the
* remaining bits.
*/
if (p < lim) {
if (y != 0 && (*p & (0x00ff >> y)) != 0)
return 0;
for (p = p + 1; p < lim; p++)
if (*p != 0)
return 0;
}
prefix = x * NBBY + y;
break;
}
#endif
default:
errno = EAFNOSUPPORT;
return -1;
}
#ifndef NDEBUG
/* Ensure the calculation is correct */
if (!sa_inprefix) {
union sa_ss ss = { .sa = { .sa_family = sa->sa_family } };
sa_inprefix = true;
sa_fromprefix(&ss.sa, prefix);
assert(sa_cmp(sa, &ss.sa) == 0);
sa_inprefix = false;
}
#endif
return prefix;
}
static void
ipbytes_fromprefix(uint8_t *ap, int prefix, int max_prefix)
{
int bytes, bits, i;
bytes = prefix / NBBY;
bits = prefix % NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0xff;
if (bits) {
uint8_t a;
a = 0xff;
a = (uint8_t)(a << (8 - bits));
*ap++ = a;
}
bytes = (max_prefix - prefix) / NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0x00;
}
void
in6_addr_fromprefix(struct in6_addr *addr, int prefix)
{
ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
}
int
sa_fromprefix(struct sockaddr *sa, int prefix)
{
uint8_t *ap;
int max_prefix;
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
max_prefix = 32;
#ifdef HAVE_SA_LEN
sa->sa_len = sizeof(struct sockaddr_in);
#endif
break;
#endif
#ifdef INET6
case AF_INET6:
max_prefix = 128;
#ifdef HAVE_SA_LEN
sa->sa_len = sizeof(struct sockaddr_in6);
#endif
break;
#endif
default:
errno = EAFNOSUPPORT;
return -1;
}
ap = (uint8_t *)sa + sa_addroffset(sa);
ipbytes_fromprefix(ap, prefix, max_prefix);
#ifndef NDEBUG
/* Ensure the calculation is correct */
if (!sa_inprefix) {
sa_inprefix = true;
assert(sa_toprefix(sa) == prefix);
sa_inprefix = false;
}
#endif
return 0;
}
/* inet_ntop, but for sockaddr. */
const char *
sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
{
const void *addr;
assert(buf != NULL);
assert(len > 0);
if (sa->sa_family == 0) {
*buf = '\0';
return NULL;
}
#ifdef AF_LINK
#ifndef CLLADDR
#define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
#endif
if (sa->sa_family == AF_LINK) {
const struct sockaddr_dl *sdl;
sdl = (const void *)sa;
if (sdl->sdl_alen == 0) {
if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
return NULL;
return buf;
}
return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
}
#elif defined(AF_PACKET)
if (sa->sa_family == AF_PACKET) {
const struct sockaddr_ll *sll;
sll = (const void *)sa;
return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
}
#endif
addr = (const char *)sa + sa_addroffset(sa);
return inet_ntop(sa->sa_family, addr, buf, len);
}
int
sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
{
socklen_t offset, len;
assert(sa1 != NULL);
assert(sa2 != NULL);
/* Treat AF_UNSPEC as the unspecified address. */
if ((sa1->sa_family == AF_UNSPEC || sa2->sa_family == AF_UNSPEC) &&
sa_is_unspecified(sa1) && sa_is_unspecified(sa2))
return 0;
if (sa1->sa_family != sa2->sa_family)
return sa1->sa_family - sa2->sa_family;
#ifdef HAVE_SA_LEN
len = MIN(sa1->sa_len, sa2->sa_len);
#endif
switch (sa1->sa_family) {
#ifdef INET
case AF_INET:
offset = offsetof(struct sockaddr_in, sin_addr);
#ifdef HAVE_SA_LEN
len -= offset;
len = MIN(len, sizeof(struct in_addr));
#else
len = sizeof(struct in_addr);
#endif
break;
#endif
#ifdef INET6
case AF_INET6:
offset = offsetof(struct sockaddr_in6, sin6_addr);
#ifdef HAVE_SA_LEN
len -= offset;
len = MIN(len, sizeof(struct in6_addr));
#else
len = sizeof(struct in6_addr);
#endif
break;
#endif
default:
offset = 0;
#ifndef HAVE_SA_LEN
len = sizeof(struct sockaddr);
#endif
break;
}
return memcmp((const char *)sa1 + offset,
(const char *)sa2 + offset,
len);
}
#ifdef INET
void
sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
{
struct sockaddr_in *sin;
assert(sa != NULL);
assert(addr != NULL);
sin = satosin(sa);
sin->sin_family = AF_INET;
#ifdef HAVE_SA_LEN
sin->sin_len = sizeof(*sin);
#endif
sin->sin_addr.s_addr = addr->s_addr;
}
#endif
#ifdef INET6
void
sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
{
struct sockaddr_in6 *sin6;
assert(sa != NULL);
assert(addr != NULL);
sin6 = satosin6(sa);
sin6->sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN
sin6->sin6_len = sizeof(*sin6);
#endif
memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
sizeof(sin6->sin6_addr.s6_addr));
}
#endif

76
external/bsd/dhcpcd/dist/src/sa.h vendored Normal file
View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Socket Address handling for dhcpcd
* Copyright (c) 2015-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef SA_H
#define SA_H
#include <sys/socket.h>
#include <netinet/in.h>
union sa_ss {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
#ifdef BSD
#define HAVE_SA_LEN
#endif
/* Allow for a sockaddr_dl being printed too. */
#define INET_MAX_ADDRSTRLEN (20 * 3)
#ifdef INET
#define satosin(sa) ((struct sockaddr_in *)(void *)(sa))
#define satocsin(sa) ((const struct sockaddr_in *)(const void *)(sa))
#endif
#ifdef INET6
#define satosin6(sa) ((struct sockaddr_in6 *)(void *)(sa))
#define satocsin6(sa) ((const struct sockaddr_in6 *)(const void *)(sa))
#endif
socklen_t sa_addroffset(const struct sockaddr *sa);
socklen_t sa_addrlen(const struct sockaddr *sa);
#ifdef HAVE_SA_LEN
#define sa_len(sa) ((sa)->sa_len)
#else
socklen_t sa_len(const struct sockaddr *sa);
#endif
bool sa_is_unspecified(const struct sockaddr *);
bool sa_is_allones(const struct sockaddr *);
bool sa_is_loopback(const struct sockaddr *);
void *sa_toaddr(struct sockaddr *);
int sa_toprefix(const struct sockaddr *);
int sa_fromprefix(struct sockaddr *, int);
void in6_addr_fromprefix(struct in6_addr *, int);
const char *sa_addrtop(const struct sockaddr *, char *, socklen_t);
int sa_cmp(const struct sockaddr *, const struct sockaddr *);
void sa_in_init(struct sockaddr *, const struct in_addr *);
void sa_in6_init(struct sockaddr *, const struct in6_addr *);
#endif

801
external/bsd/dhcpcd/dist/src/script.c vendored Normal file
View File

@ -0,0 +1,801 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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/stat.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "common.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "eloop.h"
#include "if.h"
#include "if-options.h"
#include "ipv4ll.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "script.h"
#define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin"
static const char * const if_params[] = {
"interface",
"protocol",
"reason",
"pid",
"ifcarrier",
"ifmetric",
"ifwireless",
"ifflags",
"ssid",
"profile",
"interface_order",
NULL
};
static const char * true_str = "true";
static const char * false_str = "false";
void
if_printoptions(void)
{
const char * const *p;
for (p = if_params; *p; p++)
printf(" - %s\n", *p);
}
pid_t
script_exec(char *const *argv, char *const *env)
{
pid_t pid = 0;
posix_spawnattr_t attr;
int r;
#ifdef USE_SIGNALS
size_t i;
short flags;
sigset_t defsigs;
#else
UNUSED(ctx);
#endif
/* posix_spawn is a safe way of executing another image
* and changing signals back to how they should be. */
if (posix_spawnattr_init(&attr) == -1)
return -1;
#ifdef USE_SIGNALS
flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
posix_spawnattr_setflags(&attr, flags);
sigemptyset(&defsigs);
posix_spawnattr_setsigmask(&attr, &defsigs);
for (i = 0; i < dhcpcd_signals_len; i++)
sigaddset(&defsigs, dhcpcd_signals[i]);
for (i = 0; i < dhcpcd_signals_ignore_len; i++)
sigaddset(&defsigs, dhcpcd_signals_ignore[i]);
posix_spawnattr_setsigdefault(&attr, &defsigs);
#endif
errno = 0;
r = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
posix_spawnattr_destroy(&attr);
if (r) {
errno = r;
return -1;
}
return pid;
}
#ifdef INET
static int
append_config(FILE *fp, const char *prefix, const char *const *config)
{
size_t i;
if (config == NULL)
return 0;
/* Do we need to replace existing config rather than append? */
for (i = 0; config[i] != NULL; i++) {
if (efprintf(fp, "%s_%s", prefix, config[i]) == -1)
return -1;
}
return 1;
}
#endif
#define PROTO_LINK 0
#define PROTO_DHCP 1
#define PROTO_IPV4LL 2
#define PROTO_RA 3
#define PROTO_DHCP6 4
#define PROTO_STATIC6 5
static const char *protocols[] = {
"link",
"dhcp",
"ipv4ll",
"ra",
"dhcp6",
"static6"
};
int
efprintf(FILE *fp, const char *fmt, ...)
{
va_list args;
int r;
va_start(args, fmt);
r = vfprintf(fp, fmt, args);
va_end(args);
if (r == -1)
return -1;
/* Write a trailing NULL so we can easily create env strings. */
if (fputc('\0', fp) == EOF)
return -1;
return r;
}
char **
script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len)
{
char **env, **envp, *bufp, *endp;
size_t nenv;
/* Count the terminated env strings.
* Assert that the terminations are correct. */
nenv = 0;
endp = buf + len;
for (bufp = buf; bufp < endp; bufp++) {
if (*bufp == '\0') {
#ifndef NDEBUG
if (bufp + 1 < endp)
assert(*(bufp + 1) != '\0');
#endif
nenv++;
}
}
assert(*(bufp - 1) == '\0');
if (nenv == 0)
return NULL;
if (ctx->script_envlen < nenv) {
env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
if (env == NULL)
return NULL;
ctx->script_env = env;
ctx->script_envlen = nenv;
}
bufp = buf;
envp = ctx->script_env;
*envp++ = bufp++;
endp--; /* Avoid setting the last \0 to an invalid pointer */
for (; bufp < endp; bufp++) {
if (*bufp == '\0')
*envp++ = bufp + 1;
}
*envp = NULL;
return ctx->script_env;
}
static long
make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp,
const char *reason)
{
FILE *fp;
long buf_pos, i;
char *path;
int protocol = PROTO_LINK;
const struct if_options *ifo;
const struct interface *ifp2;
int af;
bool is_stdin = ifp->name[0] == '\0';
const char *if_up, *if_down;
rb_tree_t ifaces;
struct rt *rt;
#ifdef INET
const struct dhcp_state *state;
#ifdef IPV4LL
const struct ipv4ll_state *istate;
#endif
#endif
#ifdef DHCP6
const struct dhcp6_state *d6_state;
#endif
#ifdef HAVE_OPEN_MEMSTREAM
if (ctx->script_fp == NULL) {
fp = open_memstream(&ctx->script_buf, &ctx->script_buflen);
if (fp == NULL)
goto eexit;
ctx->script_fp = fp;
} else {
fp = ctx->script_fp;
rewind(fp);
}
#else
char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX";
int tmpfd;
fp = NULL;
tmpfd = mkstemp(tmpfile);
if (tmpfd == -1) {
logerr("%s: mkstemp", __func__);
return -1;
}
unlink(tmpfile);
fp = fdopen(tmpfd, "w+");
if (fp == NULL) {
close(tmpfd);
goto eexit;
}
#endif
if (!(ifp->ctx->options & DHCPCD_DUMPLEASE)) {
/* Needed for scripts */
path = getenv("PATH");
if (efprintf(fp, "PATH=%s",
path == NULL ? DEFAULT_PATH : path) == -1)
goto eexit;
if (efprintf(fp, "pid=%d", getpid()) == -1)
goto eexit;
}
if (!is_stdin) {
if (efprintf(fp, "reason=%s", reason) == -1)
goto eexit;
}
ifo = ifp->options;
#ifdef INET
state = D_STATE(ifp);
#ifdef IPV4LL
istate = IPV4LL_CSTATE(ifp);
#endif
#endif
#ifdef DHCP6
d6_state = D6_CSTATE(ifp);
#endif
if (strcmp(reason, "TEST") == 0) {
if (1 == 2) {
/* This space left intentionally blank
* as all the below statements are optional. */
}
#ifdef INET6
#ifdef DHCP6
else if (d6_state && d6_state->new)
protocol = PROTO_DHCP6;
#endif
else if (ipv6nd_hasra(ifp))
protocol = PROTO_RA;
#endif
#ifdef INET
#ifdef IPV4LL
else if (istate && istate->addr != NULL)
protocol = PROTO_IPV4LL;
#endif
else
protocol = PROTO_DHCP;
#endif
}
#ifdef INET6
else if (strcmp(reason, "STATIC6") == 0)
protocol = PROTO_STATIC6;
#ifdef DHCP6
else if (reason[strlen(reason) - 1] == '6')
protocol = PROTO_DHCP6;
#endif
else if (strcmp(reason, "ROUTERADVERT") == 0)
protocol = PROTO_RA;
#endif
else if (strcmp(reason, "PREINIT") == 0 ||
strcmp(reason, "CARRIER") == 0 ||
strcmp(reason, "NOCARRIER") == 0 ||
strcmp(reason, "NOCARRIER_ROAMING") == 0 ||
strcmp(reason, "UNKNOWN") == 0 ||
strcmp(reason, "DEPARTED") == 0 ||
strcmp(reason, "STOPPED") == 0)
protocol = PROTO_LINK;
#ifdef INET
#ifdef IPV4LL
else if (strcmp(reason, "IPV4LL") == 0)
protocol = PROTO_IPV4LL;
#endif
else
protocol = PROTO_DHCP;
#endif
if (!is_stdin) {
if (efprintf(fp, "interface=%s", ifp->name) == -1)
goto eexit;
if (protocols[protocol] != NULL) {
if (efprintf(fp, "protocol=%s",
protocols[protocol]) == -1)
goto eexit;
}
}
if (ifp->ctx->options & DHCPCD_DUMPLEASE && protocol != PROTO_LINK)
goto dumplease;
if (efprintf(fp, "if_configured=%s",
ifo->options & DHCPCD_CONFIGURE ? "true" : "false") == -1)
goto eexit;
if (efprintf(fp, "ifcarrier=%s",
ifp->carrier == LINK_UNKNOWN ? "unknown" :
ifp->carrier == LINK_UP ? "up" : "down") == -1)
goto eexit;
if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1)
goto eexit;
if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1)
goto eexit;
if (efprintf(fp, "ifflags=%u", ifp->flags) == -1)
goto eexit;
if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1)
goto eexit;
if (ifp->wireless) {
char pssid[IF_SSIDLEN * 4];
if (print_string(pssid, sizeof(pssid), OT_ESCSTRING,
ifp->ssid, ifp->ssid_len) != -1)
{
if (efprintf(fp, "ifssid=%s", pssid) == -1)
goto eexit;
}
}
if (*ifp->profile != '\0') {
if (efprintf(fp, "profile=%s", ifp->profile) == -1)
goto eexit;
}
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
goto dumplease;
ifp->ctx->rt_order = 0;
rb_tree_init(&ifaces, &rt_compare_proto_ops);
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (!ifp2->active)
continue;
rt = rt_new(UNCONST(ifp2));
if (rt == NULL)
goto eexit;
if (rt_proto_add(&ifaces, rt) != rt)
goto eexit;
}
if (fprintf(fp, "interface_order=") == -1)
goto eexit;
RB_TREE_FOREACH(rt, &ifaces) {
if (rt != RB_TREE_MIN(&ifaces) &&
fprintf(fp, "%s", " ") == -1)
goto eexit;
if (fprintf(fp, "%s", rt->rt_ifp->name) == -1)
goto eexit;
}
rt_headclear(&ifaces, AF_UNSPEC);
if (fputc('\0', fp) == EOF)
goto eexit;
if (strcmp(reason, "STOPPED") == 0) {
if_up = false_str;
if_down = ifo->options & DHCPCD_RELEASE ? true_str : false_str;
} else if (strcmp(reason, "TEST") == 0 ||
strcmp(reason, "PREINIT") == 0 ||
strcmp(reason, "CARRIER") == 0 ||
strcmp(reason, "UNKNOWN") == 0)
{
if_up = false_str;
if_down = false_str;
} else if (strcmp(reason, "NOCARRIER") == 0) {
if_up = false_str;
if_down = true_str;
} else if (strcmp(reason, "NOCARRIER_ROAMING") == 0) {
if_up = true_str;
if_down = false_str;
} else if (1 == 2 /* appease ifdefs */
#ifdef INET
|| (protocol == PROTO_DHCP && state && state->new)
#ifdef IPV4LL
|| (protocol == PROTO_IPV4LL && IPV4LL_STATE_RUNNING(ifp))
#endif
#endif
#ifdef INET6
|| (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp))
#ifdef DHCP6
|| (protocol == PROTO_DHCP6 && d6_state && d6_state->new)
#endif
|| (protocol == PROTO_RA && ipv6nd_hasra(ifp))
#endif
)
{
if_up = true_str;
if_down = false_str;
} else {
if_up = false_str;
if_down = true_str;
}
if (efprintf(fp, "if_up=%s", if_up) == -1)
goto eexit;
if (efprintf(fp, "if_down=%s", if_down) == -1)
goto eexit;
if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
if (efprintf(fp, "if_afwaiting=%d", af) == -1)
goto eexit;
}
if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) {
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX)
break;
}
}
if (af != AF_MAX) {
if (efprintf(fp, "af_waiting=%d", af) == -1)
goto eexit;
}
if (ifo->options & DHCPCD_DEBUG) {
if (efprintf(fp, "syslog_debug=true") == -1)
goto eexit;
}
#ifdef INET
if (protocol == PROTO_DHCP && state && state->old) {
if (dhcp_env(fp, "old", ifp,
state->old, state->old_len) == -1)
goto eexit;
if (append_config(fp, "old",
(const char *const *)ifo->config) == -1)
goto eexit;
}
#endif
#ifdef DHCP6
if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) {
if (dhcp6_env(fp, "old", ifp,
d6_state->old, d6_state->old_len) == -1)
goto eexit;
}
#endif
dumplease:
#ifdef INET
#ifdef IPV4LL
if (protocol == PROTO_IPV4LL && istate) {
if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1)
goto eexit;
}
#endif
if (protocol == PROTO_DHCP && state && state->new) {
if (dhcp_env(fp, "new", ifp,
state->new, state->new_len) == -1)
goto eexit;
if (append_config(fp, "new",
(const char *const *)ifo->config) == -1)
goto eexit;
}
#endif
#ifdef INET6
if (protocol == PROTO_STATIC6) {
if (ipv6_env(fp, "new", ifp) == -1)
goto eexit;
}
#ifdef DHCP6
if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) {
if (dhcp6_env(fp, "new", ifp,
d6_state->new, d6_state->new_len) == -1)
goto eexit;
}
#endif
if (protocol == PROTO_RA) {
if (ipv6nd_env(fp, ifp) == -1)
goto eexit;
}
#endif
/* Add our base environment */
if (ifo->environ) {
for (i = 0; ifo->environ[i] != NULL; i++)
if (efprintf(fp, "%s", ifo->environ[i]) == -1)
goto eexit;
}
/* Convert buffer to argv */
fflush(fp);
buf_pos = ftell(fp);
if (buf_pos == -1) {
logerr(__func__);
goto eexit;
}
#ifndef HAVE_OPEN_MEMSTREAM
size_t buf_len = (size_t)buf_pos;
if (ctx->script_buflen < buf_len) {
char *buf = realloc(ctx->script_buf, buf_len);
if (buf == NULL)
goto eexit;
ctx->script_buf = buf;
ctx->script_buflen = buf_len;
}
rewind(fp);
if (fread(ctx->script_buf, sizeof(char), buf_len, fp) != buf_len)
goto eexit;
fclose(fp);
fp = NULL;
#endif
if (is_stdin)
return buf_pos;
if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL)
goto eexit;
return buf_pos;
eexit:
logerr(__func__);
#ifndef HAVE_OPEN_MEMSTREAM
if (fp != NULL)
fclose(fp);
#endif
return -1;
}
static int
send_interface1(struct fd_list *fd, const struct interface *ifp,
const char *reason)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
long len;
len = make_env(ifp->ctx, ifp, reason);
if (len == -1)
return -1;
return control_queue(fd, ctx->script_buf, (size_t)len);
}
int
send_interface(struct fd_list *fd, const struct interface *ifp, int af)
{
int retval = 0;
#ifdef INET
const struct dhcp_state *d;
#endif
#ifdef DHCP6
const struct dhcp6_state *d6;
#endif
#ifndef AF_LINK
#define AF_LINK AF_PACKET
#endif
if (af == AF_UNSPEC || af == AF_LINK) {
const char *reason;
switch (ifp->carrier) {
case LINK_UP:
reason = "CARRIER";
break;
case LINK_DOWN:
reason = "NOCARRIER";
break;
default:
reason = "UNKNOWN";
break;
}
if (fd != NULL) {
if (send_interface1(fd, ifp, reason) == -1)
retval = -1;
} else
retval++;
}
#ifdef INET
if (af == AF_UNSPEC || af == AF_INET) {
if (D_STATE_RUNNING(ifp)) {
d = D_CSTATE(ifp);
if (fd != NULL) {
if (send_interface1(fd, ifp, d->reason) == -1)
retval = -1;
} else
retval++;
}
#ifdef IPV4LL
if (IPV4LL_STATE_RUNNING(ifp)) {
if (fd != NULL) {
if (send_interface1(fd, ifp, "IPV4LL") == -1)
retval = -1;
} else
retval++;
}
#endif
}
#endif
#ifdef INET6
if (af == AF_UNSPEC || af == AF_INET6) {
if (IPV6_STATE_RUNNING(ifp)) {
if (fd != NULL) {
if (send_interface1(fd, ifp, "STATIC6") == -1)
retval = -1;
} else
retval++;
}
if (RS_STATE_RUNNING(ifp)) {
if (fd != NULL) {
if (send_interface1(fd, ifp,
"ROUTERADVERT") == -1)
retval = -1;
} else
retval++;
}
#ifdef DHCP6
if (D6_STATE_RUNNING(ifp)) {
d6 = D6_CSTATE(ifp);
if (fd != NULL) {
if (send_interface1(fd, ifp, d6->reason) == -1)
retval = -1;
} else
retval++;
}
#endif
}
#endif
return retval;
}
static int
script_status(const char *script, int status)
{
if (WIFEXITED(status)) {
if (WEXITSTATUS(status))
logerrx("%s: %s: WEXITSTATUS %d",
__func__, script, WEXITSTATUS(status));
} else if (WIFSIGNALED(status))
logerrx("%s: %s: %s",
__func__, script, strsignal(WTERMSIG(status)));
return WEXITSTATUS(status);
}
static int
script_run(struct dhcpcd_ctx *ctx, char **argv)
{
pid_t pid;
int status;
pid = script_exec(argv, ctx->script_env);
if (pid == -1) {
logerr("%s: %s", __func__, argv[0]);
return -1;
} else if (pid == 0)
return 0;
/* Wait for the script to finish */
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
logerr("%s: waitpid", __func__);
status = 0;
break;
}
}
return script_status(argv[0], status);
}
int
script_dump(const char *env, size_t len)
{
const char *ep = env + len;
if (len == 0)
return 0;
if (*(ep - 1) != '\0') {
errno = EINVAL;
return -1;
}
for (; env < ep; env += strlen(env) + 1) {
if (strncmp(env, "new_", 4) == 0)
env += 4;
printf("%s\n", env);
}
return 0;
}
int
script_runreason(const struct interface *ifp, const char *reason)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
char *argv[2];
int status = 0;
struct fd_list *fd;
long buflen;
if (ctx->script == NULL &&
TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
return 0;
/* Make our env */
if ((buflen = make_env(ifp->ctx, ifp, reason)) == -1) {
logerr(__func__);
return -1;
}
if (strncmp(reason, "DUMP", 4) == 0)
return script_dump(ctx->script_buf, (size_t)buflen);
if (ctx->script == NULL)
goto send_listeners;
argv[0] = ctx->script;
argv[1] = NULL;
logdebugx("%s: executing: %s %s", ifp->name, argv[0], reason);
#ifdef PRIVSEP
if (IN_PRIVSEP(ctx)) {
ssize_t err;
err = ps_root_script(ctx, ctx->script_buf, (size_t)buflen);
if (err == -1)
logerr(__func__);
else
script_status(ctx->script, (int)err);
goto send_listeners;
}
#endif
script_run(ctx, argv);
send_listeners:
/* Send to our listeners */
status = 0;
TAILQ_FOREACH(fd, &ctx->control_fds, next) {
if (!(fd->flags & FD_LISTEN))
continue;
if (control_queue(fd, ctx->script_buf, ctx->script_buflen)== -1)
logerr("%s: control_queue", __func__);
else
status = 1;
}
return status;
}

41
external/bsd/dhcpcd/dist/src/script.h vendored Normal file
View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
* 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.
*/
#ifndef SCRIPT_H
#define SCRIPT_H
#include "control.h"
__printflike(2, 3) int efprintf(FILE *, const char *, ...);
void if_printoptions(void);
char ** script_buftoenv(struct dhcpcd_ctx *, char *, size_t);
pid_t script_exec(char *const *, char *const *);
int send_interface(struct fd_list *, const struct interface *, int);
int script_dump(const char *, size_t);
int script_runreason(const struct interface *, const char *);
#endif

23
external/bsd/openresolv/dist/LICENSE vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2007-2020 Roy Marples <roy@marples.name>
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.

68
external/bsd/openresolv/dist/README.md vendored Normal file
View File

@ -0,0 +1,68 @@
# openresolv
openresolv is a [resolvconf](https://en.wikipedia.org/wiki/Resolvconf)
implementation which manages `/etc/resolv.conf`.
`/etc/resolv.conf` is a file that holds the configuration for the local
resolution of domain names.
Normally this file is either static or maintained by a local daemon,
normally a DHCP daemon. But what happens if more than one thing wants to
control the file?
Say you have wired and wireless interfaces to different subnets and run a VPN
or two on top of that, how do you say which one controls the file?
It's also not as easy as just adding and removing the nameservers each client
knows about as different clients could add the same nameservers.
Enter resolvconf, the middleman between the network configuration services and
`/etc/resolv.conf`.
resolvconf itself is just a script that stores, removes and lists a full
`resolv.conf` generated for the interface. It then calls all the helper scripts
it knows about so it can configure the real `/etc/resolv.conf` and optionally
any local nameservers other than libc.
## Reasons for using openresolv
Why openresolv over the
[Debian implementation](http://qref.sourceforge.net/Debian/reference/ch-gateway.en.html#s-dns-resolvconf)?
Here's some reasons:
* Works with
[POSIX shell and userland](http://www.opengroup.org/onlinepubs/009695399)
* Does not need awk, grep or sed which means we can work without `/usr`
mounted
* Works with other init systems than Debians' out of the box
* Available as a 2 clause
[BSD license](http://www.freebsd.org/copyright/freebsd-license.html)
* Prefer configs via IF_METRIC for dynamic ordering
* Configures zones for local resolvers other than libc
The last point is quite important, especially when running VPN systems.
Take the following resolv.conf files which have been generated by a
[DHCP client](https://github.com/NetworkConfiguration/dhcpcd) and sent to resolvconf:
```
# resolv.conf from bge0
search foo.com
nameserver 1.2.3.4
# resolv.conf from tap0
domain bar.org
nameserver 5.6.7.8
```
In this instance, queries for foo.com will go to 1.2.3.4 and queries for
bar.org will go to 5.6.7.8.
This does require the resolvers to be configured to pickup the resolvconf
generated configuration for them though.
openresolv ships with helpers for:
* [unbound](http://www.unbound.net/)
* [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html)
* [ISC BIND](http://www.isc.org/software/bind)
* [PowerDNS Recursor](http://wiki.powerdns.com/trac)
See the
[configuration section](https://roy.marples.name/projects/openresolv/configuration)
for more details.
If openresolv updates `/etc/resolv.conf` it can notify the following of this:
* [Bonjour (mdnsd)](https://developer.apple.com/bonjour/)
* [avahi](http://www.avahi.org/)

View File

@ -0,0 +1,32 @@
#!/bin/sh
# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# avahi-daemon notifier for resolvconf libc subscriber
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
: ${avahi_daemon_pidfile:=/var/run/avahi-daemon/pid}
if [ -s "$avahi_daemon_pidfile" ]; then
kill -HUP $(cat "$avahi_daemon_pidfile")
fi

211
external/bsd/openresolv/dist/dnsmasq.in vendored Normal file
View File

@ -0,0 +1,211 @@
#!/bin/sh
# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# dnsmasq subscriber for resolvconf
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
[ -z "${dnsmasq_conf}${dnsmasq_resolv}" ] && exit 0
[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
NL="
"
: ${dnsmasq_pid:=/var/run/dnsmasq.pid}
[ -s "$dnsmasq_pid" ] || dnsmasq_pid=/var/run/dnsmasq/dnsmasq.pid
[ -s "$dnsmasq_pid" ] || unset dnsmasq_pid
: ${dnsmasq_service:=dnsmasq}
newconf="# Generated by resolvconf$NL"
newresolv="$newconf"
# Using dbus means that we never have to restart the daemon
# This is important as it means we should not drop DNS queries
# whilst changing DNS options around. However, dbus support is optional
# so we need to validate a few things first.
# Check for DBus support in the binary
dbus=false
dbus_ex=false
dbus_introspect=$(dbus-send --print-reply --system \
--dest=uk.org.thekelleys.dnsmasq \
/uk/org/thekelleys/dnsmasq \
org.freedesktop.DBus.Introspectable.Introspect \
2>/dev/null)
if [ $? = 0 ]; then
dbus=true
if printf %s "$dbus_introspect" | \
grep -q '<method name="SetDomainServers">'
then
dbus_ex=true
fi
fi
for n in $NAMESERVERS; do
newresolv="${newresolv}nameserver $n$NL"
done
dbusdest=
dbusdest_ex=
conf=
for d in $DOMAINS; do
dn="${d%%:*}"
ns="${d#*:}"
while [ -n "$ns" ]; do
n="${ns%%,*}"
if $dbus && ! $dbus_ex; then
case "$n" in
*.*.*.*)
SIFS=${IFS-y} OIFS=$IFS
IFS=.
set -- $n
num="0x$(printf %02x $1 $2 $3 $4)"
if [ "$SIFS" = y ]; then
unset IFS
else
IFS=$OIFS
fi
dbusdest="$dbusdest uint32:$(printf %u $num)"
dbusdest="$dbusdest string:$dn"
;;
*:*%*)
# This version of dnsmasq won't accept
# scoped IPv6 addresses
dbus=false
;;
*:*)
SIFS=${IFS-y} OIFS=$IFS bytes= front= back=
empty=false i=0
IFS=:
set -- $n
while [ -n "$1" ] || [ -n "$2" ]; do
addr="$1"
shift
if [ -z "$addr" ]; then
empty=true
continue
fi
i=$((i + 1))
while [ ${#addr} -lt 4 ]; do
addr="0${addr}"
done
byte1="$(printf %d 0x${addr%??})"
byte2="$(printf %d 0x${addr#??})"
if $empty; then
back="$back byte:$byte1 byte:$byte2"
else
front="$front byte:$byte1 byte:$byte2"
fi
done
while [ $i != 8 ]; do
i=$((i + 1))
front="$front byte:0 byte:0"
done
front="${front}$back"
if [ "$SIFS" = y ]; then
unset IFS
else
IFS=$OIFS
fi
dbusdest="${dbusdest}$front string:$dn"
;;
*)
if ! $dbus_ex; then
dbus=false
fi
;;
esac
fi
dbusdest_ex="$dbusdest_ex${dbusdest_ex:+,}/$dn/$n"
conf="${conf}server=/$dn/$n$NL"
[ "$ns" = "${ns#*,}" ] && break
ns="${ns#*,}"
done
done
if $dbus; then
newconf="$newconf$NL# Domain specific servers will"
newconf="$newconf be sent over dbus${NL}"
else
newconf="$newconf$conf"
fi
# Try to ensure that config dirs exist
if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$dnsmasq_conf" "$dnsmasq_resolv"
else
@SBINDIR@/resolvconf -D "$dnsmasq_conf" "$dnsmasq_resolv"
fi
changed=false
if [ -n "$dnsmasq_conf" ]; then
if [ ! -f "$dnsmasq_conf" ] || \
[ "$(cat "$dnsmasq_conf")" != "$(printf %s "$newconf")" ]
then
changed=true
printf %s "$newconf" >"$dnsmasq_conf"
fi
fi
if [ -n "$dnsmasq_resolv" ]; then
# dnsmasq polls this file so no need to set changed=true
if [ -f "$dnsmasq_resolv" ]; then
if [ "$(cat "$dnsmasq_resolv")" != "$(printf %s "$newresolv")" ]
then
printf %s "$newresolv" >"$dnsmasq_resolv"
fi
else
printf %s "$newresolv" >"$dnsmasq_resolv"
fi
fi
if $changed; then
# dnsmasq does not re-read the configuration file on SIGHUP
if [ -n "$dnsmasq_restart" ]; then
eval $dnsmasq_restart
elif [ -n "$RESTARTCMD" ]; then
set -- ${dnsmasq_service}
eval "$RESTARTCMD"
else
@SBINDIR@/resolvconf -r ${dnsmasq_service}
fi
fi
if $dbus; then
if [ -s "$dnsmasq_pid" ]; then
$changed || kill -HUP $(cat "$dnsmasq_pid")
fi
# Send even if empty so old servers are cleared
if $dbus_ex; then
method=SetDomainServers
if [ -n "$dbusdest_ex" ]; then
dbusdest_ex="array:string:$dbusdest_ex"
fi
dbusdest="$dbusdest_ex"
else
method=SetServers
fi
dbus-send --system --dest=uk.org.thekelleys.dnsmasq \
/uk/org/thekelleys/dnsmasq uk.org.thekelleys.$method \
$dbusdest
dbus-send --system --dest=uk.org.thekelleys.dnsmasq \
/uk/org/thekelleys/dnsmasq uk.org.thekelleys.ClearCache
fi

271
external/bsd/openresolv/dist/libc.in vendored Normal file
View File

@ -0,0 +1,271 @@
#!/bin/sh
# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# libc subscriber for resolvconf
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
SYSCONFDIR=@SYSCONFDIR@
LIBEXECDIR=@LIBEXECDIR@
VARDIR=@VARDIR@
IFACEDIR="$VARDIR/interfaces"
NL="
"
# sed may not be available, and this is faster on small files
key_get_value()
{
key="$1"
shift
if [ $# -eq 0 ]; then
while read -r line; do
case "$line" in
"$key"*) echo "${line##$key}";;
esac
done
else
for x do
while read -r line; do
case "$line" in
"$key"*) echo "${line##$key}";;
esac
done < "$x"
done
fi
}
keys_remove()
{
while read -r line; do
found=false
for key do
case "$line" in
"$key"*|"#"*|" "*|" "*|"") found=true;;
esac
$found && break
done
$found || echo "$line"
done
}
local_nameservers="127.* 0.0.0.0 255.255.255.255 ::1"
# Support original resolvconf configuration layout
# as well as the openresolv config file
if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
. "$SYSCONFDIR"/resolvconf.conf
elif [ -d "$SYSCONFDIR"/resolvconf ]; then
SYSCONFDIR="$SYSCONFDIR/resolvconf"
base="$SYSCONFDIR/resolv.conf.d/base"
if [ -f "$base" ]; then
prepend_nameservers="$(key_get_value "nameserver " "$base")"
domain="$(key_get_value "domain " "$base")"
prepend_search="$(key_get_value "search " "$base")"
resolv_conf_options="$(key_get_value "options " "$base")"
resolv_conf_sortlist="$(key_get_value "sortlist " "$base")"
fi
if [ -f "$SYSCONFDIR"/resolv.conf.d/head ]; then
resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.d/head)"
fi
if [ -f "$SYSCONFDIR"/resolv.conf.d/tail ]; then
resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.d/tail)"
fi
fi
: ${resolv_conf:=/etc/resolv.conf}
: ${resolv_conf_tmp:="$resolv_conf.$$.openresolv"}
: ${libc_service:=nscd}
: ${list_resolv:=@SBINDIR@/resolvconf -l}
if [ "${resolv_conf_head-x}" = x ] && [ -f "$SYSCONFDIR"/resolv.conf.head ]
then
resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.head)"
fi
if [ "${resolv_conf_tail-x}" = x ] && [ -f "$SYSCONFDIR"/resolv.conf.tail ]
then
resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.tail)"
fi
backup=true
signature="# Generated by resolvconf"
uniqify()
{
result=
while [ -n "$1" ]; do
case " $result " in
*" $1 "*);;
*) result="$result $1";;
esac
shift
done
echo "${result# *}"
}
case "${resolv_conf_passthrough:-NO}" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
backup=false
newest=
for conf in "$IFACEDIR"/*; do
if [ -z "$newest" ] || [ "$conf" -nt "$newest" ]; then
newest="$conf"
fi
done
[ -z "$newest" ] && exit 0
newconf="$(cat "$newest")$NL"
;;
/dev/null|[Nn][Uu][Ll][Ll])
: ${resolv_conf_local_only:=NO}
if [ "$local_nameservers" = "127.* 0.0.0.0 255.255.255.255 ::1" ]; then
local_nameservers=
fi
# Need to overwrite our variables.
eval "$(@SBINDIR@/resolvconf -V)"
;;
*)
[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
;;
esac
case "${resolv_conf_passthrough:-NO}" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
*)
: ${domain:=$DOMAIN}
newsearch="$(uniqify $prepend_search $SEARCH $append_search)"
NS="$LOCALNAMESERVERS $NAMESERVERS"
newns=
gotlocal=false
for n in $(uniqify $prepend_nameservers $NS $append_nameservers); do
add=true
islocal=false
for l in $local_nameservers; do
case "$n" in
$l) islocal=true; gotlocal=true; break;;
esac
done
if ! $islocal; then
case "${resolv_conf_local_only:-YES}" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
$gotlocal && add=false;;
esac
fi
$add && newns="$newns $n"
done
# Hold our new resolv.conf in a variable to save on temporary files
newconf="$signature$NL"
if [ -n "$resolv_conf_head" ]; then
newconf="$newconf$resolv_conf_head$NL"
fi
[ -n "$domain" ] && newconf="${newconf}domain $domain$NL"
if [ -n "$newsearch" ] && [ "$newsearch" != "$domain" ]; then
newconf="${newconf}search $newsearch$NL"
fi
for n in $newns; do
newconf="${newconf}nameserver $n$NL"
done
# Now add anything we don't care about such as sortlist and options
stuff="$($list_resolv | keys_remove nameserver domain search)"
if [ -n "$stuff" ]; then
newconf="$newconf$stuff$NL"
fi
# Append any user defined ones
if [ -n "$resolv_conf_options" ]; then
newconf="${newconf}options $resolv_conf_options$NL"
fi
if [ -n "$resolv_conf_sortlist" ]; then
newconf="${newconf}sortlist $resolv_conf_sortlist$NL"
fi
if [ -n "$resolv_conf_tail" ]; then
newconf="$newconf$resolv_conf_tail$NL"
fi
;;
esac
# Check if the file has actually changed or not
if [ -e "$resolv_conf" ]; then
[ "$(cat "$resolv_conf")" = "$(printf %s "$newconf")" ] && exit 0
fi
# Change is good.
# If the old file does not have our signature, back it up.
# If the new file just has our signature, restore the backup.
if $backup; then
if [ "$newconf" = "$signature$NL" ]; then
if [ -e "$resolv_conf.bak" ]; then
newconf="$(cat "$resolv_conf.bak")$NL"
fi
elif [ -e "$resolv_conf" ]; then
read line <"$resolv_conf"
if [ "$line" != "$signature" ]; then
cp "$resolv_conf" "$resolv_conf.bak"
fi
fi
fi
# There are pros and cons for writing directly to resolv.conf
# instead of a temporary file and then moving it over.
# The default is to write to resolv.conf as it has the least
# issues and has been the long standing default behaviour.
case "${resolv_conf_mv:-NO}" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
# Protect against symlink attack, ensure new file does not exist
rm -f "$resolv_conf_tmp"
# Keep original file owner, group and mode
[ -r "$resolv_conf" ] && cp -p "$resolv_conf" "$resolv_conf_tmp"
# Create our resolv.conf now
if (umask 022; printf %s "$newconf" >"$resolv_conf_tmp"); then
mv "$resolv_conf_tmp" "$resolv_conf"
fi
;;
*)
(umask 022; printf %s "$newconf" >"$resolv_conf")
;;
esac
if [ -n "$libc_restart" ]; then
eval $libc_restart
elif [ -n "$RESTARTCMD" ]; then
set -- ${libc_service}
eval "$RESTARTCMD"
else
@SBINDIR@/resolvconf -r ${libc_service}
fi
retval=0
# Notify users of the resolver
for script in "$LIBEXECDIR"/libc.d/*; do
if [ -f "$script" ]; then
if [ -x "$script" ]; then
"$script" "$@"
else
(. "$script")
fi
retval=$(($retval + $?))
fi
done
exit $retval

32
external/bsd/openresolv/dist/mdnsd.in vendored Normal file
View File

@ -0,0 +1,32 @@
#!/bin/sh
# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# mdnsd notifier for resolvconf libc subscriber
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
: ${mdnsd_pidfile:=/var/run/mdnsd/mdnsd.pid}
if [ -s "$mdnsd_pidfile" ]; then
kill -HUP $(cat "$mdnsd_pidfile")
fi

118
external/bsd/openresolv/dist/named.in vendored Normal file
View File

@ -0,0 +1,118 @@
#!/bin/sh
# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# named subscriber for resolvconf
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
[ -z "${named_zones}${named_options}" ] && exit 0
[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
NL="
"
# Platform specific kludges
if [ -z "${named_service}${named_restart}" ] &&
[ -d "$RCDIR" ] && ! [ -x "$RCDIR"/named ]
then
if [ -x "$RCDIR"/bind9 ]; then
# Debian and derivatives
named_service=bind9
elif [ -x "$RCDIR"/rc.bind ]; then
# Slackware
named_service=rc.bind
fi
fi
: ${named_service:=named}
: ${named_pid:=/var/run/$named_service.pid}
[ -s "$named_pid" ] || named_pid=/var/run/$named_service/$named_service.pid
[ -s "$named_pid" ] || unset named_pid
newoptions="# Generated by resolvconf$NL"
newzones="$newoptions"
forward=
for n in $NAMESERVERS; do
case "$forward" in
*"$NL $n;"*);;
*) forward="$forward$NL $n;";;
esac
done
if [ -n "$forward" ]; then
newoptions="${newoptions}forward first;${NL}forwarders {$forward${NL}};$NL"
fi
for d in $DOMAINS; do
newzones="${newzones}zone \"${d%%:*}\" {$NL"
newzones="$newzones type forward;$NL"
newzones="$newzones forward first;$NL forwarders {$NL"
ns="${d#*:}"
while [ -n "$ns" ]; do
newzones="$newzones ${ns%%,*};$NL"
[ "$ns" = "${ns#*,}" ] && break
ns="${ns#*,}"
done
newzones="$newzones };$NL};$NL"
done
# Try to ensure that config dirs exist
if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$named_options" "$named_zones"
else
@SBINDIR@/resolvconf -D "$named_options" "$named_zones"
fi
# No point in changing files or reloading bind if the end result has not
# changed
changed=false
if [ -n "$named_options" ]; then
if [ ! -f "$named_options" ] || \
[ "$(cat "$named_options")" != "$(printf %s "$newoptions")" ]
then
printf %s "$newoptions" >"$named_options"
changed=true
fi
fi
if [ -n "$named_zones" ]; then
if [ ! -f "$named_zones" ] || \
[ "$(cat "$named_zones")" != "$(printf %s "$newzones")" ]
then
printf %s "$newzones" >"$named_zones"
changed=true
fi
fi
# named does not seem to work with SIGHUP which is a same
if $changed; then
if [ -n "$named_restart" ]; then
eval $named_restart
elif [ -n "$RESTARTCMD" ]; then
set -- ${named_service}
eval "$RESTARTCMD"
else
@SBINDIR@/resolvconf -r ${named_service}
fi
fi

View File

@ -0,0 +1,75 @@
#!/bin/sh
# Copyright (c) 2009-2023 Roy Marples
# All rights reserved
# PowerDNS Recursor subscriber for resolvconf
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
[ -z "$pdns_zones" ] && exit 0
[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
NL="
"
: ${pdns_service:=pdns-recursor}
newzones=
for n in $NAMESERVERS; do
newzones="$newzones${newzones:+,}$n"
done
[ -n "$newzones" ] && newzones="+.=$newzones$NL"
for d in $DOMAINS; do
newns=
ns="${d#*:}"
while [ -n "$ns" ]; do
newns="$newns${newns:+,}${ns%%,*}"
[ "$ns" = "${ns#*,}" ] && break
ns="${ns#*,}"
done
[ -n "$newns" ] && newzones="$newzones${d%%:*}=$newns$NL"
done
# Try to ensure that config dirs exist
if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$pdnsd_zones"
else
@SBINDIR@/resolvconf -D "$pdnsd_zones"
fi
if [ ! -f "$pdns_zones" ] || \
[ "$(cat "$pdns_zones")" != "$(printf %s "$newzones")" ]
then
printf %s "$newzones" >"$pdns_zones"
if [ -n "$pdns_restart" ]; then
eval $pdns_restart
elif [ -n "$RESTARTCMD" ]; then
set -- ${pdns_service}
eval "$RESTARTCMD"
else
@SBINDIR@/resolvconf -r ${pdns_service}
fi
fi

165
external/bsd/openresolv/dist/pdnsd.in vendored Normal file
View File

@ -0,0 +1,165 @@
#!/bin/sh
# Copyright (c) 2010-2023 Roy Marples
# All rights reserved
# pdnsd subscriber for resolvconf
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
[ -z "${pdnsd_conf}${pdnsd_resolv}" ] && exit 0
[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
NL="
"
: ${pdnsd_restart:=pdnsd-ctl config $pdnsd_conf}
signature="# Generated by resolvconf"
signature_end="# End of resolvconf"
# We normally use sed to remove markers from a configuration file
# but sed may not always be available at the time.
remove_markers()
{
m1="$1"
m2="$2"
in_marker=0
shift; shift
if command -v sed >/dev/null 2>&1; then
sed "/^$m1/,/^$m2/d" $@
else
for x do
while read line; do
case "$line" in
"$m1"*) in_marker=1;;
"$m2"*) in_marker=0;;
*) [ $in_marker = 0 ] && echo "$line";;
esac
done < "$x"
done
fi
}
# Compare two files
# If different, replace first with second otherwise remove second
change_file()
{
if [ -e "$1" ]; then
if command -v cmp >/dev/null 2>&1; then
cmp -s "$1" "$2"
elif command -v diff >/dev/null 2>&1; then
diff -q "$1" "$2" >/dev/null
else
# Hopefully we're only working on small text files ...
[ "$(cat "$1")" = "$(cat "$2")" ]
fi
if [ $? -eq 0 ]; then
rm -f "$2"
return 1
fi
fi
cat "$2" > "$1"
rm -f "$2"
return 0
}
newresolv="# Generated by resolvconf$NL"
changed=false
# Try to ensure that config dirs exist
if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$pdnsd_resolv" "$pdnsd_conf"
else
@SBINDIR@/resolvconf -D "$pdnsd_resolv" "$pdnsd_conf"
fi
if [ -n "$pdnsd_resolv" ]; then
for n in $NAMESERVERS; do
newresolv="${newresolv}nameserver $n$NL"
done
fi
# Only modify the configuration if it exists and we can write to it
if [ -w "$pdnsd_conf" ]; then
cf="$pdnsd_conf.new"
newconf=
if [ -z "$pdnsd_resolv" ]; then
newconf="${newconf}server {$NL"
newconf="${newconf} label=resolvconf;$NL"
if [ -n "$NAMESERVERS" ]; then
newconf="${newconf} ip="
first=true
for n in $NAMESERVERS; do
if $first; then
first=false
else
newconf="${newconf},"
fi
newconf="$newconf$n"
done
newconf="${newconf};$NL"
fi
newconf="${newconf}}$NL"
fi
for d in $DOMAINS; do
newconf="${newconf}server {$NL"
newconf="${newconf} include=.${d%%:*}.;$NL"
newconf="${newconf} policy=excluded;$NL"
newconf="${newconf} ip="
ns="${d#*:}"
while [ -n "$ns" ]; do
newconf="${newconf}${ns%%,*}"
[ "$ns" = "${ns#*,}" ] && break
ns="${ns#*,}"
newconf="${newconf},"
done
newconf="${newconf};$NL}$NL"
done
rm -f "$cf"
remove_markers "$signature" "$signature_end" "$pdnsd_conf" > "$cf"
if [ -n "$newconf" ]; then
echo "$signature" >> "$cf"
printf %s "$newconf" >> "$cf"
echo "$signature_end" >> "$cf"
fi
if change_file "$pdnsd_conf" "$cf"; then
changed=true
fi
fi
if [ -n "$pdnsd_resolv" ]; then
if [ ! -f "$pdnsd_resolv" ] || \
[ "$(cat "$pdnsd_resolv")" != "$(printf %s "$newresolv")" ]
then
changed=true
printf %s "$newresolv" >"$pdnsd_resolv"
fi
fi
if $changed; then
eval $pdnsd_restart
fi

View File

@ -0,0 +1,336 @@
.\" Copyright (c) 2007-2023 Roy Marples
.\" 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.
.\"
.Dd December 23, 2016
.Dt RESOLVCONF 8
.Os
.Sh NAME
.Nm resolvconf
.Nd a framework for managing multiple DNS configurations
.Sh SYNOPSIS
.Nm
.Fl I
.Nm
.Op Fl m Ar metric
.Op Fl p
.Op Fl x
.Fl a Ar interface Ns Op Ar .protocol
.No < Ns Pa file
.Nm
.Fl C Ar pattern
.Nm
.Fl c Ar pattern
.Nm
.Op Fl f
.Fl d Ar interface Ns Op Ar .protocol
.Nm
.Op Fl x
.Fl il Ar pattern
.Nm
.Fl u
.Nm
.Fl Fl version
.Sh DESCRIPTION
.Nm
manages
.Xr resolv.conf 5
files from multiple sources, such as DHCP and VPN clients.
Traditionally, the host runs just one client and that updates
.Pa /etc/resolv.conf .
More modern systems frequently have wired and wireless interfaces and there is
no guarantee both are on the same network.
With the advent of VPN and other
types of networking daemons, many things now contend for the contents of
.Pa /etc/resolv.conf .
.Pp
.Nm
solves this by letting the daemon send their
.Xr resolv.conf 5
file to
.Nm
via
.Xr stdin 4
with the argument
.Fl a Ar interface Ns Op Ar .protocol
instead of the filesystem.
.Nm
then updates
.Pa /etc/resolv.conf
as it thinks best.
When a local resolver other than libc is installed, such as
.Xr dnsmasq 8
or
.Xr named 8 ,
then
.Nm
will supply files that the resolver should be configured to include.
.Pp
.Nm
assumes it has a job to do.
In some situations
.Nm
needs to act as a deterrent to writing to
.Pa /etc/resolv.conf .
Where this file cannot be made immutable or you just need to toggle this
behaviour,
.Nm
can be disabled by adding
.Sy resolvconf Ns = Ns NO
to
.Xr resolvconf.conf 5 .
.Pp
.Nm
can mark an interfaces
.Pa resolv.conf
as private.
This means that the name servers listed in that
.Pa resolv.conf
are only used for queries against the domain/search listed in the same file.
This only works when a local resolver other than libc is installed.
See
.Xr resolvconf.conf 5
for how to configure
.Nm
to use a local name server and how to remove the private marking.
.Pp
.Nm
can mark an interfaces
.Pa resolv.conf
as exclusive.
Only the latest exclusive interface is used for processing, otherwise all are.
.Pp
When an interface goes down, it should then call
.Nm
with
.Fl d Ar interface.*
arguments to delete the
.Pa resolv.conf
file(s) for all the
.Ar protocols
on the
.Ar interface .
For systems that support the concept of persisting configuration when
the carrier goes down, then it should instead call
.Nm
with
.Fl C Ar interface.*
arguments to deprecate the matching interfaces and
.Fl c Ar interface.*
to activate the matching interfaces when the carrier comes up.
This only affects the order in which interfaces are processed.
.Pp
Here are some options for the above commands:-
.Bl -tag -width pattern_opt
.It Fl f
Ignore non existent interfaces.
Only really useful for deleting interfaces.
.It Fl m Ar metric
Set the metric of the interface when adding it, default of 0.
Lower metrics take precedence.
This affects the default order of interfaces when listed.
.It Fl p
Marks the interface
.Pa resolv.conf
as private.
.It Fl x
Mark the interface
.Pa resolv.conf
as exclusive when adding, otherwise only use the latest exclusive interface.
.El
.Pp
.Nm
has some more commands for general usage:-
.Bl -tag -width pattern_opt
.It Fl i Ar pattern
List the interfaces and protocols, optionally matching
.Ar pattern ,
we have
.Pa resolv.conf
files for.
.It Fl l Ar pattern
List the
.Pa resolv.conf
files we have.
If
.Ar pattern
is specified then we list the files for the interfaces and protocols
that match it.
.It Fl u
Force
.Nm
to update all its subscribers.
.Nm
does not update the subscribers when adding a resolv.conf that matches
what it already has for that interface.
.It Fl Fl version
Echo the resolvconf version to
.Em stdout .
.El
.Pp
.Nm
also has some commands designed to be used by its subscribers and
system startup:-
.Bl -tag -width pattern_opt
.It Fl I
Initialise the state directory
.Pa @VARDIR@ .
This only needs to be called if the initial system boot sequence does not
automatically clean it out; for example the state directory is moved
somewhere other than
.Pa /var/run .
If used, it should only be called once as early in the system boot sequence
as possible and before
.Nm
is used to add interfaces.
.It Fl R
Echo the command used to restart a service.
.It Fl r Ar service
If the
.Ar service
is running then restart it.
If the service does not exist or is not running then zero is returned,
otherwise the result of restarting the service.
.It Fl v
Echo variables DOMAINS, SEARCH and NAMESERVERS so that the subscriber can
configure the resolver easily.
.It Fl V
Same as
.Fl v
except that only the information configured in
.Xr resolvconf.conf 5
is set.
.El
.Sh INTERFACE ORDERING
For
.Nm
to work effectively, it has to process the resolv.confs for the interfaces
in the correct order.
.Nm
first processes interfaces from the
.Sy interface_order
list, then interfaces without a metric and that match the
.Sy dynamic_order
list, then interfaces with a metric in order and finally the rest in
the operating systems lexical order.
See
.Xr resolvconf.conf 5
for details on these lists.
.Sh PROTOCOLS
Here are some suggested protocol tags to use for each
.Pa resolv.conf
file registered on an
.Ar interface Ns No :-
.Bl -tag -width pattern_opt
.It dhcp
Dynamic Host Configuration Protocol.
Initial versions of
.Nm
did not recommend a
.Ar protocol
tag be appended to the
.Ar interface
name.
When the protocol is absent, it is assumed to be the DHCP protocol.
.It ppp
Point-to-Point Protocol.
.It ra
IPv6 Router Advertisement.
.It dhcp6
Dynamic Host Configuration Protocol, version 6.
.El
.Sh IMPLEMENTATION NOTES
If a subscriber has the executable bit then it is executed otherwise it is
assumed to be a shell script and sourced into the current environment in a
subshell.
This is done so that subscribers can remain fast, but are also not limited
to the shell language.
.Pp
Portable subscribers should not use anything outside of
.Pa /bin
and
.Pa /sbin
because
.Pa /usr
and others may not be available when booting.
Also, it would be unwise to assume any shell specific features.
.Sh ENVIRONMENT
.Bl -ohang
.It Va IF_METRIC
If the
.Fl m
option is not present then we use
.Va IF_METRIC
for the metric.
.It Va IF_PRIVATE
Marks the interface
.Pa resolv.conf
as private.
.It Va IF_EXCLUSIVE
Marks the interface
.Pa resolv.conf
as exclusive.
.El
.Sh FILES
.Bl -ohang
.It Pa /etc/resolv.conf.bak
Backup file of the original resolv.conf.
.It Pa @SYSCONFDIR@/resolvconf.conf
Configuration file for
.Nm .
.It Pa @LIBEXECDIR@
Directory of subscribers which are run every time
.Nm
adds, deletes or updates.
.It Pa @LIBEXECDIR@/libc.d
Directory of subscribers which are run after the libc subscriber is run.
.It Pa @VARDIR@
State directory for
.Nm .
.El
.Sh SEE ALSO
.Xr resolver 3 ,
.Xr stdin 4 ,
.Xr resolv.conf 5 ,
.Xr resolvconf.conf 5
.Sh HISTORY
This implementation of
.Nm
is called openresolv and is fully command line compatible with Debian's
resolvconf, as written by Thomas Hood.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Please report them to
.Lk http://roy.marples.name/projects/openresolv
.Pp
.Nm
does not validate any of the files given to it.
.Pp
When running a local resolver other than libc, you will need to configure it
to include files that
.Nm
will generate.
You should consult
.Xr resolvconf.conf 5
for instructions on how to configure your resolver.

View File

@ -0,0 +1,7 @@
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details
resolv_conf=/etc/resolv.conf
# If you run a local name server, you should uncomment the below line and
# configure your subscribers configuration files below.
#name_servers=127.0.0.1

View File

@ -0,0 +1,397 @@
.\" Copyright (c) 2009-2023 Roy Marples
.\" 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.
.\"
.Dd May 23, 2023
.Dt RESOLVCONF.CONF 5
.Os
.Sh NAME
.Nm resolvconf.conf
.Nd resolvconf configuration file
.Sh DESCRIPTION
.Nm
is the configuration file for
.Xr resolvconf 8 .
The
.Nm
file is a shell script that is sourced by
.Xr resolvconf 8 ,
meaning that
.Nm
must contain valid shell commands.
Listed below are the standard
.Nm
variables that may be set.
If the values contain whitespace, wildcards or other special shell characters,
ensure they are quoted and escaped correctly.
See the
.Sy replace
variable for an example on quoting.
.Pp
After updating this file, you may wish to run
.Nm resolvconf -u
to apply the new configuration.
.Pp
When a dynamically generated list is appended or prepended to, the whole
is made unique where left-most wins.
.Sh RESOLVCONF OPTIONS
.Bl -tag -width indent
.It Sy resolvconf
Set to NO to disable
.Nm resolvconf
from running any subscribers.
Defaults to YES.
.It Sy allow_interfaces
If set, only these interfaces will be processed.
.It Sy deny_interfaces
If set, these interfaces will not be processed.
.It Sy interface_order
These interfaces will always be processed first.
If unset, defaults to the following:-
.Bd -compact -literal -offset indent
lo lo[0-9]*
.Ed
.It Sy dynamic_order
These interfaces will be processed next, unless they have a metric.
If unset, defaults to the following:-
.Bd -compact -literal -offset indent
tap[0-9]* tun[0-9]* vpn vpn[0-9]* wg[0-9]* ppp[0-9]* ippp[0-9]*
.Ed
.It Sy inclusive_interfaces
Ignore any exclusive marking for these interfaces.
This is handy when 3rd party integrations force the
.Nm resolvconf -x
option and you want to disable it easily.
.It Sy local_nameservers
If unset, defaults to the following:-
.Bd -compact -literal -offset indent
127.* 0.0.0.0 255.255.255.255 ::1
.Ed
.It Sy search_domains
Prepend search domains to the dynamically generated list.
.It Sy search_domains_append
Append search domains to the dynamically generated list.
.It Sy domain_blacklist
A list of domains to be removed from consideration.
To remove a domain, you can use foo.*
To remove a sub domain, you can use *.bar
.It Sy name_servers
Prepend name servers to the dynamically generated list.
You should set this to 127.0.0.1 if you use a local name server other than
libc.
.It Sy name_servers_append
Append name servers to the dynamically generated list.
.It Sy name_server_blacklist
A list of name servers to be removed from consideration.
The default is 0.0.0.0 as some faulty routers send it via DHCP.
To remove a block, you can use 192.168.*
.It Sy private_interfaces
These interfaces name servers will only be queried for the domains listed
in their resolv.conf.
Useful for VPN domains.
Setting
.Sy private_interfaces Ns ="*"
will stop the forwarding of the root zone and allows the local resolver to
recursively query the root servers directly.
Requires a local nameserver other than libc.
This is equivalent to the
.Nm resolvconf -p
option.
.It Sy public_interfaces
Force these interface to be public, overriding the private marking.
This is handy when 3rd party integrations force the
.Nm resolvconf -p
option and you want to disable it easily.
.It Sy replace
Is a space separated list of replacement keywords.
The syntax is this:
.Va $keyword Ns / Ns Va $match Ns / Ns Va $replacement
.Pp
Example, given this resolv.conf:
.Bd -compact -literal -offset indent
domain foo.org
search foo.org dead.beef
nameserver 1.2.3.4
nameserver 2.3.4.5
.Ed
and this configuration:
.Bd -compact -literal -offset indent
replace="search/foo*/bar.com"
replace="$replace nameserver/1.2.3.4/5.6.7.8"
replace="$replace nameserver/2.3.4.5/"
.Ed
you would get this resolv.conf instead:
.Bd -compact -literal -offset indent
domain foo.org
search bar.com
nameserver 5.6.7.8
.Ed
.It Sy replace_sub
Works the same way as
.Sy replace
except it works on each space separated value rather than the whole line,
so it's useful for the replacing a single domain within the search directive.
Using the same example resolv.conf and changing
.Sy replace
to
.Sy replace_sub ,
you would get this resolv.conf instead:
.Bd -compact -literal -offset indent
domain foo.org
search bar.com dead.beef
nameserver 5.6.7.8
.Ed
.It Sy state_dir
Override the default state directory of
.Pa @VARDIR@ .
This should not be changed once
.Nm resolvconf
is in use unless the old directory is copied to the new one.
.El
.Sh LIBC OPTIONS
The following variables affect
.Xr resolv.conf 5
directly:-
.Bl -tag -width indent
.It Sy resolv_conf
Defaults to
.Pa /etc/resolv.conf
if not set.
.It Sy resolv_conf_options
A list of libc resolver options, as specified in
.Xr resolv.conf 5 .
.It Sy resolv_conf_passthrough
When set to YES the latest resolv.conf is written to
.Sy resolv_conf
without any alteration.
When set to /dev/null or NULL,
.Sy resolv_conf_local_only
is defaulted to NO,
.Sy local_nameservers
is unset unless overridden and only the information set in
.Nm
is written to
.Sy resolv_conf .
.It Sy resolv_conf_sortlist
A libc resolver sortlist, as specified in
.Xr resolv.conf 5 .
.It Sy resolv_conf_local_only
If a local name server is configured then the default is just to specify that
and ignore all other entries as they will be configured for the local
name server.
Set this to NO to also list non-local nameservers.
This will give you working DNS even if the local nameserver stops functioning
at the expense of duplicated server queries.
.It Sy append_nameservers
Append name servers to the dynamically generated list.
.It Sy prepend_nameservers
Prepend name servers to the dynamically generated list.
.It Sy append_search
Append search domains to the dynamically generated list.
.It Sy prepend_search
Prepend search domains to the dynamically generated list.
.It Sy resolv_conf_mv
Defaults to NO.
Defines if
.Pa /etc/resolv.conf
is updated by writing to a temporary file and then moving it
vs writing directly to it.
.El
.Sh SUBSCRIBER OPTIONS
openresolv ships with subscribers for the name servers
.Xr dnsmasq 8 ,
.Xr named 8 ,
.Xr pdnsd 8 ,
.Xr pdns_recursor 1 ,
and
.Xr unbound 8 .
Each subscriber can create configuration files which should be included in
the subscribers main configuration file.
.Pp
To disable a subscriber, simply set its name to NO.
For example, to disable the libc subscriber you would set:
.Bd -compact -literal -offset indent
libc=NO
.Ed
.Bl -tag -width indent
.It Sy dnsmasq_conf
This file tells dnsmasq which name servers to use for specific domains.
.It Sy dnsmasq_resolv
This file tells dnsmasq which name servers to use for global lookups.
.Pp
Example resolvconf.conf for dnsmasq:
.Bd -compact -literal -offset indent
name_servers=127.0.0.1
dnsmasq_conf=/etc/dnsmasq-conf.conf
dnsmasq_resolv=/etc/dnsmasq-resolv.conf
.Ed
.Pp
Example dnsmasq.conf:
.Bd -compact -literal -offset indent
listen-address=127.0.0.1
# If dnsmasq is compiled for DBus then we can take
# advantage of not having to restart dnsmasq.
enable-dbus
conf-file=/etc/dnsmasq-conf.conf
resolv-file=/etc/dnsmasq-resolv.conf
.Ed
.It Sy named_options
Include this file in the named options block.
This file tells named which name servers to use for global lookups.
.It Sy named_zones
Include this file in the named global scope, after the options block.
This file tells named which name servers to use for specific domains.
.Pp
Example resolvconf.conf for named:
.Bd -compact -literal -offset indent
name_servers=127.0.0.1
named_options=/etc/named-options.conf
named_zones=/etc/named-zones.conf
.Ed
.Pp
Example named.conf:
.Bd -compact -literal -offset indent
options {
listen-on { 127.0.0.1; };
include "/etc/named-options.conf";
};
include "/etc/named-zones.conf";
.Ed
.It Sy pdnsd_conf
This is the main pdnsd configuration file which we modify to add our
forward domains to.
If this variable is not set then we rely on the pdnsd configuration file
setup to read
.Pa pdnsd_resolv
as documented below.
.It Sy pdnsd_resolv
This file tells pdnsd about global name servers.
If this variable is not set then it's written to
.Pa pdnsd_conf .
.Pp
Example resolvconf.conf for pdnsd:
.Bd -compact -literal -offset indent
name_servers=127.0.0.1
pdnsd_conf=/etc/pdnsd.conf
# pdnsd_resolv=/etc/pdnsd-resolv.conf
.Ed
.Pp
Example pdnsd.conf:
.Bd -compact -literal -offset indent
global {
server_ip = 127.0.0.1;
status_ctl = on;
}
server {
# A server definition is required, even if empty.
label="empty";
proxy_only=on;
# file="/etc/pdnsd-resolv.conf";
}
.Ed
.It Sy pdns_zones
This file tells pdns_recursor about specific and global name servers.
.Pp
Example resolvconf.conf for pdns_recursor:
.Bd -compact -literal -offset indent
name_servers=127.0.0.1
pdns_zones=/etc/pdns/recursor-zones.conf
.Ed
.Pp
Example recursor.conf:
.Bd -compact -literal -offset indent
allow-from=127.0.0.0/8, ::1/128
forward-zones-file=/etc/pdns/recursor-zones.conf
.Ed
.It Sy unbound_conf
This file tells unbound about specific and global name servers.
.It Sy unbound_insecure
When set to YES, unbound marks the domains as insecure, thus ignoring DNSSEC.
.It Sy unbound_forward_zone_options
Options appended to each forward zone.
Each option should be separated by an embedded new line.
.Pp
Example resolvconf.conf for unbound:
.Bd -compact -literal -offset indent
name_servers=127.0.0.1
unbound_conf=/etc/unbound-resolvconf.conf
.Ed
.Pp
Example unbound.conf:
.Bd -compact -literal -offset indent
include: /etc/unbound-resolvconf.conf
.Ed
.El
.Sh SUBSCRIBER INTEGRATION
Not all distributions store the files the subscribers need in the same
locations.
For example, named service scripts have been called named, bind and rc.bind
and they could be located in a directory called /etc/rc.d, /etc/init.d or
similar.
Each subscriber attempts to automatically configure itself, but not every
distribution has been catered for.
Also, users could equally want to use a different version from the one
installed by default, such as bind8 and bind9.
To accommodate this, the subscribers have these files in configurable
variables, documented below.
.Bl -tag -width indent
.It Sy dnsmasq_service
Name of the dnsmasq service.
.It Sy dnsmasq_restart
Command to restart the dnsmasq service.
.It Sy dnsmasq_pid
Location of the dnsmasq pidfile.
.It Sy libc_service
Name of the libc service.
.It Sy libc_restart
Command to restart the libc service.
.It Sy named_service
Name of the named service.
.It Sy named_restart
Command to restart the named service.
.It Sy pdnsd_restart
Command to restart the pdnsd service.
.It Sy pdns_service
Command to restart the pdns_recursor service.
.It Sy pdns_restart
Command to restart the pdns_recursor service.
.It Sy unbound_service
Name of the unbound service.
.It Sy unbound_restart
Command to restart the unbound service.
.It Sy unbound_pid
Location of the unbound pidfile.
.El
.Sh SEE ALSO
.Xr sh 1 ,
.Xr resolv.conf 5 ,
.Xr resolvconf 8
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Each distribution is a special snowflake and likes to name the same thing
differently, namely the named service script.
.Pp
Please report them to
.Lk https://roy.marples.name/projects/openresolv

1101
external/bsd/openresolv/dist/resolvconf.in vendored Normal file

File diff suppressed because it is too large Load Diff

103
external/bsd/openresolv/dist/unbound.in vendored Normal file
View File

@ -0,0 +1,103 @@
#!/bin/sh
# Copyright (c) 2009-2023 Roy Marples
# All rights reserved
# unbound subscriber for resolvconf
# 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.
#
# 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 COPYRIGHT
# OWNER 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.
unbound_insecure=
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
[ -z "$unbound_conf" ] && exit 0
[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
NL="
"
: ${unbound_pid:=/var/run/unbound.pid}
: ${unbound_service:=unbound}
newconf="# Generated by resolvconf$NL"
for d in $DOMAINS; do
dn="${d%%:*}"
ns="${d#*:}"
case "$unbound_insecure" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
newconf="$newconf${NL}server:$NL"
newconf="$newconf domain-insecure: \"$dn\"$NL"
;;
esac
newconf="$newconf${NL}forward-zone:$NL name: \"$dn\"$NL"
if [ -n "$unbound_forward_zone_options" ]; then
newconf="$newconf $unbound_forward_zone_options${NL}"
fi
while [ -n "$ns" ]; do
newconf="$newconf forward-addr: ${ns%%,*}$NL"
[ "$ns" = "${ns#*,}" ] && break
ns="${ns#*,}"
done
done
if [ -n "$NAMESERVERS" ]; then
newconf="$newconf${NL}forward-zone:$NL name: \".\"$NL"
if [ -n "$unbound_forward_zone_options" ]; then
newconf="$newconf $unbound_forward_zone_options${NL}"
fi
for n in $NAMESERVERS; do
newconf="$newconf forward-addr: $n$NL"
done
fi
# Try to ensure that config dirs exist
if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$unbound_conf"
else
@SBINDIR@/resolvconf -D "$unbound_conf"
fi
restart_unbound()
{
if [ -n "$unbound_restart" ]; then
eval $unbound_restart
elif [ -n "$RESTARTCMD" ]; then
set -- ${unbound_service}
eval "$RESTARTCMD"
else
@SBINDIR@/resolvconf -r ${unbound_service}
fi
}
if [ ! -f "$unbound_conf" ] || \
[ "$(cat "$unbound_conf")" != "$(printf %s "$newconf")" ]
then
printf %s "$newconf" >"$unbound_conf"
# If we can't sent a HUP then force a restart
if [ -s "$unbound_pid" ]; then
if ! kill -HUP $(cat "$unbound_pid") 2>/dev/null; then
restart_unbound
fi
else
restart_unbound
fi
fi