Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/networking


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

Location:
branches/stable/mindi-busybox/networking
Files:
27 deleted
66 edited
14 copied

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/networking/Config.in

    r821 r1770  
    66menu "Networking Utilities"
    77
    8 config CONFIG_FEATURE_IPV6
     8config FEATURE_IPV6
    99    bool "Enable IPv6 support"
    1010    default n
     
    1313      This adds IPv6 support in the networking applets.
    1414
    15 config CONFIG_ARPING
     15config VERBOSE_RESOLUTION_ERRORS
     16    bool "Verbose resolution errors"
     17    default n
     18    help
     19      Enable if you are not satisfied with simplistic
     20      "can't resolve 'hostname.com'" and want to know more.
     21      This may increase size of your executable a bit.
     22
     23config ARP
     24    bool "arp"
     25    default n
     26    help
     27      Manipulate the system ARP cache.
     28
     29config ARPING
    1630    bool "arping"
    1731    default n
    1832    help
    19       Ping hosts by ARP packets
    20 
    21 config CONFIG_DNSD
     33      Ping hosts by ARP packets.
     34
     35config DNSD
    2236    bool "dnsd"
    2337    default n
    2438    help
    25       Small and static DNS server daemon. 
    26 
    27 config CONFIG_ETHER_WAKE
     39      Small and static DNS server daemon.
     40
     41config ETHER_WAKE
    2842    bool "ether-wake"
    2943    default n
     
    3145      Send a magic packet to wake up sleeping machines.
    3246
    33 config CONFIG_FAKEIDENTD
     47config FAKEIDENTD
    3448    bool "fakeidentd"
    3549    default n
     50    select FEATURE_SYSLOG
    3651    help
    3752      fakeidentd listens on the ident port and returns a predefined
    3853      fake value on any query.
    3954
    40 config CONFIG_FTPGET
     55config FTPGET
    4156    bool "ftpget"
    4257    default n
     
    4459      Retrieve a remote file via FTP.
    4560
    46 config CONFIG_FTPPUT
     61config FTPPUT
    4762    bool "ftpput"
    4863    default n
     
    5065      Store a remote file via FTP.
    5166
    52 config CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS
     67config FEATURE_FTPGETPUT_LONG_OPTIONS
    5368    bool "Enable long options in ftpget/ftpput"
    5469    default n
    55     depends on CONFIG_GETOPT_LONG && (CONFIG_FTPGET || CONFIG_FTPPUT)
     70    depends on GETOPT_LONG && (FTPGET || FTPPUT)
    5671    help
    5772      Support long options for the ftpget/ftpput applet.
    5873
    59 config CONFIG_HOSTNAME
     74config HOSTNAME
    6075    bool "hostname"
    6176    default n
    6277    help
    63       Show or set the system's host name
    64 
    65 config CONFIG_HTTPD
     78      Show or set the system's host name.
     79
     80config HTTPD
    6681    bool "httpd"
    6782    default n
     
    6984      Serve web pages via an HTTP server.
    7085
    71 config CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    72     bool "Support using httpd as a daemon (not from inetd)"
    73     default n
    74     depends on CONFIG_HTTPD
    75     help
    76       This option enables uid and port options for the httpd applet,
    77       and eliminates the need to be called from the inetd server daemon.
    78 
    79 config CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
     86config FEATURE_HTTPD_USE_SENDFILE
     87    bool "Use sendfile system call"
     88    default n
     89    depends on HTTPD
     90    help
     91      When enabled, httpd will use the kernel sendfile() function
     92      instead of read/write loop.
     93
     94config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    8095    bool "Support reloading the global config file using hup signal"
    8196    default n
    82     depends on CONFIG_HTTPD && CONFIG_FEATURE_HTTPD_WITHOUT_INETD
     97    depends on HTTPD
    8398    help
    8499      This option enables processing of SIGHUP to reload cached
    85100      configuration settings.
    86101
    87 config CONFIG_FEATURE_HTTPD_SETUID
    88     bool "Enable support -u <user> option"
    89     default n
    90     depends on CONFIG_HTTPD && CONFIG_FEATURE_HTTPD_WITHOUT_INETD
     102config FEATURE_HTTPD_SETUID
     103    bool "Enable -u <user> option"
     104    default n
     105    depends on HTTPD
    91106    help
    92107      This option allows the server to run as a specific user
     
    95110      different user.
    96111
    97 config CONFIG_FEATURE_HTTPD_BASIC_AUTH
     112config FEATURE_HTTPD_BASIC_AUTH
    98113    bool "Enable Basic http Authentication"
    99114    default y
    100     depends on CONFIG_HTTPD
     115    depends on HTTPD
    101116    help
    102117      Utilizes password settings from /etc/httpd.conf for basic
    103118      authentication on a per url basis.
    104119
    105 config CONFIG_FEATURE_HTTPD_AUTH_MD5
     120config FEATURE_HTTPD_AUTH_MD5
    106121    bool "Support MD5 crypted passwords for http Authentication"
    107122    default n
    108     depends on CONFIG_FEATURE_HTTPD_BASIC_AUTH
     123    depends on FEATURE_HTTPD_BASIC_AUTH
    109124    help
    110125      Enables basic per URL authentication from /etc/httpd.conf
    111126      using md5 passwords.
    112127
    113 config CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     128config FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    114129    bool "Support loading additional MIME types at run-time"
    115130    default n
    116     depends on CONFIG_HTTPD
     131    depends on HTTPD
    117132    help
    118133      This option enables support for additional MIME types at
    119134      run-time to be specified in the configuration file.
    120135
    121 config CONFIG_FEATURE_HTTPD_CGI
     136config FEATURE_HTTPD_CGI
    122137    bool "Support Common Gateway Interface (CGI)"
    123138    default y
    124     depends on CONFIG_HTTPD
     139    depends on HTTPD
    125140    help
    126141      This option allows scripts and executables to be invoked
    127142      when specific URLs are requested.
    128143
    129 config CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     144config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    130145    bool "Enable support for running scripts through an interpreter"
    131146    default n
    132     depends on CONFIG_FEATURE_HTTPD_CGI
    133     help
    134       This option enables support for running scripts through an 
    135       interpreter. Turn this on if you want PHP scripts to work 
    136       properly. You need to supply an addition line in your httpd
     147    depends on FEATURE_HTTPD_CGI
     148    help
     149      This option enables support for running scripts through an
     150      interpreter. Turn this on if you want PHP scripts to work
     151      properly. You need to supply an additional line in your httpd
    137152      config file:
    138153      *.php:/path/to/your/php
    139154
    140 config CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
     155config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
    141156    bool "Support the REMOTE_PORT environment variable for CGI"
    142157    default n
    143     depends on CONFIG_FEATURE_HTTPD_CGI
     158    depends on FEATURE_HTTPD_CGI
    144159    help
    145160      Use of this option can assist scripts in generating
    146161      references that contain a unique port number.
    147162
    148 config CONFIG_FEATURE_HTTPD_ENCODE_URL_STR
     163config FEATURE_HTTPD_ENCODE_URL_STR
    149164    bool "Enable the -e option for shell script CGI simplification."
    150165    default y
    151     depends on CONFIG_HTTPD
     166    depends on HTTPD
    152167    help
    153168      This option allows html encoding arbitrary
     
    156171      "&#60Hello&#32World&#62".
    157172
    158 config CONFIG_IFCONFIG
     173config FEATURE_HTTPD_ERROR_PAGES
     174    bool "Enable support for custom error pages"
     175    default n
     176    depends on HTTPD
     177    help
     178      This option allows you to define custom error pages in
     179      the configuration file instead of the default HTTP status
     180      error pages. For instance, if you add the line:
     181            E404:/path/e404.html
     182      in the config file, the server will respond the specified
     183      '/path/e404.html' file instead of the terse '404 NOT FOUND'
     184      message.
     185
     186config IFCONFIG
    159187    bool "ifconfig"
    160188    default n
     
    162190      Ifconfig is used to configure the kernel-resident network interfaces.
    163191
    164 config CONFIG_FEATURE_IFCONFIG_STATUS
     192config FEATURE_IFCONFIG_STATUS
    165193    bool "Enable status reporting output (+7k)"
    166194    default y
    167     depends on CONFIG_IFCONFIG
     195    depends on IFCONFIG
    168196    help
    169197      If ifconfig is called with no arguments it will display the status
    170198      of the currently active interfaces.
    171199
    172 config CONFIG_FEATURE_IFCONFIG_SLIP
     200config FEATURE_IFCONFIG_SLIP
    173201    bool "Enable slip-specific options \"keepalive\" and \"outfill\""
    174202    default n
    175     depends on CONFIG_IFCONFIG
     203    depends on IFCONFIG
    176204    help
    177205      Allow "keepalive" and "outfill" support for SLIP.  If you're not
    178206      planning on using serial lines, leave this unchecked.
    179207
    180 config CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
     208config FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    181209    bool "Enable options \"mem_start\", \"io_addr\", and \"irq\""
    182210    default n
    183     depends on CONFIG_IFCONFIG
     211    depends on IFCONFIG
    184212    help
    185213      Allow the start address for shared memory, start address for I/O,
    186214      and/or the interrupt line used by the specified device.
    187215
    188 config CONFIG_FEATURE_IFCONFIG_HW
     216config FEATURE_IFCONFIG_HW
    189217    bool "Enable option \"hw\" (ether only)"
    190218    default y
    191     depends on CONFIG_IFCONFIG
     219    depends on IFCONFIG
    192220    help
    193221      Set the hardware address of this interface, if the device driver
     
    195223      class.
    196224
    197 config CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
     225config FEATURE_IFCONFIG_BROADCAST_PLUS
    198226    bool "Set the broadcast automatically"
    199227    default n
    200     depends on CONFIG_IFCONFIG
     228    depends on IFCONFIG
    201229    help
    202230      Setting this will make ifconfig attempt to find the broadcast
    203231      automatically if the value '+' is used.
    204232
    205 config CONFIG_IFUPDOWN
     233config IFUPDOWN
    206234    bool "ifupdown"
    207235    default n
    208     select CONFIG_RUN_PARTS
    209236    help
    210237      Activate or deactivate the specified interfaces.  This applet makes
    211238      use of either "ifconfig" and "route" or the "ip" command to actually
    212239      configure network interfaces.  Therefore, you will probably also want
    213       to enable either CONFIG_IFCONFIG and CONFIG_ROUTE, or enable
    214       CONFIG_FEATURE_IFUPDOWN_IP and the various CONFIG_IP options.  Of
     240      to enable either IFCONFIG and ROUTE, or enable
     241      FEATURE_IFUPDOWN_IP and the various IP options.  Of
    215242      course you could use non-busybox versions of these programs, so
    216243      against my better judgement (since this will surely result in plenty
    217244      of support questions on the mailing list), I do not force you to
    218245      enable these additional options.  It is up to you to supply either
    219       "ifconfig" and "route" or the "ip" command, either via busybox or via
    220       standalone utilities.
    221 
    222 config CONFIG_FEATURE_IFUPDOWN_IP
     246      "ifconfig", "route" and "run-parts" or the "ip" command, either
     247      via busybox or via standalone utilities.
     248
     249config IFUPDOWN_IFSTATE_PATH
     250    string "Absolute path to ifstate file"
     251    default "/var/run/ifstate"
     252    help
     253      ifupdown keeps state information in a file called ifstate.
     254      Typically it is located in /var/run/ifstate, however
     255      some distributions tend to put it in other places
     256      (debian, for example, uses /etc/network/run/ifstate).
     257      This config option defines location of ifstate.
     258
     259config FEATURE_IFUPDOWN_IP
    223260    bool "Use ip applet"
    224261    default n
    225     depends on CONFIG_IFUPDOWN
     262    depends on IFUPDOWN
    226263    help
    227264      Use the iproute "ip" command to implement "ifup" and "ifdown", rather
    228265      than the default of using the older 'ifconfig' and 'route' utilities.
    229266
    230 config CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN
     267config FEATURE_IFUPDOWN_IP_BUILTIN
    231268    bool "Use busybox ip applet"
    232269    default y
    233     depends on CONFIG_FEATURE_IFUPDOWN_IP
    234     select CONFIG_IP
    235     select CONFIG_FEATURE_IP_ADDRESS
    236     select CONFIG_FEATURE_IP_LINK
    237     select CONFIG_FEATURE_IP_ROUTE
     270    depends on FEATURE_IFUPDOWN_IP
     271    select IP
     272    select FEATURE_IP_ADDRESS
     273    select FEATURE_IP_LINK
     274    select FEATURE_IP_ROUTE
    238275    help
    239276      Use the busybox iproute "ip" applet to implement "ifupdown".
    240277
    241       If leave this disabled, you must install the full-blown iproute2
     278      If left disabled, you must install the full-blown iproute2
    242279      utility or the  "ifup" and "ifdown" applets will not work.
    243280
    244 config CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN
     281config FEATURE_IFUPDOWN_IFCONFIG_BUILTIN
    245282    bool "Use busybox ifconfig and route applets"
    246283    default y
    247     depends on CONFIG_IFUPDOWN && !CONFIG_FEATURE_IFUPDOWN_IP
    248     select CONFIG_IFCONFIG
    249     select CONFIG_ROUTE
     284    depends on IFUPDOWN && !FEATURE_IFUPDOWN_IP
     285    select IFCONFIG
     286    select ROUTE
    250287    help
    251288      Use the busybox iproute "ifconfig" and "route" applets to
    252289      implement the "ifup" and "ifdown" utilities.
    253290
    254       If leave this disabled, you must install the full-blown ifconfig
     291      If left disabled, you must install the full-blown ifconfig
    255292      and route utilities, or the  "ifup" and "ifdown" applets will not
    256293      work.
    257294
    258 config CONFIG_FEATURE_IFUPDOWN_IPV4
     295config FEATURE_IFUPDOWN_IPV4
    259296    bool "Enable support for IPv4"
    260297    default y
    261     depends on CONFIG_IFUPDOWN
    262     help
    263       If you want busybox to talk IPv4, leave this on.
    264 
    265 config CONFIG_FEATURE_IFUPDOWN_IPV6
     298    depends on IFUPDOWN
     299    help
     300      If you want ifup/ifdown to talk IPv4, leave this on.
     301
     302config FEATURE_IFUPDOWN_IPV6
    266303    bool "Enable support for IPv6"
    267304    default n
    268     depends on CONFIG_IFUPDOWN && CONFIG_FEATURE_IPV6
     305    depends on IFUPDOWN && FEATURE_IPV6
    269306    help
    270307      If you need support for IPv6, turn this option on.
    271308
    272 config CONFIG_FEATURE_IFUPDOWN_IPX
    273     bool "Enable support for IPX"
    274     default n
    275     depends on CONFIG_IFUPDOWN
    276     help
    277       If this option is selected you can use busybox to work with IPX
    278       networks.
    279 
    280 config CONFIG_FEATURE_IFUPDOWN_MAPPING
     309### UNUSED
     310### config FEATURE_IFUPDOWN_IPX
     311###     bool "Enable support for IPX"
     312###     default n
     313###     depends on IFUPDOWN
     314###     help
     315###       If this option is selected you can use busybox to work with IPX
     316###       networks.
     317
     318config FEATURE_IFUPDOWN_MAPPING
    281319    bool "Enable mapping support"
    282320    default n
    283     depends on CONFIG_IFUPDOWN
     321    depends on IFUPDOWN
    284322    help
    285323      This enables support for the "mapping" stanza, unless you have
    286324      a weird network setup you don't need it.
    287325
    288 config CONFIG_INETD
     326config FEATURE_IFUPDOWN_EXTERNAL_DHCP
     327    bool "Enable support for external dhcp clients"
     328    default n
     329    depends on IFUPDOWN
     330    help
     331      This enables support for the external dhcp clients. Clients are
     332      tried in the following order: dhcpcd, dhclient, pump and udhcpc.
     333      Otherwise, if udhcpc applet is enabled, it is used.
     334      Otherwise, ifup/ifdown will have no support for DHCP.
     335
     336config INETD
    289337    bool "inetd"
    290338    default n
     339    select FEATURE_SYSLOG
    291340    help
    292341      Internet superserver daemon
    293342
    294 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     343config FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    295344    bool "Support echo service"
    296345    default y
    297     depends on CONFIG_INETD
     346    depends on INETD
    298347    help
    299348      Echo received data internal inetd service
    300349
    301 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     350config FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    302351    bool "Support discard service"
    303352    default y
    304     depends on CONFIG_INETD
     353    depends on INETD
    305354    help
    306355      Internet /dev/null internal inetd service
    307356
    308 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     357config FEATURE_INETD_SUPPORT_BUILTIN_TIME
    309358    bool "Support time service"
    310359    default y
    311     depends on CONFIG_INETD
     360    depends on INETD
    312361    help
    313362      Return 32 bit time since 1900 internal inetd service
    314363
    315 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     364config FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    316365    bool "Support daytime service"
    317366    default y
    318     depends on CONFIG_INETD
     367    depends on INETD
    319368    help
    320369      Return human-readable time internal inetd service
    321370
    322 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     371config FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    323372    bool "Support chargen service"
    324373    default y
    325     depends on CONFIG_INETD
     374    depends on INETD
    326375    help
    327376      Familiar character generator internal inetd service
    328377
    329 config CONFIG_FEATURE_INETD_RPC
     378config FEATURE_INETD_RPC
    330379    bool "Support RPC services"
    331380    default n
    332     depends on CONFIG_INETD
    333     help
    334       Suuport Sun-RPC based services
    335 
    336 
    337 config CONFIG_IP
     381    depends on INETD
     382    select FEATURE_HAVE_RPC
     383    help
     384      Support Sun-RPC based services
     385
     386config IP
    338387    bool "ip"
    339388    default n
     
    343392      TCP/IP.
    344393
    345 config CONFIG_FEATURE_IP_ADDRESS
     394config FEATURE_IP_ADDRESS
    346395    bool "ip address"
    347396    default y
    348     depends on CONFIG_IP
     397    depends on IP
    349398    help
    350399      Address manipulation support for the "ip" applet.
    351400
    352 config CONFIG_FEATURE_IP_LINK
     401config FEATURE_IP_LINK
    353402    bool "ip link"
    354403    default y
    355     depends on CONFIG_IP
     404    depends on IP
    356405    help
    357406      Configure network devices with "ip".
    358407
    359 config CONFIG_FEATURE_IP_ROUTE
     408config FEATURE_IP_ROUTE
    360409    bool "ip route"
    361410    default y
    362     depends on CONFIG_IP
     411    depends on IP
    363412    help
    364413      Add support for routing table management to "ip".
    365414
    366 config CONFIG_FEATURE_IP_TUNNEL
     415config FEATURE_IP_TUNNEL
    367416    bool "ip tunnel"
    368417    default n
    369     depends on CONFIG_IP
     418    depends on IP
    370419    help
    371420      Add support for tunneling commands to "ip".
    372421
    373 config CONFIG_FEATURE_IP_SHORT_FORMS
     422config FEATURE_IP_RULE
     423    bool "ip rule"
     424    default n
     425    depends on IP
     426    help
     427      Add support for rule commands to "ip".
     428
     429config FEATURE_IP_SHORT_FORMS
    374430    bool "Support short forms of ip commands."
    375431    default n
    376     depends on CONFIG_IP
     432    depends on IP
    377433    help
    378434      Also support short-form of ip <OBJECT> commands:
     
    381437      ip route  -> iproute
    382438      ip tunnel -> iptunnel
     439      ip rule   -> iprule
    383440
    384441      Say N unless you desparately need the short form of the ip
    385442      object commands.
    386443
    387 config CONFIG_IPADDR
     444config IPADDR
    388445    bool
    389446    default y
    390     depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_ADDRESS
    391 
    392 config CONFIG_IPLINK
     447    depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_ADDRESS
     448
     449config IPLINK
    393450    bool
    394451    default y
    395     depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_LINK
    396 
    397 config CONFIG_IPROUTE
     452    depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_LINK
     453
     454config IPROUTE
    398455    bool
    399456    default y
    400     depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_ROUTE
    401 
    402 config CONFIG_IPTUNNEL
     457    depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_ROUTE
     458
     459config IPTUNNEL
    403460    bool
    404461    default y
    405     depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_TUNNEL
    406 
    407 config CONFIG_IPCALC
     462    depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_TUNNEL
     463
     464config IPRULE
     465    bool
     466    default y
     467    depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_RULE
     468
     469config IPCALC
    408470    bool "ipcalc"
    409471    default n
     
    412474      resulting broadcast, network, and host range.
    413475
    414 config CONFIG_FEATURE_IPCALC_FANCY
     476config FEATURE_IPCALC_FANCY
    415477    bool "Fancy IPCALC, more options, adds 1 kbyte"
    416478    default y
    417     depends on CONFIG_IPCALC
     479    depends on IPCALC
    418480    help
    419481      Adds the options hostname, prefix and silent to the output of "ipcalc".
    420482
    421 config CONFIG_FEATURE_IPCALC_LONG_OPTIONS
     483config FEATURE_IPCALC_LONG_OPTIONS
    422484    bool "Enable long options"
    423485    default n
    424     depends on CONFIG_IPCALC && CONFIG_GETOPT_LONG
     486    depends on IPCALC && GETOPT_LONG
    425487    help
    426488      Support long options for the ipcalc applet.
    427489
    428 config CONFIG_NAMEIF
     490config NAMEIF
    429491    bool "nameif"
    430492    default n
     493    select FEATURE_SYSLOG
    431494    help
    432495      nameif is used to rename network interface by its MAC address.
     
    440503      new_interface_name    XX:XX:XX:XX:XX:XX
    441504
    442 config CONFIG_NC
     505config NC
    443506    bool "nc"
    444507    default n
     
    447510      connections.
    448511
    449 config CONFIG_NC_GAPING_SECURITY_HOLE
    450     bool "gaping security hole"
    451     default n
    452     depends on CONFIG_NC
    453     help
    454       Add support for executing a program after making or receiving a
    455       successful connection (-e option).
    456 
    457 config CONFIG_NETSTAT
     512config NC_SERVER
     513    bool "Netcat server options (-l)"
     514    default n
     515    depends on NC
     516    help
     517      Allow netcat to act as a server.
     518
     519config NC_EXTRA
     520    bool "Netcat extensions (-eiw and filename)"
     521    default n
     522    depends on NC
     523    help
     524      Add -e (support for executing the rest of the command line after
     525      making or receiving a successful connection), -i (delay interval for
     526      lines sent), -w (timeout for initial connection).
     527
     528config NETSTAT
    458529    bool "netstat"
    459530    default n
     
    461532      netstat prints information about the Linux networking subsystem.
    462533
    463 config CONFIG_NSLOOKUP
     534config FEATURE_NETSTAT_WIDE
     535    bool "  Enable wide netstat output"
     536    default n
     537    depends on NETSTAT
     538    help
     539      Add support for wide columns. Useful when displaying IPv6 addresses
     540      (-W option).
     541
     542config NSLOOKUP
    464543    bool "nslookup"
    465544    default n
     
    467546      nslookup is a tool to query Internet name servers.
    468547
    469 config CONFIG_PING
     548config PING
    470549    bool "ping"
    471550    default n
     
    474553      elicit an ICMP ECHO_RESPONSE from a host or gateway.
    475554
    476 config CONFIG_FEATURE_FANCY_PING
     555config PING6
     556    bool "ping6"
     557    default n
     558    depends on FEATURE_IPV6 && PING
     559    help
     560      This will give you a ping that can talk IPv6.
     561
     562config PSCAN
     563    bool "pscan"
     564    default n
     565    help
     566      Simple network port scanner.
     567
     568config FEATURE_FANCY_PING
    477569    bool "Enable fancy ping output"
    478570    default y
    479     depends on CONFIG_PING
     571    depends on PING
    480572    help
    481573      Make the output from the ping applet include statistics, and at the
    482574      same time provide full support for ICMP packets.
    483575
    484 config CONFIG_PING6
    485     bool "ping6"
    486     default n
    487     depends on CONFIG_FEATURE_IPV6
    488     help
    489       This will give you a ping that can talk IPv6.
    490 
    491 config CONFIG_FEATURE_FANCY_PING6
    492     bool "Enable fancy ping6 output"
    493     default y
    494     depends on CONFIG_PING6
    495     help
    496       Make the output from the ping6 applet include statistics, and at the
    497       same time provide full support for ICMP packets.
    498 
    499 config CONFIG_ROUTE
     576config ROUTE
    500577    bool "route"
    501578    default n
     
    503580      Route displays or manipulates the kernel's IP routing tables.
    504581
    505 config CONFIG_TELNET
     582config SLATTACH
     583    bool "slattach"
     584    default n
     585    help
     586      slattach is a small utility to attach network interfaces to serial lines.
     587
     588config TELNET
    506589    bool "telnet"
    507590    default n
     
    510593      used to test other simple protocols.
    511594
    512 config CONFIG_FEATURE_TELNET_TTYPE
     595config FEATURE_TELNET_TTYPE
    513596    bool "Pass TERM type to remote host"
    514597    default y
    515     depends on CONFIG_TELNET
     598    depends on TELNET
    516599    help
    517600      Setting this option will forward the TERM environment variable to the
     
    519602      things like ANSI colors and other control sequences behave.
    520603
    521 config CONFIG_FEATURE_TELNET_AUTOLOGIN
     604config FEATURE_TELNET_AUTOLOGIN
    522605    bool "Pass USER type to remote host"
    523606    default y
    524     depends on CONFIG_TELNET
     607    depends on TELNET
    525608    help
    526609      Setting this option will forward the USER environment variable to the
     
    529612      option enables `-a' and `-l USER' arguments.
    530613
    531 config CONFIG_TELNETD
     614config TELNETD
    532615    bool "telnetd"
    533616    default n
     617    select FEATURE_SYSLOG
    534618    help
    535619      A daemon for the TELNET protocol, allowing you to log onto the host
     
    543627      Note that for busybox telnetd to work you need several things:
    544628      First of all, your kernel needs:
    545           CONFIG_UNIX98_PTYS=y
    546           CONFIG_DEVPTS_FS=y
     629          UNIX98_PTYS=y
     630          DEVPTS_FS=y
    547631
    548632      Next, you need a /dev/pts directory on your root filesystem:
     
    561645          mount -t devpts devpts /dev/pts
    562646
    563       You need to be sure that Busybox has CONFIG_LOGIN and
    564       CONFIG_FEATURE_SUID enabled.  And finally, you should make
     647      You need to be sure that Busybox has LOGIN and
     648      FEATURE_SUID enabled.  And finally, you should make
    565649      certain that Busybox has been installed setuid root:
    566650
     
    571655
    572656
    573 config CONFIG_FEATURE_TELNETD_INETD
    574     bool "Support call from inetd only"
    575     default n
    576     depends on CONFIG_TELNETD
    577     help
    578       Selecting this will make telnetd only callable from inetd,
    579       removing the standalone support.
    580 
    581 config CONFIG_TFTP
     657config FEATURE_TELNETD_STANDALONE
     658    bool "Support standalone telnetd (not inetd only)"
     659    default n
     660    depends on TELNETD
     661    help
     662      Selecting this will make telnetd able to run standalone.
     663
     664config TFTP
    582665    bool "tftp"
    583666    default n
     
    587670      for a network-enabled bootloader.
    588671
    589 config CONFIG_FEATURE_TFTP_GET
     672config FEATURE_TFTP_GET
    590673    bool "Enable \"get\" command"
    591674    default y
    592     depends on CONFIG_TFTP
     675    depends on TFTP
    593676    help
    594677      Add support for the GET command within the TFTP client.  This allows
    595678      a client to retrieve a file from a TFTP server.
    596679
    597 config CONFIG_FEATURE_TFTP_PUT
     680config FEATURE_TFTP_PUT
    598681    bool "Enable \"put\" command"
    599682    default y
    600     depends on CONFIG_TFTP
     683    depends on TFTP
    601684    help
    602685      Add support for the PUT command within the TFTP client.  This allows
    603686      a client to transfer a file to a TFTP server.
    604687
    605 config CONFIG_FEATURE_TFTP_BLOCKSIZE
     688config FEATURE_TFTP_BLOCKSIZE
    606689    bool "Enable \"blocksize\" command"
    607690    default n
    608     depends on CONFIG_TFTP
     691    depends on TFTP
    609692    help
    610693      Allow the client to specify the desired block size for transfers.
    611694
    612 config CONFIG_DEBUG_TFTP
     695config DEBUG_TFTP
    613696    bool "Enable debug"
    614697    default n
    615     depends on CONFIG_TFTP
     698    depends on TFTP
    616699    help
    617700      Enable debug settings for tftp.  This is useful if you're running
     
    619702      you run into problems.
    620703
    621 config CONFIG_TRACEROUTE
     704config TRACEROUTE
    622705    bool "traceroute"
    623706    default n
     
    625708      Utility to trace the route of IP packets
    626709
    627 config CONFIG_FEATURE_TRACEROUTE_VERBOSE
     710config FEATURE_TRACEROUTE_VERBOSE
    628711    bool "Enable verbose output"
    629712    default n
    630     depends on CONFIG_TRACEROUTE
     713    depends on TRACEROUTE
    631714    help
    632715      Add some verbosity to traceroute.  This includes amongst other things
    633716      hostnames and ICMP response types.
    634717
    635 config CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     718config FEATURE_TRACEROUTE_SOURCE_ROUTE
    636719    bool "Enable loose source route"
    637720    default n
    638     depends on CONFIG_TRACEROUTE
     721    depends on TRACEROUTE
    639722    help
    640723      Add option to specify a loose source route gateway
    641724      (8 maximum).
    642725
    643 config CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     726config FEATURE_TRACEROUTE_USE_ICMP
    644727    bool "Use ICMP instead of UDP"
    645728    default n
    646     depends on CONFIG_TRACEROUTE
     729    depends on TRACEROUTE
    647730    help
    648731      Add feature to allow for ICMP ECHO instead of UDP datagrams.
     
    650733source networking/udhcp/Config.in
    651734
    652 config CONFIG_VCONFIG
     735config VCONFIG
    653736    bool "vconfig"
    654737    default n
     
    656739      Creates, removes, and configures VLAN interfaces
    657740
    658 config CONFIG_WGET
     741config WGET
    659742    bool "wget"
    660743    default n
     
    663746      HTTPS, and FTP servers.
    664747
    665 config CONFIG_FEATURE_WGET_STATUSBAR
     748config FEATURE_WGET_STATUSBAR
    666749    bool "Enable a nifty process meter (+2k)"
    667750    default y
    668     depends on CONFIG_WGET
     751    depends on WGET
    669752    help
    670753      Enable the transfer progress bar for wget transfers.
    671754
    672 config CONFIG_FEATURE_WGET_AUTHENTICATION
     755config FEATURE_WGET_AUTHENTICATION
    673756    bool "Enable HTTP authentication"
    674757    default y
    675     depends on CONFIG_WGET
     758    depends on WGET
    676759    help
    677760      Support authenticated HTTP transfers.
    678761
    679 config CONFIG_FEATURE_WGET_IP6_LITERAL
    680     bool "Enable IPv6 literal addresses"
    681     default y
    682     depends on CONFIG_WGET && CONFIG_FEATURE_IPV6
    683     help
    684       Support IPv6 address literal notation in URLs.
    685 
    686 config CONFIG_FEATURE_WGET_LONG_OPTIONS
     762config FEATURE_WGET_LONG_OPTIONS
    687763    bool "Enable long options"
    688764    default n
    689     depends on CONFIG_WGET && CONFIG_GETOPT_LONG
     765    depends on WGET && GETOPT_LONG
    690766    help
    691767      Support long options for the wget applet.
    692768
    693 config CONFIG_ZCIP
     769config ZCIP
    694770    bool "zcip"
    695771    default n
     772    select FEATURE_SYSLOG
    696773    help
    697774      ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927.
  • branches/stable/mindi-busybox/networking/arping.c

    r821 r1770  
    99 */
    1010
    11 #include <sys/ioctl.h>
    12 #include <signal.h>
    13 
    14 #include <errno.h>
    15 #include <stdlib.h>
    16 #include <string.h>
    17 #include <unistd.h>
    18 
    1911#include <arpa/inet.h>
    2012#include <net/if.h>
     
    2214#include <netpacket/packet.h>
    2315
    24 #include "busybox.h"
     16#include "libbb.h"
     17
     18/* We don't expect to see 1000+ seconds delay, unsigned is enough */
     19#define MONOTONIC_US() ((unsigned)monotonic_us())
    2520
    2621static struct in_addr src;
     
    2823static struct sockaddr_ll me;
    2924static struct sockaddr_ll he;
    30 static struct timeval last;
    31 
    32 enum cfg_e {
    33     dad = 1,
    34     unsolicited = 2,
    35     advert = 4,
    36     quiet = 8,
    37     quit_on_reply = 16,
    38     broadcast_only = 32,
    39     unicasting = 64
     25static unsigned last;
     26
     27enum {
     28    DAD = 1,
     29    UNSOLICITED = 2,
     30    ADVERT = 4,
     31    QUIET = 8,
     32    QUIT_ON_REPLY = 16,
     33    BCAST_ONLY = 32,
     34    UNICASTING = 64
    4035};
    41 static int cfg;
    42 
    43 static int s;
    44 static int count = -1;
    45 static int timeout;
    46 static int sent;
    47 static int brd_sent;
    48 static int received;
    49 static int brd_recv;
    50 static int req_recv;
    51 
    52 
    53 #define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
    54                ((tv1).tv_usec-(tv2).tv_usec)/1000 )
    55 #if 0
    56 static void set_signal(int signo, void (*handler) (void))
    57 {
    58     struct sigaction sa;
    59 
    60     memset(&sa, 0, sizeof(sa));
    61     sa.sa_handler = (void (*)(int)) handler;
    62     sa.sa_flags = SA_RESTART;
    63     sigaction(signo, &sa, NULL);
    64 }
    65 #endif
    66 
    67 static int send_pack(int sock, struct in_addr *src_addr,
    68                      struct in_addr *dst_addr, struct sockaddr_ll *ME,
    69                      struct sockaddr_ll *HE)
     36
     37static int sock;
     38static unsigned count = UINT_MAX;
     39static unsigned timeout_us;
     40static unsigned sent;
     41static unsigned brd_sent;
     42static unsigned received;
     43static unsigned brd_recv;
     44static unsigned req_recv;
     45
     46static int send_pack(struct in_addr *src_addr,
     47            struct in_addr *dst_addr, struct sockaddr_ll *ME,
     48            struct sockaddr_ll *HE)
    7049{
    7150    int err;
    72     struct timeval now;
    73     RESERVE_CONFIG_UBUFFER(buf, 256);
     51    unsigned now;
     52    unsigned char buf[256];
    7453    struct arphdr *ah = (struct arphdr *) buf;
    7554    unsigned char *p = (unsigned char *) (ah + 1);
     
    8059    ah->ar_hln = ME->sll_halen;
    8160    ah->ar_pln = 4;
    82     ah->ar_op = cfg&advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
     61    ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
    8362
    8463    memcpy(p, &ME->sll_addr, ah->ar_hln);
     
    8867    p += 4;
    8968
    90     if (cfg&advert)
     69    if (option_mask32 & ADVERT)
    9170        memcpy(p, &ME->sll_addr, ah->ar_hln);
    9271    else
     
    9776    p += 4;
    9877
    99     gettimeofday(&now, NULL);
     78    now = MONOTONIC_US();
    10079    err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
    10180    if (err == p - buf) {
    10281        last = now;
    10382        sent++;
    104         if (!(cfg&unicasting))
     83        if (!(option_mask32 & UNICASTING))
    10584            brd_sent++;
    10685    }
    107     RELEASE_CONFIG_BUFFER(buf);
    10886    return err;
    10987}
    11088
     89static void finish(void) ATTRIBUTE_NORETURN;
    11190static void finish(void)
    11291{
    113     if (!(cfg&quiet)) {
    114         printf("Sent %d probes (%d broadcast(s))\n"
    115             "Received %d repl%s",
     92    if (!(option_mask32 & QUIET)) {
     93        printf("Sent %u probe(s) (%u broadcast(s))\n"
     94            "Received %u repl%s"
     95            " (%u request(s), %u broadcast(s))\n",
    11696            sent, brd_sent,
    117             received, (received > 1) ? "ies" : "y");
    118         if (brd_recv || req_recv) {
    119             printf(" (");
    120             if (req_recv)
    121                 printf("%d request(s)", req_recv);
    122             if (brd_recv)
    123                 printf("%s%d broadcast(s)", req_recv ? ", " : "", brd_recv);
    124             putchar(')');
    125         }
    126         putchar('\n');
    127         fflush(stdout);
    128     }
    129     if (cfg&dad)
     97            received, (received == 1) ? "ies" : "y",
     98            req_recv, brd_recv);
     99    }
     100    if (option_mask32 & DAD)
    130101        exit(!!received);
    131     if (cfg&unsolicited)
     102    if (option_mask32 & UNSOLICITED)
    132103        exit(0);
    133104    exit(!received);
     
    136107static void catcher(void)
    137108{
    138     struct timeval tv;
    139     static struct timeval start;
    140 
    141     gettimeofday(&tv, NULL);
    142 
    143     if (start.tv_sec == 0)
    144         start = tv;
    145 
    146     if (count-- == 0
    147         || (timeout && MS_TDIFF(tv, start) > timeout * 1000 + 500))
     109    static unsigned start;
     110
     111    unsigned now;
     112
     113    now = MONOTONIC_US();
     114    if (start == 0)
     115        start = now;
     116
     117    if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000)))
    148118        finish();
    149119
    150     if (last.tv_sec == 0 || MS_TDIFF(tv, last) > 500) {
    151         send_pack(s, &src, &dst, &me, &he);
    152         if (count == 0 && cfg&unsolicited)
     120    count--;
     121
     122    if (last == 0 || (now - last) > 500000) {
     123        send_pack(&src, &dst, &me, &he);
     124        if (count == 0 && (option_mask32 & UNSOLICITED))
    153125            finish();
    154126    }
     
    163135
    164136    /* Filter out wild packets */
    165     if (FROM->sll_pkttype != PACKET_HOST &&
    166         FROM->sll_pkttype != PACKET_BROADCAST &&
    167         FROM->sll_pkttype != PACKET_MULTICAST)
     137    if (FROM->sll_pkttype != PACKET_HOST
     138     && FROM->sll_pkttype != PACKET_BROADCAST
     139     && FROM->sll_pkttype != PACKET_MULTICAST)
    168140        return 0;
    169141
     
    173145
    174146    /* ARPHRD check and this darned FDDI hack here :-( */
    175     if (ah->ar_hrd != htons(FROM->sll_hatype) &&
    176         (FROM->sll_hatype != ARPHRD_FDDI
    177          || ah->ar_hrd != htons(ARPHRD_ETHER)))
     147    if (ah->ar_hrd != htons(FROM->sll_hatype)
     148     && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
    178149        return 0;
    179150
     
    189160    memcpy(&src_ip, p + ah->ar_hln, 4);
    190161    memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
    191     if (!(cfg&dad)) {
     162    if (!(option_mask32 & DAD)) {
    192163        if (src_ip.s_addr != dst.s_addr)
    193164            return 0;
     
    217188            return 0;
    218189    }
    219     if (!(cfg&quiet)) {
     190    if (!(option_mask32 & QUIET)) {
    220191        int s_printed = 0;
    221         struct timeval tv;
    222 
    223         gettimeofday(&tv, NULL);
    224 
    225         printf("%s %s from %s [%s]",
    226             FROM->sll_pkttype == PACKET_HOST ? "Unicast" : "Broadcast",
    227             ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request",
     192
     193        printf("%scast re%s from %s [%s]",
     194            FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
     195            ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
    228196            inet_ntoa(src_ip),
    229197            ether_ntoa((struct ether_addr *) p));
     
    236204                printf("for ");
    237205            printf("[%s]",
    238                    ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4));
    239         }
    240 
    241         if (last.tv_sec) {
    242             long usecs = (tv.tv_sec - last.tv_sec) * 1000000 +
    243                 tv.tv_usec - last.tv_usec;
    244             long msecs = (usecs + 500) / 1000;
    245 
    246             usecs -= msecs * 1000 - 500;
    247             printf(" %ld.%03ldms\n", msecs, usecs);
     206                ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4));
     207        }
     208
     209        if (last) {
     210            printf(" %u.%03ums\n", last / 1000, last % 1000);
    248211        } else {
    249212            printf(" UNSOLICITED?\n");
     
    256219    if (ah->ar_op == htons(ARPOP_REQUEST))
    257220        req_recv++;
    258     if (cfg&quit_on_reply)
     221    if (option_mask32 & QUIT_ON_REPLY)
    259222        finish();
    260     if (!(cfg&broadcast_only)) {
     223    if (!(option_mask32 & BCAST_ONLY)) {
    261224        memcpy(he.sll_addr, p, me.sll_halen);
    262         cfg |= unicasting;
     225        option_mask32 |= UNICASTING;
    263226    }
    264227    return 1;
    265228}
    266229
     230int arping_main(int argc, char **argv);
    267231int arping_main(int argc, char **argv)
    268232{
    269     char *device = "eth0";
     233    const char *device = "eth0";
    270234    int ifindex;
    271235    char *source = NULL;
    272236    char *target;
    273 
    274     s = socket(PF_PACKET, SOCK_DGRAM, 0);
    275     ifindex = errno;
     237    unsigned char *packet;
     238
     239    sock = xsocket(PF_PACKET, SOCK_DGRAM, 0);
    276240
    277241    // Drop suid root privileges
     
    279243
    280244    {
    281         unsigned long opt;
    282         char *_count, *_timeout, *_device;
     245        unsigned opt;
     246        char *str_count, *str_timeout;
    283247
    284248        /* Dad also sets quit_on_reply.
    285249         * Advert also sets unsolicited.
    286250         */
    287         bb_opt_complementally = "Df:AU";
    288         opt = bb_getopt_ulflags(argc, argv, "DUAqfbc:w:i:s:",
    289                         &_count, &_timeout, &_device);
    290         cfg |= opt & 63; /* set respective flags */
    291         if (opt & 64) /* count */
    292             count = atoi(_count);
    293         if (opt & 128) /* timeout */
    294             timeout = atoi(_timeout);
    295         if (opt & 256) { /* interface */
    296             if (strlen(_device) > IF_NAMESIZE) {
    297                 bb_error_msg_and_die("Interface name `%s' must be less than %d",
    298                                 _device, IF_NAMESIZE);
    299             }
    300             device = _device;
    301         }
    302         if (opt & 512) /* source */
    303             source = optarg;
    304     }
    305     argc -= optind;
    306     argv += optind;
    307 
    308     if (argc != 1)
    309         bb_show_usage();
    310 
    311     target = *argv;
    312 
    313 
    314     if (s < 0) {
    315         bb_default_error_retval = ifindex;
    316         bb_perror_msg_and_die("socket");
    317     }
    318     bb_default_error_retval = 2;
     251        opt_complementary = "=1:Df:AU";
     252        opt = getopt32(argv, "DUAqfbc:w:I:s:",
     253                &str_count, &str_timeout, &device, &source);
     254        if (opt & 0x40) /* -c: count */
     255            count = xatou(str_count);
     256        if (opt & 0x80) /* -w: timeout */
     257            timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000;
     258        //if (opt & 0x100) /* -I: interface */
     259        if (strlen(device) >= IF_NAMESIZE) {
     260            bb_error_msg_and_die("interface name '%s' is too long",
     261                            device);
     262        }
     263        //if (opt & 0x200) /* -s: source */
     264        option_mask32 &= 0x3f; /* set respective flags */
     265    }
     266
     267    target = argv[optind];
     268
     269    xfunc_error_retval = 2;
    319270
    320271    {
     
    323274        memset(&ifr, 0, sizeof(ifr));
    324275        strncpy(ifr.ifr_name, device, IFNAMSIZ - 1);
    325         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
    326             bb_error_msg_and_die("Interface %s not found", device);
    327         }
     276        ioctl_or_perror_and_die(sock, SIOCGIFINDEX, &ifr, "interface %s not found", device);
    328277        ifindex = ifr.ifr_ifindex;
    329278
    330         if (ioctl(s, SIOCGIFFLAGS, (char *) &ifr)) {
    331             bb_error_msg_and_die("SIOCGIFFLAGS");
    332         }
     279        xioctl(sock, SIOCGIFFLAGS, (char *) &ifr);
     280
    333281        if (!(ifr.ifr_flags & IFF_UP)) {
    334             bb_error_msg_and_die("Interface %s is down", device);
     282            bb_error_msg_and_die("interface %s is down", device);
    335283        }
    336284        if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
    337             bb_error_msg("Interface %s is not ARPable", device);
    338             exit(cfg&dad ? 0 : 2);
     285            bb_error_msg("interface %s is not ARPable", device);
     286            return (option_mask32 & DAD ? 0 : 2);
    339287        }
    340288    }
    341289
    342290    if (!inet_aton(target, &dst)) {
    343         struct hostent *hp;
    344 
    345         hp = gethostbyname2(target, AF_INET);
    346         if (!hp) {
    347             bb_error_msg_and_die("invalid or unknown target %s", target);
    348         }
    349         memcpy(&dst, hp->h_addr, 4);
     291        len_and_sockaddr *lsa;
     292        lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
     293        memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4);
     294        if (ENABLE_FEATURE_CLEAN_UP)
     295            free(lsa);
    350296    }
    351297
     
    354300    }
    355301
    356     if (!(cfg&dad) && cfg&unsolicited && src.s_addr == 0)
     302    if (!(option_mask32 & DAD) && (option_mask32 & UNSOLICITED) && src.s_addr == 0)
    357303        src = dst;
    358304
    359     if (!(cfg&dad) || src.s_addr) {
     305    if (!(option_mask32 & DAD) || src.s_addr) {
    360306        struct sockaddr_in saddr;
    361         int probe_fd = socket(AF_INET, SOCK_DGRAM, 0); /* maybe use bb_xsocket? */
    362 
    363         if (probe_fd < 0) {
    364             bb_error_msg_and_die("socket");
    365         }
     307        int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     308
    366309        if (device) {
    367             if (setsockopt
    368                 (probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device,
    369                  strlen(device) + 1) == -1)
    370                 bb_error_msg("WARNING: interface %s is ignored", device);
     310            if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1)
     311                bb_error_msg("warning: interface %s is ignored", device);
    371312        }
    372313        memset(&saddr, 0, sizeof(saddr));
     
    374315        if (src.s_addr) {
    375316            saddr.sin_addr = src;
    376             if (bind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) {
    377                 bb_error_msg_and_die("bind");
    378             }
    379         } else if (!(cfg&dad)) {
    380             int on = 1;
     317            xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
     318        } else if (!(option_mask32 & DAD)) {
    381319            socklen_t alen = sizeof(saddr);
    382320
     
    384322            saddr.sin_addr = dst;
    385323
    386             if (setsockopt
    387                 (probe_fd, SOL_SOCKET, SO_DONTROUTE, (char *) &on,
    388                  sizeof(on)) == -1)
    389                 bb_perror_msg("WARNING: setsockopt(SO_DONTROUTE)");
    390             if (connect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr))
    391                 == -1) {
    392                 bb_error_msg_and_die("connect");
    393             }
    394             if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) ==
    395                 -1) {
     324            if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1)
     325                bb_perror_msg("warning: setsockopt(SO_DONTROUTE)");
     326            xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
     327            if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) {
    396328                bb_error_msg_and_die("getsockname");
    397329            }
     
    399331        }
    400332        close(probe_fd);
    401     };
     333    }
    402334
    403335    me.sll_family = AF_PACKET;
    404336    me.sll_ifindex = ifindex;
    405337    me.sll_protocol = htons(ETH_P_ARP);
    406     if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) {
    407         bb_error_msg_and_die("bind");
    408     }
     338    xbind(sock, (struct sockaddr *) &me, sizeof(me));
    409339
    410340    {
    411341        socklen_t alen = sizeof(me);
    412342
    413         if (getsockname(s, (struct sockaddr *) &me, &alen) == -1) {
     343        if (getsockname(sock, (struct sockaddr *) &me, &alen) == -1) {
    414344            bb_error_msg_and_die("getsockname");
    415345        }
    416346    }
    417347    if (me.sll_halen == 0) {
    418         bb_error_msg("Interface \"%s\" is not ARPable (no ll address)", device);
    419         exit(cfg&dad ? 0 : 2);
     348        bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device);
     349        return (option_mask32 & DAD ? 0 : 2);
    420350    }
    421351    he = me;
    422352    memset(he.sll_addr, -1, he.sll_halen);
    423353
    424     if (!(cfg&quiet)) {
     354    if (!(option_mask32 & QUIET)) {
    425355        printf("ARPING to %s from %s via %s\n",
    426356            inet_ntoa(dst), inet_ntoa(src),
     
    428358    }
    429359
    430     if (!src.s_addr && !(cfg&dad)) {
     360    if (!src.s_addr && !(option_mask32 & DAD)) {
    431361        bb_error_msg_and_die("no src address in the non-DAD mode");
    432362    }
     
    447377    catcher();
    448378
     379    packet = xmalloc(4096);
    449380    while (1) {
    450381        sigset_t sset, osset;
    451         RESERVE_CONFIG_UBUFFER(packet, 4096);
    452382        struct sockaddr_ll from;
    453383        socklen_t alen = sizeof(from);
    454384        int cc;
    455385
    456         if ((cc = recvfrom(s, packet, 4096, 0,
    457                            (struct sockaddr *) &from, &alen)) < 0) {
    458             perror("recvfrom");
     386        cc = recvfrom(sock, packet, 4096, 0, (struct sockaddr *) &from, &alen);
     387        if (cc < 0) {
     388            bb_perror_msg("recvfrom");
    459389            continue;
    460390        }
     
    465395        recv_pack(packet, cc, &from);
    466396        sigprocmask(SIG_SETMASK, &osset, NULL);
    467         RELEASE_CONFIG_BUFFER(packet);
    468     }
    469 }
     397    }
     398}
  • branches/stable/mindi-busybox/networking/dnsd.c

    r902 r1770  
    1818 */
    1919
    20 #include <unistd.h>
    21 #include <string.h>
    22 #include <signal.h>
    23 #include <arpa/inet.h>
    24 #include <sys/socket.h>
    25 #include <ctype.h>
    26 #include "busybox.h"
    27 
    28 static char *fileconf = "/etc/dnsd.conf";
    29 #define LOCK_FILE       "/var/run/dnsd.lock"
    30 #define LOG_FILE        "/var/log/dnsd.log"
    31 
    32 #define is_daemon()  (flags&16)
    33 #define is_verbose() (flags&32)
    34 //#define DEBUG
    35 
     20#include <syslog.h>
     21#include "libbb.h"
     22
     23//#define DEBUG 1
     24#define DEBUG 0
    3625
    3726enum {
     
    8170};
    8271
    83 static struct dns_entry *dnsentry = NULL;
    84 static int daemonmode = 0;
     72static struct dns_entry *dnsentry;
    8573static uint32_t ttl = DEFAULT_TTL;
    8674
     75static const char *fileconf = "/etc/dnsd.conf";
     76
     77// Must match getopt32 call
     78#define OPT_daemon  (option_mask32 & 0x10)
     79#define OPT_verbose (option_mask32 & 0x20)
     80
     81
    8782/*
    8883 * Convert host name from C-string to dns length/string.
     
    9186{
    9287    int i = (q[0] == '.') ? 0 : 1;
    93     for(; i < MAX_HOST_LEN-1 && *q; i++, q++)
     88    for (; i < MAX_HOST_LEN-1 && *q; i++, q++)
    9489        a[i] = tolower(*q);
    9590    a[0] = i - 1;
     
    10398{
    10499    int i = 0, s = 0;
    105     while(rip[i]) i++;
    106     for(--i; i >= 0; i--) {
    107         if(rip[i] == '.') {
     100    while (rip[i])
     101        i++;
     102    for (--i; i >= 0; i--) {
     103        if (rip[i] == '.') {
    108104            rip[i] = s;
    109105            s = 0;
     
    113109
    114110/*
    115  * Append message to log file
    116  */
    117 static void log_message(char *filename, char *message)
    118 {
    119     FILE *logfile;
    120     if (!daemonmode)
    121         return;
    122     logfile = fopen(filename, "a");
    123     if (!logfile)
    124         return;
    125     fprintf(logfile, "%s\n", message);
    126     fclose(logfile);
    127 }
    128 
    129 /*
    130111 * Read one line of hostname/IP from file
    131112 * Returns 0 for each valid entry read, -1 at EOF
    132113 * Assumes all host names are lower case only
    133  * Hostnames with more than one label is not handled correctly.
     114 * Hostnames with more than one label are not handled correctly.
    134115 * Presently the dot is copied into name without
    135116 * converting to a length/string substring for that label.
    136117 */
    137 
    138 static int getfileentry(FILE * fp, struct dns_entry *s, int verb)
     118static int getfileentry(FILE * fp, struct dns_entry *s)
    139119{
    140120    unsigned int a,b,c,d;
    141     char *r, *name;
    142 
    143 restart:
    144     if(!(r = bb_get_line_from_file(fp)))
     121    char *line, *r, *name;
     122
     123 restart:
     124    line = r = xmalloc_fgets(fp);
     125    if (!r)
    145126        return -1;
    146     while(*r == ' ' || *r == '\t') {
     127    while (*r == ' ' || *r == '\t') {
    147128        r++;
    148         if(!*r || *r == '#' || *r == '\n')
     129        if (!*r || *r == '#' || *r == '\n') {
     130            free(line);
    149131            goto restart; /* skipping empty/blank and commented lines  */
     132        }
    150133    }
    151134    name = r;
    152     while(*r != ' ' && *r != '\t')
     135    while (*r != ' ' && *r != '\t')
    153136        r++;
    154     *r++ = 0;
    155     if(sscanf(r,"%u.%u.%u.%u",&a,&b,&c,&d) != 4)
    156             goto restart; /* skipping wrong lines */
    157 
    158     sprintf(s->ip,"%u.%u.%u.%u",a,b,c,d);
    159     sprintf(s->rip,".%u.%u.%u.%u",d,c,b,a);
     137    *r++ = '\0';
     138    if (sscanf(r, ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4) {
     139        free(line);
     140        goto restart; /* skipping wrong lines */
     141    }
     142
     143    sprintf(s->ip, ".%u.%u.%u.%u"+1, a, b, c, d);
     144    sprintf(s->rip, ".%u.%u.%u.%u", d, c, b, a);
    160145    undot((uint8_t*)s->rip);
    161     convname(s->name,(uint8_t*)name);
    162 
    163     if(verb)
    164         fprintf(stderr,"\tname:%s, ip:%s\n",&(s->name[1]),s->ip);
    165 
    166     return 0; /* warningkiller */
     146    convname(s->name, (uint8_t*)name);
     147
     148    if (OPT_verbose)
     149        fprintf(stderr, "\tname:%s, ip:%s\n", &(s->name[1]),s->ip);
     150
     151    free(line);
     152    return 0;
    167153}
    168154
     
    170156 * Read hostname/IP records from file
    171157 */
    172 static void dnsentryinit(int verb)
     158static void dnsentryinit(void)
    173159{
    174160    FILE *fp;
    175161    struct dns_entry *m, *prev;
     162
    176163    prev = dnsentry = NULL;
    177 
    178     fp = bb_xfopen(fileconf, "r");
     164    fp = xfopen(fileconf, "r");
    179165
    180166    while (1) {
    181         m = xmalloc(sizeof(struct dns_entry));
    182 
    183         m->next = NULL;
    184         if (getfileentry(fp, m, verb))
     167        m = xzalloc(sizeof(*m));
     168        /*m->next = NULL;*/
     169        if (getfileentry(fp, m))
    185170            break;
    186171
     
    194179}
    195180
    196 
    197 /*
    198  * Set up UDP socket
    199  */
    200 static int listen_socket(char *iface_addr, int listen_port)
    201 {
    202     struct sockaddr_in a;
    203     char msg[100];
    204     int s;
    205     int yes = 1;
    206     s = bb_xsocket(PF_INET, SOCK_DGRAM, 0);
    207 #ifdef SO_REUSEADDR
    208     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
    209         bb_perror_msg_and_die("setsockopt() failed");
    210 #endif
    211     memset(&a, 0, sizeof(a));
    212     a.sin_port = htons(listen_port);
    213     a.sin_family = AF_INET;
    214     if (!inet_aton(iface_addr, &a.sin_addr))
    215         bb_perror_msg_and_die("bad iface address");
    216     bb_xbind(s, (struct sockaddr *)&a, sizeof(a));
    217     listen(s, 50); /* bb_xlisten? */
    218     sprintf(msg, "accepting UDP packets on addr:port %s:%d\n",
    219         iface_addr, (int)listen_port);
    220     log_message(LOG_FILE, msg);
    221     return s;
    222 }
    223 
    224181/*
    225182 * Look query up in dns records and return answer if found
     
    231188    struct dns_entry *d = dnsentry;
    232189
    233     if(d) do {
    234 #ifdef DEBUG
    235         if(qs && d) {
    236             char *p,*q;
    237             q = (char *)&(qs[1]);
    238             p = &(d->name[1]);
    239             fprintf(stderr, "\n%s: %d/%d p:%s q:%s %d",
    240                 __FUNCTION__, strlen(p), (int)(d->name[0]),
    241                 p, q, strlen(q));
    242         }
     190    do {
     191#if DEBUG
     192        char *p,*q;
     193        q = (char *)&(qs[1]);
     194        p = &(d->name[1]);
     195        fprintf(stderr, "\n%s: %d/%d p:%s q:%s %d",
     196            __FUNCTION__, (int)strlen(p), (int)(d->name[0]),
     197            p, q, (int)strlen(q));
    243198#endif
    244         if (type == REQ_A) {            /* search by host name */
    245             for(i = 1; i <= (int)(d->name[0]); i++)
    246                 if(tolower(qs[i]) != d->name[i])
     199        if (type == REQ_A) { /* search by host name */
     200            for (i = 1; i <= (int)(d->name[0]); i++)
     201                if (tolower(qs[i]) != d->name[i])
    247202                    break;
    248             if(i > (int)(d->name[0])) {
    249 #ifdef DEBUG
    250                 fprintf(stderr, " OK");
    251 #endif
     203            if (i > (int)(d->name[0])) {
    252204                strcpy((char *)as, d->ip);
    253 #ifdef DEBUG
    254                 fprintf(stderr, " as:%s\n", as);
     205#if DEBUG
     206                fprintf(stderr, " OK as:%s\n", as);
    255207#endif
    256208                return 0;
    257209            }
    258         } else
    259         if (type == REQ_PTR) {          /* search by IP-address */
     210        } else if (type == REQ_PTR) { /* search by IP-address */
    260211            if (!strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) {
    261212                strcpy((char *)as, d->name);
     
    263214            }
    264215        }
    265     } while ((d = d->next) != NULL);
     216        d = d->next;
     217    } while (d);
    266218    return -1;
    267219}
     
    271223 * Decode message and generate answer
    272224 */
    273 #define eret(s) do { fprintf (stderr, "%s\n", s); return -1; } while (0)
    274225static int process_packet(uint8_t * buf)
    275226{
     
    286237
    287238    head = (struct dns_head *)buf;
    288     if (head->nquer == 0)
    289         eret("no queries");
    290 
    291     if ((head->flags & 0x8000))
    292         eret("ignoring response packet");
     239    if (head->nquer == 0) {
     240        bb_error_msg("no queries");
     241        return -1;
     242    }
     243
     244    if (head->flags & 0x8000) {
     245        bb_error_msg("ignoring response packet");
     246        return -1;
     247    }
    293248
    294249    from = (void *)&head[1];    //  start of query string
     
    317272
    318273    // We have a standard query
    319     log_message(LOG_FILE, (char *)from);
     274    bb_info_msg("%s", (char *)from);
    320275    lookup_result = table_lookup(type, answstr, (uint8_t*)from);
    321276    if (lookup_result != 0) {
     
    331286        memcpy(answstr, &a.s_addr, 4);  // save before a disappears
    332287        outr.rlen = 4;          // uint32_t IP
    333     }
    334     else
     288    } else
    335289        outr.rlen = strlen((char *)answstr) + 1;    // a host name
    336290    outr.r = answstr;           // 32 bit ip or a host name
     
    352306    next += outr.rlen;
    353307
    354 empty_packet:
     308 empty_packet:
     309
    355310    flags = ntohs(head->flags);
    356311    // clear rcode and RA, set responsebit and our new flags
     
    360315    head->nquer = htons(1);
    361316
    362     packet_len = next - (void *)buf;
     317    packet_len = (uint8_t *)next - buf;
    363318    return packet_len;
    364319}
     
    369324static void interrupt(int x)
    370325{
    371     unlink(LOCK_FILE);
    372     write(2, "interrupt exiting\n", 18);
     326    /* unlink("/var/run/dnsd.lock"); */
     327    bb_error_msg("interrupt, exiting\n");
    373328    exit(2);
    374329}
    375330
    376 
     331int dnsd_main(int argc, char **argv);
    377332int dnsd_main(int argc, char **argv)
    378333{
     334    const char *listen_interface = "0.0.0.0";
     335    char *sttl, *sport;
     336    len_and_sockaddr *lsa;
    379337    int udps;
    380338    uint16_t port = 53;
    381339    uint8_t buf[MAX_PACK_LEN];
    382     unsigned long flags = 0;
    383     char *listen_interface = "0.0.0.0";
    384     char *sttl=NULL, *sport=NULL;
    385 
    386     if(argc > 1)
    387         flags = bb_getopt_ulflags(argc, argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport);
    388     if(sttl)
    389         if(!(ttl = atol(sttl)))
    390             bb_show_usage();
    391     if(sport)
    392         if(!(port = atol(sport)))
    393             bb_show_usage();
    394 
    395     if(is_verbose()) {
    396         fprintf(stderr,"listen_interface: %s\n", listen_interface);
    397         fprintf(stderr,"ttl: %d, port: %d\n", ttl, port);
    398         fprintf(stderr,"fileconf: %s\n", fileconf);
    399     }
    400 
    401     if(is_daemon())
    402 #ifdef BB_NOMMU
    403         /* reexec for vfork() do continue parent */
    404         vfork_daemon_rexec(1, 0, argc, argv, "-d");
    405 #else
    406         bb_xdaemon(1, 0);
    407 #endif
    408 
    409     dnsentryinit(is_verbose());
     340
     341    getopt32(argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport);
     342    //if (option_mask32 & 0x1) // -i
     343    //if (option_mask32 & 0x2) // -c
     344    if (option_mask32 & 0x4) // -t
     345        ttl = xatou_range(sttl, 1, 0xffffffff);
     346    if (option_mask32 & 0x8) // -p
     347        port = xatou_range(sport, 1, 0xffff);
     348
     349    if (OPT_verbose) {
     350        bb_info_msg("listen_interface: %s", listen_interface);
     351        bb_info_msg("ttl: %d, port: %d", ttl, port);
     352        bb_info_msg("fileconf: %s", fileconf);
     353    }
     354
     355    if (OPT_daemon) {
     356        bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
     357        openlog(applet_name, LOG_PID, LOG_DAEMON);
     358        logmode = LOGMODE_SYSLOG;
     359    }
     360
     361    dnsentryinit();
    410362
    411363    signal(SIGINT, interrupt);
    412     signal(SIGPIPE, SIG_IGN);
     364    /* why? signal(SIGPIPE, SIG_IGN); */
    413365    signal(SIGHUP, SIG_IGN);
    414366#ifdef SIGTSTP
     
    419371#endif
    420372
    421     udps = listen_socket(listen_interface, port);
    422     if (udps < 0)
    423         exit(1);
     373    lsa = xdotted2sockaddr(listen_interface, port);
     374    udps = xsocket(lsa->sa.sa_family, SOCK_DGRAM, 0);
     375    xbind(udps, &lsa->sa, lsa->len);
     376    /* xlisten(udps, 50); - ?!! DGRAM sockets are never listened on I think? */
     377    bb_info_msg("Accepting UDP packets on %s",
     378            xmalloc_sockaddr2dotted(&lsa->sa));
    424379
    425380    while (1) {
    426         fd_set fdset;
    427381        int r;
    428 
    429         FD_ZERO(&fdset);
    430         FD_SET(udps, &fdset);
    431         // Block until a message arrives
    432         if((r = select(udps + 1, &fdset, NULL, NULL, NULL)) < 0)
    433             bb_perror_msg_and_die("select error");
    434         else
    435         if(r == 0)
    436             bb_perror_msg_and_die("select spurious return");
    437 
    438         /* Can this test ever be false? */
    439         if (FD_ISSET(udps, &fdset)) {
    440             struct sockaddr_in from;
    441             int fromlen = sizeof(from);
    442             r = recvfrom(udps, buf, sizeof(buf), 0,
    443                      (struct sockaddr *)&from,
    444                      (void *)&fromlen);
    445             if(is_verbose())
    446                 fprintf(stderr, "\n--- Got UDP size=%d ", r);
    447             log_message(LOG_FILE, "\n--- Got UDP ");
    448 
    449             if (r < 12 || r > 512) {
    450                 bb_error_msg("invalid packet size");
    451                 continue;
    452             }
    453             if (r > 0) {
    454                 r = process_packet(buf);
    455                 if (r > 0)
    456                     sendto(udps, buf,
    457                            r, 0, (struct sockaddr *)&from,
    458                            fromlen);
    459             }
    460         }       // end if
    461     }           // end while
     382        socklen_t fromlen = lsa->len;
     383// FIXME: need to get *DEST* address (to which of our addresses
     384// this query was directed), and reply from the same address.
     385// Or else we can exhibit usual UDP ugliness:
     386// [ip1.multihomed.ip2] <=  query to ip1  <= peer
     387// [ip1.multihomed.ip2] => reply from ip2 => peer (confused)
     388        r = recvfrom(udps, buf, sizeof(buf), 0, &lsa->sa, &fromlen);
     389        if (OPT_verbose)
     390            bb_info_msg("Got UDP packet");
     391        if (r < 12 || r > 512) {
     392            bb_error_msg("invalid packet size");
     393            continue;
     394        }
     395        r = process_packet(buf);
     396        if (r <= 0)
     397            continue;
     398        sendto(udps, buf, r, 0, &lsa->sa, fromlen);
     399    }
    462400    return 0;
    463401}
    464 
    465 
  • branches/stable/mindi-busybox/networking/ether-wake.c

    r821 r1770  
    6666
    6767
    68 #include <unistd.h>
    69 #include <stdlib.h>
    70 #include <stdio.h>
    71 #include <errno.h>
    72 #include <ctype.h>
    73 #include <string.h>
    74 
    75 #include <sys/socket.h>
    76 #include <sys/types.h>
    77 #include <sys/ioctl.h>
    78 #include <features.h>
    7968#include <netpacket/packet.h>
    8069#include <net/ethernet.h>
    81 #include <netdb.h>
    8270#include <netinet/ether.h>
    83 
    84 #ifdef __linux__
    8571#include <linux/if.h>
    86 #endif
    87 
    88 #include "busybox.h"
     72
     73#include "libbb.h"
    8974
    9075/* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to
     
    9479#ifdef PF_PACKET
    9580# define whereto_t sockaddr_ll
    96 # define make_socket() bb_xsocket(PF_PACKET, SOCK_RAW, 0)
     81# define make_socket() xsocket(PF_PACKET, SOCK_RAW, 0)
    9782#else
    9883# define whereto_t sockaddr
    99 # define make_socket() bb_xsocket(AF_INET, SOCK_PACKET, SOCK_PACKET)
     84# define make_socket() xsocket(AF_INET, SOCK_PACKET, SOCK_PACKET)
    10085#endif
    10186
     
    10893    for (i = 0; i < pktsize; ++i) {
    10994        printf("%2.2x ", outpack[i]);
    110         if (i % 20 == 19) printf("\n");
     95        if (i % 20 == 19) puts("");
    11196    }
    11297    printf("\n\n");
    11398}
    11499#else
    115 # define bb_debug_msg(fmt, args...)
    116 # define bb_debug_dump_packet(outpack, pktsize)
    117 #endif
    118 
    119 static inline void get_dest_addr(const char *arg, struct ether_addr *eaddr);
    120 static inline int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast);
    121 static inline int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd);
    122 
    123 int etherwake_main(int argc, char *argv[])
    124 {
    125     char *ifname = "eth0", *pass = NULL;
    126     unsigned long flags;
     100# define bb_debug_msg(fmt, args...)             ((void)0)
     101# define bb_debug_dump_packet(outpack, pktsize) ((void)0)
     102#endif
     103
     104/* Convert the host ID string to a MAC address.
     105 * The string may be a:
     106 *    Host name
     107 *    IP address string
     108 *    MAC address string
     109*/
     110static void get_dest_addr(const char *hostid, struct ether_addr *eaddr)
     111{
     112    struct ether_addr *eap;
     113
     114    eap = ether_aton(hostid);
     115    if (eap) {
     116        *eaddr = *eap;
     117        bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr));
     118#if !defined(__UCLIBC__)
     119    } else if (ether_hostton(hostid, eaddr) == 0) {
     120        bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));
     121#endif
     122    } else
     123        bb_show_usage();
     124}
     125
     126static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
     127{
     128    int i;
     129    unsigned char *station_addr = eaddr->ether_addr_octet;
     130
     131    memset(pkt, 0xff, 6);
     132    if (!broadcast)
     133        memcpy(pkt, station_addr, 6);
     134    pkt += 6;
     135
     136    memcpy(pkt, station_addr, 6); /* 6 */
     137    pkt += 6;
     138
     139    *pkt++ = 0x08; /* 12 */ /* Or 0x0806 for ARP, 0x8035 for RARP */
     140    *pkt++ = 0x42; /* 13 */
     141
     142    memset(pkt, 0xff, 6); /* 14 */
     143
     144    for (i = 0; i < 16; ++i) {
     145        pkt += 6;
     146        memcpy(pkt, station_addr, 6); /* 20,26,32,... */
     147    }
     148
     149    return 20 + 16*6; /* length of packet */
     150}
     151
     152static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)
     153{
     154    unsigned passwd[6];
     155    int byte_cnt, i;
     156
     157    /* handle MAC format */
     158    byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x",
     159                      &passwd[0], &passwd[1], &passwd[2],
     160                      &passwd[3], &passwd[4], &passwd[5]);
     161    /* handle IP format */
     162// FIXME: why < 4?? should it be < 6?
     163    if (byte_cnt < 4)
     164        byte_cnt = sscanf(ethoptarg, "%u.%u.%u.%u",
     165                          &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
     166    if (byte_cnt < 4) {
     167        bb_error_msg("cannot read Wake-On-LAN pass");
     168        return 0;
     169    }
     170// TODO: check invalid numbers >255??
     171    for (i = 0; i < byte_cnt; ++i)
     172        wol_passwd[i] = passwd[i];
     173
     174    bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n",
     175                 wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3],
     176                 byte_cnt);
     177
     178    return byte_cnt;
     179}
     180
     181int ether_wake_main(int argc, char **argv);
     182int ether_wake_main(int argc, char **argv)
     183{
     184    const char *ifname = "eth0";
     185    char *pass;
     186    unsigned flags;
    127187    unsigned char wol_passwd[6];
    128188    int wol_passwd_sz = 0;
    129 
    130189    int s;                      /* Raw socket */
    131190    int pktsize;
     
    136195
    137196    /* handle misc user options */
    138     flags = bb_getopt_ulflags(argc, argv, "bi:p:", &ifname, &pass);
    139     if (optind == argc)
    140         bb_show_usage();
    141     if (pass)
     197    opt_complementary = "=1";
     198    flags = getopt32(argv, "bi:p:", &ifname, &pass);
     199    if (flags & 4) /* -p */
    142200        wol_passwd_sz = get_wol_pw(pass, wol_passwd);
     201    flags &= 1; /* we further interested only in -b [bcast] flag */
    143202
    144203    /* create the raw socket */
     
    146205
    147206    /* now that we have a raw socket we can drop root */
    148     xsetuid(getuid());
     207    /* xsetuid(getuid()); - but save on code size... */
    149208
    150209    /* look up the dest mac address */
     
    152211
    153212    /* fill out the header of the packet */
    154     pktsize = get_fill(outpack, &eaddr, flags /*& 1 [OPT_BROADCAST]*/);
     213    pktsize = get_fill(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */);
    155214
    156215    bb_debug_dump_packet(outpack, pktsize);
     
    161220        struct ifreq if_hwaddr;
    162221
    163         strcpy(if_hwaddr.ifr_name, ifname);
    164         if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0)
    165             bb_perror_msg_and_die("SIOCGIFHWADDR on %s failed", ifname);
     222        strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name));
     223        ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname);
    166224
    167225        memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6);
     
    190248
    191249    /* This is necessary for broadcasts to work */
    192     if (flags /*& 1 [OPT_BROADCAST]*/) {
    193         int one = 1;
    194         if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(one)) < 0)
     250    if (flags /* & 1 OPT_BROADCAST */) {
     251        if (setsockopt_broadcast(s) != 0)
    195252            bb_perror_msg("SO_BROADCAST");
    196253    }
     
    200257        struct ifreq ifr;
    201258        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    202         if (ioctl(s, SIOCGIFINDEX, &ifr) == -1)
    203             bb_perror_msg_and_die("SIOCGIFINDEX");
     259        xioctl(s, SIOCGIFINDEX, &ifr);
    204260        memset(&whereto, 0, sizeof(whereto));
    205261        whereto.sll_family = AF_PACKET;
     
    214270    strcpy(whereto.sa_data, ifname);
    215271#endif
    216 
    217     if (sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto, sizeof(whereto)) < 0)
    218         bb_perror_msg(bb_msg_write_error);
    219 
    220     close(s);
    221 
     272    xsendto(s, outpack, pktsize, (struct sockaddr *)&whereto, sizeof(whereto));
     273    if (ENABLE_FEATURE_CLEAN_UP)
     274        close(s);
    222275    return EXIT_SUCCESS;
    223276}
    224 
    225 /* Convert the host ID string to a MAC address.
    226  * The string may be a:
    227  *    Host name
    228  *    IP address string
    229  *    MAC address string
    230 */
    231 static inline void get_dest_addr(const char *hostid, struct ether_addr *eaddr)
    232 {
    233     struct ether_addr *eap;
    234 
    235     eap = ether_aton(hostid);
    236     if (eap) {
    237         *eaddr = *eap;
    238         bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr));
    239 #if !defined(__UCLIBC__)
    240     } else if (ether_hostton(hostid, eaddr) == 0) {
    241         bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));
    242 #else
    243 # warning Need to implement ether_hostton() for uClibc
    244 #endif
    245     } else
    246         bb_show_usage();
    247 }
    248 
    249 static inline int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
    250 {
    251     int offset, i;
    252     unsigned char *station_addr = eaddr->ether_addr_octet;
    253 
    254     if (broadcast)
    255         memset(pkt+0, 0xff, 6);
    256     else
    257         memcpy(pkt, station_addr, 6);
    258     memcpy(pkt+6, station_addr, 6);
    259     pkt[12] = 0x08;             /* Or 0x0806 for ARP, 0x8035 for RARP */
    260     pkt[13] = 0x42;
    261     offset = 14;
    262 
    263     memset(pkt+offset, 0xff, 6);
    264     offset += 6;
    265 
    266     for (i = 0; i < 16; ++i) {
    267         memcpy(pkt+offset, station_addr, 6);
    268         offset += 6;
    269     }
    270 
    271     return offset;
    272 }
    273 
    274 static inline int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)
    275 {
    276     int passwd[6];
    277     int byte_cnt, i;
    278 
    279     /* handle MAC format */
    280     byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x",
    281                       &passwd[0], &passwd[1], &passwd[2],
    282                       &passwd[3], &passwd[4], &passwd[5]);
    283     /* handle IP format */
    284     if (byte_cnt < 4)
    285         byte_cnt = sscanf(ethoptarg, "%d.%d.%d.%d",
    286                           &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
    287     if (byte_cnt < 4) {
    288         bb_error_msg("Unable to read the Wake-On-LAN pass");
    289         return 0;
    290     }
    291 
    292     for (i = 0; i < byte_cnt; ++i)
    293         wol_passwd[i] = passwd[i];
    294 
    295     bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n",
    296                  wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3],
    297                  byte_cnt);
    298 
    299     return byte_cnt;
    300 }
  • branches/stable/mindi-busybox/networking/ftpgetput.c

    r821 r1770  
    1414 */
    1515
    16 #include <sys/ioctl.h>
    17 
    18 #include <ctype.h>
    19 #include <errno.h>
    20 #include <fcntl.h>
    2116#include <getopt.h>
    22 #include <signal.h>
    23 #include <string.h>
    24 #include <unistd.h>
    25 
    26 #include <sys/socket.h>
    27 
    28 #include "busybox.h"
     17#include "libbb.h"
    2918
    3019typedef struct ftp_host_info_s {
    31     char *user;
    32     char *password;
    33     struct sockaddr_in *s_in;
     20    const char *user;
     21    const char *password;
     22    struct len_and_sockaddr *lsa;
    3423} ftp_host_info_t;
    3524
    36 static char verbose_flag = 0;
    37 static char do_continue = 0;
     25static smallint verbose_flag;
     26static smallint do_continue;
     27
     28static void ftp_die(const char *msg, const char *remote) ATTRIBUTE_NORETURN;
     29static void ftp_die(const char *msg, const char *remote)
     30{
     31    /* Guard against garbage from remote server */
     32    const char *cp = remote;
     33    while (*cp >= ' ' && *cp < '\x7f') cp++;
     34    bb_error_msg_and_die("unexpected server response%s%s: %.*s",
     35            msg ? " to " : "", msg ? msg : "",
     36            (int)(cp - remote), remote);
     37}
     38
    3839
    3940static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
    4041{
     42    unsigned n;
    4143    if (verbose_flag) {
    42         bb_error_msg("cmd %s%s", s1, s2);
     44        bb_error_msg("cmd %s %s", s1, s2);
    4345    }
    4446
    4547    if (s1) {
    4648        if (s2) {
    47             fprintf(stream, "%s%s\r\n", s1, s2);
     49            fprintf(stream, "%s %s\r\n", s1, s2);
    4850        } else {
    4951            fprintf(stream, "%s\r\n", s1);
     
    5456
    5557        if (fgets(buf, 510, stream) == NULL) {
    56             bb_perror_msg_and_die("fgets()");
     58            bb_perror_msg_and_die("fgets");
    5759        }
    5860        buf_ptr = strstr(buf, "\r\n");
     
    6062            *buf_ptr = '\0';
    6163        }
    62     } while (! isdigit(buf[0]) || buf[3] != ' ');
    63 
    64     return atoi(buf);
    65 }
    66 
    67 static int xconnect_ftpdata(ftp_host_info_t *server, const char *buf)
     64    } while (!isdigit(buf[0]) || buf[3] != ' ');
     65
     66    buf[3] = '\0';
     67    n = xatou(buf);
     68    buf[3] = ' ';
     69    return n;
     70}
     71
     72static int xconnect_ftpdata(ftp_host_info_t *server, char *buf)
    6873{
    6974    char *buf_ptr;
    7075    unsigned short port_num;
    7176
     77    /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]
     78     * Server's IP is N1.N2.N3.N4 (we ignore it)
     79     * Server's port for data connection is P1*256+P2 */
     80    buf_ptr = strrchr(buf, ')');
     81    if (buf_ptr) *buf_ptr = '\0';
     82
    7283    buf_ptr = strrchr(buf, ',');
    7384    *buf_ptr = '\0';
    74     port_num = atoi(buf_ptr + 1);
     85    port_num = xatoul_range(buf_ptr + 1, 0, 255);
    7586
    7687    buf_ptr = strrchr(buf, ',');
    7788    *buf_ptr = '\0';
    78     port_num += atoi(buf_ptr + 1) * 256;
    79 
    80     server->s_in->sin_port=htons(port_num);
    81     return(xconnect(server->s_in));
     89    port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
     90
     91    set_nport(server->lsa, htons(port_num));
     92    return xconnect_stream(server->lsa);
    8293}
    8394
     
    8899
    89100    /* Connect to the command socket */
    90     control_stream = fdopen(xconnect(server->s_in), "r+");
     101    control_stream = fdopen(xconnect_stream(server->lsa), "r+");
    91102    if (control_stream == NULL) {
    92         bb_perror_msg_and_die("Couldnt open control stream");
     103        /* fdopen failed - extremely unlikely */
     104        bb_perror_nomsg_and_die();
    93105    }
    94106
    95107    if (ftpcmd(NULL, NULL, control_stream, buf) != 220) {
    96         bb_error_msg_and_die("%s", buf + 4);
     108        ftp_die(NULL, buf);
    97109    }
    98110
    99111    /*  Login to the server */
    100     switch (ftpcmd("USER ", server->user, control_stream, buf)) {
     112    switch (ftpcmd("USER", server->user, control_stream, buf)) {
    101113    case 230:
    102114        break;
    103115    case 331:
    104         if (ftpcmd("PASS ", server->password, control_stream, buf) != 230) {
    105             bb_error_msg_and_die("PASS error: %s", buf + 4);
     116        if (ftpcmd("PASS", server->password, control_stream, buf) != 230) {
     117            ftp_die("PASS", buf);
    106118        }
    107119        break;
    108120    default:
    109         bb_error_msg_and_die("USER error: %s", buf + 4);
     121        ftp_die("USER", buf);
    110122    }
    111123
    112124    ftpcmd("TYPE I", NULL, control_stream, buf);
    113125
    114     return(control_stream);
     126    return control_stream;
    115127}
    116128
    117129#if !ENABLE_FTPGET
    118 #define ftp_receive 0
     130int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
     131        const char *local_path, char *server_path);
    119132#else
    120 static int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
     133static
     134int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
    121135        const char *local_path, char *server_path)
    122136{
    123137    char buf[512];
    124     off_t filesize = 0;
     138/* I think 'filesize' usage here is bogus. Let's see... */
     139    //off_t filesize = -1;
     140#define filesize ((off_t)-1)
    125141    int fd_data;
    126142    int fd_local = -1;
     
    129145    /* Connect to the data socket */
    130146    if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
    131         bb_error_msg_and_die("PASV error: %s", buf + 4);
     147        ftp_die("PASV", buf);
    132148    }
    133149    fd_data = xconnect_ftpdata(server, buf);
    134150
    135     if (ftpcmd("SIZE ", server_path, control_stream, buf) == 213) {
    136         unsigned long value=filesize;
    137         if (safe_strtoul(buf + 4, &value))
    138             bb_error_msg_and_die("SIZE error: %s", buf + 4);
    139         filesize = value;
     151    if (ftpcmd("SIZE", server_path, control_stream, buf) == 213) {
     152        //filesize = BB_STRTOOFF(buf + 4, NULL, 10);
     153        //if (errno || filesize < 0)
     154        //  ftp_die("SIZE", buf);
    140155    } else {
    141         filesize = -1;
    142156        do_continue = 0;
    143157    }
    144158
    145     if ((local_path[0] == '-') && (local_path[1] == '\0')) {
     159    if (LONE_DASH(local_path)) {
    146160        fd_local = STDOUT_FILENO;
    147161        do_continue = 0;
     
    151165        struct stat sbuf;
    152166        if (lstat(local_path, &sbuf) < 0) {
    153             bb_perror_msg_and_die("fstat()");
     167            bb_perror_msg_and_die("lstat");
    154168        }
    155169        if (sbuf.st_size > 0) {
     
    161175
    162176    if (do_continue) {
    163         sprintf(buf, "REST %ld", (long)beg_range);
     177        sprintf(buf, "REST %"OFF_FMT"d", beg_range);
    164178        if (ftpcmd(buf, NULL, control_stream, buf) != 350) {
    165179            do_continue = 0;
    166180        } else {
    167             filesize -= beg_range;
    168         }
    169     }
    170 
    171     if (ftpcmd("RETR ", server_path, control_stream, buf) > 150) {
    172         bb_error_msg_and_die("RETR error: %s", buf + 4);
     181            //if (filesize != -1)
     182            //  filesize -= beg_range;
     183        }
     184    }
     185
     186    if (ftpcmd("RETR", server_path, control_stream, buf) > 150) {
     187        ftp_die("RETR", buf);
    173188    }
    174189
     
    176191    if (fd_local == -1) {
    177192        if (do_continue) {
    178             fd_local = bb_xopen(local_path, O_APPEND | O_WRONLY);
     193            fd_local = xopen(local_path, O_APPEND | O_WRONLY);
    179194        } else {
    180             fd_local = bb_xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY);
     195            fd_local = xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY);
    181196        }
    182197    }
     
    184199    /* Copy the file */
    185200    if (filesize != -1) {
    186         if (-1 == bb_copyfd_size(fd_data, fd_local, filesize))
    187             exit(EXIT_FAILURE);
     201        if (bb_copyfd_size(fd_data, fd_local, filesize) == -1)
     202            return EXIT_FAILURE;
    188203    } else {
    189         if (-1 == bb_copyfd_eof(fd_data, fd_local))
    190             exit(EXIT_FAILURE);
     204        if (bb_copyfd_eof(fd_data, fd_local) == -1)
     205            return EXIT_FAILURE;
    191206    }
    192207
     
    194209    close(fd_data);
    195210    if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
    196         bb_error_msg_and_die("ftp error: %s", buf + 4);
     211        ftp_die(NULL, buf);
    197212    }
    198213    ftpcmd("QUIT", NULL, control_stream, buf);
    199214
    200     return(EXIT_SUCCESS);
     215    return EXIT_SUCCESS;
    201216}
    202217#endif
    203218
    204219#if !ENABLE_FTPPUT
    205 #define ftp_send 0
     220int ftp_send(ftp_host_info_t *server, FILE *control_stream,
     221        const char *server_path, char *local_path);
    206222#else
    207 static int ftp_send(ftp_host_info_t *server, FILE *control_stream,
     223static
     224int ftp_send(ftp_host_info_t *server, FILE *control_stream,
    208225        const char *server_path, char *local_path)
    209226{
     
    216233    /*  Connect to the data socket */
    217234    if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
    218         bb_error_msg_and_die("PASV error: %s", buf + 4);
     235        ftp_die("PASV", buf);
    219236    }
    220237    fd_data = xconnect_ftpdata(server, buf);
    221238
    222239    /* get the local file */
    223     if ((local_path[0] == '-') && (local_path[1] == '\0')) {
    224         fd_local = STDIN_FILENO;
    225     } else {
    226         fd_local = bb_xopen(local_path, O_RDONLY);
     240    fd_local = STDIN_FILENO;
     241    if (NOT_LONE_DASH(local_path)) {
     242        fd_local = xopen(local_path, O_RDONLY);
    227243        fstat(fd_local, &sbuf);
    228244
    229         sprintf(buf, "ALLO %lu", (unsigned long)sbuf.st_size);
     245        sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size);
    230246        response = ftpcmd(buf, NULL, control_stream, buf);
    231247        switch (response) {
     
    235251        default:
    236252            close(fd_local);
    237             bb_error_msg_and_die("ALLO error: %s", buf + 4);
     253            ftp_die("ALLO", buf);
    238254            break;
    239255        }
    240256    }
    241     response = ftpcmd("STOR ", server_path, control_stream, buf);
     257    response = ftpcmd("STOR", server_path, control_stream, buf);
    242258    switch (response) {
    243259    case 125:
     
    246262    default:
    247263        close(fd_local);
    248         bb_error_msg_and_die("STOR error: %s", buf + 4);
     264        ftp_die("STOR", buf);
    249265    }
    250266
     
    257273    close(fd_data);
    258274    if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
    259         bb_error_msg_and_die("error: %s", buf + 4);
     275        ftp_die("close", buf);
    260276    }
    261277    ftpcmd("QUIT", NULL, control_stream, buf);
    262278
    263     return(EXIT_SUCCESS);
     279    return EXIT_SUCCESS;
    264280}
    265281#endif
     
    272288
    273289#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
    274 static const struct option ftpgetput_long_options[] = {
    275     {"continue", 1, NULL, 'c'},
    276     {"verbose", 0, NULL, 'v'},
    277     {"username", 1, NULL, 'u'},
    278     {"password", 1, NULL, 'p'},
    279     {"port", 1, NULL, 'P'},
    280     {0, 0, 0, 0}
    281 };
    282 #else
    283 #define ftpgetput_long_options 0
    284 #endif
    285 
     290static const char ftpgetput_longopts[] ALIGN1 =
     291    "continue\0" Required_argument "c"
     292    "verbose\0"  No_argument       "v"
     293    "username\0" Required_argument "u"
     294    "password\0" Required_argument "p"
     295    "port\0"     Required_argument "P"
     296    ;
     297#endif
     298
     299int ftpgetput_main(int argc, char **argv);
    286300int ftpgetput_main(int argc, char **argv)
    287301{
    288302    /* content-length of the file */
    289     unsigned long opt;
    290     char *port = "ftp";
    291 
     303    unsigned opt;
     304    const char *port = "ftp";
    292305    /* socket to ftp server */
    293306    FILE *control_stream;
    294     struct sockaddr_in s_in;
    295 
    296     /* continue a prev transfer (-c) */
     307    /* continue previous transfer (-c) */
    297308    ftp_host_info_t *server;
    298309
    299     int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = NULL;
    300 
     310#if ENABLE_FTPPUT && !ENABLE_FTPGET
     311# define ftp_action ftp_send
     312#elif ENABLE_FTPGET && !ENABLE_FTPPUT
     313# define ftp_action ftp_receive
     314#else
     315    int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = ftp_send;
    301316    /* Check to see if the command is ftpget or ftput */
    302     if (ENABLE_FTPPUT && (!ENABLE_FTPGET || bb_applet_name[3] == 'p')) {
    303         ftp_action = ftp_send;
    304     }
    305     if (ENABLE_FTPGET && (!ENABLE_FTPPUT || bb_applet_name[3] == 'g')) {
     317    if (applet_name[3] == 'g') {
    306318        ftp_action = ftp_receive;
    307319    }
     320#endif
    308321
    309322    /* Set default values */
    310     server = xmalloc(sizeof(ftp_host_info_t));
     323    server = xmalloc(sizeof(*server));
    311324    server->user = "anonymous";
    312325    server->password = "busybox@";
    313     verbose_flag = 0;
    314326
    315327    /*
    316328     * Decipher the command line
    317329     */
    318     if (ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS)
    319         bb_applet_long_options = ftpgetput_long_options;
    320 
    321     opt = bb_getopt_ulflags(argc, argv, "cvu:p:P:", &server->user, &server->password, &port);
     330#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
     331    applet_long_options = ftpgetput_longopts;
     332#endif
     333    opt_complementary = "=3"; /* must have 3 params */
     334    opt = getopt32(argv, "cvu:p:P:", &server->user, &server->password, &port);
     335    argv += optind;
    322336
    323337    /* Process the non-option command line arguments */
    324     if (argc - optind != 3) {
    325         bb_show_usage();
    326     }
    327 
    328338    if (opt & FTPGETPUT_OPT_CONTINUE) {
    329339        do_continue = 1;
     
    336346     * sites (i.e. ftp.us.debian.org) use round-robin DNS
    337347     * and we want to connect to only one IP... */
    338     server->s_in = &s_in;
    339     bb_lookup_host(&s_in, argv[optind]);
    340     s_in.sin_port = bb_lookup_port(port, "tcp", 21);
     348    server->lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
    341349    if (verbose_flag) {
    342         printf("Connecting to %s[%s]:%d\n",
    343                 argv[optind], inet_ntoa(s_in.sin_addr), ntohs(s_in.sin_port));
     350        printf("Connecting to %s (%s)\n", argv[0],
     351            xmalloc_sockaddr2dotted(&server->lsa->sa));
    344352    }
    345353
     
    347355    control_stream = ftp_login(server);
    348356
    349     return(ftp_action(server, control_stream, argv[optind + 1], argv[optind + 2]));
    350 }
     357    return ftp_action(server, control_stream, argv[1], argv[2]);
     358}
  • branches/stable/mindi-busybox/networking/hostname.c

    r821 r1770  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * $Id: hostname.c,v 1.36 2003/07/14 21:21:01 andersen Exp $
    43 * Mini hostname implementation for busybox
    54 *
     
    98 * use of long options and GNU getopt.  Improved the usage info.
    109 *
    11  * This program is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 2 of the License, or
    14  * (at your option) any later version.
     10 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    1511 *
    16  * This program is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    19  * General Public License for more details.
    20  *
    21  * You should have received a copy of the GNU General Public License
    22  * along with this program; if not, write to the Free Software
    23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     12 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    2413 */
    2514
    26 #include <errno.h>
    27 #include <arpa/inet.h>
    28 #include <netdb.h>
    29 #include <unistd.h>
    30 #include <string.h>
    31 #include <stdio.h>
    32 #include <stdlib.h>
    33 #include <getopt.h>
    34 #include "busybox.h"
    35 
    36 extern char *optarg; /* in unistd.h */
    37 extern int  optind, opterr, optopt; /* in unistd.h */
     15#include "libbb.h"
    3816
    3917static void do_sethostname(char *s, int isfile)
    4018{
    4119    FILE *f;
    42     char buf[255];
    4320
    4421    if (!s)
     
    4724        if (sethostname(s, strlen(s)) < 0) {
    4825            if (errno == EPERM)
    49                 bb_error_msg_and_die("you must be root to change the hostname");
     26                bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
    5027            else
    5128                bb_perror_msg_and_die("sethostname");
    5229        }
    5330    } else {
    54         f = bb_xfopen(s, "r");
    55         while (fgets(buf, 255, f) != NULL) {
    56             if (buf[0] =='#') {
     31        f = xfopen(s, "r");
     32#define strbuf bb_common_bufsiz1
     33        while (fgets(strbuf, sizeof(strbuf), f) != NULL) {
     34            if (strbuf[0] == '#') {
    5735                continue;
    5836            }
    59             chomp(buf);
    60             do_sethostname(buf, 0);
     37            chomp(strbuf);
     38            do_sethostname(strbuf, 0);
    6139        }
    62 #ifdef CONFIG_FEATURE_CLEAN_UP
    63         fclose(f);
    64 #endif
     40        if (ENABLE_FEATURE_CLEAN_UP)
     41            fclose(f);
    6542    }
    6643}
    6744
     45int hostname_main(int argc, char **argv);
    6846int hostname_main(int argc, char **argv)
    6947{
    70     int opt;
    71     int type = 0;
    72     struct hostent *hp;
    73     char *filename = NULL;
    74     char buf[255];
    75     char *p = NULL;
     48    enum {
     49        OPT_d = 0x1,
     50        OPT_f = 0x2,
     51        OPT_i = 0x4,
     52        OPT_s = 0x8,
     53        OPT_F = 0x10,
     54        OPT_dfis = 0xf,
     55    };
     56
     57    char buf[256];
     58    char *hostname_str;
    7659
    7760    if (argc < 1)
    7861        bb_show_usage();
    7962
    80     while ((opt = getopt(argc, argv, "dfisF:")) > 0) {
    81         switch (opt) {
    82         case 'd':
    83         case 'f':
    84         case 'i':
    85         case 's':
    86             type = opt;
    87             break;
    88         case 'F':
    89             filename = optarg;
    90             break;
    91         default:
    92             bb_show_usage();
    93         }
    94     }
     63    getopt32(argv, "dfisF:", &hostname_str);
    9564
    9665    /* Output in desired format */
    97     if (type != 0) {
    98         gethostname(buf, 255);
     66    if (option_mask32 & OPT_dfis) {
     67        struct hostent *hp;
     68        char *p;
     69        gethostname(buf, sizeof(buf));
    9970        hp = xgethostbyname(buf);
    10071        p = strchr(hp->h_name, '.');
    101         if (type == 'f') {
     72        if (option_mask32 & OPT_f) {
    10273            puts(hp->h_name);
    103         } else if (type == 's') {
     74        } else if (option_mask32 & OPT_s) {
    10475            if (p != NULL) {
    105                 *p = 0;
     76                *p = '\0';
    10677            }
    10778            puts(hp->h_name);
    108         } else if (type == 'd') {
    109             if (p) puts(p + 1);
    110         } else if (type == 'i') {
     79        } else if (option_mask32 & OPT_d) {
     80            if (p)
     81                puts(p + 1);
     82        } else if (option_mask32 & OPT_i) {
    11183            while (hp->h_addr_list[0]) {
    11284                printf("%s ", inet_ntoa(*(struct in_addr *) (*hp->h_addr_list++)));
    11385            }
    114             printf("\n");
     86            puts("");
    11587        }
    11688    }
    11789    /* Set the hostname */
    118     else if (filename != NULL) {
    119         do_sethostname(filename, 1);
     90    else if (option_mask32 & OPT_F) {
     91        do_sethostname(hostname_str, 1);
    12092    } else if (optind < argc) {
    12193        do_sethostname(argv[optind], 0);
     
    12395    /* Or if all else fails,
    12496     * just print the current hostname */
    125      else {
    126         gethostname(buf, 255);
     97    else {
     98        gethostname(buf, sizeof(buf));
    12799        puts(buf);
    128100    }
    129     return(0);
     101    return 0;
    130102}
  • branches/stable/mindi-busybox/networking/httpd.c

    r902 r1770  
    2121 *
    2222 *
    23  * When a url contains "cgi-bin" it is assumed to be a cgi script.  The
     23 * When a url starts by "/cgi-bin/" it is assumed to be a cgi script.  The
    2424 * server changes directory to the location of the script and executes it
    2525 * after setting QUERY_STRING and other environment variables.
     26 *
     27 * Doc:
     28 * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html
    2629 *
    2730 * The server can also be invoked as a url arg decoder and html text encoder
     
    4043 * A:127.0.0.1       # Allow local loopback connections
    4144 * D:*               # Deny from other IP connections
     45 * E404:/path/e404.html # /path/e404.html is the 404 (not found) error page
    4246 * /cgi-bin:foo:bar  # Require user foo, pwd bar on urls starting with /cgi-bin/
    4347 * /adm:admin:setup  # Require user admin, pwd setup on urls starting with /adm/
     
    8286 * result, the subdir settings only have a lifetime of a single request.
    8387 *
     88 * Custom error pages can contain an absolute path or be relative to
     89 * 'home_httpd'. Error pages are to be static files (no CGI or script). Error
     90 * page can only be defined in the root configuration file and are not taken
     91 * into account in local (directories) config files.
    8492 *
    8593 * If -c is not set, an attempt will be made to open the default
     
    8795 * server exits with an error.
    8896 *
    89 */
    90 
    91 
    92 #include <stdio.h>
    93 #include <ctype.h>         /* for isspace           */
    94 #include <string.h>
    95 #include <stdlib.h>        /* for malloc            */
    96 #include <time.h>
    97 #include <unistd.h>        /* for close             */
    98 #include <signal.h>
    99 #include <sys/types.h>
    100 #include <sys/socket.h>    /* for connect and socket*/
    101 #include <netinet/in.h>    /* for sockaddr_in       */
    102 #include <sys/stat.h>
    103 #include <sys/wait.h>
    104 #include <fcntl.h>         /* for open modes        */
    105 #include "busybox.h"
    106 
    107 
    108 static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004";
    109 static const char default_path_httpd_conf[] = "/etc";
    110 static const char httpd_conf[] = "httpd.conf";
    111 static const char home[] = "./";
    112 
    113 #ifdef CONFIG_LFS
    114 # define cont_l_fmt "%lld"
    115 # define cont_l_type (long long)
    116 #else
    117 # define cont_l_fmt "%ld"
    118 # define cont_l_type (long)
    119 #endif
    120 
    121 #define TIMEOUT 60
    122 
    123 // Note: busybox xfuncs are not used because we want the server to keep running
    124 //       if something bad happens due to a malformed user request.
    125 //       As a result, all memory allocation after daemonize
    126 //       is checked rigorously
     97 */
     98
     99#include "libbb.h"
     100#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
     101#include <sys/sendfile.h>
     102#endif
    127103
    128104//#define DEBUG 1
    129 
    130 #ifndef DEBUG
    131 # define DEBUG 0
    132 #endif
    133 
    134 #define MAX_MEMORY_BUFF 8192    /* IO buffer */
    135 
    136 typedef struct HT_ACCESS {
     105#define DEBUG 0
     106
     107/* amount of buffering in a pipe */
     108#ifndef PIPE_BUF
     109# define PIPE_BUF 4096
     110#endif
     111
     112#define IOBUF_SIZE 8192    /* IO buffer */
     113
     114#define HEADER_READ_TIMEOUT 60
     115
     116static const char default_path_httpd_conf[] ALIGN1 = "/etc";
     117static const char httpd_conf[] ALIGN1 = "httpd.conf";
     118static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n";
     119
     120typedef struct has_next_ptr {
     121    struct has_next_ptr *next;
     122} has_next_ptr;
     123
     124/* Must have "next" as a first member */
     125typedef struct Htaccess {
     126    struct Htaccess *next;
    137127    char *after_colon;
    138     struct HT_ACCESS *next;
    139     char before_colon[1];         /* really bigger, must last */
     128    char before_colon[1];  /* really bigger, must be last */
    140129} Htaccess;
    141130
    142 typedef struct HT_ACCESS_IP {
    143     unsigned int ip;
    144     unsigned int mask;
     131/* Must have "next" as a first member */
     132typedef struct Htaccess_IP {
     133    struct Htaccess_IP *next;
     134    unsigned ip;
     135    unsigned mask;
    145136    int allow_deny;
    146     struct HT_ACCESS_IP *next;
    147137} Htaccess_IP;
    148138
    149 typedef struct
    150 {
    151   char buf[MAX_MEMORY_BUFF];
    152 
    153   USE_FEATURE_HTTPD_BASIC_AUTH(const char *realm;)
    154   USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
    155 
    156   const char *query;
    157 
    158   USE_FEATURE_HTTPD_CGI(char *referer;)
    159 
    160   const char *configFile;
    161 
    162   unsigned int rmt_ip;
    163 #if defined(CONFIG_FEATURE_HTTPD_CGI) || DEBUG
    164   char rmt_ip_str[16];     /* for set env REMOTE_ADDR */
    165 #endif
    166   unsigned port;           /* server initial port and for
    167                   set env REMOTE_PORT */
    168   union HTTPD_FOUND {
     139enum {
     140    HTTP_OK = 200,
     141    HTTP_MOVED_TEMPORARILY = 302,
     142    HTTP_BAD_REQUEST = 400,       /* malformed syntax */
     143    HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */
     144    HTTP_NOT_FOUND = 404,
     145    HTTP_FORBIDDEN = 403,
     146    HTTP_REQUEST_TIMEOUT = 408,
     147    HTTP_NOT_IMPLEMENTED = 501,   /* used for unrecognized requests */
     148    HTTP_INTERNAL_SERVER_ERROR = 500,
     149    HTTP_CONTINUE = 100,
     150#if 0   /* future use */
     151    HTTP_SWITCHING_PROTOCOLS = 101,
     152    HTTP_CREATED = 201,
     153    HTTP_ACCEPTED = 202,
     154    HTTP_NON_AUTHORITATIVE_INFO = 203,
     155    HTTP_NO_CONTENT = 204,
     156    HTTP_MULTIPLE_CHOICES = 300,
     157    HTTP_MOVED_PERMANENTLY = 301,
     158    HTTP_NOT_MODIFIED = 304,
     159    HTTP_PAYMENT_REQUIRED = 402,
     160    HTTP_BAD_GATEWAY = 502,
     161    HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */
     162    HTTP_RESPONSE_SETSIZE = 0xffffffff
     163#endif
     164};
     165
     166static const uint16_t http_response_type[] ALIGN2 = {
     167    HTTP_OK,
     168    HTTP_MOVED_TEMPORARILY,
     169    HTTP_REQUEST_TIMEOUT,
     170    HTTP_NOT_IMPLEMENTED,
     171#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     172    HTTP_UNAUTHORIZED,
     173#endif
     174    HTTP_NOT_FOUND,
     175    HTTP_BAD_REQUEST,
     176    HTTP_FORBIDDEN,
     177    HTTP_INTERNAL_SERVER_ERROR,
     178#if 0   /* not implemented */
     179    HTTP_CREATED,
     180    HTTP_ACCEPTED,
     181    HTTP_NO_CONTENT,
     182    HTTP_MULTIPLE_CHOICES,
     183    HTTP_MOVED_PERMANENTLY,
     184    HTTP_NOT_MODIFIED,
     185    HTTP_BAD_GATEWAY,
     186    HTTP_SERVICE_UNAVAILABLE,
     187#endif
     188};
     189
     190static const struct {
     191    const char *name;
     192    const char *info;
     193} http_response[ARRAY_SIZE(http_response_type)] = {
     194    { "OK", NULL },
     195    { "Found", "Directories must end with a slash" }, /* ?? */
     196    { "Request Timeout", "No request appeared within 60 seconds" },
     197    { "Not Implemented", "The requested method is not recognized" },
     198#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     199    { "Unauthorized", "" },
     200#endif
     201    { "Not Found", "The requested URL was not found" },
     202    { "Bad Request", "Unsupported method" },
     203    { "Forbidden", ""  },
     204    { "Internal Server Error", "Internal Server Error" },
     205#if 0   /* not implemented */
     206    { "Created" },
     207    { "Accepted" },
     208    { "No Content" },
     209    { "Multiple Choices" },
     210    { "Moved Permanently" },
     211    { "Not Modified" },
     212    { "Bad Gateway", "" },
     213    { "Service Unavailable", "" },
     214#endif
     215};
     216
     217struct globals {
     218    int verbose;            /* must be int (used by getopt32) */
     219    smallint flg_deny_all;
     220
     221    unsigned rmt_ip;    /* used for IP-based allow/deny rules */
     222    time_t last_mod;
     223    off_t ContentLength;    /* -1 - unknown */
     224    char *rmt_ip_str;       /* for $REMOTE_ADDR and $REMOTE_PORT */
     225    const char *bind_addr_or_port;
     226
     227    const char *g_query;
     228    const char *configFile;
     229    const char *home_httpd;
     230
    169231    const char *found_mime_type;
    170232    const char *found_moved_temporarily;
    171   } httpd_found;
    172 
    173   off_t ContentLength;          /* -1 - unknown */
    174   time_t last_mod;
    175 
    176   Htaccess_IP *ip_a_d;          /* config allow/deny lines */
    177   int flg_deny_all;
    178 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    179   Htaccess *auth;               /* config user:password lines */
    180 #endif
    181 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    182   Htaccess *mime_a;             /* config mime types */
    183 #endif
    184 
    185 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    186   int accepted_socket;
    187 # define a_c_r config->accepted_socket
    188 # define a_c_w config->accepted_socket
    189 #else
    190 # define a_c_r 0
    191 # define a_c_w 1
    192 #endif
    193   volatile int alarm_signaled;
    194 
    195 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    196   Htaccess *script_i;           /* config script interpreters */
    197 #endif
    198 } HttpdConfig;
    199 
    200 static HttpdConfig *config;
    201 
    202 static const char request_GET[] = "GET";    /* size algorithmic optimize */
    203 
    204 static const char* const suffixTable [] = {
    205 /* Warning: shorted equivalent suffix in one line must be first */
    206   ".htm.html", "text/html",
    207   ".jpg.jpeg", "image/jpeg",
    208   ".gif", "image/gif",
    209   ".png", "image/png",
    210   ".txt.h.c.cc.cpp", "text/plain",
    211   ".css", "text/css",
    212   ".wav", "audio/wav",
    213   ".avi", "video/x-msvideo",
    214   ".qt.mov", "video/quicktime",
    215   ".mpe.mpeg", "video/mpeg",
    216   ".mid.midi", "audio/midi",
    217   ".mp3", "audio/mpeg",
    218 #if 0                        /* unpopular */
    219   ".au", "audio/basic",
    220   ".pac", "application/x-ns-proxy-autoconfig",
    221   ".vrml.wrl", "model/vrml",
    222 #endif
    223   0, "application/octet-stream" /* default */
    224   };
    225 
    226 typedef enum
    227 {
    228   HTTP_OK = 200,
    229   HTTP_MOVED_TEMPORARILY = 302,
    230   HTTP_BAD_REQUEST = 400,       /* malformed syntax */
    231   HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */
    232   HTTP_NOT_FOUND = 404,
    233   HTTP_FORBIDDEN = 403,
    234   HTTP_REQUEST_TIMEOUT = 408,
    235   HTTP_NOT_IMPLEMENTED = 501,   /* used for unrecognized requests */
    236   HTTP_INTERNAL_SERVER_ERROR = 500,
    237 #if 0 /* future use */
    238   HTTP_CONTINUE = 100,
    239   HTTP_SWITCHING_PROTOCOLS = 101,
    240   HTTP_CREATED = 201,
    241   HTTP_ACCEPTED = 202,
    242   HTTP_NON_AUTHORITATIVE_INFO = 203,
    243   HTTP_NO_CONTENT = 204,
    244   HTTP_MULTIPLE_CHOICES = 300,
    245   HTTP_MOVED_PERMANENTLY = 301,
    246   HTTP_NOT_MODIFIED = 304,
    247   HTTP_PAYMENT_REQUIRED = 402,
    248   HTTP_BAD_GATEWAY = 502,
    249   HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */
    250   HTTP_RESPONSE_SETSIZE=0xffffffff
    251 #endif
    252 } HttpResponseNum;
    253 
    254 typedef struct
    255 {
    256   HttpResponseNum type;
    257   const char *name;
    258   const char *info;
    259 } HttpEnumString;
    260 
    261 static const HttpEnumString httpResponseNames[] = {
    262   { HTTP_OK, "OK", NULL },
    263   { HTTP_MOVED_TEMPORARILY, "Found", "Directories must end with a slash." },
    264   { HTTP_REQUEST_TIMEOUT, "Request Timeout",
    265     "No request appeared within a reasonable time period." },
    266   { HTTP_NOT_IMPLEMENTED, "Not Implemented",
    267     "The requested method is not recognized by this server." },
    268 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    269   { HTTP_UNAUTHORIZED, "Unauthorized", "" },
    270 #endif
    271   { HTTP_NOT_FOUND, "Not Found",
    272     "The requested URL was not found on this server." },
    273   { HTTP_BAD_REQUEST, "Bad Request", "Unsupported method." },
    274   { HTTP_FORBIDDEN, "Forbidden", "" },
    275   { HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error",
    276     "Internal Server Error" },
    277 #if 0                               /* not implemented */
    278   { HTTP_CREATED, "Created" },
    279   { HTTP_ACCEPTED, "Accepted" },
    280   { HTTP_NO_CONTENT, "No Content" },
    281   { HTTP_MULTIPLE_CHOICES, "Multiple Choices" },
    282   { HTTP_MOVED_PERMANENTLY, "Moved Permanently" },
    283   { HTTP_NOT_MODIFIED, "Not Modified" },
    284   { HTTP_BAD_GATEWAY, "Bad Gateway", "" },
    285   { HTTP_SERVICE_UNAVAILABLE, "Service Unavailable", "" },
     233    Htaccess_IP *ip_a_d;    /* config allow/deny lines */
     234
     235    USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
     236    USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
     237    USE_FEATURE_HTTPD_CGI(char *referer;)
     238    USE_FEATURE_HTTPD_CGI(char *user_agent;)
     239
     240#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     241    Htaccess *g_auth;       /* config user:password lines */
     242#endif
     243#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     244    Htaccess *mime_a;       /* config mime types */
     245#endif
     246#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     247    Htaccess *script_i;     /* config script interpreters */
     248#endif
     249    char *iobuf;            /* [IOBUF_SIZE] */
     250#define hdr_buf bb_common_bufsiz1
     251    char *hdr_ptr;
     252    int hdr_cnt;
     253#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
     254    const char *http_error_page[ARRAY_SIZE(http_response_type)];
    286255#endif
    287256};
    288 
    289 
    290 static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT";
    291 static const char Content_length[] = "Content-length:";
    292 
    293 
    294 static int
    295 scan_ip (const char **ep, unsigned int *ip, unsigned char endc)
    296 {
    297   const char *p = *ep;
    298   int auto_mask = 8;
    299   int j;
    300 
    301   *ip = 0;
    302   for (j = 0; j < 4; j++) {
    303     unsigned int octet;
    304 
    305     if ((*p < '0' || *p > '9') && (*p != '/' || j == 0) && *p != 0)
    306       return -auto_mask;
    307     octet = 0;
    308     while (*p >= '0' && *p <= '9') {
    309       octet *= 10;
    310       octet += *p - '0';
    311       if (octet > 255)
     257#define G (*ptr_to_globals)
     258#define verbose           (G.verbose          )
     259#define flg_deny_all      (G.flg_deny_all     )
     260#define rmt_ip            (G.rmt_ip           )
     261#define bind_addr_or_port (G.bind_addr_or_port)
     262#define g_query           (G.g_query          )
     263#define configFile        (G.configFile       )
     264#define home_httpd        (G.home_httpd       )
     265#define found_mime_type   (G.found_mime_type  )
     266#define found_moved_temporarily (G.found_moved_temporarily)
     267#define ContentLength     (G.ContentLength    )
     268#define last_mod          (G.last_mod         )
     269#define ip_a_d            (G.ip_a_d           )
     270#define g_realm           (G.g_realm          )
     271#define remoteuser        (G.remoteuser       )
     272#define referer           (G.referer          )
     273#define user_agent        (G.user_agent       )
     274#define rmt_ip_str        (G.rmt_ip_str       )
     275#define g_auth            (G.g_auth           )
     276#define mime_a            (G.mime_a           )
     277#define script_i          (G.script_i         )
     278#define iobuf             (G.iobuf            )
     279#define hdr_ptr           (G.hdr_ptr          )
     280#define hdr_cnt           (G.hdr_cnt          )
     281#define http_error_page   (G.http_error_page  )
     282#define INIT_G() do { \
     283    PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
     284    USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
     285    bind_addr_or_port = "80"; \
     286    ContentLength = -1; \
     287} while (0)
     288
     289
     290#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
     291
     292/* Prototypes */
     293static void send_file_and_exit(const char *url, int headers) ATTRIBUTE_NORETURN;
     294
     295static void free_llist(has_next_ptr **pptr)
     296{
     297    has_next_ptr *cur = *pptr;
     298    while (cur) {
     299        has_next_ptr *t = cur;
     300        cur = cur->next;
     301        free(t);
     302    }
     303    *pptr = NULL;
     304}
     305
     306#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
     307 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
     308 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     309static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr)
     310{
     311    free_llist((has_next_ptr**)pptr);
     312}
     313#endif
     314
     315static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
     316{
     317    free_llist((has_next_ptr**)pptr);
     318}
     319
     320/* Returns presumed mask width in bits or < 0 on error.
     321 * Updates strp, stores IP at provided pointer */
     322static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc)
     323{
     324    const char *p = *strp;
     325    int auto_mask = 8;
     326    unsigned ip = 0;
     327    int j;
     328
     329    if (*p == '/')
    312330        return -auto_mask;
    313       p++;
    314     }
    315     if (*p == '.')
    316       p++;
    317     if (*p != '/' && *p != 0)
    318       auto_mask += 8;
    319     *ip = ((*ip) << 8) | octet;
    320   }
    321   if (*p != 0) {
    322     if (*p != endc)
    323         return -auto_mask;
    324     p++;
    325     if(*p == 0)
    326         return -auto_mask;
    327   }
    328   *ep = p;
    329   return auto_mask;
    330 }
    331 
    332 static int
    333 scan_ip_mask (const char *ipm, unsigned int *ip, unsigned int *mask)
    334 {
    335   int i;
    336   unsigned int msk;
    337 
    338   i = scan_ip(&ipm, ip, '/');
    339   if(i < 0)
    340     return i;
    341   if(*ipm) {
    342     const char *p = ipm;
    343 
    344     i = 0;
    345     while (*p) {
    346         if (*p < '0' || *p > '9') {
    347             if (*p == '.') {
    348                 i = scan_ip (&ipm, mask, 0);
    349                 return i != 32;
    350             }
     331
     332    for (j = 0; j < 4; j++) {
     333        unsigned octet;
     334
     335        if ((*p < '0' || *p > '9') && *p != '/' && *p)
     336            return -auto_mask;
     337        octet = 0;
     338        while (*p >= '0' && *p <= '9') {
     339            octet *= 10;
     340            octet += *p - '0';
     341            if (octet > 255)
     342                return -auto_mask;
     343            p++;
     344        }
     345        if (*p == '.')
     346            p++;
     347        if (*p != '/' && *p)
     348            auto_mask += 8;
     349        ip = (ip << 8) | octet;
     350    }
     351    if (*p) {
     352        if (*p != endc)
     353            return -auto_mask;
     354        p++;
     355        if (*p == '\0')
     356            return -auto_mask;
     357    }
     358    *ipp = ip;
     359    *strp = p;
     360    return auto_mask;
     361}
     362
     363/* Returns 0 on success. Stores IP and mask at provided pointers */
     364static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp)
     365{
     366    int i;
     367    unsigned mask;
     368    char *p;
     369
     370    i = scan_ip(&str, ipp, '/');
     371    if (i < 0)
     372        return i;
     373
     374    if (*str) {
     375        /* there is /xxx after dotted-IP address */
     376        i = bb_strtou(str, &p, 10);
     377        if (*p == '.') {
     378            /* 'xxx' itself is dotted-IP mask, parse it */
     379            /* (return 0 (success) only if it has N.N.N.N form) */
     380            return scan_ip(&str, maskp, '\0') - 32;
     381        }
     382        if (*p)
    351383            return -1;
    352         }
    353         i *= 10;
    354         i += *p - '0';
    355         p++;
    356     }
    357   }
    358   if (i > 32 || i < 0)
    359       return -1;
    360   msk = 0x80000000;
    361   *mask = 0;
    362   while (i > 0) {
    363     *mask |= msk;
    364     msk >>= 1;
    365     i--;
    366   }
    367   return 0;
    368 }
    369 
    370 #if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES)
    371 static void free_config_lines(Htaccess **pprev)
    372 {
    373     Htaccess *prev = *pprev;
    374 
    375     while( prev ) {
    376     Htaccess *cur = prev;
    377 
    378     prev = cur->next;
    379     free(cur);
    380     }
    381     *pprev = NULL;
    382 }
    383 #endif
    384 
     384    }
     385
     386    if (i > 32)
     387        return -1;
     388
     389    if (sizeof(unsigned) == 4 && i == 32) {
     390        /* mask >>= 32 below may not work */
     391        mask = 0;
     392    } else {
     393        mask = 0xffffffff;
     394        mask >>= i;
     395    }
     396    /* i == 0 -> *maskp = 0x00000000
     397     * i == 1 -> *maskp = 0x80000000
     398     * i == 4 -> *maskp = 0xf0000000
     399     * i == 31 -> *maskp = 0xfffffffe
     400     * i == 32 -> *maskp = 0xffffffff */
     401    *maskp = (uint32_t)(~mask);
     402    return 0;
     403}
     404
     405/*
     406 * Parse configuration file into in-memory linked list.
     407 *
     408 * The first non-white character is examined to determine if the config line
     409 * is one of the following:
     410 *    .ext:mime/type   # new mime type not compiled into httpd
     411 *    [adAD]:from      # ip address allow/deny, * for wildcard
     412 *    /path:user:pass  # username/password
     413 *    Ennn:error.html  # error page for status nnn
     414 *
     415 * Any previous IP rules are discarded.
     416 * If the flag argument is not SUBDIR_PARSE then all /path and mime rules
     417 * are also discarded.  That is, previous settings are retained if flag is
     418 * SUBDIR_PARSE.
     419 * Error pages are only parsed on the main config file.
     420 *
     421 * path   Path where to look for httpd.conf (without filename).
     422 * flag   Type of the parse request.
     423 */
    385424/* flag */
    386425#define FIRST_PARSE          0
     
    388427#define SIGNALED_PARSE       2
    389428#define FIND_FROM_HTTPD_ROOT 3
    390 /****************************************************************************
    391  *
    392  > $Function: parse_conf()
    393  *
    394  * $Description: parse configuration file into in-memory linked list.
    395  *
    396  * The first non-white character is examined to determine if the config line
    397  * is one of the following:
    398  *    .ext:mime/type   # new mime type not compiled into httpd
    399  *    [adAD]:from      # ip address allow/deny, * for wildcard
    400  *    /path:user:pass  # username/password
    401  *
    402  * Any previous IP rules are discarded.
    403  * If the flag argument is not SUBDIR_PARSE then all /path and mime rules
    404  * are also discarded.  That is, previous settings are retained if flag is
    405  * SUBDIR_PARSE.
    406  *
    407  * $Parameters:
    408  *      (const char *) path . . null for ip address checks, path for password
    409  *                              checks.
    410  *      (int) flag  . . . . . . the source of the parse request.
    411  *
    412  * $Return: (None)
    413  *
    414  ****************************************************************************/
    415429static void parse_conf(const char *path, int flag)
    416430{
    417     FILE *f;
    418 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    419     Htaccess *prev, *cur;
    420 #elif CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    421     Htaccess *cur;
    422 #endif
    423 
    424     const char *cf = config->configFile;
    425     char buf[160];
    426     char *p0 = NULL;
    427     char *c, *p;
    428 
    429     /* free previous ip setup if present */
    430     Htaccess_IP *pip = config->ip_a_d;
    431 
    432     while( pip ) {
    433     Htaccess_IP *cur_ipl = pip;
    434 
    435     pip = cur_ipl->next;
    436     free(cur_ipl);
    437     }
    438     config->ip_a_d = NULL;
    439 
    440     config->flg_deny_all = 0;
    441 
    442 #if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR)
    443     /* retain previous auth and mime config only for subdir parse */
    444     if(flag != SUBDIR_PARSE) {
    445 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    446     free_config_lines(&config->auth);
    447 #endif
    448 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    449     free_config_lines(&config->mime_a);
    450 #endif
    451 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    452     free_config_lines(&config->script_i);
    453 #endif
    454     }
    455 #endif
    456 
    457     if(flag == SUBDIR_PARSE || cf == NULL) {
    458     cf = alloca(strlen(path) + sizeof(httpd_conf) + 2);
    459     if(cf == NULL) {
    460         if(flag == FIRST_PARSE)
    461         bb_error_msg_and_die(bb_msg_memory_exhausted);
    462         return;
    463     }
    464     sprintf((char *)cf, "%s/%s", path, httpd_conf);
    465     }
    466 
    467     while((f = fopen(cf, "r")) == NULL) {
    468     if(flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) {
    469         /* config file not found, no changes to config */
    470         return;
    471     }
    472     if(config->configFile && flag == FIRST_PARSE) /* if -c option given */
    473         bb_perror_msg_and_die("%s", cf);
    474     flag = FIND_FROM_HTTPD_ROOT;
    475     cf = httpd_conf;
    476     }
    477 
    478 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    479     prev = config->auth;
    480 #endif
    481     /* This could stand some work */
    482     while ( (p0 = fgets(buf, sizeof(buf), f)) != NULL) {
    483     c = NULL;
    484     for(p = p0; *p0 != 0 && *p0 != '#'; p0++) {
    485         if(!isspace(*p0)) {
    486             *p++ = *p0;
    487             if(*p0 == ':' && c == NULL)
    488             c = p;
    489         }
    490     }
    491     *p = 0;
    492 
    493     /* test for empty or strange line */
    494     if (c == NULL || *c == 0)
    495         continue;
    496     p0 = buf;
    497     if(*p0 == 'd')
    498         *p0 = 'D';
    499     if(*c == '*') {
    500         if(*p0 == 'D') {
    501         /* memorize deny all */
    502         config->flg_deny_all++;
    503         }
    504         /* skip default other "word:*" config lines */
    505         continue;
    506     }
    507 
    508     if(*p0 == 'a')
    509         *p0 = 'A';
    510     else if(*p0 != 'D' && *p0 != 'A'
    511 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    512        && *p0 != '/'
    513 #endif
    514 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    515        && *p0 != '.'
    516 #endif
    517 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    518        && *p0 != '*'
    519 #endif
    520       )
    521            continue;
    522     if(*p0 == 'A' || *p0 == 'D') {
    523         /* storing current config IP line */
    524         pip = calloc(1, sizeof(Htaccess_IP));
    525         if(pip) {
    526             if(scan_ip_mask (c, &(pip->ip), &(pip->mask))) {
    527             /* syntax IP{/mask} error detected, protect all */
     431    FILE *f;
     432#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     433    Htaccess *prev;
     434#endif
     435#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
     436 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
     437 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     438    Htaccess *cur;
     439#endif
     440    const char *cf = configFile;
     441    char buf[160];
     442    char *p0 = NULL;
     443    char *c, *p;
     444    Htaccess_IP *pip;
     445
     446    /* discard old rules */
     447    free_Htaccess_IP_list(&ip_a_d);
     448    flg_deny_all = 0;
     449#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
     450 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
     451 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     452    /* retain previous auth and mime config only for subdir parse */
     453    if (flag != SUBDIR_PARSE) {
     454#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     455        free_Htaccess_list(&g_auth);
     456#endif
     457#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     458        free_Htaccess_list(&mime_a);
     459#endif
     460#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     461        free_Htaccess_list(&script_i);
     462#endif
     463    }
     464#endif
     465
     466    if (flag == SUBDIR_PARSE || cf == NULL) {
     467        cf = alloca(strlen(path) + sizeof(httpd_conf) + 2);
     468        sprintf((char *)cf, "%s/%s", path, httpd_conf);
     469    }
     470
     471    while ((f = fopen(cf, "r")) == NULL) {
     472        if (flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) {
     473            /* config file not found, no changes to config */
     474            return;
     475        }
     476        if (configFile && flag == FIRST_PARSE) /* if -c option given */
     477            bb_perror_msg_and_die("%s", cf);
     478        flag = FIND_FROM_HTTPD_ROOT;
     479        cf = httpd_conf;
     480    }
     481
     482#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     483    prev = g_auth;
     484#endif
     485    /* This could stand some work */
     486    while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) {
     487        c = NULL;
     488        for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) {
     489            if (!isspace(*p0)) {
     490                *p++ = *p0;
     491                if (*p0 == ':' && c == NULL)
     492                    c = p;
     493            }
     494        }
     495        *p = '\0';
     496
     497        /* test for empty or strange line */
     498        if (c == NULL || *c == '\0')
     499            continue;
     500        p0 = buf;
     501        if (*p0 == 'd')
    528502            *p0 = 'D';
    529             pip->mask = 0;
    530             }
    531             pip->allow_deny = *p0;
    532             if(*p0 == 'D') {
    533             /* Deny:form_IP move top */
    534             pip->next = config->ip_a_d;
    535             config->ip_a_d = pip;
    536             } else {
    537             /* add to bottom A:form_IP config line */
    538             Htaccess_IP *prev_IP = config->ip_a_d;
    539 
    540             if(prev_IP == NULL) {
    541                 config->ip_a_d = pip;
    542             } else {
    543                 while(prev_IP->next)
    544                     prev_IP = prev_IP->next;
    545                 prev_IP->next = pip;
    546             }
    547             }
    548         }
    549         continue;
    550     }
    551 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    552     if(*p0 == '/') {
    553         /* make full path from httpd root / curent_path / config_line_path */
    554         cf = flag == SUBDIR_PARSE ? path : "";
    555         p0 = malloc(strlen(cf) + (c - buf) + 2 + strlen(c));
    556         if(p0 == NULL)
    557         continue;
    558         c[-1] = 0;
    559         sprintf(p0, "/%s%s", cf, buf);
    560 
    561         /* another call bb_simplify_path */
    562         cf = p = p0;
    563 
    564         do {
    565             if (*p == '/') {
    566             if (*cf == '/') {    /* skip duplicate (or initial) slash */
    567                 continue;
    568             } else if (*cf == '.') {
    569                 if (cf[1] == '/' || cf[1] == 0) { /* remove extra '.' */
     503        if (*c == '*') {
     504            if (*p0 == 'D') {
     505                /* memorize deny all */
     506                flg_deny_all = 1;
     507            }
     508            /* skip default other "word:*" config lines */
     509            continue;
     510        }
     511
     512        if (*p0 == 'a')
     513            *p0 = 'A';
     514        if (*p0 == 'A' || *p0 == 'D') {
     515            /* storing current config IP line */
     516            pip = xzalloc(sizeof(Htaccess_IP));
     517            if (pip) {
     518                if (scan_ip_mask(c, &(pip->ip), &(pip->mask))) {
     519                    /* syntax IP{/mask} error detected, protect all */
     520                    *p0 = 'D';
     521                    pip->mask = 0;
     522                }
     523                pip->allow_deny = *p0;
     524                if (*p0 == 'D') {
     525                    /* Deny:from_IP move top */
     526                    pip->next = ip_a_d;
     527                    ip_a_d = pip;
     528                } else {
     529                    /* add to bottom A:form_IP config line */
     530                    Htaccess_IP *prev_IP = ip_a_d;
     531
     532                    if (prev_IP == NULL) {
     533                        ip_a_d = pip;
     534                    } else {
     535                        while (prev_IP->next)
     536                            prev_IP = prev_IP->next;
     537                        prev_IP->next = pip;
     538                    }
     539                }
     540            }
     541            continue;
     542        }
     543
     544#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
     545        if (flag == FIRST_PARSE && *p0 == 'E') {
     546            int i;
     547            /* error status code */
     548            int status = atoi(++p0);
     549            /* c already points at the character following ':' in parse loop */
     550            /* c = strchr(p0, ':'); c++; */
     551            if (status < HTTP_CONTINUE) {
     552                bb_error_msg("config error '%s' in '%s'", buf, cf);
    570553                continue;
    571                 } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == 0)) {
    572                 ++cf;
    573                 if (p > p0) {
    574                     while (*--p != '/');    /* omit previous dir */
    575                 }
    576                 continue;
    577                 }
    578             }
    579             }
    580             *++p = *cf;
    581         } while (*++cf);
    582 
    583         if ((p == p0) || (*p != '/')) {      /* not a trailing slash */
    584         ++p;                             /* so keep last character */
    585         }
    586         *p = 0;
    587         sprintf(p0, "%s:%s", p0, c);
    588     }
    589 #endif
    590 
    591 #if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR)
    592     /* storing current config line */
    593     cur = calloc(1, sizeof(Htaccess) + strlen(p0));
    594     if(cur) {
    595         cf = strcpy(cur->before_colon, p0);
    596         c = strchr(cf, ':');
    597         *c++ = 0;
    598         cur->after_colon = c;
    599 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    600         if(*cf == '.') {
    601         /* config .mime line move top for overwrite previous */
    602         cur->next = config->mime_a;
    603         config->mime_a = cur;
    604         continue;
    605         }
    606 #endif
    607 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    608         if(*cf == '*' && cf[1] == '.') {
    609         /* config script interpreter line move top for overwrite previous */
    610         cur->next = config->script_i;
    611         config->script_i = cur;
    612         continue;
    613         }
    614 #endif
    615 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    616         free(p0);
    617         if(prev == NULL) {
    618         /* first line */
    619         config->auth = prev = cur;
    620         } else {
    621         /* sort path, if current lenght eq or bigger then move up */
    622         Htaccess *prev_hti = config->auth;
    623         size_t l = strlen(cf);
    624         Htaccess *hti;
    625 
    626         for(hti = prev_hti; hti; hti = hti->next) {
    627             if(l >= strlen(hti->before_colon)) {
    628             /* insert before hti */
    629             cur->next = hti;
    630             if(prev_hti != hti) {
    631                 prev_hti->next = cur;
    632             } else {
    633                 /* insert as top */
    634                 config->auth = cur;
    635             }
    636             break;
    637             }
    638             if(prev_hti != hti)
    639                 prev_hti = prev_hti->next;
    640         }
    641         if(!hti)  {       /* not inserted, add to bottom */
    642             prev->next = cur;
    643             prev = cur;
    644         }
    645         }
    646 #endif
    647     }
    648 #endif
    649    }
    650    fclose(f);
    651 }
    652 
    653 #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR
    654 /****************************************************************************
    655  *
    656  > $Function: encodeString()
    657  *
    658  * $Description: Given a string, html encode special characters.
    659  *   This is used for the -e command line option to provide an easy way
    660  *   for scripts to encode result data without confusing browsers.  The
    661  *   returned string pointer is memory allocated by malloc().
    662  *
    663  * $Parameters:
    664  *      (const char *) string . . The first string to encode.
    665  *
    666  * $Return: (char *) . . . .. . . A pointer to the encoded string.
    667  *
    668  * $Errors: Returns a null string ("") if memory is not available.
    669  *
    670  ****************************************************************************/
    671 static char *encodeString(const char *string)
    672 {
    673   /* take the simple route and encode everything */
    674   /* could possibly scan once to get length.     */
    675   int len = strlen(string);
    676   char *out = malloc(len * 6 + 1);
    677   char *p=out;
    678   char ch;
    679 
    680   if (!out) return "";
    681   while ((ch = *string++)) {
    682     // very simple check for what to encode
    683     if (isalnum(ch)) *p++ = ch;
    684     else p += sprintf(p, "&#%d;", (unsigned char) ch);
    685   }
    686   *p=0;
    687   return out;
    688 }
    689 #endif          /* CONFIG_FEATURE_HTTPD_ENCODE_URL_STR */
    690 
    691 /****************************************************************************
    692  *
    693  > $Function: decodeString()
    694  *
    695  * $Description: Given a URL encoded string, convert it to plain ascii.
    696  *   Since decoding always makes strings smaller, the decode is done in-place.
    697  *   Thus, callers should strdup() the argument if they do not want the
    698  *   argument modified.  The return is the original pointer, allowing this
    699  *   function to be easily used as arguments to other functions.
    700  *
    701  * $Parameters:
    702  *      (char *) string . . . The first string to decode.
    703  *      (int)    flag   . . . 1 if require decode '+' as ' ' for CGI
    704  *
    705  * $Return: (char *)  . . . . A pointer to the decoded string (same as input).
    706  *
    707  * $Errors: None
    708  *
    709  ****************************************************************************/
    710 static char *decodeString(char *orig, int flag_plus_to_space)
    711 {
    712   /* note that decoded string is always shorter than original */
    713   char *string = orig;
    714   char *ptr = string;
    715 
    716   while (*ptr)
    717   {
    718     if (*ptr == '+' && flag_plus_to_space)    { *string++ = ' '; ptr++; }
    719     else if (*ptr != '%') *string++ = *ptr++;
    720     else  {
    721       unsigned int value1, value2;
    722 
    723       ptr++;
    724       if(sscanf(ptr, "%1X", &value1) != 1 ||
    725                 sscanf(ptr+1, "%1X", &value2) != 1) {
    726     if(!flag_plus_to_space)
    727         return NULL;
    728     *string++ = '%';
    729       } else {
    730     value1 = value1 * 16 + value2;
    731     if(value1 == '/' || value1 == 0)
    732         return orig+1;
    733     *string++ = value1;
    734     ptr += 2;
    735       }
    736     }
    737   }
    738   *string = '\0';
    739   return orig;
    740 }
    741 
    742 
    743 #ifdef CONFIG_FEATURE_HTTPD_CGI
    744 /****************************************************************************
    745  *
    746  > $Function: addEnv()
    747  *
    748  * $Description: Add an environment variable setting to the global list.
    749  *    A NAME=VALUE string is allocated, filled, and added to the list of
    750  *    environment settings passed to the cgi execution script.
    751  *
    752  * $Parameters:
    753  *  (char *) name_before_underline - The first part environment variable name.
    754  *  (char *) name_after_underline  - The second part environment variable name.
    755  *  (char *) value  . . The value to which the env variable is set.
    756  *
    757  * $Return: (void)
    758  *
    759  * $Errors: Silently returns if the env runs out of space to hold the new item
    760  *
    761  ****************************************************************************/
    762 static void addEnv(const char *name_before_underline,
    763             const char *name_after_underline, const char *value)
    764 {
    765   char *s = NULL;
    766   const char *underline;
    767 
    768   if (!value)
    769     value = "";
    770   underline = *name_after_underline ? "_" : "";
    771   asprintf(&s, "%s%s%s=%s", name_before_underline, underline,
    772                     name_after_underline, value);
    773   if(s) {
    774     putenv(s);
    775   }
    776 }
    777 
    778 #if defined(CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV) || defined(CONFIG_FEATURE_HTTPD_WITHOUT_INETD)
    779 /* set environs SERVER_PORT and REMOTE_PORT */
    780 static void addEnvPort(const char *port_name)
    781 {
    782       char buf[16];
    783 
    784       sprintf(buf, "%u", config->port);
    785       addEnv(port_name, "PORT", buf);
    786 }
    787 #endif
    788 #endif          /* CONFIG_FEATURE_HTTPD_CGI */
    789 
    790 
    791 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    792 /****************************************************************************
    793  *
    794  > $Function: decodeBase64()
    795  *
    796  > $Description: Decode a base 64 data stream as per rfc1521.
    797  *    Note that the rfc states that none base64 chars are to be ignored.
    798  *    Since the decode always results in a shorter size than the input, it is
    799  *    OK to pass the input arg as an output arg.
    800  *
    801  * $Parameter:
    802  *      (char *) Data . . . . A pointer to a base64 encoded string.
    803  *                            Where to place the decoded data.
    804  *
    805  * $Return: void
    806  *
    807  * $Errors: None
    808  *
    809  ****************************************************************************/
    810 static void decodeBase64(char *Data)
    811 {
    812 
    813   const unsigned char *in = (const unsigned char *)Data;
    814   // The decoded size will be at most 3/4 the size of the encoded
    815   unsigned long ch = 0;
    816   int i = 0;
    817 
    818   while (*in) {
    819     int t = *in++;
    820 
    821     if(t >= '0' && t <= '9')
    822     t = t - '0' + 52;
    823     else if(t >= 'A' && t <= 'Z')
    824     t = t - 'A';
    825     else if(t >= 'a' && t <= 'z')
    826     t = t - 'a' + 26;
    827     else if(t == '+')
    828     t = 62;
    829     else if(t == '/')
    830     t = 63;
    831     else if(t == '=')
    832     t = 0;
    833     else
    834     continue;
    835 
    836     ch = (ch << 6) | t;
    837     i++;
    838     if (i == 4) {
    839     *Data++ = (char) (ch >> 16);
    840     *Data++ = (char) (ch >> 8);
    841     *Data++ = (char) ch;
    842     i = 0;
    843     }
    844   }
    845   *Data = 0;
    846 }
    847 #endif
    848 
    849 
    850 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    851 /****************************************************************************
    852  *
    853  > $Function: openServer()
    854  *
    855  * $Description: create a listen server socket on the designated port.
    856  *
    857  * $Return: (int)  . . . A connection socket. -1 for errors.
    858  *
    859  * $Errors: None
    860  *
    861  ****************************************************************************/
    862 static int openServer(void)
    863 {
    864   struct sockaddr_in lsocket;
    865   int fd;
    866   int on = 1;
    867 
    868   /* create the socket right now */
    869   /* inet_addr() returns a value that is already in network order */
    870   memset(&lsocket, 0, sizeof(lsocket));
    871   lsocket.sin_family = AF_INET;
    872   lsocket.sin_addr.s_addr = INADDR_ANY;
    873   lsocket.sin_port = htons(config->port);
    874   fd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
    875   /* tell the OS it's OK to reuse a previous address even though */
    876   /* it may still be in a close down state.  Allows bind to succeed. */
    877 #ifdef SO_REUSEPORT
    878   setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on)) ;
    879 #else
    880   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) ;
    881 #endif
    882   bb_xbind(fd, (struct sockaddr *)&lsocket, sizeof(lsocket));
    883   listen(fd, 9); /* bb_xlisten? */
    884   signal(SIGCHLD, SIG_IGN);   /* prevent zombie (defunct) processes */
    885   return fd;
    886 }
    887 #endif  /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */
    888 
    889 /****************************************************************************
    890  *
    891  > $Function: sendHeaders()
    892  *
    893  * $Description: Create and send HTTP response headers.
    894  *   The arguments are combined and sent as one write operation.  Note that
    895  *   IE will puke big-time if the headers are not sent in one packet and the
    896  *   second packet is delayed for any reason.
    897  *
    898  * $Parameter:
    899  *      (HttpResponseNum) responseNum . . . The result code to send.
    900  *
    901  * $Return: (int)  . . . . writing errors
    902  *
    903  ****************************************************************************/
    904 static int sendHeaders(HttpResponseNum responseNum)
    905 {
    906   char *buf = config->buf;
    907   const char *responseString = "";
    908   const char *infoString = 0;
    909   const char *mime_type;
    910   unsigned int i;
    911   time_t timer = time(0);
    912   char timeStr[80];
    913   int len;
    914 
    915   for (i = 0;
    916     i < (sizeof(httpResponseNames)/sizeof(httpResponseNames[0])); i++) {
    917         if (httpResponseNames[i].type == responseNum) {
    918             responseString = httpResponseNames[i].name;
    919             infoString = httpResponseNames[i].info;
    920             break;
    921         }
    922   }
    923   /* error message is HTML */
    924   mime_type = responseNum == HTTP_OK ?
    925         config->httpd_found.found_mime_type : "text/html";
    926 
    927   /* emit the current date */
    928   strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer));
    929   len = sprintf(buf,
    930     "HTTP/1.0 %d %s\r\nContent-type: %s\r\n"
    931     "Date: %s\r\nConnection: close\r\n",
    932       responseNum, responseString, mime_type, timeStr);
    933 
    934 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    935   if (responseNum == HTTP_UNAUTHORIZED) {
    936     len += sprintf(buf+len, "WWW-Authenticate: Basic realm=\"%s\"\r\n",
    937                                 config->realm);
    938   }
    939 #endif
    940   if(responseNum == HTTP_MOVED_TEMPORARILY) {
    941     len += sprintf(buf+len, "Location: %s/%s%s\r\n",
    942         config->httpd_found.found_moved_temporarily,
    943         (config->query ? "?" : ""),
    944         (config->query ? config->query : ""));
    945   }
    946 
    947   if (config->ContentLength != -1) {    /* file */
    948     strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod));
    949     len += sprintf(buf+len, "Last-Modified: %s\r\n%s " cont_l_fmt "\r\n",
    950                   timeStr, Content_length, cont_l_type config->ContentLength);
    951   }
    952   strcat(buf, "\r\n");
    953   len += 2;
    954   if (infoString) {
    955     len += sprintf(buf+len,
    956         "<HEAD><TITLE>%d %s</TITLE></HEAD>\n"
    957         "<BODY><H1>%d %s</H1>\n%s\n</BODY>\n",
    958         responseNum, responseString,
    959         responseNum, responseString, infoString);
    960   }
    961 #if DEBUG
    962   fprintf(stderr, "Headers: '%s'", buf);
    963 #endif
    964   return bb_full_write(a_c_w, buf, len);
    965 }
    966 
    967 /****************************************************************************
    968  *
    969  > $Function: getLine()
    970  *
    971  * $Description: Read from the socket until an end of line char found.
    972  *
    973  *   Characters are read one at a time until an eol sequence is found.
    974  *
    975  * $Return: (int) . . . . number of characters read.  -1 if error.
    976  *
    977  ****************************************************************************/
    978 static int getLine(void)
    979 {
    980   int  count = 0;
    981   char *buf = config->buf;
    982 
    983   while (read(a_c_r, buf + count, 1) == 1) {
    984     if (buf[count] == '\r') continue;
    985     if (buf[count] == '\n') {
    986       buf[count] = 0;
    987       return count;
    988     }
    989     if(count < (MAX_MEMORY_BUFF-1))      /* check owerflow */
    990     count++;
    991   }
    992   if (count) return count;
    993   else return -1;
    994 }
    995 
    996 #ifdef CONFIG_FEATURE_HTTPD_CGI
    997 /****************************************************************************
    998  *
    999  > $Function: sendCgi()
    1000  *
    1001  * $Description: Execute a CGI script and send it's stdout back
    1002  *
    1003  *   Environment variables are set up and the script is invoked with pipes
    1004  *   for stdin/stdout.  If a post is being done the script is fed the POST
    1005  *   data in addition to setting the QUERY_STRING variable (for GETs or POSTs).
    1006  *
    1007  * $Parameters:
    1008  *      (const char *) url . . . . . . The requested URL (with leading /).
    1009  *      (int bodyLen)  . . . . . . . . Length of the post body.
    1010  *      (const char *cookie) . . . . . For set HTTP_COOKIE.
    1011  *      (const char *content_type) . . For set CONTENT_TYPE.
    1012 
    1013  *
    1014  * $Return: (char *)  . . . . A pointer to the decoded string (same as input).
    1015  *
    1016  * $Errors: None
    1017  *
    1018  ****************************************************************************/
    1019 static int sendCgi(const char *url,
    1020            const char *request, int bodyLen, const char *cookie,
    1021            const char *content_type)
    1022 {
    1023   int fromCgi[2];  /* pipe for reading data from CGI */
    1024   int toCgi[2];    /* pipe for sending data to CGI */
    1025 
    1026   static char * argp[] = { 0, 0 };
    1027   int pid = 0;
    1028   int inFd;
    1029   int outFd;
    1030   int firstLine = 1;
    1031 
    1032   do {
    1033     if (pipe(fromCgi) != 0) {
    1034       break;
    1035     }
    1036     if (pipe(toCgi) != 0) {
    1037       break;
    1038     }
    1039 
    1040     pid = fork();
    1041     if (pid < 0) {
    1042     pid = 0;
    1043     break;
    1044     }
    1045 
    1046     if (!pid) {
    1047       /* child process */
    1048       char *script;
    1049       char *purl = strdup( url );
    1050       char realpath_buff[MAXPATHLEN];
    1051 
    1052       if(purl == NULL)
    1053     _exit(242);
    1054 
    1055       inFd  = toCgi[0];
    1056       outFd = fromCgi[1];
    1057 
    1058       dup2(inFd, 0);  // replace stdin with the pipe
    1059       dup2(outFd, 1);  // replace stdout with the pipe
    1060       if(!DEBUG)
    1061     dup2(outFd, 2);  // replace stderr with the pipe
    1062 
    1063       close(toCgi[0]);
    1064       close(toCgi[1]);
    1065       close(fromCgi[0]);
    1066       close(fromCgi[1]);
    1067 
    1068       /*
    1069        * Find PATH_INFO.
    1070        */
    1071       script = purl;
    1072       while((script = strchr( script + 1, '/' )) != NULL) {
    1073     /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */
    1074     struct stat sb;
    1075 
    1076     *script = '\0';
    1077     if(is_directory(purl + 1, 1, &sb) == 0) {
    1078         /* not directory, found script.cgi/PATH_INFO */
    1079         *script = '/';
    1080         break;
    1081     }
    1082     *script = '/';          /* is directory, find next '/' */
    1083       }
    1084       addEnv("PATH", "INFO", script);   /* set /PATH_INFO or NULL */
    1085       addEnv("PATH",           "",         getenv("PATH"));
    1086       addEnv("REQUEST",        "METHOD",   request);
    1087       if(config->query) {
    1088     char *uri = alloca(strlen(purl) + 2 + strlen(config->query));
    1089     if(uri)
    1090         sprintf(uri, "%s?%s", purl, config->query);
    1091     addEnv("REQUEST",        "URI",   uri);
    1092       } else {
    1093     addEnv("REQUEST",        "URI",   purl);
    1094       }
    1095       if(script != NULL)
    1096     *script = '\0';         /* reduce /PATH_INFO */
    1097        /* SCRIPT_FILENAME required by PHP in CGI mode */
    1098        if(realpath(purl + 1, realpath_buff))
    1099      addEnv("SCRIPT", "FILENAME", realpath_buff);
    1100        else
    1101      *realpath_buff = 0;
    1102       /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
    1103       addEnv("SCRIPT_NAME",    "",         purl);
    1104       addEnv("QUERY_STRING",   "",         config->query);
    1105       addEnv("SERVER",         "SOFTWARE", httpdVersion);
    1106       addEnv("SERVER",         "PROTOCOL", "HTTP/1.0");
    1107       addEnv("GATEWAY_INTERFACE", "",      "CGI/1.1");
    1108       addEnv("REMOTE",         "ADDR",     config->rmt_ip_str);
    1109 #ifdef CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
    1110       addEnvPort("REMOTE");
    1111 #endif
    1112       if(bodyLen) {
    1113     char sbl[32];
    1114 
    1115     sprintf(sbl, "%d", bodyLen);
    1116     addEnv("CONTENT", "LENGTH", sbl);
    1117       }
    1118       if(cookie)
    1119     addEnv("HTTP", "COOKIE", cookie);
    1120       if(content_type)
    1121     addEnv("CONTENT", "TYPE", content_type);
    1122 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1123       if(config->remoteuser) {
    1124     addEnv("REMOTE", "USER", config->remoteuser);
    1125     addEnv("AUTH_TYPE", "", "Basic");
    1126       }
    1127 #endif
    1128       if(config->referer)
    1129     addEnv("HTTP", "REFERER", config->referer);
    1130 
    1131     /* set execve argp[0] without path */
    1132       argp[0] = strrchr( purl, '/' ) + 1;
    1133     /* but script argp[0] must have absolute path and chdiring to this */
    1134       if(*realpath_buff) {
    1135         script = strrchr(realpath_buff, '/');
    1136         if(script) {
    1137         *script = '\0';
    1138         if(chdir(realpath_buff) == 0) {
    1139           // now run the program.  If it fails,
    1140           // use _exit() so no destructors
    1141           // get called and make a mess.
    1142 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    1143           char *interpr = NULL;
    1144           char *suffix = strrchr(purl, '.');
    1145 
    1146           if(suffix) {
    1147             Htaccess * cur;
    1148             for (cur = config->script_i; cur; cur = cur->next)
    1149                 if(strcmp(cur->before_colon + 1, suffix) == 0) {
    1150                     interpr = cur->after_colon;
     554            }
     555
     556            /* then error page; find matching status */
     557            for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
     558                if (http_response_type[i] == status) {
     559                    http_error_page[i] = concat_path_file((*c == '/') ? NULL : home_httpd, c);
    1151560                    break;
    1152561                }
    1153           }
    1154 #endif
    1155           *script = '/';
    1156 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    1157           if (interpr)
    1158             execv(interpr, argp);
    1159           else
    1160 #endif
    1161             execv(realpath_buff, argp);
    1162         }
    1163         }
    1164       }
    1165 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1166       config->accepted_socket = 1;      /* send to stdout */
    1167 #endif
    1168       sendHeaders(HTTP_NOT_FOUND);
    1169       _exit(242);
    1170     } /* end child */
    1171 
    1172   } while (0);
    1173 
    1174   if (pid) {
    1175     /* parent process */
    1176     int status;
    1177     size_t post_readed_size = 0, post_readed_idx = 0;
    1178 
    1179     inFd  = fromCgi[0];
    1180     outFd = toCgi[1];
    1181     close(fromCgi[1]);
    1182     close(toCgi[0]);
    1183     signal(SIGPIPE, SIG_IGN);
    1184 
    1185     while (1) {
    1186       fd_set readSet;
    1187       fd_set writeSet;
    1188       char wbuf[128];
    1189       int nfound;
    1190       int count;
    1191 
    1192       FD_ZERO(&readSet);
    1193       FD_ZERO(&writeSet);
    1194       FD_SET(inFd, &readSet);
    1195       if(bodyLen > 0 || post_readed_size > 0) {
    1196     FD_SET(outFd, &writeSet);
    1197     nfound = outFd > inFd ? outFd : inFd;
    1198     if(post_readed_size == 0) {
    1199         FD_SET(a_c_r, &readSet);
    1200         if(nfound < a_c_r)
    1201             nfound = a_c_r;
    1202     }
    1203       /* Now wait on the set of sockets! */
    1204     nfound = select(nfound + 1, &readSet, &writeSet, 0, NULL);
    1205       } else {
    1206     if(!bodyLen) {
    1207         close(outFd);
    1208         bodyLen = -1;
    1209     }
    1210     nfound = select(inFd + 1, &readSet, 0, 0, NULL);
    1211       }
    1212 
    1213       if (nfound <= 0) {
    1214     if (waitpid(pid, &status, WNOHANG) > 0) {
    1215       close(inFd);
     562            }
     563            continue;
     564        }
     565#endif
     566
     567#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     568        if (*p0 == '/') {
     569            /* make full path from httpd root / current_path / config_line_path */
     570            cf = (flag == SUBDIR_PARSE ? path : "");
     571            p0 = xmalloc(strlen(cf) + (c - buf) + 2 + strlen(c));
     572            c[-1] = '\0';
     573            sprintf(p0, "/%s%s", cf, buf);
     574
     575            /* another call bb_simplify_path */
     576            cf = p = p0;
     577
     578            do {
     579                if (*p == '/') {
     580                    if (*cf == '/') {    /* skip duplicate (or initial) slash */
     581                        continue;
     582                    } else if (*cf == '.') {
     583                        if (cf[1] == '/' || cf[1] == '\0') { /* remove extra '.' */
     584                            continue;
     585                        } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == '\0')) {
     586                            ++cf;
     587                            if (p > p0) {
     588                                while (*--p != '/') /* omit previous dir */;
     589                            }
     590                            continue;
     591                        }
     592                    }
     593                }
     594                *++p = *cf;
     595            } while (*++cf);
     596
     597            if ((p == p0) || (*p != '/')) {      /* not a trailing slash */
     598                ++p;                             /* so keep last character */
     599            }
     600            *p = '\0';
     601            sprintf(p0 + strlen(p0), ":%s", c);
     602        }
     603#endif
     604
     605#if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
     606 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
     607 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     608        /* storing current config line */
     609        cur = xzalloc(sizeof(Htaccess) + strlen(p0));
     610        if (cur) {
     611            cf = strcpy(cur->before_colon, p0);
     612            c = strchr(cf, ':');
     613            *c++ = 0;
     614            cur->after_colon = c;
     615#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     616            if (*cf == '.') {
     617                /* config .mime line move top for overwrite previous */
     618                cur->next = mime_a;
     619                mime_a = cur;
     620                continue;
     621            }
     622#endif
     623#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     624            if (*cf == '*' && cf[1] == '.') {
     625                /* config script interpreter line move top for overwrite previous */
     626                cur->next = script_i;
     627                script_i = cur;
     628                continue;
     629            }
     630#endif
     631#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     632            free(p0);
     633            if (prev == NULL) {
     634                /* first line */
     635                g_auth = prev = cur;
     636            } else {
     637                /* sort path, if current lenght eq or bigger then move up */
     638                Htaccess *prev_hti = g_auth;
     639                size_t l = strlen(cf);
     640                Htaccess *hti;
     641
     642                for (hti = prev_hti; hti; hti = hti->next) {
     643                    if (l >= strlen(hti->before_colon)) {
     644                        /* insert before hti */
     645                        cur->next = hti;
     646                        if (prev_hti != hti) {
     647                            prev_hti->next = cur;
     648                        } else {
     649                            /* insert as top */
     650                            g_auth = cur;
     651                        }
     652                        break;
     653                    }
     654                    if (prev_hti != hti)
     655                        prev_hti = prev_hti->next;
     656                }
     657                if (!hti) {       /* not inserted, add to bottom */
     658                    prev->next = cur;
     659                    prev = cur;
     660                }
     661            }
     662#endif
     663        }
     664#endif
     665     }
     666     fclose(f);
     667}
     668
     669#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
     670/*
     671 * Given a string, html-encode special characters.
     672 * This is used for the -e command line option to provide an easy way
     673 * for scripts to encode result data without confusing browsers.  The
     674 * returned string pointer is memory allocated by malloc().
     675 *
     676 * Returns a pointer to the encoded string (malloced).
     677 */
     678static char *encodeString(const char *string)
     679{
     680    /* take the simple route and encode everything */
     681    /* could possibly scan once to get length.     */
     682    int len = strlen(string);
     683    char *out = xmalloc(len * 6 + 1);
     684    char *p = out;
     685    char ch;
     686
     687    while ((ch = *string++)) {
     688        /* very simple check for what to encode */
     689        if (isalnum(ch))
     690            *p++ = ch;
     691        else
     692            p += sprintf(p, "&#%d;", (unsigned char) ch);
     693    }
     694    *p = '\0';
     695    return out;
     696}
     697#endif          /* FEATURE_HTTPD_ENCODE_URL_STR */
     698
     699/*
     700 * Given a URL encoded string, convert it to plain ascii.
     701 * Since decoding always makes strings smaller, the decode is done in-place.
     702 * Thus, callers should strdup() the argument if they do not want the
     703 * argument modified.  The return is the original pointer, allowing this
     704 * function to be easily used as arguments to other functions.
     705 *
     706 * string    The first string to decode.
     707 * option_d  1 if called for httpd -d
     708 *
     709 * Returns a pointer to the decoded string (same as input).
     710 */
     711static unsigned hex_to_bin(unsigned char c)
     712{
     713    unsigned v;
     714
     715    v = c - '0';
     716    if (v <= 9)
     717        return v;
     718    /* c | 0x20: letters to lower case, non-letters
     719     * to (potentially different) non-letters */
     720    v = (unsigned)(c | 0x20) - 'a';
     721    if (v <= 5)
     722        return v + 10;
     723    return ~0;
     724}
     725/* For testing:
     726void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
     727int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
     728t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
     729*/
     730static char *decodeString(char *orig, int option_d)
     731{
     732    /* note that decoded string is always shorter than original */
     733    char *string = orig;
     734    char *ptr = string;
     735    char c;
     736
     737    while ((c = *ptr++) != '\0') {
     738        unsigned v;
     739
     740        if (option_d && c == '+') {
     741            *string++ = ' ';
     742            continue;
     743        }
     744        if (c != '%') {
     745            *string++ = c;
     746            continue;
     747        }
     748        v = hex_to_bin(ptr[0]);
     749        if (v > 15) {
     750 bad_hex:
     751            if (!option_d)
     752                return NULL;
     753            *string++ = '%';
     754            continue;
     755        }
     756        v = (v * 16) | hex_to_bin(ptr[1]);
     757        if (v > 255)
     758            goto bad_hex;
     759        if (!option_d && (v == '/' || v == '\0')) {
     760            /* caller takes it as indication of invalid
     761             * (dangerous wrt exploits) chars */
     762            return orig + 1;
     763        }
     764        *string++ = v;
     765        ptr += 2;
     766    }
     767    *string = '\0';
     768    return orig;
     769}
     770
     771#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     772/*
     773 * Decode a base64 data stream as per rfc1521.
     774 * Note that the rfc states that non base64 chars are to be ignored.
     775 * Since the decode always results in a shorter size than the input,
     776 * it is OK to pass the input arg as an output arg.
     777 * Parameter: a pointer to a base64 encoded string.
     778 * Decoded data is stored in-place.
     779 */
     780static void decodeBase64(char *Data)
     781{
     782    const unsigned char *in = (const unsigned char *)Data;
     783    /* The decoded size will be at most 3/4 the size of the encoded */
     784    unsigned ch = 0;
     785    int i = 0;
     786
     787    while (*in) {
     788        int t = *in++;
     789
     790        if (t >= '0' && t <= '9')
     791            t = t - '0' + 52;
     792        else if (t >= 'A' && t <= 'Z')
     793            t = t - 'A';
     794        else if (t >= 'a' && t <= 'z')
     795            t = t - 'a' + 26;
     796        else if (t == '+')
     797            t = 62;
     798        else if (t == '/')
     799            t = 63;
     800        else if (t == '=')
     801            t = 0;
     802        else
     803            continue;
     804
     805        ch = (ch << 6) | t;
     806        i++;
     807        if (i == 4) {
     808            *Data++ = (char) (ch >> 16);
     809            *Data++ = (char) (ch >> 8);
     810            *Data++ = (char) ch;
     811            i = 0;
     812        }
     813    }
     814    *Data = '\0';
     815}
     816#endif
     817
     818/*
     819 * Create a listen server socket on the designated port.
     820 */
     821static int openServer(void)
     822{
     823    int n = bb_strtou(bind_addr_or_port, NULL, 10);
     824    if (!errno && n && n <= 0xffff)
     825        n = create_and_bind_stream_or_die(NULL, n);
     826    else
     827        n = create_and_bind_stream_or_die(bind_addr_or_port, 80);
     828    xlisten(n, 9);
     829    return n;
     830}
     831
     832/*
     833 * Log the connection closure and exit.
     834 */
     835static void log_and_exit(void) ATTRIBUTE_NORETURN;
     836static void log_and_exit(void)
     837{
     838    /* Paranoia. IE said to be buggy. It may send some extra data
     839     * or be confused by us just exiting without SHUT_WR. Oh well. */
     840    shutdown(1, SHUT_WR);
     841    ndelay_on(0);
     842    while (read(0, iobuf, IOBUF_SIZE) > 0)
     843        continue;
     844
     845    if (verbose > 2)
     846        bb_error_msg("closed");
     847    _exit(xfunc_error_retval);
     848}
     849
     850/*
     851 * Create and send HTTP response headers.
     852 * The arguments are combined and sent as one write operation.  Note that
     853 * IE will puke big-time if the headers are not sent in one packet and the
     854 * second packet is delayed for any reason.
     855 * responseNum - the result code to send.
     856 */
     857static void send_headers(int responseNum)
     858{
     859    static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT";
     860
     861    const char *responseString = "";
     862    const char *infoString = NULL;
     863    const char *mime_type;
     864#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
     865    const char *error_page = 0;
     866#endif
     867    unsigned i;
     868    time_t timer = time(0);
     869    char tmp_str[80];
     870    int len;
     871
     872    for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
     873        if (http_response_type[i] == responseNum) {
     874            responseString = http_response[i].name;
     875            infoString = http_response[i].info;
     876#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
     877            error_page = http_error_page[i];
     878#endif
     879            break;
     880        }
     881    }
     882    /* error message is HTML */
     883    mime_type = responseNum == HTTP_OK ?
     884                found_mime_type : "text/html";
     885
     886    if (verbose)
     887        bb_error_msg("response:%u", responseNum);
     888
     889    /* emit the current date */
     890    strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&timer));
     891    len = sprintf(iobuf,
     892            "HTTP/1.0 %d %s\r\nContent-type: %s\r\n"
     893            "Date: %s\r\nConnection: close\r\n",
     894            responseNum, responseString, mime_type, tmp_str);
     895
     896#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     897    if (responseNum == HTTP_UNAUTHORIZED) {
     898        len += sprintf(iobuf + len,
     899                "WWW-Authenticate: Basic realm=\"%s\"\r\n",
     900                g_realm);
     901    }
     902#endif
     903    if (responseNum == HTTP_MOVED_TEMPORARILY) {
     904        len += sprintf(iobuf + len, "Location: %s/%s%s\r\n",
     905                found_moved_temporarily,
     906                (g_query ? "?" : ""),
     907                (g_query ? g_query : ""));
     908    }
     909
     910#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
     911    if (error_page && !access(error_page, R_OK)) {
     912        strcat(iobuf, "\r\n");
     913        len += 2;
     914
     915        if (DEBUG)
     916            fprintf(stderr, "headers: '%s'\n", iobuf);
     917        full_write(1, iobuf, len);
     918        if (DEBUG)
     919            fprintf(stderr, "writing error page: '%s'\n", error_page);
     920        return send_file_and_exit(error_page, FALSE);
     921    }
     922#endif
     923
     924    if (ContentLength != -1) {    /* file */
     925        strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&last_mod));
     926        len += sprintf(iobuf + len, "Last-Modified: %s\r\n%s %"OFF_FMT"d\r\n",
     927            tmp_str, "Content-length:", ContentLength);
     928    }
     929    iobuf[len++] = '\r';
     930    iobuf[len++] = '\n';
     931    if (infoString) {
     932        len += sprintf(iobuf + len,
     933                "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n"
     934                "<BODY><H1>%d %s</H1>\n%s\n</BODY></HTML>\n",
     935                responseNum, responseString,
     936                responseNum, responseString, infoString);
     937    }
     938    if (DEBUG)
     939        fprintf(stderr, "headers: '%s'\n", iobuf);
     940    if (full_write(1, iobuf, len) != len) {
     941        if (verbose > 1)
     942            bb_perror_msg("error");
     943        log_and_exit();
     944    }
     945}
     946
     947static void send_headers_and_exit(int responseNum) ATTRIBUTE_NORETURN;
     948static void send_headers_and_exit(int responseNum)
     949{
     950    send_headers(responseNum);
     951    log_and_exit();
     952}
     953
     954/*
     955 * Read from the socket until '\n' or EOF. '\r' chars are removed.
     956 * '\n' is replaced with NUL.
     957 * Return number of characters read or 0 if nothing is read
     958 * ('\r' and '\n' are not counted).
     959 * Data is returned in iobuf.
     960 */
     961static int get_line(void)
     962{
     963    int count = 0;
     964    char c;
     965
     966    while (1) {
     967        if (hdr_cnt <= 0) {
     968            hdr_cnt = safe_read(0, hdr_buf, sizeof(hdr_buf));
     969            if (hdr_cnt <= 0)
     970                break;
     971            hdr_ptr = hdr_buf;
     972        }
     973        iobuf[count] = c = *hdr_ptr++;
     974        hdr_cnt--;
     975
     976        if (c == '\r')
     977            continue;
     978        if (c == '\n') {
     979            iobuf[count] = '\0';
     980            return count;
     981        }
     982        if (count < (IOBUF_SIZE - 1))      /* check overflow */
     983            count++;
     984    }
     985    return count;
     986}
     987
     988#if ENABLE_FEATURE_HTTPD_CGI
     989static void setenv1(const char *name, const char *value)
     990{
     991    setenv(name, value ? value : "", 1);
     992}
     993
     994/*
     995 * Spawn CGI script, forward CGI's stdin/out <=> network
     996 *
     997 * Environment variables are set up and the script is invoked with pipes
     998 * for stdin/stdout.  If a post is being done the script is fed the POST
     999 * data in addition to setting the QUERY_STRING variable (for GETs or POSTs).
     1000 *
     1001 * Parameters:
     1002 * const char *url              The requested URL (with leading /).
     1003 * int bodyLen                  Length of the post body.
     1004 * const char *cookie           For set HTTP_COOKIE.
     1005 * const char *content_type     For set CONTENT_TYPE.
     1006 */
     1007static void send_cgi_and_exit(
     1008        const char *url,
     1009        const char *request,
     1010        int bodyLen,
     1011        const char *cookie,
     1012        const char *content_type) ATTRIBUTE_NORETURN;
     1013static void send_cgi_and_exit(
     1014        const char *url,
     1015        const char *request,
     1016        int bodyLen,
     1017        const char *cookie,
     1018        const char *content_type)
     1019{
     1020    struct { int rd; int wr; } fromCgi;  /* CGI -> httpd pipe */
     1021    struct { int rd; int wr; } toCgi;    /* httpd -> CGI pipe */
     1022    char *fullpath;
     1023    char *script;
     1024    char *purl;
     1025    int buf_count;
     1026    int status;
     1027    int pid = 0;
     1028
     1029    /*
     1030     * We are mucking with environment _first_ and then vfork/exec,
     1031     * this allows us to use vfork safely. Parent don't care about
     1032     * these environment changes anyway.
     1033     */
     1034
     1035    /*
     1036     * Find PATH_INFO.
     1037     */
     1038    purl = xstrdup(url);
     1039    script = purl;
     1040    while ((script = strchr(script + 1, '/')) != NULL) {
     1041        /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */
     1042        struct stat sb;
     1043
     1044        *script = '\0';
     1045        if (!is_directory(purl + 1, 1, &sb)) {
     1046            /* not directory, found script.cgi/PATH_INFO */
     1047            *script = '/';
     1048            break;
     1049        }
     1050        *script = '/';          /* is directory, find next '/' */
     1051    }
     1052    setenv1("PATH_INFO", script);   /* set /PATH_INFO or "" */
     1053    setenv1("REQUEST_METHOD", request);
     1054    if (g_query) {
     1055        putenv(xasprintf("%s=%s?%s", "REQUEST_URI", purl, g_query));
     1056    } else {
     1057        setenv1("REQUEST_URI", purl);
     1058    }
     1059    if (script != NULL)
     1060        *script = '\0';         /* cut off /PATH_INFO */
     1061
     1062    /* SCRIPT_FILENAME required by PHP in CGI mode */
     1063    fullpath = concat_path_file(home_httpd, purl);
     1064    setenv1("SCRIPT_FILENAME", fullpath);
     1065    /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
     1066    setenv1("SCRIPT_NAME", purl);
     1067    /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
     1068     * QUERY_STRING: The information which follows the ? in the URL
     1069     * which referenced this script. This is the query information.
     1070     * It should not be decoded in any fashion. This variable
     1071     * should always be set when there is query information,
     1072     * regardless of command line decoding. */
     1073    /* (Older versions of bbox seem to do some decoding) */
     1074    setenv1("QUERY_STRING", g_query);
     1075    putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER);
     1076    putenv((char*)"SERVER_PROTOCOL=HTTP/1.0");
     1077    putenv((char*)"GATEWAY_INTERFACE=CGI/1.1");
     1078    /* Having _separate_ variables for IP and port defeats
     1079     * the purpose of having socket abstraction. Which "port"
     1080     * are you using on Unix domain socket?
     1081     * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense.
     1082     * Oh well... */
     1083    {
     1084        char *p = rmt_ip_str ? rmt_ip_str : (char*)"";
     1085        char *cp = strrchr(p, ':');
     1086        if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']'))
     1087            cp = NULL;
     1088        if (cp) *cp = '\0'; /* delete :PORT */
     1089        setenv1("REMOTE_ADDR", p);
     1090        if (cp) {
     1091            *cp = ':';
     1092#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
     1093            setenv1("REMOTE_PORT", cp + 1);
     1094#endif
     1095        }
     1096    }
     1097    setenv1("HTTP_USER_AGENT", user_agent);
     1098    if (bodyLen)
     1099        putenv(xasprintf("CONTENT_LENGTH=%d", bodyLen));
     1100    if (cookie)
     1101        setenv1("HTTP_COOKIE", cookie);
     1102    if (content_type)
     1103        setenv1("CONTENT_TYPE", content_type);
     1104#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     1105    if (remoteuser) {
     1106        setenv1("REMOTE_USER", remoteuser);
     1107        putenv((char*)"AUTH_TYPE=Basic");
     1108    }
     1109#endif
     1110    if (referer)
     1111        setenv1("HTTP_REFERER", referer);
     1112
     1113    xpipe(&fromCgi.rd);
     1114    xpipe(&toCgi.rd);
     1115
     1116    pid = vfork();
     1117    if (pid < 0) {
     1118        /* TODO: log perror? */
     1119        log_and_exit();
     1120    }
     1121
     1122    if (!pid) {
     1123        /* Child process */
     1124        xfunc_error_retval = 242;
     1125
     1126        xmove_fd(toCgi.rd, 0);  /* replace stdin with the pipe */
     1127        xmove_fd(fromCgi.wr, 1);  /* replace stdout with the pipe */
     1128        close(fromCgi.rd);
     1129        close(toCgi.wr);
     1130        /* User seeing stderr output can be a security problem.
     1131         * If CGI really wants that, it can always do dup itself. */
     1132        /* dup2(1, 2); */
     1133
     1134        /* script must have absolute path */
     1135        script = strrchr(fullpath, '/');
     1136        if (!script)
     1137            goto error_execing_cgi;
     1138        *script = '\0';
     1139        /* chdiring to script's dir */
     1140        if (chdir(fullpath) == 0) {
     1141            char *argv[2];
     1142#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     1143            char *interpr = NULL;
     1144            char *suffix = strrchr(purl, '.');
     1145
     1146            if (suffix) {
     1147                Htaccess *cur;
     1148                for (cur = script_i; cur; cur = cur->next) {
     1149                    if (strcmp(cur->before_colon + 1, suffix) == 0) {
     1150                        interpr = cur->after_colon;
     1151                        break;
     1152                    }
     1153                }
     1154            }
     1155#endif
     1156            *script = '/';
     1157            /* set argv[0] to name without path */
     1158            argv[0] = (char*)bb_basename(purl);
     1159            argv[1] = NULL;
     1160#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     1161            if (interpr)
     1162                execv(interpr, argv);
     1163            else
     1164#endif
     1165                execv(fullpath, argv);
     1166        }
     1167 error_execing_cgi:
     1168        /* send to stdout
     1169         * (we are CGI here, our stdout is pumped to the net) */
     1170        send_headers_and_exit(HTTP_NOT_FOUND);
     1171    } /* end child */
     1172
     1173    /* Parent process */
     1174
     1175    /* First, restore variables possibly changed by child */
     1176    xfunc_error_retval = 0;
     1177
     1178    /* Prepare for pumping data.
     1179     * iobuf is used for CGI -> network data,
     1180     * hdr_buf is for network -> CGI data (POSTDATA) */
     1181    buf_count = 0;
     1182    close(fromCgi.wr);
     1183    close(toCgi.rd);
     1184
     1185    /* If CGI dies, we still want to correctly finish reading its output
     1186     * and send it to the peer. So please no SIGPIPEs! */
     1187    signal(SIGPIPE, SIG_IGN);
     1188
     1189    /* This loop still looks messy. What is an exit criteria?
     1190     * "CGI's output closed"? Or "CGI has exited"?
     1191     * What to do if CGI has closed both input and output, but
     1192     * didn't exit? etc... */
     1193
     1194    /* NB: breaking out of this loop jumps to log_and_exit() */
     1195    while (1) {
     1196        fd_set readSet;
     1197        fd_set writeSet;
     1198        int nfound;
     1199        int count;
     1200
     1201        FD_ZERO(&readSet);
     1202        FD_ZERO(&writeSet);
     1203        FD_SET(fromCgi.rd, &readSet);
     1204        if (bodyLen > 0 || hdr_cnt > 0) {
     1205            FD_SET(toCgi.wr, &writeSet);
     1206            nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd;
     1207            if (hdr_cnt <= 0)
     1208                FD_SET(0, &readSet);
     1209            /* Now wait on the set of sockets! */
     1210            nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
     1211        } else {
     1212            if (!bodyLen) {
     1213                close(toCgi.wr); /* no more POST data to CGI */
     1214                bodyLen = -1;
     1215            }
     1216            nfound = select(fromCgi.rd + 1, &readSet, NULL, NULL, NULL);
     1217        }
     1218
     1219        if (nfound <= 0) {
     1220            if (waitpid(pid, &status, WNOHANG) <= 0) {
     1221                /* Weird. CGI didn't exit and no fd's
     1222                 * are ready, yet select returned?! */
     1223                continue;
     1224            }
     1225            close(fromCgi.rd);
     1226            if (DEBUG && WIFEXITED(status))
     1227                bb_error_msg("CGI exited, status=%d", WEXITSTATUS(status));
     1228            if (DEBUG && WIFSIGNALED(status))
     1229                bb_error_msg("CGI killed, signal=%d", WTERMSIG(status));
     1230            break;
     1231        }
     1232
     1233        if (hdr_cnt > 0 && FD_ISSET(toCgi.wr, &writeSet)) {
     1234            /* Have data from peer and can write to CGI */
     1235            count = safe_write(toCgi.wr, hdr_ptr, hdr_cnt);
     1236            /* Doesn't happen, we dont use nonblocking IO here
     1237             *if (count < 0 && errno == EAGAIN) {
     1238             *  ...
     1239             *} else */
     1240            if (count > 0) {
     1241                hdr_ptr += count;
     1242                hdr_cnt -= count;
     1243            } else {
     1244                hdr_cnt = bodyLen = 0; /* EOF/broken pipe to CGI */
     1245            }
     1246        } else if (bodyLen > 0 && hdr_cnt == 0
     1247         && FD_ISSET(0, &readSet)
     1248        ) {
     1249            /* We expect data, prev data portion is eaten by CGI
     1250             * and there *is* data to read from the peer
     1251             * (POSTDATA?) */
     1252            count = bodyLen > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : bodyLen;
     1253            count = safe_read(0, hdr_buf, count);
     1254            if (count > 0) {
     1255                hdr_cnt = count;
     1256                hdr_ptr = hdr_buf;
     1257                bodyLen -= count;
     1258            } else {
     1259                bodyLen = 0; /* closed */
     1260            }
     1261        }
     1262
     1263#define PIPESIZE PIPE_BUF
     1264#if PIPESIZE >= IOBUF_SIZE
     1265# error "PIPESIZE >= IOBUF_SIZE"
     1266#endif
     1267        if (FD_ISSET(fromCgi.rd, &readSet)) {
     1268            /* There is something to read from CGI */
     1269            char *rbuf = iobuf;
     1270
     1271            /* Are we still buffering CGI output? */
     1272            if (buf_count >= 0) {
     1273                /* HTTP_200[] has single "\r\n" at the end.
     1274                 * According to http://hoohoo.ncsa.uiuc.edu/cgi/out.html,
     1275                 * CGI scripts MUST send their own header terminated by
     1276                 * empty line, then data. That's why we have only one
     1277                 * <cr><lf> pair here. We will output "200 OK" line
     1278                 * if needed, but CGI still has to provide blank line
     1279                 * between header and body */
     1280
     1281                /* Must use safe_read, not full_read, because
     1282                 * CGI may output a few first bytes and then wait
     1283                 * for POSTDATA without closing stdout.
     1284                 * With full_read we may wait here forever. */
     1285                count = safe_read(fromCgi.rd, rbuf + buf_count, PIPESIZE - 8);
     1286                if (count <= 0) {
     1287                    /* eof (or error) and there was no "HTTP",
     1288                     * so write it, then write received data */
     1289                    if (buf_count) {
     1290                        full_write(1, HTTP_200, sizeof(HTTP_200)-1);
     1291                        full_write(1, rbuf, buf_count);
     1292                    }
     1293                    break; /* CGI stdout is closed, exiting */
     1294                }
     1295                buf_count += count;
     1296                count = 0;
     1297                /* "Status" header format is: "Status: 302 Redirected\r\n" */
     1298                if (buf_count >= 8 && memcmp(rbuf, "Status: ", 8) == 0) {
     1299                    /* send "HTTP/1.0 " */
     1300                    if (full_write(1, HTTP_200, 9) != 9)
     1301                        break;
     1302                    rbuf += 8; /* skip "Status: " */
     1303                    count = buf_count - 8;
     1304                    buf_count = -1; /* buffering off */
     1305                } else if (buf_count >= 4) {
     1306                    /* Did CGI add "HTTP"? */
     1307                    if (memcmp(rbuf, HTTP_200, 4) != 0) {
     1308                        /* there is no "HTTP", do it ourself */
     1309                        if (full_write(1, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
     1310                            break;
     1311                    }
     1312                    /* Commented out:
     1313                    if (!strstr(rbuf, "ontent-")) {
     1314                        full_write(s, "Content-type: text/plain\r\n\r\n", 28);
     1315                    }
     1316                     * Counter-example of valid CGI without Content-type:
     1317                     * echo -en "HTTP/1.0 302 Found\r\n"
     1318                     * echo -en "Location: http://www.busybox.net\r\n"
     1319                     * echo -en "\r\n"
     1320                     */
     1321                    count = buf_count;
     1322                    buf_count = -1; /* buffering off */
     1323                }
     1324            } else {
     1325                count = safe_read(fromCgi.rd, rbuf, PIPESIZE);
     1326                if (count <= 0)
     1327                    break;  /* eof (or error) */
     1328            }
     1329            if (full_write(1, rbuf, count) != count)
     1330                break;
     1331            if (DEBUG)
     1332                fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
     1333        } /* if (FD_ISSET(fromCgi.rd)) */
     1334    } /* while (1) */
     1335    log_and_exit();
     1336}
     1337#endif          /* FEATURE_HTTPD_CGI */
     1338
     1339/*
     1340 * Send a file response to a HTTP request, and exit
     1341 *
     1342 * Parameters:
     1343 * const char *url    The requested URL (with leading /).
     1344 * headers            Don't send headers before if FALSE.
     1345 */
     1346static void send_file_and_exit(const char *url, int headers)
     1347{
     1348    static const char *const suffixTable[] = {
     1349    /* Warning: shorter equivalent suffix in one line must be first */
     1350        ".htm.html", "text/html",
     1351        ".jpg.jpeg", "image/jpeg",
     1352        ".gif",      "image/gif",
     1353        ".png",      "image/png",
     1354        ".txt.h.c.cc.cpp", "text/plain",
     1355        ".css",      "text/css",
     1356        ".wav",      "audio/wav",
     1357        ".avi",      "video/x-msvideo",
     1358        ".qt.mov",   "video/quicktime",
     1359        ".mpe.mpeg", "video/mpeg",
     1360        ".mid.midi", "audio/midi",
     1361        ".mp3",      "audio/mpeg",
     1362#if 0                        /* unpopular */
     1363        ".au",       "audio/basic",
     1364        ".pac",      "application/x-ns-proxy-autoconfig",
     1365        ".vrml.wrl", "model/vrml",
     1366#endif
     1367        NULL
     1368    };
     1369
     1370    char *suffix;
     1371    int f;
     1372    const char *const *table;
     1373    const char *try_suffix;
     1374    ssize_t count;
     1375#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
     1376    off_t offset = 0;
     1377#endif
     1378
     1379    suffix = strrchr(url, '.');
     1380
     1381    /* If not found, set default as "application/octet-stream";  */
     1382    found_mime_type = "application/octet-stream";
     1383    if (suffix) {
     1384#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     1385        Htaccess *cur;
     1386#endif
     1387        for (table = suffixTable; *table; table += 2) {
     1388            try_suffix = strstr(table[0], suffix);
     1389            if (try_suffix) {
     1390                try_suffix += strlen(suffix);
     1391                if (*try_suffix == '\0' || *try_suffix == '.') {
     1392                    found_mime_type = table[1];
     1393                    break;
     1394                }
     1395            }
     1396        }
     1397#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     1398        for (cur = mime_a; cur; cur = cur->next) {
     1399            if (strcmp(cur->before_colon, suffix) == 0) {
     1400                found_mime_type = cur->after_colon;
     1401                break;
     1402            }
     1403        }
     1404#endif
     1405    }
     1406
     1407    if (DEBUG)
     1408        bb_error_msg("sending file '%s' content-type: %s",
     1409            url, found_mime_type);
     1410
     1411    f = open(url, O_RDONLY);
     1412    if (f < 0) {
     1413        if (DEBUG)
     1414            bb_perror_msg("cannot open '%s'", url);
     1415        if (headers)
     1416            send_headers_and_exit(HTTP_NOT_FOUND);
     1417    }
     1418
     1419    if (headers)
     1420        send_headers(HTTP_OK);
     1421
     1422    /* If you want to know about EPIPE below
     1423     * (happens if you abort downloads from local httpd): */
     1424    signal(SIGPIPE, SIG_IGN);
     1425
     1426#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
     1427    do {
     1428        /* byte count (3rd arg) is rounded down to 64k */
     1429        count = sendfile(1, f, &offset, MAXINT(ssize_t) - 0xffff);
     1430        if (count < 0) {
     1431            if (offset == 0)
     1432                goto fallback;
     1433            goto fin;
     1434        }
     1435    } while (count > 0);
     1436    log_and_exit();
     1437
     1438 fallback:
     1439#endif
     1440    while ((count = safe_read(f, iobuf, IOBUF_SIZE)) > 0) {
     1441        ssize_t n = count;
     1442        count = full_write(1, iobuf, count);
     1443        if (count != n)
     1444            break;
     1445    }
     1446#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
     1447 fin:
     1448#endif
     1449    if (count < 0 && verbose > 1)
     1450        bb_perror_msg("error");
     1451    log_and_exit();
     1452}
     1453
     1454static int checkPermIP(void)
     1455{
     1456    Htaccess_IP *cur;
     1457
     1458    /* This could stand some work */
     1459    for (cur = ip_a_d; cur; cur = cur->next) {
    12161460#if DEBUG
    1217       if (WIFEXITED(status))
    1218           bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status));
    1219       if (WIFSIGNALED(status))
    1220           bb_error_msg("piped has exited with signal=%d", WTERMSIG(status));
    1221 #endif
    1222       break;
    1223     }
    1224       } else if(post_readed_size > 0 && FD_ISSET(outFd, &writeSet)) {
    1225         count = bb_full_write(outFd, wbuf + post_readed_idx, post_readed_size);
    1226         if(count > 0) {
    1227             post_readed_size -= count;
    1228             post_readed_idx += count;
    1229             if(post_readed_size == 0)
    1230                 post_readed_idx = 0;
    1231         } else {
    1232             post_readed_size = post_readed_idx = bodyLen = 0; /* broken pipe to CGI */
    1233         }
    1234       } else if(bodyLen > 0 && post_readed_size == 0 && FD_ISSET(a_c_r, &readSet)) {
    1235         count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen;
    1236         count = safe_read(a_c_r, wbuf, count);
    1237         if(count > 0) {
    1238             post_readed_size += count;
    1239             bodyLen -= count;
    1240         } else {
    1241             bodyLen = 0;    /* closed */
    1242         }
    1243       }
    1244       if(FD_ISSET(inFd, &readSet)) {
    1245     int s = a_c_w;
    1246     char *rbuf = config->buf;
    1247 
    1248 #ifndef PIPE_BUF
    1249 # define PIPESIZE 4096          /* amount of buffering in a pipe */
     1461        fprintf(stderr,
     1462            "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n",
     1463            rmt_ip_str,
     1464            (unsigned char)(cur->ip >> 24),
     1465            (unsigned char)(cur->ip >> 16),
     1466            (unsigned char)(cur->ip >> 8),
     1467            (unsigned char)(cur->ip),
     1468            (unsigned char)(cur->mask >> 24),
     1469            (unsigned char)(cur->mask >> 16),
     1470            (unsigned char)(cur->mask >> 8),
     1471            (unsigned char)(cur->mask)
     1472        );
     1473#endif
     1474        if ((rmt_ip & cur->mask) == cur->ip)
     1475            return cur->allow_deny == 'A';   /* Allow/Deny */
     1476    }
     1477
     1478    /* if unconfigured, return 1 - access from all */
     1479    return !flg_deny_all;
     1480}
     1481
     1482#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     1483/*
     1484 * Check the permission file for access password protected.
     1485 *
     1486 * If config file isn't present, everything is allowed.
     1487 * Entries are of the form you can see example from header source
     1488 *
     1489 * path      The file path.
     1490 * request   User information to validate.
     1491 *
     1492 * Returns 1 if request is OK.
     1493 */
     1494static int checkPerm(const char *path, const char *request)
     1495{
     1496    Htaccess *cur;
     1497    const char *p;
     1498    const char *p0;
     1499
     1500    const char *prev = NULL;
     1501
     1502    /* This could stand some work */
     1503    for (cur = g_auth; cur; cur = cur->next) {
     1504        size_t l;
     1505
     1506        p0 = cur->before_colon;
     1507        if (prev != NULL && strcmp(prev, p0) != 0)
     1508            continue;       /* find next identical */
     1509        p = cur->after_colon;
     1510        if (DEBUG)
     1511            fprintf(stderr, "checkPerm: '%s' ? '%s'\n", p0, request);
     1512
     1513        l = strlen(p0);
     1514        if (strncmp(p0, path, l) == 0
     1515         && (l == 1 || path[l] == '/' || path[l] == '\0')
     1516        ) {
     1517            char *u;
     1518            /* path match found.  Check request */
     1519            /* for check next /path:user:password */
     1520            prev = p0;
     1521            u = strchr(request, ':');
     1522            if (u == NULL) {
     1523                /* bad request, ':' required */
     1524                break;
     1525            }
     1526
     1527            if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
     1528                char *cipher;
     1529                char *pp;
     1530
     1531                if (strncmp(p, request, u - request) != 0) {
     1532                    /* user doesn't match */
     1533                    continue;
     1534                }
     1535                pp = strchr(p, ':');
     1536                if (pp && pp[1] == '$' && pp[2] == '1'
     1537                 && pp[3] == '$' && pp[4]
     1538                ) {
     1539                    pp++;
     1540                    cipher = pw_encrypt(u+1, pp);
     1541                    if (strcmp(cipher, pp) == 0)
     1542                        goto set_remoteuser_var;   /* Ok */
     1543                    /* unauthorized */
     1544                    continue;
     1545                }
     1546            }
     1547
     1548            if (strcmp(p, request) == 0) {
     1549 set_remoteuser_var:
     1550                remoteuser = strdup(request);
     1551                if (remoteuser)
     1552                    remoteuser[u - request] = '\0';
     1553                return 1;   /* Ok */
     1554            }
     1555            /* unauthorized */
     1556        }
     1557    } /* for */
     1558
     1559    return prev == NULL;
     1560}
     1561#endif  /* FEATURE_HTTPD_BASIC_AUTH */
     1562
     1563/*
     1564 * Handle timeouts
     1565 */
     1566static void exit_on_signal(int sig) ATTRIBUTE_NORETURN;
     1567static void exit_on_signal(int sig)
     1568{
     1569    send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
     1570}
     1571
     1572/*
     1573 * Handle an incoming http request and exit.
     1574 */
     1575static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN;
     1576static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
     1577{
     1578    static const char request_GET[] ALIGN1 = "GET";
     1579
     1580    struct stat sb;
     1581    char *urlcopy;
     1582    char *urlp;
     1583    char *tptr;
     1584    int http_major_version;
     1585    int ip_allowed;
     1586#if ENABLE_FEATURE_HTTPD_CGI
     1587    const char *prequest;
     1588    unsigned long length = 0;
     1589    char *cookie = 0;
     1590    char *content_type = 0;
     1591#endif
     1592    struct sigaction sa;
     1593#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     1594    int credentials = -1;  /* if not required this is Ok */
     1595#endif
     1596
     1597    /* Allocation of iobuf is postponed until now
     1598     * (IOW, server process doesn't need to waste 8k) */
     1599    iobuf = xmalloc(IOBUF_SIZE);
     1600
     1601    rmt_ip = 0;
     1602    if (fromAddr->sa.sa_family == AF_INET) {
     1603        rmt_ip = ntohl(fromAddr->sin.sin_addr.s_addr);
     1604    }
     1605#if ENABLE_FEATURE_IPV6
     1606    if (fromAddr->sa.sa_family == AF_INET6
     1607     && fromAddr->sin6.sin6_addr.s6_addr32[0] == 0
     1608     && fromAddr->sin6.sin6_addr.s6_addr32[1] == 0
     1609     && ntohl(fromAddr->sin6.sin6_addr.s6_addr32[2]) == 0xffff)
     1610        rmt_ip = ntohl(fromAddr->sin6.sin6_addr.s6_addr32[3]);
     1611#endif
     1612    if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
     1613        rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->sa);
     1614    }
     1615    if (verbose) {
     1616        /* this trick makes -v logging much simpler */
     1617        applet_name = rmt_ip_str;
     1618        if (verbose > 2)
     1619            bb_error_msg("connected");
     1620    }
     1621
     1622    /* Install timeout handler */
     1623    memset(&sa, 0, sizeof(sa));
     1624    sa.sa_handler = exit_on_signal;
     1625    /* sigemptyset(&sa.sa_mask); - memset should be enough */
     1626    /*sa.sa_flags = 0; - no SA_RESTART */
     1627    sigaction(SIGALRM, &sa, NULL);
     1628    alarm(HEADER_READ_TIMEOUT);
     1629
     1630    if (!get_line()) /* EOF or error or empty line */
     1631        send_headers_and_exit(HTTP_BAD_REQUEST);
     1632
     1633    /* Determine type of request (GET/POST) */
     1634    urlp = strpbrk(iobuf, " \t");
     1635    if (urlp == NULL)
     1636        send_headers_and_exit(HTTP_BAD_REQUEST);
     1637    *urlp++ = '\0';
     1638#if ENABLE_FEATURE_HTTPD_CGI
     1639    prequest = request_GET;
     1640    if (strcasecmp(iobuf, prequest) != 0) {
     1641        prequest = "POST";
     1642        if (strcasecmp(iobuf, prequest) != 0)
     1643            send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
     1644    }
    12501645#else
    1251 # define PIPESIZE PIPE_BUF
    1252 #endif
    1253 #if PIPESIZE >= MAX_MEMORY_BUFF
    1254 # error "PIPESIZE >= MAX_MEMORY_BUFF"
    1255 #endif
    1256 
    1257     // There is something to read
    1258     count = safe_read(inFd, rbuf, PIPESIZE);
    1259     if (count == 0)
    1260         break;  /* closed */
    1261     if (count > 0) {
    1262       if (firstLine) {
    1263         rbuf[count] = 0;
    1264         /* check to see if the user script added headers */
    1265         if(strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) {
    1266           bb_full_write(s, "HTTP/1.0 200 OK\r\n", 17);
    1267         }
    1268         if (strstr(rbuf, "ontent-") == 0) {
    1269           bb_full_write(s, "Content-type: text/plain\r\n\r\n", 28);
    1270         }
    1271         firstLine = 0;
    1272       }
    1273       if (bb_full_write(s, rbuf, count) != count)
    1274           break;
    1275 
    1276 #if DEBUG
    1277       fprintf(stderr, "cgi read %d bytes\n", count);
    1278 #endif
    1279     }
    1280       }
    1281     }
    1282   }
    1283   return 0;
    1284 }
    1285 #endif          /* CONFIG_FEATURE_HTTPD_CGI */
    1286 
    1287 /****************************************************************************
    1288  *
    1289  > $Function: sendFile()
    1290  *
    1291  * $Description: Send a file response to an HTTP request
    1292  *
    1293  * $Parameter:
    1294  *      (const char *) url . . The URL requested.
    1295  *
    1296  * $Return: (int)  . . . . . . Always 0.
    1297  *
    1298  ****************************************************************************/
    1299 static int sendFile(const char *url)
    1300 {
    1301   char * suffix;
    1302   int  f;
    1303   const char * const * table;
    1304   const char * try_suffix;
    1305 
    1306   suffix = strrchr(url, '.');
    1307 
    1308   for (table = suffixTable; *table; table += 2)
    1309     if(suffix != NULL && (try_suffix = strstr(*table, suffix)) != 0) {
    1310         try_suffix += strlen(suffix);
    1311         if(*try_suffix == 0 || *try_suffix == '.')
    1312             break;
    1313     }
    1314   /* also, if not found, set default as "application/octet-stream";  */
    1315   config->httpd_found.found_mime_type = *(table+1);
    1316 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    1317   if (suffix) {
    1318     Htaccess * cur;
    1319 
    1320     for (cur = config->mime_a; cur; cur = cur->next) {
    1321     if(strcmp(cur->before_colon, suffix) == 0) {
    1322         config->httpd_found.found_mime_type = cur->after_colon;
    1323         break;
    1324     }
    1325     }
    1326   }
    1327 #endif  /* CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES */
    1328 
    1329 #if DEBUG
    1330   fprintf(stderr, "Sending file '%s' Content-type: %s\n",
    1331             url, config->httpd_found.found_mime_type);
    1332 #endif
    1333 
    1334   f = open(url, O_RDONLY);
    1335   if (f >= 0) {
    1336     int count;
    1337     char *buf = config->buf;
    1338 
    1339     sendHeaders(HTTP_OK);
    1340     while ((count = bb_full_read(f, buf, MAX_MEMORY_BUFF)) > 0) {
    1341         if (bb_full_write(a_c_w, buf, count) != count)
    1342             break;
    1343     }
    1344     close(f);
    1345   } else {
    1346 #if DEBUG
    1347     bb_perror_msg("Unable to open '%s'", url);
    1348 #endif
    1349     sendHeaders(HTTP_NOT_FOUND);
    1350   }
    1351 
    1352   return 0;
    1353 }
    1354 
    1355 static int checkPermIP(void)
    1356 {
    1357     Htaccess_IP * cur;
    1358 
    1359     /* This could stand some work */
    1360     for (cur = config->ip_a_d; cur; cur = cur->next) {
    1361 #if DEBUG
    1362     fprintf(stderr, "checkPermIP: '%s' ? ", config->rmt_ip_str);
    1363     fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n",
    1364         (unsigned char)(cur->ip >> 24),
    1365         (unsigned char)(cur->ip >> 16),
    1366         (unsigned char)(cur->ip >> 8),
    1367                 cur->ip & 0xff,
    1368         (unsigned char)(cur->mask >> 24),
    1369         (unsigned char)(cur->mask >> 16),
    1370         (unsigned char)(cur->mask >> 8),
    1371                 cur->mask & 0xff);
    1372 #endif
    1373     if((config->rmt_ip & cur->mask) == cur->ip)
    1374         return cur->allow_deny == 'A';   /* Allow/Deny */
    1375     }
    1376 
    1377     /* if unconfigured, return 1 - access from all */
    1378     return !config->flg_deny_all;
    1379 }
    1380 
    1381 /****************************************************************************
    1382  *
    1383  > $Function: checkPerm()
    1384  *
    1385  * $Description: Check the permission file for access password protected.
    1386  *
    1387  *   If config file isn't present, everything is allowed.
    1388  *   Entries are of the form you can see example from header source
    1389  *
    1390  * $Parameters:
    1391  *      (const char *) path  . . . . The file path.
    1392  *      (const char *) request . . . User information to validate.
    1393  *
    1394  * $Return: (int)  . . . . . . . . . 1 if request OK, 0 otherwise.
    1395  *
    1396  ****************************************************************************/
    1397 
    1398 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1399 static int checkPerm(const char *path, const char *request)
    1400 {
    1401     Htaccess * cur;
    1402     const char *p;
    1403     const char *p0;
    1404 
    1405     const char *prev = NULL;
    1406 
    1407     /* This could stand some work */
    1408     for (cur = config->auth; cur; cur = cur->next) {
    1409     p0 = cur->before_colon;
    1410     if(prev != NULL && strcmp(prev, p0) != 0)
    1411         continue;       /* find next identical */
    1412     p = cur->after_colon;
    1413 #if DEBUG
    1414     fprintf(stderr,"checkPerm: '%s' ? '%s'\n", p0, request);
    1415 #endif
     1646    if (strcasecmp(iobuf, request_GET) != 0)
     1647        send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
     1648#endif
     1649    urlp = skip_whitespace(urlp);
     1650    if (urlp[0] != '/')
     1651        send_headers_and_exit(HTTP_BAD_REQUEST);
     1652
     1653    /* Find end of URL and parse HTTP version, if any */
     1654    http_major_version = -1;
     1655    tptr = strchrnul(urlp, ' ');
     1656    /* Is it " HTTP/"? */
     1657    if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0)
     1658        http_major_version = (tptr[6] - '0');
     1659    *tptr = '\0';
     1660
     1661    /* Copy URL from after "GET "/"POST " to stack-allocated char[] */
     1662    urlcopy = alloca((tptr - urlp) + sizeof("/index.html"));
     1663    /*if (urlcopy == NULL)
     1664     *  send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/
     1665    strcpy(urlcopy, urlp);
     1666    /* NB: urlcopy ptr is never changed after this */
     1667
     1668    /* Extract url args if present */
     1669    tptr = strchr(urlcopy, '?');
     1670    g_query = NULL;
     1671    if (tptr) {
     1672        *tptr++ = '\0';
     1673        g_query = tptr;
     1674    }
     1675
     1676    /* Decode URL escape sequences */
     1677    tptr = decodeString(urlcopy, 0);
     1678    if (tptr == NULL)
     1679        send_headers_and_exit(HTTP_BAD_REQUEST);
     1680    if (tptr == urlcopy + 1) {
     1681        /* '/' or NUL is encoded */
     1682        send_headers_and_exit(HTTP_NOT_FOUND);
     1683    }
     1684
     1685    /* Canonicalize path */
     1686    /* Algorithm stolen from libbb bb_simplify_path(),
     1687     * but don't strdup and reducing trailing slash and protect out root */
     1688    urlp = tptr = urlcopy;
     1689    do {
     1690        if (*urlp == '/') {
     1691            /* skip duplicate (or initial) slash */
     1692            if (*tptr == '/') {
     1693                continue;
     1694            }
     1695            if (*tptr == '.') {
     1696                /* skip extra '.' */
     1697                if (tptr[1] == '/' || !tptr[1]) {
     1698                    continue;
     1699                }
     1700                /* '..': be careful */
     1701                if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) {
     1702                    ++tptr;
     1703                    if (urlp == urlcopy) /* protect root */
     1704                        send_headers_and_exit(HTTP_BAD_REQUEST);
     1705                    while (*--urlp != '/') /* omit previous dir */;
     1706                        continue;
     1707                }
     1708            }
     1709        }
     1710        *++urlp = *tptr;
     1711    } while (*++tptr);
     1712    *++urlp = '\0';       /* so keep last character */
     1713    tptr = urlp;          /* end ptr */
     1714
     1715    /* If URL is a directory, add '/' */
     1716    if (tptr[-1] != '/') {
     1717        if (is_directory(urlcopy + 1, 1, &sb)) {
     1718            found_moved_temporarily = urlcopy;
     1719        }
     1720    }
     1721
     1722    /* Log it */
     1723    if (verbose > 1)
     1724        bb_error_msg("url:%s", urlcopy);
     1725
     1726    tptr = urlcopy;
     1727    ip_allowed = checkPermIP();
     1728    while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) {
     1729        /* have path1/path2 */
     1730        *tptr = '\0';
     1731        if (is_directory(urlcopy + 1, 1, &sb)) {
     1732            /* may be having subdir config */
     1733            parse_conf(urlcopy + 1, SUBDIR_PARSE);
     1734            ip_allowed = checkPermIP();
     1735        }
     1736        *tptr = '/';
     1737    }
     1738    if (http_major_version >= 0) {
     1739        /* Request was with "... HTTP/nXXX", and n >= 0 */
     1740
     1741        /* Read until blank line for HTTP version specified, else parse immediate */
     1742        while (1) {
     1743            alarm(HEADER_READ_TIMEOUT);
     1744            if (!get_line())
     1745                break; /* EOF or error or empty line */
     1746            if (DEBUG)
     1747                bb_error_msg("header: '%s'", iobuf);
     1748
     1749#if ENABLE_FEATURE_HTTPD_CGI
     1750            /* try and do our best to parse more lines */
     1751            if ((STRNCASECMP(iobuf, "Content-length:") == 0)) {
     1752                /* extra read only for POST */
     1753                if (prequest != request_GET) {
     1754                    tptr = iobuf + sizeof("Content-length:") - 1;
     1755                    if (!tptr[0])
     1756                        send_headers_and_exit(HTTP_BAD_REQUEST);
     1757                    errno = 0;
     1758                    /* not using strtoul: it ignores leading minus! */
     1759                    length = strtol(tptr, &tptr, 10);
     1760                    /* length is "ulong", but we need to pass it to int later */
     1761                    /* so we check for negative or too large values in one go: */
     1762                    /* (long -> ulong conv caused negatives to be seen as > INT_MAX) */
     1763                    if (tptr[0] || errno || length > INT_MAX)
     1764                        send_headers_and_exit(HTTP_BAD_REQUEST);
     1765                }
     1766            } else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
     1767                cookie = strdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
     1768            } else if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
     1769                content_type = strdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
     1770            } else if (STRNCASECMP(iobuf, "Referer:") == 0) {
     1771                referer = strdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
     1772            } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) {
     1773                user_agent = strdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
     1774            }
     1775#endif
     1776#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     1777            if (STRNCASECMP(iobuf, "Authorization:") == 0) {
     1778                /* We only allow Basic credentials.
     1779                 * It shows up as "Authorization: Basic <userid:password>" where
     1780                 * the userid:password is base64 encoded.
     1781                 */
     1782                tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1);
     1783                if (STRNCASECMP(tptr, "Basic") != 0)
     1784                    continue;
     1785                tptr += sizeof("Basic")-1;
     1786                /* decodeBase64() skips whitespace itself */
     1787                decodeBase64(tptr);
     1788                credentials = checkPerm(urlcopy, tptr);
     1789            }
     1790#endif          /* FEATURE_HTTPD_BASIC_AUTH */
     1791        } /* while extra header reading */
     1792    }
     1793
     1794    /* We read headers, disable peer timeout */
     1795    alarm(0);
     1796
     1797    if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || ip_allowed == 0) {
     1798        /* protect listing [/path]/httpd_conf or IP deny */
     1799        send_headers_and_exit(HTTP_FORBIDDEN);
     1800    }
     1801
     1802#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
     1803    if (credentials <= 0 && checkPerm(urlcopy, ":") == 0) {
     1804        send_headers_and_exit(HTTP_UNAUTHORIZED);
     1805    }
     1806#endif
     1807
     1808    if (found_moved_temporarily) {
     1809        send_headers_and_exit(HTTP_MOVED_TEMPORARILY);
     1810    }
     1811
     1812    tptr = urlcopy + 1;      /* skip first '/' */
     1813
     1814#if ENABLE_FEATURE_HTTPD_CGI
     1815    if (strncmp(tptr, "cgi-bin/", 8) == 0) {
     1816        if (tptr[8] == '\0') {
     1817            /* protect listing "cgi-bin/" */
     1818            send_headers_and_exit(HTTP_FORBIDDEN);
     1819        }
     1820        send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
     1821    }
     1822#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    14161823    {
    1417         size_t l = strlen(p0);
    1418 
    1419         if(strncmp(p0, path, l) == 0 &&
    1420                 (l == 1 || path[l] == '/' || path[l] == 0)) {
    1421         char *u;
    1422         /* path match found.  Check request */
    1423         /* for check next /path:user:password */
    1424         prev = p0;
    1425         u = strchr(request, ':');
    1426         if(u == NULL) {
    1427             /* bad request, ':' required */
    1428             break;
    1429             }
    1430 
    1431 #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5
    1432         {
    1433             char *cipher;
    1434             char *pp;
    1435 
    1436             if(strncmp(p, request, u-request) != 0) {
    1437                 /* user uncompared */
    1438                 continue;
    1439             }
    1440             pp = strchr(p, ':');
    1441             if(pp && pp[1] == '$' && pp[2] == '1' &&
    1442                          pp[3] == '$' && pp[4]) {
    1443                 pp++;
    1444                 cipher = pw_encrypt(u+1, pp);
    1445                 if (strcmp(cipher, pp) == 0)
    1446                     goto set_remoteuser_var;   /* Ok */
    1447                 /* unauthorized */
    1448                 continue;
    1449             }
    1450         }
    1451 #endif
    1452         if (strcmp(p, request) == 0) {
    1453 #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5
    1454 set_remoteuser_var:
    1455 #endif
    1456             config->remoteuser = strdup(request);
    1457             if(config->remoteuser)
    1458             config->remoteuser[(u - request)] = 0;
    1459             return 1;   /* Ok */
    1460         }
    1461         /* unauthorized */
    1462         }
    1463     }
    1464     }   /* for */
    1465 
    1466     return prev == NULL;
    1467 }
    1468 
    1469 #endif  /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */
    1470 
    1471 /****************************************************************************
    1472  *
    1473  > $Function: handle_sigalrm()
    1474  *
    1475  * $Description: Handle timeouts
    1476  *
    1477  ****************************************************************************/
    1478 
    1479 static void
    1480 handle_sigalrm( int sig )
    1481 {
    1482     sendHeaders(HTTP_REQUEST_TIMEOUT);
    1483     config->alarm_signaled = sig;
    1484 }
    1485 
    1486 /****************************************************************************
    1487  *
    1488  > $Function: handleIncoming()
    1489  *
    1490  * $Description: Handle an incoming http request.
    1491  *
    1492  ****************************************************************************/
    1493 static void handleIncoming(void)
    1494 {
    1495   char *buf = config->buf;
    1496   char *url;
    1497   char *purl;
    1498   int  blank = -1;
    1499   char *test;
    1500   struct stat sb;
    1501   int ip_allowed;
    1502 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1503   const char *prequest = request_GET;
    1504   long length=0;
    1505   char *cookie = 0;
    1506   char *content_type = 0;
    1507 #endif
    1508   fd_set s_fd;
    1509   struct timeval tv;
    1510   int retval;
    1511   struct sigaction sa;
    1512 
    1513 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1514   int credentials = -1;  /* if not requred this is Ok */
    1515 #endif
    1516 
    1517   sa.sa_handler = handle_sigalrm;
    1518   sigemptyset(&sa.sa_mask);
    1519   sa.sa_flags = 0; /* no SA_RESTART */
    1520   sigaction(SIGALRM, &sa, NULL);
    1521 
    1522   do {
    1523     int  count;
    1524 
    1525     (void) alarm( TIMEOUT );
    1526     if (getLine() <= 0)
    1527     break;  /* closed */
    1528 
    1529     purl = strpbrk(buf, " \t");
    1530     if(purl == NULL) {
    1531 BAD_REQUEST:
    1532       sendHeaders(HTTP_BAD_REQUEST);
    1533       break;
    1534     }
    1535     *purl = 0;
    1536 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1537     if(strcasecmp(buf, prequest) != 0) {
    1538     prequest = "POST";
    1539     if(strcasecmp(buf, prequest) != 0) {
    1540         sendHeaders(HTTP_NOT_IMPLEMENTED);
    1541         break;
    1542     }
    1543     }
     1824        char *suffix = strrchr(tptr, '.');
     1825        if (suffix) {
     1826            Htaccess *cur;
     1827            for (cur = script_i; cur; cur = cur->next) {
     1828                if (strcmp(cur->before_colon + 1, suffix) == 0) {
     1829                    send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
     1830                }
     1831            }
     1832        }
     1833    }
     1834#endif
     1835    if (prequest != request_GET) {
     1836        send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
     1837    }
     1838#endif  /* FEATURE_HTTPD_CGI */
     1839
     1840    if (urlp[-1] == '/')
     1841        strcpy(urlp, "index.html");
     1842    if (stat(tptr, &sb) == 0) {
     1843        /* It's a dir URL and there is index.html */
     1844        ContentLength = sb.st_size;
     1845        last_mod = sb.st_mtime;
     1846    }
     1847#if ENABLE_FEATURE_HTTPD_CGI
     1848    else if (urlp[-1] == '/') {
     1849        /* It's a dir URL and there is no index.html
     1850         * Try cgi-bin/index.cgi */
     1851        if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
     1852            urlp[0] = '\0';
     1853            g_query = urlcopy;
     1854            send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
     1855        }
     1856    }
     1857#endif
     1858    /* else {
     1859     *  fall through to send_file, it errors out if open fails
     1860     * }
     1861     */
     1862
     1863    send_file_and_exit(tptr, TRUE);
     1864}
     1865
     1866/*
     1867 * The main http server function.
     1868 * Given a socket, listen for new connections and farm out
     1869 * the processing as a [v]forked process.
     1870 * Never returns.
     1871 */
     1872#if BB_MMU
     1873static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN;
     1874static void mini_httpd(int server_socket)
     1875{
     1876    /* NB: it's best to not use xfuncs in this loop before fork().
     1877     * Otherwise server may die on transient errors (temporary
     1878     * out-of-memory condition, etc), which is Bad(tm).
     1879     * Try to do any dangerous calls after fork.
     1880     */
     1881    while (1) {
     1882        int n;
     1883        len_and_sockaddr fromAddr;
     1884       
     1885        /* Wait for connections... */
     1886        fromAddr.len = LSA_SIZEOF_SA;
     1887        n = accept(server_socket, &fromAddr.sa, &fromAddr.len);
     1888
     1889        if (n < 0)
     1890            continue;
     1891        /* set the KEEPALIVE option to cull dead connections */
     1892        setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     1893
     1894        if (fork() == 0) {
     1895            /* child */
     1896#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
     1897            /* Do not reload config on HUP */
     1898            signal(SIGHUP, SIG_IGN);
     1899#endif
     1900            close(server_socket);
     1901            xmove_fd(n, 0);
     1902            xdup2(0, 1);
     1903
     1904            handle_incoming_and_exit(&fromAddr);
     1905        }
     1906        /* parent, or fork failed */
     1907        close(n);
     1908    } /* while (1) */
     1909    /* never reached */
     1910}
    15441911#else
    1545     if(strcasecmp(buf, request_GET) != 0) {
    1546     sendHeaders(HTTP_NOT_IMPLEMENTED);
    1547     break;
    1548     }
    1549 #endif
    1550     *purl = ' ';
    1551     count = sscanf(purl, " %[^ ] HTTP/%d.%*d", buf, &blank);
    1552 
    1553     if (count < 1 || buf[0] != '/') {
    1554       /* Garbled request/URL */
    1555       goto BAD_REQUEST;
    1556     }
    1557     url = alloca(strlen(buf) + 12);      /* + sizeof("/index.html\0") */
    1558     if(url == NULL) {
    1559     sendHeaders(HTTP_INTERNAL_SERVER_ERROR);
    1560     break;
    1561     }
    1562     strcpy(url, buf);
    1563     /* extract url args if present */
    1564     test = strchr(url, '?');
    1565     if (test) {
    1566       *test++ = 0;
    1567       config->query = test;
    1568     }
    1569 
    1570     test = decodeString(url, 0);
    1571     if(test == NULL)
    1572     goto BAD_REQUEST;
    1573     if(test == (buf+1)) {
    1574     sendHeaders(HTTP_NOT_FOUND);
    1575     break;
    1576     }
    1577     /* algorithm stolen from libbb bb_simplify_path(),
    1578        but don`t strdup and reducing trailing slash and protect out root */
    1579     purl = test = url;
    1580 
    1581     do {
    1582     if (*purl == '/') {
    1583         if (*test == '/') {        /* skip duplicate (or initial) slash */
    1584         continue;
    1585         } else if (*test == '.') {
    1586         if (test[1] == '/' || test[1] == 0) { /* skip extra '.' */
    1587             continue;
    1588         } else if ((test[1] == '.') && (test[2] == '/' || test[2] == 0)) {
    1589             ++test;
    1590             if (purl == url) {
    1591             /* protect out root */
    1592             goto BAD_REQUEST;
    1593             }
    1594             while (*--purl != '/');    /* omit previous dir */
    1595             continue;
    1596         }
    1597         }
    1598     }
    1599     *++purl = *test;
    1600     } while (*++test);
    1601 
    1602     *++purl = 0;        /* so keep last character */
    1603     test = purl;        /* end ptr */
    1604 
    1605     /* If URL is directory, adding '/' */
    1606     if(test[-1] != '/') {
    1607         if ( is_directory(url + 1, 1, &sb) ) {
    1608             config->httpd_found.found_moved_temporarily = url;
    1609         }
    1610     }
    1611 #if DEBUG
    1612     fprintf(stderr, "url='%s', args=%s\n", url, config->query);
    1613 #endif
    1614 
    1615     test = url;
    1616     ip_allowed = checkPermIP();
    1617     while(ip_allowed && (test = strchr( test + 1, '/' )) != NULL) {
    1618     /* have path1/path2 */
    1619     *test = '\0';
    1620     if( is_directory(url + 1, 1, &sb) ) {
    1621         /* may be having subdir config */
    1622         parse_conf(url + 1, SUBDIR_PARSE);
    1623         ip_allowed = checkPermIP();
    1624     }
    1625     *test = '/';
    1626     }
    1627     if(blank >= 0) {
    1628       // read until blank line for HTTP version specified, else parse immediate
    1629       while(1) {
    1630     alarm(TIMEOUT);
    1631     count = getLine();
    1632     if(count <= 0)
    1633         break;
    1634 
    1635 #if DEBUG
    1636     fprintf(stderr, "Header: '%s'\n", buf);
    1637 #endif
    1638 
    1639 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1640     /* try and do our best to parse more lines */
    1641     if ((strncasecmp(buf, Content_length, 15) == 0)) {
    1642       if(prequest != request_GET)
    1643           length = strtol(buf + 15, 0, 0); // extra read only for POST
    1644     } else if ((strncasecmp(buf, "Cookie:", 7) == 0)) {
    1645           for(test = buf + 7; isspace(*test); test++)
    1646               ;
    1647           cookie = strdup(test);
    1648     } else if ((strncasecmp(buf, "Content-Type:", 13) == 0)) {
    1649           for(test = buf + 13; isspace(*test); test++)
    1650               ;
    1651           content_type = strdup(test);
    1652     } else if ((strncasecmp(buf, "Referer:", 8) == 0)) {
    1653           for(test = buf + 8; isspace(*test); test++)
    1654               ;
    1655           config->referer = strdup(test);
    1656     }
    1657 #endif
    1658 
    1659 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1660     if (strncasecmp(buf, "Authorization:", 14) == 0) {
    1661       /* We only allow Basic credentials.
    1662        * It shows up as "Authorization: Basic <userid:password>" where
    1663        * the userid:password is base64 encoded.
    1664        */
    1665       for(test = buf + 14; isspace(*test); test++)
    1666           ;
    1667       if (strncasecmp(test, "Basic", 5) != 0)
    1668           continue;
    1669 
    1670       test += 5;  /* decodeBase64() skiping space self */
    1671       decodeBase64(test);
    1672       credentials = checkPerm(url, test);
    1673     }
    1674 #endif          /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */
    1675 
    1676       }   /* while extra header reading */
    1677     }
    1678     (void) alarm( 0 );
    1679     if(config->alarm_signaled)
    1680     break;
    1681 
    1682     if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) {
    1683         /* protect listing [/path]/httpd_conf or IP deny */
    1684 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1685 FORBIDDEN:      /* protect listing /cgi-bin */
    1686 #endif
    1687         sendHeaders(HTTP_FORBIDDEN);
    1688         break;
    1689     }
    1690 
    1691 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1692     if (credentials <= 0 && checkPerm(url, ":") == 0) {
    1693       sendHeaders(HTTP_UNAUTHORIZED);
    1694       break;
    1695     }
    1696 #endif
    1697 
    1698     if(config->httpd_found.found_moved_temporarily) {
    1699     sendHeaders(HTTP_MOVED_TEMPORARILY);
    1700 #if DEBUG
    1701     /* clear unforked memory flag */
    1702     config->httpd_found.found_moved_temporarily = NULL;
    1703 #endif
    1704     break;
    1705     }
    1706 
    1707     test = url + 1;      /* skip first '/' */
    1708 
    1709 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1710     /* if strange Content-Length */
    1711     if (length < 0)
    1712     break;
    1713 
    1714     if (strncmp(test, "cgi-bin", 7) == 0) {
    1715         if(test[7] == '/' && test[8] == 0)
    1716             goto FORBIDDEN;     // protect listing cgi-bin/
    1717         sendCgi(url, prequest, length, cookie, content_type);
    1718     } else {
    1719     if (prequest != request_GET)
    1720         sendHeaders(HTTP_NOT_IMPLEMENTED);
    1721     else {
    1722 #endif  /* CONFIG_FEATURE_HTTPD_CGI */
    1723         if(purl[-1] == '/')
    1724             strcpy(purl, "index.html");
    1725         if ( stat(test, &sb ) == 0 ) {
    1726             config->ContentLength = sb.st_size;
    1727             config->last_mod = sb.st_mtime;
    1728         }
    1729         sendFile(test);
    1730 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1731         /* unset if non inetd looped */
    1732         config->ContentLength = -1;
    1733 #endif
    1734 
    1735 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1736     }
    1737     }
    1738 #endif
    1739 
    1740   } while (0);
    1741 
    1742 
    1743 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1744 /* from inetd don`t looping: freeing, closing automatic from exit always */
    1745 # if DEBUG
    1746   fprintf(stderr, "closing socket\n");
    1747 # endif
    1748 # ifdef CONFIG_FEATURE_HTTPD_CGI
    1749   free(cookie);
    1750   free(content_type);
    1751   free(config->referer);
    1752 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1753   free(config->remoteuser);
    1754 #endif
    1755 # endif
    1756 #endif  /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */
    1757   shutdown(a_c_w, SHUT_WR);
    1758 
    1759   /* Properly wait for remote to closed */
    1760   FD_ZERO (&s_fd) ;
    1761   FD_SET (a_c_r, &s_fd) ;
    1762 
    1763   do {
    1764     tv.tv_sec = 2 ;
    1765     tv.tv_usec = 0 ;
    1766     retval = select (a_c_r + 1, &s_fd, NULL, NULL, &tv);
    1767   } while (retval > 0 && (read (a_c_r, buf, sizeof (config->buf)) > 0));
    1768 
    1769   shutdown(a_c_r, SHUT_RD);
    1770 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1771   close(config->accepted_socket);
    1772 #endif  /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */
    1773 }
    1774 
    1775 /****************************************************************************
    1776  *
    1777  > $Function: miniHttpd()
    1778  *
    1779  * $Description: The main http server function.
    1780  *
    1781  *   Given an open socket fildes, listen for new connections and farm out
    1782  *   the processing as a forked process.
    1783  *
    1784  * $Parameters:
    1785  *      (int) server. . . The server socket fildes.
    1786  *
    1787  * $Return: (int) . . . . Always 0.
    1788  *
    1789  ****************************************************************************/
    1790 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1791 static int miniHttpd(int server)
    1792 {
    1793   fd_set readfd, portfd;
    1794 
    1795   FD_ZERO(&portfd);
    1796   FD_SET(server, &portfd);
    1797 
    1798   /* copy the ports we are watching to the readfd set */
    1799   while (1) {
    1800     readfd = portfd;
    1801 
    1802     /* Now wait INDEFINITELY on the set of sockets! */
    1803     if (select(server + 1, &readfd, 0, 0, 0) > 0) {
    1804       if (FD_ISSET(server, &readfd)) {
    1805     int on;
    1806     struct sockaddr_in fromAddr;
    1807 
    1808     socklen_t fromAddrLen = sizeof(fromAddr);
    1809     int s = accept(server,
    1810                (struct sockaddr *)&fromAddr, &fromAddrLen);
    1811 
    1812     if (s < 0) {
    1813         continue;
    1814     }
    1815     config->accepted_socket = s;
    1816     config->rmt_ip = ntohl(fromAddr.sin_addr.s_addr);
    1817 #if defined(CONFIG_FEATURE_HTTPD_CGI) || DEBUG
    1818     sprintf(config->rmt_ip_str, "%u.%u.%u.%u",
    1819         (unsigned char)(config->rmt_ip >> 24),
    1820         (unsigned char)(config->rmt_ip >> 16),
    1821         (unsigned char)(config->rmt_ip >> 8),
    1822                 config->rmt_ip & 0xff);
    1823     config->port = ntohs(fromAddr.sin_port);
    1824 #if DEBUG
    1825     bb_error_msg("connection from IP=%s, port %u\n",
    1826                     config->rmt_ip_str, config->port);
    1827 #endif
    1828 #endif /* CONFIG_FEATURE_HTTPD_CGI */
    1829 
    1830     /*  set the KEEPALIVE option to cull dead connections */
    1831     on = 1;
    1832     setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof (on));
    1833 
    1834 #if !DEBUG
    1835     if (fork() == 0)
    1836 #endif
    1837     {
    1838         /* This is the spawned thread */
    1839 #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    1840         /* protect reload config, may be confuse checking */
    1841         signal(SIGHUP, SIG_IGN);
    1842 #endif
    1843         handleIncoming();
    1844 #if !DEBUG
    1845         exit(0);
    1846 #endif
    1847     }
    1848     close(s);
    1849       }
    1850     }
    1851   } // while (1)
    1852   return 0;
    1853 }
    1854 
    1855 #else
    1856     /* from inetd */
    1857 
    1858 static int miniHttpd(void)
    1859 {
    1860   struct sockaddr_in fromAddrLen;
    1861   socklen_t sinlen = sizeof (struct sockaddr_in);
    1862 
    1863   getpeername (0, (struct sockaddr *)&fromAddrLen, &sinlen);
    1864   config->rmt_ip = ntohl(fromAddrLen.sin_addr.s_addr);
    1865 #ifdef CONFIG_FEATURE_HTTPD_CGI
    1866   sprintf(config->rmt_ip_str, "%u.%u.%u.%u",
    1867         (unsigned char)(config->rmt_ip >> 24),
    1868         (unsigned char)(config->rmt_ip >> 16),
    1869         (unsigned char)(config->rmt_ip >> 8),
    1870                 config->rmt_ip & 0xff);
    1871 #endif
    1872   config->port = ntohs(fromAddrLen.sin_port);
    1873   handleIncoming();
    1874   return 0;
    1875 }
    1876 #endif  /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */
    1877 
    1878 #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
     1912static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN;
     1913static void mini_httpd_nommu(int server_socket, int argc, char **argv)
     1914{
     1915    char *argv_copy[argc + 2];
     1916
     1917    argv_copy[0] = argv[0];
     1918    argv_copy[1] = (char*)"-i";
     1919    memcpy(&argv_copy[2], &argv[1], argc * sizeof(argv[0]));
     1920
     1921    /* NB: it's best to not use xfuncs in this loop before vfork().
     1922     * Otherwise server may die on transient errors (temporary
     1923     * out-of-memory condition, etc), which is Bad(tm).
     1924     * Try to do any dangerous calls after fork.
     1925     */
     1926    while (1) {
     1927        int n;
     1928        len_and_sockaddr fromAddr;
     1929       
     1930        /* Wait for connections... */
     1931        fromAddr.len = LSA_SIZEOF_SA;
     1932        n = accept(server_socket, &fromAddr.sa, &fromAddr.len);
     1933
     1934        if (n < 0)
     1935            continue;
     1936        /* set the KEEPALIVE option to cull dead connections */
     1937        setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     1938
     1939        if (vfork() == 0) {
     1940            /* child */
     1941#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
     1942            /* Do not reload config on HUP */
     1943            signal(SIGHUP, SIG_IGN);
     1944#endif
     1945            close(server_socket);
     1946            xmove_fd(n, 0);
     1947            xdup2(0, 1);
     1948
     1949            /* Run a copy of ourself in inetd mode */
     1950            re_exec(argv_copy);
     1951        }
     1952        /* parent, or vfork failed */
     1953        close(n);
     1954    } /* while (1) */
     1955    /* never reached */
     1956}
     1957#endif
     1958
     1959/*
     1960 * Process a HTTP connection on stdin/out.
     1961 * Never returns.
     1962 */
     1963static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN;
     1964static void mini_httpd_inetd(void)
     1965{
     1966    len_and_sockaddr fromAddr;
     1967
     1968    fromAddr.len = LSA_SIZEOF_SA;
     1969    getpeername(0, &fromAddr.sa, &fromAddr.len);
     1970    handle_incoming_and_exit(&fromAddr);
     1971}
     1972
     1973#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    18791974static void sighup_handler(int sig)
    18801975{
    1881     /* set and reset */
    18821976    struct sigaction sa;
    18831977
    1884     parse_conf(default_path_httpd_conf,
    1885             sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
     1978    parse_conf(default_path_httpd_conf, sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
     1979
     1980    memset(&sa, 0, sizeof(sa));
    18861981    sa.sa_handler = sighup_handler;
    1887     sigemptyset(&sa.sa_mask);
     1982    /*sigemptyset(&sa.sa_mask); - memset should be enough */
    18881983    sa.sa_flags = SA_RESTART;
    18891984    sigaction(SIGHUP, &sa, NULL);
     
    18911986#endif
    18921987
    1893 enum httpd_opts_nums {
     1988enum {
    18941989    c_opt_config_file = 0,
    18951990    d_opt_decode_url,
    18961991    h_opt_home_httpd,
    18971992    USE_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,)
    1898     USE_FEATURE_HTTPD_BASIC_AUTH(r_opt_realm,)
    1899     USE_FEATURE_HTTPD_AUTH_MD5(m_opt_md5,)
    1900     USE_FEATURE_HTTPD_SETUID(u_opt_setuid,)
    1901     USE_FEATURE_HTTPD_WITHOUT_INETD(p_opt_port,)
     1993    USE_FEATURE_HTTPD_BASIC_AUTH(    r_opt_realm     ,)
     1994    USE_FEATURE_HTTPD_AUTH_MD5(      m_opt_md5       ,)
     1995    USE_FEATURE_HTTPD_SETUID(        u_opt_setuid    ,)
     1996    p_opt_port      ,
     1997    p_opt_inetd     ,
     1998    p_opt_foreground,
     1999    p_opt_verbose   ,
     2000    OPT_CONFIG_FILE = 1 << c_opt_config_file,
     2001    OPT_DECODE_URL  = 1 << d_opt_decode_url,
     2002    OPT_HOME_HTTPD  = 1 << h_opt_home_httpd,
     2003    OPT_ENCODE_URL  = USE_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0,
     2004    OPT_REALM       = USE_FEATURE_HTTPD_BASIC_AUTH(    (1 << r_opt_realm     )) + 0,
     2005    OPT_MD5         = USE_FEATURE_HTTPD_AUTH_MD5(      (1 << m_opt_md5       )) + 0,
     2006    OPT_SETUID      = USE_FEATURE_HTTPD_SETUID(        (1 << u_opt_setuid    )) + 0,
     2007    OPT_PORT        = 1 << p_opt_port,
     2008    OPT_INETD       = 1 << p_opt_inetd,
     2009    OPT_FOREGROUND  = 1 << p_opt_foreground,
     2010    OPT_VERBOSE     = 1 << p_opt_verbose,
    19022011};
    19032012
    1904 static const char httpd_opts[]="c:d:h:"
    1905     USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
    1906     USE_FEATURE_HTTPD_BASIC_AUTH("r:")
    1907     USE_FEATURE_HTTPD_AUTH_MD5("m:")
    1908     USE_FEATURE_HTTPD_SETUID("u:")
    1909     USE_FEATURE_HTTPD_WITHOUT_INETD("p:");
    1910 
    1911 #define OPT_CONFIG_FILE (1<<c_opt_config_file)
    1912 #define OPT_DECODE_URL  (1<<d_opt_decode_url)
    1913 #define OPT_HOME_HTTPD  (1<<h_opt_home_httpd)
    1914 
    1915 #define OPT_ENCODE_URL  USE_FEATURE_HTTPD_ENCODE_URL_STR((1<<e_opt_encode_url)) \
    1916             SKIP_FEATURE_HTTPD_ENCODE_URL_STR(0)
    1917 
    1918 #define OPT_REALM       USE_FEATURE_HTTPD_BASIC_AUTH((1<<r_opt_realm)) \
    1919             SKIP_FEATURE_HTTPD_BASIC_AUTH(0)
    1920 
    1921 #define OPT_MD5         USE_FEATURE_HTTPD_AUTH_MD5((1<<m_opt_md5)) \
    1922             SKIP_FEATURE_HTTPD_AUTH_MD5(0)
    1923 
    1924 #define OPT_SETUID      USE_FEATURE_HTTPD_SETUID((1<<u_opt_setuid)) \
    1925             SKIP_FEATURE_HTTPD_SETUID(0)
    1926 
    1927 #define OPT_PORT        USE_FEATURE_HTTPD_WITHOUT_INETD((1<<p_opt_port)) \
    1928             SKIP_FEATURE_HTTPD_WITHOUT_INETD(0)
    1929 
    1930 
    1931 int httpd_main(int argc, char *argv[])
    1932 {
    1933   unsigned long opt;
    1934   const char *home_httpd = home;
    1935   char *url_for_decode;
    1936   USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
    1937   USE_FEATURE_HTTPD_WITHOUT_INETD(const char *s_port;)
    1938   USE_FEATURE_HTTPD_WITHOUT_INETD(int server;)
    1939 
    1940   USE_FEATURE_HTTPD_SETUID(const char *s_uid;)
    1941   USE_FEATURE_HTTPD_SETUID(long uid = -1;)
    1942 
    1943   USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
    1944 
    1945   config = xcalloc(1, sizeof(*config));
    1946 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
    1947   config->realm = "Web Server Authentication";
    1948 #endif
    1949 
    1950 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1951   config->port = 80;
    1952 #endif
    1953 
    1954   config->ContentLength = -1;
    1955 
    1956   opt = bb_getopt_ulflags(argc, argv, httpd_opts,
    1957             &(config->configFile), &url_for_decode, &home_httpd
     2013
     2014int httpd_main(int argc, char **argv);
     2015int httpd_main(int argc, char **argv)
     2016{
     2017    int server_socket = server_socket; /* for gcc */
     2018    unsigned opt;
     2019    char *url_for_decode;
     2020    USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
     2021    USE_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
     2022    USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
     2023    USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
     2024
     2025    INIT_G();
     2026
     2027#if ENABLE_LOCALE_SUPPORT
     2028    /* Undo busybox.c: we want to speak English in http (dates etc) */
     2029    setlocale(LC_TIME, "C");
     2030#endif
     2031
     2032    home_httpd = xrealloc_getcwd_or_warn(NULL);
     2033    /* -v counts, -i implies -f */
     2034    opt_complementary = "vv:if";
     2035    /* We do not "absolutize" path given by -h (home) opt.
     2036     * If user gives relative path in -h, $SCRIPT_FILENAME can end up
     2037     * relative too. */
     2038    opt = getopt32(argv, "c:d:h:"
     2039            USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
     2040            USE_FEATURE_HTTPD_BASIC_AUTH("r:")
     2041            USE_FEATURE_HTTPD_AUTH_MD5("m:")
     2042            USE_FEATURE_HTTPD_SETUID("u:")
     2043            "p:ifv",
     2044            &configFile, &url_for_decode, &home_httpd
    19582045            USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
    1959             USE_FEATURE_HTTPD_BASIC_AUTH(, &(config->realm))
     2046            USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
    19602047            USE_FEATURE_HTTPD_AUTH_MD5(, &pass)
    1961             USE_FEATURE_HTTPD_SETUID(, &s_uid)
    1962             USE_FEATURE_HTTPD_WITHOUT_INETD(, &s_port)
    1963     );
    1964 
    1965   if(opt & OPT_DECODE_URL) {
    1966       printf("%s", decodeString(url_for_decode, 1));
    1967       return 0;
    1968   }
    1969 #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR
    1970   if(opt & OPT_ENCODE_URL) {
    1971       printf("%s", encodeString(url_for_encode));
    1972       return 0;
    1973   }
    1974 #endif
    1975 #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5
    1976   if(opt & OPT_MD5) {
    1977       printf("%s\n", pw_encrypt(pass, "$1$"));
    1978       return 0;
    1979   }
    1980 #endif
    1981 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1982     if(opt & OPT_PORT)
    1983     config->port = bb_xgetlarg(s_port, 10, 1, 0xffff);
    1984 #ifdef CONFIG_FEATURE_HTTPD_SETUID
    1985     if(opt & OPT_SETUID) {
    1986     char *e;
    1987 
    1988     uid = strtol(s_uid, &e, 0);
    1989     if(*e != '\0') {
    1990         /* not integer */
    1991         uid = bb_xgetpwnam(s_uid);
    1992     }
    1993       }
    1994 #endif
    1995 #endif
    1996 
    1997   bb_xchdir(home_httpd);
    1998 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    1999   server = openServer();
    2000 # ifdef CONFIG_FEATURE_HTTPD_SETUID
    2001   /* drop privileges */
    2002   if(uid > 0)
    2003     setuid(uid);
    2004 # endif
    2005 #endif
    2006 
    2007 #ifdef CONFIG_FEATURE_HTTPD_CGI
    2008    {
    2009     char *p = getenv("PATH");
    2010     if(p) {
    2011         p = bb_xstrdup(p);
    2012     }
    2013     clearenv();
    2014     if(p)
    2015         setenv("PATH", p, 1);
    2016 # ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    2017     addEnvPort("SERVER");
    2018 # endif
    2019    }
    2020 #endif
    2021 
    2022 #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    2023   sighup_handler(0);
     2048            USE_FEATURE_HTTPD_SETUID(, &s_ugid)
     2049            , &bind_addr_or_port
     2050            , &verbose
     2051        );
     2052    if (opt & OPT_DECODE_URL) {
     2053        fputs(decodeString(url_for_decode, 1), stdout);
     2054        return 0;
     2055    }
     2056#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
     2057    if (opt & OPT_ENCODE_URL) {
     2058        fputs(encodeString(url_for_encode), stdout);
     2059        return 0;
     2060    }
     2061#endif
     2062#if ENABLE_FEATURE_HTTPD_AUTH_MD5
     2063    if (opt & OPT_MD5) {
     2064        puts(pw_encrypt(pass, "$1$"));
     2065        return 0;
     2066    }
     2067#endif
     2068#if ENABLE_FEATURE_HTTPD_SETUID
     2069    if (opt & OPT_SETUID) {
     2070        if (!get_uidgid(&ugid, s_ugid, 1))
     2071            bb_error_msg_and_die("unrecognized user[:group] "
     2072                        "name '%s'", s_ugid);
     2073    }
     2074#endif
     2075
     2076#if !BB_MMU
     2077    if (!(opt & OPT_FOREGROUND)) {
     2078        bb_daemonize_or_rexec(0, argv); /* don't change current directory */
     2079    }
     2080#endif
     2081
     2082    xchdir(home_httpd);
     2083    if (!(opt & OPT_INETD)) {
     2084        signal(SIGCHLD, SIG_IGN);
     2085        server_socket = openServer();
     2086#if ENABLE_FEATURE_HTTPD_SETUID
     2087        /* drop privileges */
     2088        if (opt & OPT_SETUID) {
     2089            if (ugid.gid != (gid_t)-1) {
     2090                if (setgroups(1, &ugid.gid) == -1)
     2091                    bb_perror_msg_and_die("setgroups");
     2092                xsetgid(ugid.gid);
     2093            }
     2094            xsetuid(ugid.uid);
     2095        }
     2096#endif
     2097    }
     2098
     2099#if ENABLE_FEATURE_HTTPD_CGI
     2100    {
     2101        char *p = getenv("PATH");
     2102        /* env strings themself are not freed, no need to strdup(p): */
     2103        clearenv();
     2104        if (p)
     2105            putenv(p - 5);
     2106//      if (!(opt & OPT_INETD))
     2107//          setenv_long("SERVER_PORT", ???);
     2108    }
     2109#endif
     2110
     2111#if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
     2112    if (!(opt & OPT_INETD))
     2113        sighup_handler(0);
     2114    else /* do not install HUP handler in inetd mode */
     2115#endif
     2116        parse_conf(default_path_httpd_conf, FIRST_PARSE);
     2117
     2118    xfunc_error_retval = 0;
     2119    if (opt & OPT_INETD)
     2120        mini_httpd_inetd();
     2121#if BB_MMU
     2122    if (!(opt & OPT_FOREGROUND))
     2123        bb_daemonize(0); /* don't change current directory */
     2124    mini_httpd(server_socket); /* never returns */
    20242125#else
    2025   parse_conf(default_path_httpd_conf, FIRST_PARSE);
    2026 #endif
    2027 
    2028 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD
    2029 # if !DEBUG
    2030   bb_xdaemon(1, 0);     /* don`t change curent directory */
    2031 # endif
    2032   return miniHttpd(server);
    2033 #else
    2034   return miniHttpd();
    2035 #endif
    2036 }
     2126    mini_httpd_nommu(server_socket, argc, argv); /* never returns */
     2127#endif
     2128    /* return 0; */
     2129}
  • branches/stable/mindi-busybox/networking/ifconfig.c

    r821 r1770  
    2727 */
    2828
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>     /* strcmp and friends */
    32 #include <ctype.h>      /* isdigit and friends */
    33 #include <stddef.h>     /* offsetof */
    34 #include <unistd.h>
    35 #include <netdb.h>
    36 #include <sys/ioctl.h>
    3729#include <net/if.h>
    3830#include <net/if_arp.h>
    3931#include <netinet/in.h>
    40 #if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
     32#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1
    4133#include <netpacket/packet.h>
    4234#include <net/ethernet.h>
     
    4638#endif
    4739#include "inet_common.h"
    48 #include "busybox.h"
    49 
    50 #ifdef CONFIG_FEATURE_IFCONFIG_SLIP
     40#include "libbb.h"
     41
     42#if ENABLE_FEATURE_IFCONFIG_SLIP
    5143# include <net/if_slip.h>
    5244#endif
     
    7163#endif
    7264
    73 #ifdef CONFIG_FEATURE_IPV6
     65#if ENABLE_FEATURE_IPV6
    7466struct in6_ifreq {
    7567    struct in6_addr ifr6_addr;
     
    122114#define A_SET_AFTER      0x40   /* Set a flag at the end. */
    123115#define A_COLON_CHK      0x80   /* Is this needed?  See below. */
    124 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
     116#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
    125117#define A_HOSTNAME      0x100   /* Set if it is ip addr. */
    126118#define A_BROADCAST     0x200   /* Set if it is broadcast addr. */
     
    179171struct options {
    180172    const char *name;
    181 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
     173#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
    182174    const unsigned int flags:6;
    183175    const unsigned int arg_flags:10;
     
    198190    {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
    199191    {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
    200 #ifdef CONFIG_FEATURE_IFCONFIG_HW
     192#if ENABLE_FEATURE_IFCONFIG_HW
    201193    {"SIOCSIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr)},
    202194#endif
     
    208200    {"SIOCSOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data)},
    209201#endif
    210 #ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
     202#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    211203    {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start)},
    212204    {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr)},
     
    214206#endif
    215207    /* Last entry if for unmatched (possibly hostname) arg. */
    216 #ifdef CONFIG_FEATURE_IPV6
     208#if ENABLE_FEATURE_IPV6
    217209    {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
    218210    {"SIOCDIFADDR",    SIOCDIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
     
    228220    {"netmask",     N_ARG,         ARG_NETMASK,     0},
    229221    {"broadcast",   N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST},
    230 #ifdef CONFIG_FEATURE_IFCONFIG_HW
     222#if ENABLE_FEATURE_IFCONFIG_HW
    231223    {"hw",          N_ARG, ARG_HW,                  0},
    232224#endif
     
    238230    {"outfill",     N_ARG,         ARG_OUTFILL,     0},
    239231#endif
    240 #ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
     232#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    241233    {"mem_start",   N_ARG,         ARG_MEM_START,   0},
    242234    {"io_addr",     N_ARG,         ARG_IO_ADDR,     0},
    243235    {"irq",         N_ARG,         ARG_IRQ,         0},
    244236#endif
    245 #ifdef CONFIG_FEATURE_IPV6
     237#if ENABLE_FEATURE_IPV6
    246238    {"add",         N_ARG,         ARG_ADD_DEL,     0},
    247239    {"del",         N_ARG,         ARG_ADD_DEL,     0},
     
    262254 */
    263255
    264 #ifdef CONFIG_FEATURE_IFCONFIG_HW
    265 static int in_ether(char *bufp, struct sockaddr *sap);
    266 #endif
    267 
    268 #ifdef CONFIG_FEATURE_IFCONFIG_STATUS
    269 extern int interface_opt_a;
    270 extern int display_interfaces(char *ifname);
     256#if ENABLE_FEATURE_IFCONFIG_HW
     257static int in_ether(const char *bufp, struct sockaddr *sap);
    271258#endif
    272259
     
    275262 */
    276263
     264int ifconfig_main(int argc, char **argv);
    277265int ifconfig_main(int argc, char **argv)
    278266{
    279267    struct ifreq ifr;
    280268    struct sockaddr_in sai;
    281 #ifdef CONFIG_FEATURE_IPV6
    282     struct sockaddr_in6 sai6;
    283 #endif
    284 #ifdef CONFIG_FEATURE_IFCONFIG_HW
     269#if ENABLE_FEATURE_IFCONFIG_HW
    285270    struct sockaddr sa;
    286271#endif
     
    288273    const struct options *op;
    289274    int sockfd;         /* socket fd we use to manipulate stuff with */
    290     int goterr;
    291275    int selector;
    292 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
     276#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
    293277    unsigned int mask;
    294278    unsigned int did_flags;
     
    299283#endif
    300284    char *p;
    301     char host[128];
    302 
    303     goterr = 0;
     285    /*char host[128];*/
     286    const char *host = NULL; /* make gcc happy */
     287
    304288    did_flags = 0;
    305 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
     289#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
    306290    sai_hostname = 0;
    307291    sai_netmask = 0;
     
    312296    --argc;
    313297
    314 #ifdef CONFIG_FEATURE_IFCONFIG_STATUS
    315     if ((argc > 0) && (((*argv)[0] == '-') && ((*argv)[1] == 'a') && !(*argv)[2])) {
     298#if ENABLE_FEATURE_IFCONFIG_STATUS
     299    if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) {
    316300        interface_opt_a = 1;
    317301        --argc;
     
    321305
    322306    if (argc <= 1) {
    323 #ifdef CONFIG_FEATURE_IFCONFIG_STATUS
     307#if ENABLE_FEATURE_IFCONFIG_STATUS
    324308        return display_interfaces(argc ? *argv : NULL);
    325309#else
    326         bb_error_msg_and_die
    327             ("ifconfig was not compiled with interface status display support.");
     310        bb_error_msg_and_die("no support for status display");
    328311#endif
    329312    }
    330313
    331314    /* Create a channel to the NET kernel. */
    332     sockfd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);
     315    sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);
    333316
    334317    /* get interface name */
     
    345328        for (op = OptArray; op->name; op++) {   /* Find table entry. */
    346329            if (strcmp(p, op->name) == 0) { /* If name matches... */
    347                 if ((mask &= op->flags)) {  /* set the mask and go. */
     330                mask &= op->flags;
     331                if (mask)   /* set the mask and go. */
    348332                    goto FOUND_ARG;
    349                 }
    350333                /* If we get here, there was a valid arg with an */
    351334                /* invalid '-' prefix. */
    352                 ++goterr;
    353                 goto LOOP;
     335                bb_error_msg_and_die("bad: '%s'", p-1);
    354336            }
    355337        }
    356338
    357339        /* We fell through, so treat as possible hostname. */
    358         a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
     340        a1op = Arg1Opt + ARRAY_SIZE(Arg1Opt) - 1;
    359341        mask = op->arg_flags;
    360342        goto HOSTNAME;
    361343
    362       FOUND_ARG:
     344 FOUND_ARG:
    363345        if (mask & ARG_MASK) {
    364346            mask = op->arg_flags;
    365347            a1op = Arg1Opt + (op - OptArray);
    366             if (mask & A_NETMASK & did_flags) {
     348            if (mask & A_NETMASK & did_flags)
    367349                bb_show_usage();
    368             }
    369350            if (*++argv == NULL) {
    370                 if (mask & A_ARG_REQ) {
     351                if (mask & A_ARG_REQ)
    371352                    bb_show_usage();
    372                 } else {
    373                     --argv;
    374                     mask &= A_SET_AFTER;    /* just for broadcast */
    375                 }
     353                --argv;
     354                mask &= A_SET_AFTER;    /* just for broadcast */
    376355            } else {    /* got an arg so process it */
    377               HOSTNAME:
     356 HOSTNAME:
    378357                did_flags |= (mask & (A_NETMASK|A_HOSTNAME));
    379358                if (mask & A_CAST_HOST_COPY) {
    380 #ifdef CONFIG_FEATURE_IFCONFIG_HW
     359#if ENABLE_FEATURE_IFCONFIG_HW
    381360                    if (mask & A_CAST_RESOLVE) {
    382361#endif
    383 #ifdef CONFIG_FEATURE_IPV6
     362#if ENABLE_FEATURE_IPV6
    384363                        char *prefix;
    385364                        int prefix_len = 0;
    386365#endif
    387 
    388                         safe_strncpy(host, *argv, (sizeof host));
    389 #ifdef CONFIG_FEATURE_IPV6
    390                         if ((prefix = strchr(host, '/'))) {
    391                             if (safe_strtoi(prefix + 1, &prefix_len) ||
    392                                 (prefix_len < 0) || (prefix_len > 128))
    393                             {
    394                                 ++goterr;
    395                                 goto LOOP;
    396                             }
    397                             *prefix = 0;
     366                        /*safe_strncpy(host, *argv, (sizeof host));*/
     367                        host = *argv;
     368#if ENABLE_FEATURE_IPV6
     369                        prefix = strchr(host, '/');
     370                        if (prefix) {
     371                            prefix_len = xatou_range(prefix + 1, 0, 128);
     372                            *prefix = '\0';
    398373                        }
    399374#endif
    400 
    401375                        sai.sin_family = AF_INET;
    402376                        sai.sin_port = 0;
    403                         if (!strcmp(host, bb_INET_default)) {
     377                        if (!strcmp(host, bb_str_default)) {
    404378                            /* Default is special, meaning 0.0.0.0. */
    405379                            sai.sin_addr.s_addr = INADDR_ANY;
    406 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
    407                         } else if (((host[0] == '+') && !host[1]) && (mask & A_BROADCAST) &&
    408                                    (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)) {
     380                        }
     381#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
     382                        else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST)
     383                         && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)
     384                        ) {
    409385                            /* + is special, meaning broadcast is derived. */
    410386                            sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask);
    411 #endif
    412 #ifdef CONFIG_FEATURE_IPV6
    413                         } else if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) {
    414                             int sockfd6;
    415                             struct in6_ifreq ifr6;
    416 
    417                             memcpy((char *) &ifr6.ifr6_addr,
    418                                    (char *) &sai6.sin6_addr,
    419                                    sizeof(struct in6_addr));
    420 
    421                             /* Create a channel to the NET kernel. */
    422                             if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    423                                 bb_perror_msg_and_die("socket6");
    424                             }
    425                             if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) {
    426                                 perror("SIOGIFINDEX");
    427                                 ++goterr;
     387                        }
     388#endif
     389                        else {
     390                            len_and_sockaddr *lsa;
     391                            if (strcmp(host, "inet") == 0)
     392                                continue; /* compat stuff */
     393                            lsa = xhost2sockaddr(host, 0);
     394#if ENABLE_FEATURE_IPV6
     395                            if (lsa->sa.sa_family == AF_INET6) {
     396                                int sockfd6;
     397                                struct in6_ifreq ifr6;
     398
     399                                memcpy((char *) &ifr6.ifr6_addr,
     400                                        (char *) &(lsa->sin6.sin6_addr),
     401                                        sizeof(struct in6_addr));
     402
     403                                /* Create a channel to the NET kernel. */
     404                                sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0);
     405                                xioctl(sockfd6, SIOGIFINDEX, &ifr);
     406                                ifr6.ifr6_ifindex = ifr.ifr_ifindex;
     407                                ifr6.ifr6_prefixlen = prefix_len;
     408                                ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "%s", a1op->name);
     409                                if (ENABLE_FEATURE_CLEAN_UP)
     410                                    free(lsa);
    428411                                continue;
    429412                            }
    430                             ifr6.ifr6_ifindex = ifr.ifr_ifindex;
    431                             ifr6.ifr6_prefixlen = prefix_len;
    432                             if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) {
    433                                 perror(a1op->name);
    434                                 ++goterr;
    435                             }
    436                             continue;
    437 #endif
    438                         } else if (inet_aton(host, &sai.sin_addr) == 0) {
    439                             /* It's not a dotted quad. */
    440                             struct hostent *hp;
    441                             if ((hp = gethostbyname(host)) == (struct hostent *)NULL) {
    442                                 ++goterr;
    443                                 continue;
    444                             }
    445                             memcpy((char *) &sai.sin_addr, (char *) hp->h_addr_list[0],
    446                             sizeof(struct in_addr));
     413#endif
     414                            sai.sin_addr = lsa->sin.sin_addr;
     415                            if (ENABLE_FEATURE_CLEAN_UP)
     416                                free(lsa);
    447417                        }
    448 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
    449                         if (mask & A_HOSTNAME) {
     418#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
     419                        if (mask & A_HOSTNAME)
    450420                            sai_hostname = sai.sin_addr.s_addr;
    451                         }
    452                         if (mask & A_NETMASK) {
     421                        if (mask & A_NETMASK)
    453422                            sai_netmask = sai.sin_addr.s_addr;
    454                         }
    455423#endif
    456424                        p = (char *) &sai;
    457 #ifdef CONFIG_FEATURE_IFCONFIG_HW
     425#if ENABLE_FEATURE_IFCONFIG_HW
    458426                    } else {    /* A_CAST_HOST_COPY_IN_ETHER */
    459427                        /* This is the "hw" arg case. */
    460                         if (strcmp("ether", *argv) || (*++argv == NULL)) {
     428                        if (strcmp("ether", *argv) || !*++argv)
    461429                            bb_show_usage();
    462                         }
    463                         safe_strncpy(host, *argv, (sizeof host));
    464                         if (in_ether(host, &sa)) {
    465                             bb_error_msg("invalid hw-addr %s", host);
    466                             ++goterr;
    467                             continue;
    468                         }
     430                        /*safe_strncpy(host, *argv, sizeof(host));*/
     431                        host = *argv;
     432                        if (in_ether(host, &sa))
     433                            bb_error_msg_and_die("invalid hw-addr %s", host);
    469434                        p = (char *) &sa;
    470435                    }
    471436#endif
    472                     memcpy((((char *) (&ifr)) + a1op->ifr_offset),
     437                    memcpy( (((char *)&ifr) + a1op->ifr_offset),
    473438                           p, sizeof(struct sockaddr));
    474439                } else {
     440                    /* FIXME: error check?? */
    475441                    unsigned long i = strtoul(*argv, NULL, 0);
    476 
    477                     p = ((char *) (&ifr)) + a1op->ifr_offset;
    478 #ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
     442                    p = ((char *)&ifr) + a1op->ifr_offset;
     443#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    479444                    if (mask & A_MAP_TYPE) {
    480                         if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
    481                             ++goterr;
    482                             continue;
    483                         }
    484                         if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
     445                        xioctl(sockfd, SIOCGIFMAP, &ifr);
     446                        if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR)
    485447                            *((unsigned char *) p) = i;
    486                         } else if (mask & A_MAP_USHORT) {
     448                        else if (mask & A_MAP_USHORT)
    487449                            *((unsigned short *) p) = i;
    488                         } else {
     450                        else
    489451                            *((unsigned long *) p) = i;
    490                         }
    491452                    } else
    492453#endif
    493                     if (mask & A_CAST_CHAR_PTR) {
     454                    if (mask & A_CAST_CHAR_PTR)
    494455                        *((caddr_t *) p) = (caddr_t) i;
    495                     } else {    /* A_CAST_INT */
     456                    else    /* A_CAST_INT */
    496457                        *((int *) p) = i;
    497                     }
    498458                }
    499459
    500                 if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
    501                     perror(a1op->name);
    502                     ++goterr;
    503                     continue;
    504                 }
     460                ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "%s", a1op->name);
    505461#ifdef QUESTIONABLE_ALIAS_CASE
    506462                if (mask & A_COLON_CHK) {
    507463                    /*
    508464                     * Don't do the set_flag() if the address is an alias with
    509                      * a - at the end, since it's deleted already! - Roman
     465                     * a '-' at the end, since it's deleted already! - Roman
    510466                     *
    511467                     * Should really use regex.h here, not sure though how well
     
    514470                    char *ptr;
    515471                    short int found_colon = 0;
    516 
    517                     for (ptr = ifr.ifr_name; *ptr; ptr++) {
    518                         if (*ptr == ':') {
     472                    for (ptr = ifr.ifr_name; *ptr; ptr++)
     473                        if (*ptr == ':')
    519474                            found_colon++;
    520                         }
    521                     }
    522 
    523                     if (found_colon && *(ptr - 1) == '-') {
     475                    if (found_colon && ptr[-1] == '-')
    524476                        continue;
    525                     }
    526477                }
    527478#endif
    528479            }
    529             if (!(mask & A_SET_AFTER)) {
     480            if (!(mask & A_SET_AFTER))
    530481                continue;
    531             }
    532482            mask = N_SET;
    533483        }
    534484
    535         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
    536             perror("SIOCGIFFLAGS");
    537             ++goterr;
    538         } else {
    539             selector = op->selector;
    540             if (mask & SET_MASK) {
    541                 ifr.ifr_flags |= selector;
    542             } else {
    543                 ifr.ifr_flags &= ~selector;
    544             }
    545             if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
    546                 perror("SIOCSIFFLAGS");
    547                 ++goterr;
    548             }
    549         }
    550       LOOP:
    551         continue;
    552     }                   /* end of while-loop */
    553 
    554     if (ENABLE_FEATURE_CLEAN_UP) close(sockfd);
    555     return goterr;
     485        xioctl(sockfd, SIOCGIFFLAGS, &ifr);
     486        selector = op->selector;
     487        if (mask & SET_MASK)
     488            ifr.ifr_flags |= selector;
     489        else
     490            ifr.ifr_flags &= ~selector;
     491        xioctl(sockfd, SIOCSIFFLAGS, &ifr);
     492    } /* while () */
     493
     494    if (ENABLE_FEATURE_CLEAN_UP)
     495        close(sockfd);
     496    return 0;
    556497}
    557498
    558 #ifdef CONFIG_FEATURE_IFCONFIG_HW
     499#if ENABLE_FEATURE_IFCONFIG_HW
    559500/* Input an Ethernet address and convert to binary. */
    560 static int in_ether(char *bufp, struct sockaddr *sap)
     501static int in_ether(const char *bufp, struct sockaddr *sap)
    561502{
    562503    char *ptr;
     
    595536    } while (++i < ETH_ALEN);
    596537
    597     return (int) (*bufp);   /* Error if we don't end at end of string. */
     538    return *bufp; /* Error if we don't end at end of string. */
    598539}
    599540#endif
  • branches/stable/mindi-busybox/networking/ifupdown.c

    r821 r1770  
    1111 *  Remove checks for kernel version, assume kernel version 2.2.0 or better.
    1212 *  Lines in the interfaces file cannot wrap.
    13  *  To adhere to the FHS, the default state file is /var/run/ifstate.
     13 *  To adhere to the FHS, the default state file is /var/run/ifstate
     14 *  (defined via CONFIG_IFUPDOWN_IFSTATE_PATH) and can be overridden by build
     15 *  configuration.
    1416 *
    1517 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    1618 */
    1719
    18 /* TODO: standardise execute() return codes to return 0 for success and 1 for failure */
    19 
    20 #include <sys/stat.h>
    2120#include <sys/utsname.h>
    22 #include <sys/wait.h>
    23 
    24 #include <ctype.h>
    25 #include <errno.h>
    26 #include <fcntl.h>
    2721#include <fnmatch.h>
    2822#include <getopt.h>
    29 #include <stdarg.h>
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 #include <unistd.h>
    34 
    35 #include "busybox.h"
     23
     24#include "libbb.h"
    3625
    3726#define MAX_OPT_DEPTH 10
     
    4029#define EUNBALPER   10000
    4130
    42 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     31#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    4332#define MAX_INTERFACE_LENGTH 10
    4433#endif
    4534
    46 #if 0
    47 #define debug_noise(fmt, args...) printf(fmt, ## args)
    48 #else
    49 #define debug_noise(fmt, args...)
    50 #endif
     35#define debug_noise(args...) /*fprintf(stderr, args)*/
    5136
    5237/* Forward declaration */
    5338struct interface_defn_t;
    5439
    55 typedef int (execfn)(char *command);
    56 
    57 struct method_t
    58 {
    59     char *name;
     40typedef int execfn(char *command);
     41
     42struct method_t {
     43    const char *name;
    6044    int (*up)(struct interface_defn_t *ifd, execfn *e);
    6145    int (*down)(struct interface_defn_t *ifd, execfn *e);
    6246};
    6347
    64 struct address_family_t
    65 {
    66     char *name;
     48struct address_family_t {
     49    const char *name;
    6750    int n_methods;
    68     struct method_t *method;
     51    const struct method_t *method;
    6952};
    7053
    71 struct mapping_defn_t
    72 {
     54struct mapping_defn_t {
    7355    struct mapping_defn_t *next;
    7456
     
    8466};
    8567
    86 struct variable_t
    87 {
     68struct variable_t {
    8869    char *name;
    8970    char *value;
    9071};
    9172
    92 struct interface_defn_t
    93 {
    94     struct address_family_t *address_family;
    95     struct method_t *method;
     73struct interface_defn_t {
     74    const struct address_family_t *address_family;
     75    const struct method_t *method;
    9676
    9777    char *iface;
     
    10181};
    10282
    103 struct interfaces_file_t
    104 {
     83struct interfaces_file_t {
    10584    llist_t *autointerfaces;
    10685    llist_t *ifaces;
     
    10887};
    10988
    110 static char no_act = 0;
    111 static char verbose = 0;
    112 static char **__myenviron = NULL;
     89#define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:"
     90enum {
     91    OPT_do_all = 0x1,
     92    OPT_no_act = 0x2,
     93    OPT_verbose = 0x4,
     94    OPT_force = 0x8,
     95    OPT_no_mappings = 0x10,
     96};
     97#define DO_ALL (option_mask32 & OPT_do_all)
     98#define NO_ACT (option_mask32 & OPT_no_act)
     99#define VERBOSE (option_mask32 & OPT_verbose)
     100#define FORCE (option_mask32 & OPT_force)
     101#define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
     102
     103static char **my_environ;
     104
     105static const char *startup_PATH;
    113106
    114107#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
    115108
    116 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    117 
    118 static unsigned int count_bits(unsigned int a)
    119 {
    120     unsigned int result;
    121     result = (a & 0x55) + ((a >> 1) & 0x55);
    122     result = (result & 0x33) + ((result >> 2) & 0x33);
    123     return((result & 0x0F) + ((result >> 4) & 0x0F));
    124 }
    125 
    126 static int count_netmask_bits(char *dotted_quad)
    127 {
    128     unsigned int result, a, b, c, d;
    129     /* Found a netmask...  Check if it is dotted quad */
    130     if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
    131         return -1;
    132     result = count_bits(a);
    133     result += count_bits(b);
    134     result += count_bits(c);
    135     result += count_bits(d);
    136     return ((int)result);
    137 }
    138 #endif
    139 
    140 static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length)
    141 {
    142     if (*pos + str_length >= *len) {
    143         char *newbuf;
    144 
    145         newbuf = xrealloc(*buf, *len * 2 + str_length + 1);
    146         *buf = newbuf;
    147         *len = *len * 2 + str_length + 1;
    148     }
    149 
    150     while (str_length-- >= 1) {
    151         (*buf)[(*pos)++] = *str;
    152         str++;
    153     }
    154     (*buf)[*pos] = '\0';
    155 }
    156 
    157 static int strncmpz(char *l, char *r, size_t llen)
     109static void addstr(char **bufp, const char *str, size_t str_length)
     110{
     111    /* xasprintf trick will be smaller, but we are often
     112     * called with str_length == 1 - don't want to have
     113     * THAT much of malloc/freeing! */
     114    char *buf = *bufp;
     115    int len = (buf ? strlen(buf) : 0);
     116    str_length++;
     117    buf = xrealloc(buf, len + str_length);
     118    /* copies at most str_length-1 chars! */
     119    safe_strncpy(buf + len, str, str_length);
     120    *bufp = buf;
     121}
     122
     123static int strncmpz(const char *l, const char *r, size_t llen)
    158124{
    159125    int i = strncmp(l, r, llen);
    160126
    161     if (i == 0) {
    162         return(-r[llen]);
    163     } else {
    164         return(i);
    165     }
    166 }
    167 
    168 static char *get_var(char *id, size_t idlen, struct interface_defn_t *ifd)
     127    if (i == 0)
     128        return -r[llen];
     129    return i;
     130}
     131
     132static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd)
    169133{
    170134    int i;
     
    173137        char *result;
    174138        static char label_buf[20];
    175         strncpy(label_buf, ifd->iface, 19);
    176         label_buf[19]=0;
     139        safe_strncpy(label_buf, ifd->iface, sizeof(label_buf));
    177140        result = strchr(label_buf, ':');
    178141        if (result) {
    179             *result=0;
    180         }
    181         return( label_buf);
    182     } else if (strncmpz(id, "label", idlen) == 0) {
    183         return (ifd->iface);
    184     } else {
    185         for (i = 0; i < ifd->n_options; i++) {
    186             if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
    187                 return (ifd->option[i].value);
    188             }
    189         }
    190     }
    191 
    192     return(NULL);
    193 }
    194 
    195 static char *parse(char *command, struct interface_defn_t *ifd)
    196 {
    197 
    198     char *result = NULL;
    199     size_t pos = 0, len = 0;
     142            *result = '\0';
     143        }
     144        return label_buf;
     145    }
     146    if (strncmpz(id, "label", idlen) == 0) {
     147        return ifd->iface;
     148    }
     149    for (i = 0; i < ifd->n_options; i++) {
     150        if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
     151            return ifd->option[i].value;
     152        }
     153    }
     154    return NULL;
     155}
     156
     157#if ENABLE_FEATURE_IFUPDOWN_IP
     158static int count_netmask_bits(const char *dotted_quad)
     159{
     160//  int result;
     161//  unsigned a, b, c, d;
     162//  /* Found a netmask...  Check if it is dotted quad */
     163//  if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
     164//      return -1;
     165//  if ((a|b|c|d) >> 8)
     166//      return -1; /* one of numbers is >= 256 */
     167//  d |= (a << 24) | (b << 16) | (c << 8); /* IP */
     168//  d = ~d; /* 11110000 -> 00001111 */
     169
     170    /* Shorter version */
     171    int result;
     172    struct in_addr ip;
     173    unsigned d;
     174
     175    if (inet_aton(dotted_quad, &ip) == 0)
     176        return -1; /* malformed dotted IP */
     177    d = ntohl(ip.s_addr); /* IP in host order */
     178    d = ~d; /* 11110000 -> 00001111 */
     179    if (d & (d+1)) /* check that it is in 00001111 form */
     180        return -1; /* no it is not */
     181    result = 32;
     182    while (d) {
     183        d >>= 1;
     184        result--;
     185    }
     186    return result;
     187}
     188#endif
     189
     190static char *parse(const char *command, struct interface_defn_t *ifd)
     191{
    200192    size_t old_pos[MAX_OPT_DEPTH] = { 0 };
    201193    int okay[MAX_OPT_DEPTH] = { 1 };
    202194    int opt_depth = 1;
     195    char *result = NULL;
    203196
    204197    while (*command) {
    205198        switch (*command) {
    206 
    207             default:
    208                 addstr(&result, &len, &pos, command, 1);
     199        default:
     200            addstr(&result, command, 1);
     201            command++;
     202            break;
     203        case '\\':
     204            if (command[1]) {
     205                addstr(&result, command + 1, 1);
     206                command += 2;
     207            } else {
     208                addstr(&result, command, 1);
    209209                command++;
    210                 break;
    211             case '\\':
    212                 if (command[1]) {
    213                     addstr(&result, &len, &pos, command + 1, 1);
    214                     command += 2;
     210            }
     211            break;
     212        case '[':
     213            if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
     214                old_pos[opt_depth] = result ? strlen(result) : 0;
     215                okay[opt_depth] = 1;
     216                opt_depth++;
     217                command += 2;
     218            } else {
     219                addstr(&result, "[", 1);
     220                command++;
     221            }
     222            break;
     223        case ']':
     224            if (command[1] == ']' && opt_depth > 1) {
     225                opt_depth--;
     226                if (!okay[opt_depth]) {
     227                    result[old_pos[opt_depth]] = '\0';
     228                }
     229                command += 2;
     230            } else {
     231                addstr(&result, "]", 1);
     232                command++;
     233            }
     234            break;
     235        case '%':
     236            {
     237                char *nextpercent;
     238                char *varvalue;
     239
     240                command++;
     241                nextpercent = strchr(command, '%');
     242                if (!nextpercent) {
     243                    errno = EUNBALPER;
     244                    free(result);
     245                    return NULL;
     246                }
     247
     248                varvalue = get_var(command, nextpercent - command, ifd);
     249
     250                if (varvalue) {
     251                    addstr(&result, varvalue, strlen(varvalue));
    215252                } else {
    216                     addstr(&result, &len, &pos, command, 1);
    217                     command++;
    218                 }
    219                 break;
    220             case '[':
    221                 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
    222                     old_pos[opt_depth] = pos;
    223                     okay[opt_depth] = 1;
    224                     opt_depth++;
    225                     command += 2;
    226                 } else {
    227                     addstr(&result, &len, &pos, "[", 1);
    228                     command++;
    229                 }
    230                 break;
    231             case ']':
    232                 if (command[1] == ']' && opt_depth > 1) {
    233                     opt_depth--;
    234                     if (!okay[opt_depth]) {
    235                         pos = old_pos[opt_depth];
    236                         result[pos] = '\0';
    237                     }
    238                     command += 2;
    239                 } else {
    240                     addstr(&result, &len, &pos, "]", 1);
    241                     command++;
    242                 }
    243                 break;
    244             case '%':
    245                 {
    246                     char *nextpercent;
    247                     char *varvalue;
    248 
    249                     command++;
    250                     nextpercent = strchr(command, '%');
    251                     if (!nextpercent) {
    252                         errno = EUNBALPER;
    253                         free(result);
    254                         return (NULL);
    255                     }
    256 
    257                     varvalue = get_var(command, nextpercent - command, ifd);
    258 
    259                     if (varvalue) {
    260                         addstr(&result, &len, &pos, varvalue, strlen(varvalue));
    261                     } else {
    262 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    263                         /* Sigh...  Add a special case for 'ip' to convert from
    264                          * dotted quad to bit count style netmasks.  */
    265                         if (strncmp(command, "bnmask", 6)==0) {
    266                             int res;
    267                             varvalue = get_var("netmask", 7, ifd);
    268                             if (varvalue && (res=count_netmask_bits(varvalue)) > 0) {
    269                                 char argument[255];
    270                                 sprintf(argument, "%d", res);
    271                                 addstr(&result, &len, &pos, argument, strlen(argument));
     253#if ENABLE_FEATURE_IFUPDOWN_IP
     254                    /* Sigh...  Add a special case for 'ip' to convert from
     255                     * dotted quad to bit count style netmasks.  */
     256                    if (strncmp(command, "bnmask", 6) == 0) {
     257                        unsigned res;
     258                        varvalue = get_var("netmask", 7, ifd);
     259                        if (varvalue) {
     260                            res = count_netmask_bits(varvalue);
     261                            if (res > 0) {
     262                                const char *argument = utoa(res);
     263                                addstr(&result, argument, strlen(argument));
    272264                                command = nextpercent + 1;
    273265                                break;
    274266                            }
    275267                        }
    276 #endif
    277                         okay[opt_depth - 1] = 0;
    278268                    }
    279 
    280                     command = nextpercent + 1;
    281                 }
    282                 break;
     269#endif
     270                    okay[opt_depth - 1] = 0;
     271                }
     272
     273                command = nextpercent + 1;
     274            }
     275            break;
    283276        }
    284277    }
     
    287280        errno = EUNBALBRACK;
    288281        free(result);
    289         return(NULL);
     282        return NULL;
    290283    }
    291284
     
    293286        errno = EUNDEFVAR;
    294287        free(result);
    295         return(NULL);
    296     }
    297 
    298     return(result);
    299 }
    300 
    301 static int execute(char *command, struct interface_defn_t *ifd, execfn *exec)
     288        return NULL;
     289    }
     290
     291    return result;
     292}
     293
     294/* execute() returns 1 for success and 0 for failure */
     295static int execute(const char *command, struct interface_defn_t *ifd, execfn *exec)
    302296{
    303297    char *out;
     
    306300    out = parse(command, ifd);
    307301    if (!out) {
    308         return(0);
    309     }
    310     ret = (*exec) (out);
     302        /* parse error? */
     303        return 0;
     304    }
     305    /* out == "": parsed ok but not all needed variables known, skip */
     306    ret = out[0] ? (*exec)(out) : 1;
    311307
    312308    free(out);
    313309    if (ret != 1) {
    314         return(0);
    315     }
    316     return(1);
    317 }
    318 #endif
    319 
    320 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
     310        return 0;
     311    }
     312    return 1;
     313}
     314#endif
     315
     316#if ENABLE_FEATURE_IFUPDOWN_IPV6
    321317static int loopback_up6(struct interface_defn_t *ifd, execfn *exec)
    322318{
    323 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     319#if ENABLE_FEATURE_IFUPDOWN_IP
    324320    int result;
    325     result =execute("ip addr add ::1 dev %iface%", ifd, exec);
     321    result = execute("ip addr add ::1 dev %iface%", ifd, exec);
    326322    result += execute("ip link set %iface% up", ifd, exec);
    327323    return ((result == 2) ? 2 : 0);
    328324#else
    329     return( execute("ifconfig %iface% add ::1", ifd, exec));
     325    return execute("ifconfig %iface% add ::1", ifd, exec);
    330326#endif
    331327}
     
    333329static int loopback_down6(struct interface_defn_t *ifd, execfn *exec)
    334330{
    335 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    336     return(execute("ip link set %iface% down", ifd, exec));
     331#if ENABLE_FEATURE_IFUPDOWN_IP
     332    return execute("ip link set %iface% down", ifd, exec);
    337333#else
    338     return(execute("ifconfig %iface% del ::1", ifd, exec));
     334    return execute("ifconfig %iface% del ::1", ifd, exec);
    339335#endif
    340336}
     
    343339{
    344340    int result;
    345 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    346     result = execute("ip addr add %address%/%netmask% dev %iface% [[label %label%]]", ifd, exec);
    347     result += execute("ip link set [[mtu %mtu%]] [[address %hwaddress%]] %iface% up", ifd, exec);
    348     result += execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec);
     341#if ENABLE_FEATURE_IFUPDOWN_IP
     342    result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
     343    result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
     344    /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
     345    result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
    349346#else
    350     result = execute("ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up", ifd, exec);
     347    result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
    351348    result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
    352     result += execute("[[ route -A inet6 add ::/0 gw %gateway% ]]", ifd, exec);
     349    result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);
    353350#endif
    354351    return ((result == 3) ? 3 : 0);
     
    357354static int static_down6(struct interface_defn_t *ifd, execfn *exec)
    358355{
    359 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    360     return(execute("ip link set %iface% down", ifd, exec));
     356#if ENABLE_FEATURE_IFUPDOWN_IP
     357    return execute("ip link set %iface% down", ifd, exec);
    361358#else
    362     return(execute("ifconfig %iface% down", ifd, exec));
    363 #endif
    364 }
    365 
    366 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     359    return execute("ifconfig %iface% down", ifd, exec);
     360#endif
     361}
     362
     363#if ENABLE_FEATURE_IFUPDOWN_IP
    367364static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
    368365{
    369366    int result;
    370367    result = execute("ip tunnel add %iface% mode sit remote "
    371                 "%endpoint% [[local %local%]] [[ttl %ttl%]]", ifd, exec);
     368            "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd, exec);
    372369    result += execute("ip link set %iface% up", ifd, exec);
    373370    result += execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec);
    374     result += execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec);
     371    result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
    375372    return ((result == 4) ? 4 : 0);
    376373}
     
    378375static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
    379376{
    380     return( execute("ip tunnel del %iface%", ifd, exec));
    381 }
    382 #endif
    383 
    384 static struct method_t methods6[] = {
    385 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     377    return execute("ip tunnel del %iface%", ifd, exec);
     378}
     379#endif
     380
     381static const struct method_t methods6[] = {
     382#if ENABLE_FEATURE_IFUPDOWN_IP
    386383    { "v4tunnel", v4tunnel_up, v4tunnel_down, },
    387384#endif
     
    390387};
    391388
    392 static struct address_family_t addr_inet6 = {
     389static const struct address_family_t addr_inet6 = {
    393390    "inet6",
    394     sizeof(methods6) / sizeof(struct method_t),
     391    ARRAY_SIZE(methods6),
    395392    methods6
    396393};
    397 #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */
    398 
    399 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
     394#endif /* FEATURE_IFUPDOWN_IPV6 */
     395
     396#if ENABLE_FEATURE_IFUPDOWN_IPV4
    400397static int loopback_up(struct interface_defn_t *ifd, execfn *exec)
    401398{
    402 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     399#if ENABLE_FEATURE_IFUPDOWN_IP
    403400    int result;
    404401    result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
     
    406403    return ((result == 2) ? 2 : 0);
    407404#else
    408     return( execute("ifconfig %iface% 127.0.0.1 up", ifd, exec));
     405    return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
    409406#endif
    410407}
     
    412409static int loopback_down(struct interface_defn_t *ifd, execfn *exec)
    413410{
    414 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     411#if ENABLE_FEATURE_IFUPDOWN_IP
    415412    int result;
    416413    result = execute("ip addr flush dev %iface%", ifd, exec);
     
    418415    return ((result == 2) ? 2 : 0);
    419416#else
    420     return( execute("ifconfig %iface% 127.0.0.1 down", ifd, exec));
     417    return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
    421418#endif
    422419}
     
    425422{
    426423    int result;
    427 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    428     result = execute("ip addr add %address%/%bnmask% [[broadcast %broadcast%]] "
    429             "dev %iface% [[peer %pointopoint%]] [[label %label%]]", ifd, exec);
    430     result += execute("ip link set [[mtu %mtu%]] [[address %hwaddress%]] %iface% up", ifd, exec);
    431     result += execute("[[ ip route add default via %gateway% dev %iface% ]]", ifd, exec);
     424#if ENABLE_FEATURE_IFUPDOWN_IP
     425    result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
     426            "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
     427    result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
     428    result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
    432429    return ((result == 3) ? 3 : 0);
    433430#else
    434     result = execute("ifconfig %iface% %address% netmask %netmask% "
    435                 "[[broadcast %broadcast%]] [[pointopoint %pointopoint%]] "
    436                 "[[media %media%]] [[mtu %mtu%]] [[hw %hwaddress%]] up",
     431    /* ifconfig said to set iface up before it processes hw %hwaddress%,
     432     * which then of course fails. Thus we run two separate ifconfig */
     433    result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
    437434                ifd, exec);
    438     result += execute("[[ route add default gw %gateway% %iface% ]]", ifd, exec);
    439     return ((result == 2) ? 2 : 0);
     435    result += execute("ifconfig %iface% %address% netmask %netmask%"
     436                "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
     437                ifd, exec);
     438    result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
     439    return ((result == 3) ? 3 : 0);
    440440#endif
    441441}
     
    444444{
    445445    int result;
    446 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     446#if ENABLE_FEATURE_IFUPDOWN_IP
    447447    result = execute("ip addr flush dev %iface%", ifd, exec);
    448448    result += execute("ip link set %iface% down", ifd, exec);
    449449#else
    450     result = execute("[[ route del default gw %gateway% %iface% ]]", ifd, exec);
     450    result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec);
    451451    result += execute("ifconfig %iface% down", ifd, exec);
    452452#endif
     
    454454}
    455455
    456 static int execable(char *program)
    457 {
    458     struct stat buf;
    459     if (0 == stat(program, &buf)) {
    460         if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) {
    461             return(1);
    462         }
    463     }
    464     return(0);
    465 }
     456#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     457struct dhcp_client_t
     458{
     459    const char *name;
     460    const char *startcmd;
     461    const char *stopcmd;
     462};
     463
     464static const struct dhcp_client_t ext_dhcp_clients[] = {
     465    { "dhcpcd",
     466        "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",
     467        "dhcpcd -k %iface%",
     468    },
     469    { "dhclient",
     470        "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
     471        "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
     472    },
     473    { "pump",
     474        "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
     475        "pump -i %iface% -k",
     476    },
     477    { "udhcpc",
     478        "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
     479        "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
     480    },
     481};
     482#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
    466483
    467484static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
    468485{
    469     if (execable("/sbin/udhcpc")) {
    470         return( execute("udhcpc -n -p /var/run/udhcpc.%iface%.pid -i "
    471                     "%iface% [[-H %hostname%]] [[-c %clientid%]]", ifd, exec));
    472     } else if (execable("/sbin/pump")) {
    473         return( execute("pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]]", ifd, exec));
    474     } else if (execable("/sbin/dhclient")) {
    475         return( execute("dhclient -pf /var/run/dhclient.%iface%.pid %iface%", ifd, exec));
    476     } else if (execable("/sbin/dhcpcd")) {
    477         return( execute("dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] "
    478                     "[[-l %leasetime%]] %iface%", ifd, exec));
    479     }
    480     return(0);
     486#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     487    int i;
     488#if ENABLE_FEATURE_IFUPDOWN_IP
     489    /* ip doesn't up iface when it configures it (unlike ifconfig) */
     490    if (!execute("ip link set %iface% up", ifd, exec))
     491        return 0;
     492#endif
     493    for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
     494        if (exists_execable(ext_dhcp_clients[i].name))
     495            return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
     496    }
     497    bb_error_msg("no dhcp clients found");
     498    return 0;
     499#elif ENABLE_APP_UDHCPC
     500#if ENABLE_FEATURE_IFUPDOWN_IP
     501    /* ip doesn't up iface when it configures it (unlike ifconfig) */
     502    if (!execute("ip link set %iface% up", ifd, exec))
     503        return 0;
     504#endif
     505    return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid "
     506            "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
     507            ifd, exec);
     508#else
     509    return 0; /* no dhcp support */
     510#endif
    481511}
    482512
    483513static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
    484514{
    485     int result = 0;
    486     if (execable("/sbin/udhcpc")) {
    487         /* SIGUSR2 forces udhcpc to release the current lease and go inactive,
    488          * and SIGTERM causes udhcpc to exit.  Signals are queued and processed
    489          * sequentially so we don't need to sleep */
    490         result = execute("kill -USR2 `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
    491         result += execute("kill -TERM `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
    492     } else if (execable("/sbin/pump")) {
    493         result = execute("pump -i %iface% -k", ifd, exec);
    494     } else if (execable("/sbin/dhclient")) {
    495         result = execute("kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null", ifd, exec);
    496     } else if (execable("/sbin/dhcpcd")) {
    497         result = execute("dhcpcd -k %iface%", ifd, exec);
    498     }
    499     return (result || static_down(ifd, exec));
     515#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     516    int i;
     517    for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
     518        if (exists_execable(ext_dhcp_clients[i].name))
     519            return execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
     520    }
     521    bb_error_msg("no dhcp clients found, using static interface shutdown");
     522    return static_down(ifd, exec);
     523#elif ENABLE_APP_UDHCPC
     524    return execute("kill "
     525                   "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
     526#else
     527    return 0; /* no dhcp support */
     528#endif
     529}
     530
     531static int manual_up_down(struct interface_defn_t *ifd, execfn *exec)
     532{
     533    return 1;
    500534}
    501535
    502536static int bootp_up(struct interface_defn_t *ifd, execfn *exec)
    503537{
    504     return( execute("bootpc [[--bootfile %bootfile%]] --dev %iface% "
    505                 "[[--server %server%]] [[--hwaddr %hwaddr%]] "
    506                 "--returniffail --serverbcast", ifd, exec));
     538    return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
     539            "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
     540            " --returniffail --serverbcast", ifd, exec);
    507541}
    508542
    509543static int ppp_up(struct interface_defn_t *ifd, execfn *exec)
    510544{
    511     return( execute("pon [[%provider%]]", ifd, exec));
     545    return execute("pon[[ %provider%]]", ifd, exec);
    512546}
    513547
    514548static int ppp_down(struct interface_defn_t *ifd, execfn *exec)
    515549{
    516     return( execute("poff [[%provider%]]", ifd, exec));
     550    return execute("poff[[ %provider%]]", ifd, exec);
    517551}
    518552
    519553static int wvdial_up(struct interface_defn_t *ifd, execfn *exec)
    520554{
    521     return( execute("/sbin/start-stop-daemon --start -x /usr/bin/wvdial "
    522                 "-p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]", ifd, exec));
     555    return execute("start-stop-daemon --start -x wvdial "
     556        "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd, exec);
    523557}
    524558
    525559static int wvdial_down(struct interface_defn_t *ifd, execfn *exec)
    526560{
    527     return( execute("/sbin/start-stop-daemon --stop -x /usr/bin/wvdial "
    528                 "-p /var/run/wvdial.%iface% -s 2", ifd, exec));
    529 }
    530 
    531 static struct method_t methods[] =
    532 {
     561    return execute("start-stop-daemon --stop -x wvdial "
     562            "-p /var/run/wvdial.%iface% -s 2", ifd, exec);
     563}
     564
     565static const struct method_t methods[] = {
     566    { "manual", manual_up_down, manual_up_down, },
    533567    { "wvdial", wvdial_up, wvdial_down, },
    534568    { "ppp", ppp_up, ppp_down, },
     
    539573};
    540574
    541 static struct address_family_t addr_inet =
    542 {
     575static const struct address_family_t addr_inet = {
    543576    "inet",
    544     sizeof(methods) / sizeof(struct method_t),
     577    ARRAY_SIZE(methods),
    545578    methods
    546579};
    547580
    548 #endif  /* ifdef CONFIG_FEATURE_IFUPDOWN_IPV4 */
     581#endif  /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */
    549582
    550583static char *next_word(char **buf)
     
    553586    char *word;
    554587
    555     if ((buf == NULL) || (*buf == NULL) || (**buf == '\0')) {
     588    if (!buf || !*buf || !**buf) {
    556589        return NULL;
    557590    }
    558591
    559592    /* Skip over leading whitespace */
    560     word = *buf;
    561     while (isspace(*word)) {
    562         ++word;
    563     }
     593    word = skip_whitespace(*buf);
    564594
    565595    /* Skip over comments */
    566596    if (*word == '#') {
    567         return(NULL);
     597        return NULL;
    568598    }
    569599
     
    571601    length = strcspn(word, " \t\n");
    572602    if (length == 0) {
    573         return(NULL);
     603        return NULL;
    574604    }
    575605    *buf = word + length;
     
    583613}
    584614
    585 static struct address_family_t *get_address_family(struct address_family_t *af[], char *name)
     615static const struct address_family_t *get_address_family(const struct address_family_t *const af[], char *name)
    586616{
    587617    int i;
     618
     619    if (!name)
     620        return NULL;
    588621
    589622    for (i = 0; af[i]; i++) {
     
    595628}
    596629
    597 static struct method_t *get_method(struct address_family_t *af, char *name)
     630static const struct method_t *get_method(const struct address_family_t *af, char *name)
    598631{
    599632    int i;
     633
     634    if (!name)
     635        return NULL;
    600636
    601637    for (i = 0; i < af->n_methods; i++) {
     
    604640        }
    605641    }
    606     return(NULL);
     642    return NULL;
    607643}
    608644
    609645static const llist_t *find_list_string(const llist_t *list, const char *string)
    610646{
     647    if (string == NULL)
     648        return NULL;
     649
    611650    while (list) {
    612651        if (strcmp(list->data, string) == 0) {
    613             return(list);
     652            return list;
    614653        }
    615654        list = list->link;
    616655    }
    617     return(NULL);
     656    return NULL;
    618657}
    619658
    620659static struct interfaces_file_t *read_interfaces(const char *filename)
    621660{
    622 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     661#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    623662    struct mapping_defn_t *currmap = NULL;
    624663#endif
     
    633672    defn = xzalloc(sizeof(struct interfaces_file_t));
    634673
    635     f = bb_xfopen(filename, "r");
    636 
    637     while ((buf = bb_get_chomped_line_from_file(f)) != NULL) {
     674    f = xfopen(filename, "r");
     675
     676    while ((buf = xmalloc_getline(f)) != NULL) {
    638677        char *buf_ptr = buf;
    639678
     
    645684
    646685        if (strcmp(firstword, "mapping") == 0) {
    647 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     686#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    648687            currmap = xzalloc(sizeof(struct mapping_defn_t));
    649688
     
    654693                }
    655694
    656                 currmap->match[currmap->n_matches++] = bb_xstrdup(firstword);
     695                currmap->match[currmap->n_matches++] = xstrdup(firstword);
    657696            }
    658697            currmap->max_mappings = 0;
     
    672711            currently_processing = MAPPING;
    673712        } else if (strcmp(firstword, "iface") == 0) {
    674             {
    675                 char *iface_name;
    676                 char *address_family_name;
    677                 char *method_name;
    678                 struct address_family_t *addr_fams[] = {
    679 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
    680                     &addr_inet,
    681 #endif
    682 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
    683                     &addr_inet6,
    684 #endif
    685                     NULL
    686                 };
    687 
    688                 currif = xzalloc(sizeof(struct interface_defn_t));
    689                 iface_name = next_word(&buf_ptr);
    690                 address_family_name = next_word(&buf_ptr);
    691                 method_name = next_word(&buf_ptr);
    692 
    693                 if (buf_ptr == NULL) {
    694                     bb_error_msg("too few parameters for line \"%s\"", buf);
     713            static const struct address_family_t *const addr_fams[] = {
     714#if ENABLE_FEATURE_IFUPDOWN_IPV4
     715                &addr_inet,
     716#endif
     717#if ENABLE_FEATURE_IFUPDOWN_IPV6
     718                &addr_inet6,
     719#endif
     720                NULL
     721            };
     722
     723            char *iface_name;
     724            char *address_family_name;
     725            char *method_name;
     726            llist_t *iface_list;
     727
     728            currif = xzalloc(sizeof(struct interface_defn_t));
     729            iface_name = next_word(&buf_ptr);
     730            address_family_name = next_word(&buf_ptr);
     731            method_name = next_word(&buf_ptr);
     732
     733            if (buf_ptr == NULL) {
     734                bb_error_msg("too few parameters for line \"%s\"", buf);
     735                return NULL;
     736            }
     737
     738            /* ship any trailing whitespace */
     739            buf_ptr = skip_whitespace(buf_ptr);
     740
     741            if (buf_ptr[0] != '\0') {
     742                bb_error_msg("too many parameters \"%s\"", buf);
     743                return NULL;
     744            }
     745
     746            currif->iface = xstrdup(iface_name);
     747
     748            currif->address_family = get_address_family(addr_fams, address_family_name);
     749            if (!currif->address_family) {
     750                bb_error_msg("unknown address type \"%s\"", address_family_name);
     751                return NULL;
     752            }
     753
     754            currif->method = get_method(currif->address_family, method_name);
     755            if (!currif->method) {
     756                bb_error_msg("unknown method \"%s\"", method_name);
     757                return NULL;
     758            }
     759
     760            for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
     761                struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
     762                if ((strcmp(tmp->iface, currif->iface) == 0) &&
     763                    (tmp->address_family == currif->address_family)) {
     764                    bb_error_msg("duplicate interface \"%s\"", tmp->iface);
    695765                    return NULL;
    696766                }
    697 
    698                 /* ship any trailing whitespace */
    699                 while (isspace(*buf_ptr)) {
    700                     ++buf_ptr;
    701                 }
    702 
    703                 if (buf_ptr[0] != '\0') {
    704                     bb_error_msg("too many parameters \"%s\"", buf);
    705                     return NULL;
    706                 }
    707 
    708                 currif->iface = bb_xstrdup(iface_name);
    709 
    710                 currif->address_family = get_address_family(addr_fams, address_family_name);
    711                 if (!currif->address_family) {
    712                     bb_error_msg("unknown address type \"%s\"", address_family_name);
    713                     return NULL;
    714                 }
    715 
    716                 currif->method = get_method(currif->address_family, method_name);
    717                 if (!currif->method) {
    718                     bb_error_msg("unknown method \"%s\"", method_name);
    719                     return NULL;
    720                 }
    721 
    722 
    723                 {
    724                     llist_t *iface_list;
    725                     for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
    726                         struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
    727                         if ((strcmp(tmp->iface, currif->iface) == 0) &&
    728                             (tmp->address_family == currif->address_family)) {
    729                             bb_error_msg("duplicate interface \"%s\"", tmp->iface);
    730                             return NULL;
    731                         }
    732                     }
    733 
    734                     llist_add_to_end(&(defn->ifaces), (char*)currif);
    735                 }
    736                 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
    737             }
     767            }
     768            llist_add_to_end(&(defn->ifaces), (char*)currif);
     769
     770            debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
    738771            currently_processing = IFACE;
    739772        } else if (strcmp(firstword, "auto") == 0) {
     
    746779
    747780                /* Add the interface to the list */
    748                 llist_add_to_end(&(defn->autointerfaces), bb_xstrdup(firstword));
     781                llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword));
    749782                debug_noise("\nauto %s\n", firstword);
    750783            }
     
    752785        } else {
    753786            switch (currently_processing) {
    754                 case IFACE:
    755                     {
    756                         int i;
    757 
    758                         if (strlen(buf_ptr) == 0) {
    759                             bb_error_msg("option with empty value \"%s\"", buf);
    760                             return NULL;
    761                         }
    762 
    763                         if (strcmp(firstword, "up") != 0
    764                                 && strcmp(firstword, "down") != 0
    765                                 && strcmp(firstword, "pre-up") != 0
    766                                 && strcmp(firstword, "post-down") != 0) {
    767                             for (i = 0; i < currif->n_options; i++) {
    768                                 if (strcmp(currif->option[i].name, firstword) == 0) {
    769                                     bb_error_msg("duplicate option \"%s\"", buf);
    770                                     return NULL;
    771                                 }
     787            case IFACE:
     788                {
     789                    int i;
     790
     791                    if (strlen(buf_ptr) == 0) {
     792                        bb_error_msg("option with empty value \"%s\"", buf);
     793                        return NULL;
     794                    }
     795
     796                    if (strcmp(firstword, "up") != 0
     797                            && strcmp(firstword, "down") != 0
     798                            && strcmp(firstword, "pre-up") != 0
     799                            && strcmp(firstword, "post-down") != 0) {
     800                        for (i = 0; i < currif->n_options; i++) {
     801                            if (strcmp(currif->option[i].name, firstword) == 0) {
     802                                bb_error_msg("duplicate option \"%s\"", buf);
     803                                return NULL;
    772804                            }
    773805                        }
    774806                    }
    775                     if (currif->n_options >= currif->max_options) {
    776                         struct variable_t *opt;
    777 
    778                         currif->max_options = currif->max_options + 10;
    779                         opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
    780                         currif->option = opt;
     807                }
     808                if (currif->n_options >= currif->max_options) {
     809                    struct variable_t *opt;
     810
     811                    currif->max_options = currif->max_options + 10;
     812                    opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
     813                    currif->option = opt;
     814                }
     815                currif->option[currif->n_options].name = xstrdup(firstword);
     816                currif->option[currif->n_options].value = xstrdup(buf_ptr);
     817                if (!currif->option[currif->n_options].name) {
     818                    perror(filename);
     819                    return NULL;
     820                }
     821                if (!currif->option[currif->n_options].value) {
     822                    perror(filename);
     823                    return NULL;
     824                }
     825                debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,
     826                        currif->option[currif->n_options].value);
     827                currif->n_options++;
     828                break;
     829            case MAPPING:
     830#if ENABLE_FEATURE_IFUPDOWN_MAPPING
     831                if (strcmp(firstword, "script") == 0) {
     832                    if (currmap->script != NULL) {
     833                        bb_error_msg("duplicate script in mapping \"%s\"", buf);
     834                        return NULL;
     835                    } else {
     836                        currmap->script = xstrdup(next_word(&buf_ptr));
    781837                    }
    782                     currif->option[currif->n_options].name = bb_xstrdup(firstword);
    783                     currif->option[currif->n_options].value = bb_xstrdup(buf_ptr);
    784                     if (!currif->option[currif->n_options].name) {
    785                         perror(filename);
    786                         return NULL;
     838                } else if (strcmp(firstword, "map") == 0) {
     839                    if (currmap->max_mappings == currmap->n_mappings) {
     840                        currmap->max_mappings = currmap->max_mappings * 2 + 1;
     841                        currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
    787842                    }
    788                     if (!currif->option[currif->n_options].value) {
    789                         perror(filename);
    790                         return NULL;
    791                     }
    792                     debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,
    793                             currif->option[currif->n_options].value);
    794                     currif->n_options++;
    795                     break;
    796                 case MAPPING:
    797 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    798                     if (strcmp(firstword, "script") == 0) {
    799                         if (currmap->script != NULL) {
    800                             bb_error_msg("duplicate script in mapping \"%s\"", buf);
    801                             return NULL;
    802                         } else {
    803                             currmap->script = bb_xstrdup(next_word(&buf_ptr));
    804                         }
    805                     } else if (strcmp(firstword, "map") == 0) {
    806                         if (currmap->max_mappings == currmap->n_mappings) {
    807                             currmap->max_mappings = currmap->max_mappings * 2 + 1;
    808                             currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
    809                         }
    810                         currmap->mapping[currmap->n_mappings] = bb_xstrdup(next_word(&buf_ptr));
    811                         currmap->n_mappings++;
    812                     } else {
    813                         bb_error_msg("misplaced option \"%s\"", buf);
    814                         return NULL;
    815                     }
    816 #endif
    817                     break;
    818                 case NONE:
    819                 default:
     843                    currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));
     844                    currmap->n_mappings++;
     845                } else {
    820846                    bb_error_msg("misplaced option \"%s\"", buf);
    821847                    return NULL;
     848                }
     849#endif
     850                break;
     851            case NONE:
     852            default:
     853                bb_error_msg("misplaced option \"%s\"", buf);
     854                return NULL;
    822855            }
    823856        }
     
    825858    }
    826859    if (ferror(f) != 0) {
    827         bb_perror_msg_and_die("%s", filename);
     860        /* ferror does NOT set errno! */
     861        bb_error_msg_and_die("%s: I/O error", filename);
    828862    }
    829863    fclose(f);
     
    832866}
    833867
    834 static char *setlocalenv(char *format, const char *name, const char *value)
     868static char *setlocalenv(const char *format, const char *name, const char *value)
    835869{
    836870    char *result;
     
    838872    char *there;
    839873
    840     result = bb_xasprintf(format, name, value);
     874    result = xasprintf(format, name, value);
    841875
    842876    for (here = there = result; *there != '=' && *there; there++) {
     
    863897    char **ppch;
    864898
    865     if (__myenviron != NULL) {
    866         for (ppch = __myenviron; *ppch; ppch++) {
     899    if (my_environ != NULL) {
     900        for (ppch = my_environ; *ppch; ppch++) {
    867901            free(*ppch);
    868902            *ppch = NULL;
    869903        }
    870         free(__myenviron);
    871     }
    872     __myenviron = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
    873     environend = __myenviron;
     904        free(my_environ);
     905    }
     906    my_environ = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
     907    environend = my_environ;
    874908
    875909    for (i = 0; i < iface->n_options; i++) {
    876910        if (strcmp(iface->option[i].name, "up") == 0
    877                 || strcmp(iface->option[i].name, "down") == 0
    878                 || strcmp(iface->option[i].name, "pre-up") == 0
    879                 || strcmp(iface->option[i].name, "post-down") == 0) {
     911         || strcmp(iface->option[i].name, "down") == 0
     912         || strcmp(iface->option[i].name, "pre-up") == 0
     913         || strcmp(iface->option[i].name, "post-down") == 0
     914        ) {
    880915            continue;
    881916        }
     
    887922    *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
    888923    *(environend++) = setlocalenv("%s=%s", "MODE", mode);
    889     *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
     924    *(environend++) = setlocalenv("%s=%s", "PATH", startup_PATH);
    890925}
    891926
    892927static int doit(char *str)
    893928{
    894     if (verbose || no_act) {
    895         printf("%s\n", str);
    896     }
    897     if (!no_act) {
     929    if (option_mask32 & (OPT_no_act|OPT_verbose)) {
     930        puts(str);
     931    }
     932    if (!(option_mask32 & OPT_no_act)) {
    898933        pid_t child;
    899934        int status;
    900935
    901936        fflush(NULL);
    902         switch (child = fork()) {
    903             case -1:        /* failure */
    904                 return 0;
    905             case 0:     /* child */
    906                 execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, __myenviron);
    907                 exit(127);
     937        child = fork();
     938        switch (child) {
     939        case -1: /* failure */
     940            return 0;
     941        case 0: /* child */
     942            execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);
     943            exit(127);
    908944        }
    909945        waitpid(child, &status, 0);
     
    912948        }
    913949    }
    914     return (1);
     950    return 1;
    915951}
    916952
     
    927963    }
    928964
    929     buf = bb_xasprintf("run-parts /etc/network/if-%s.d", opt);
    930     if (doit(buf) != 1) {
    931         return 0;
    932     }
    933     return 1;
    934 }
    935 
    936 static int check(char *str) {
     965    buf = xasprintf("run-parts /etc/network/if-%s.d", opt);
     966    /* heh, we don't bother free'ing it */
     967    return doit(buf);
     968}
     969
     970static int check(char *str)
     971{
    937972    return str != NULL;
    938973}
     
    940975static int iface_up(struct interface_defn_t *iface)
    941976{
    942     if (!iface->method->up(iface,check)) return -1;
     977    if (!iface->method->up(iface, check)) return -1;
    943978    set_environ(iface, "start");
    944979    if (!execute_all(iface, "pre-up")) return 0;
     
    958993}
    959994
    960 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     995#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    961996static int popen2(FILE **in, FILE **out, char *command, ...)
    962997{
     
    9871022    fflush(NULL);
    9881023    switch (pid = fork()) {
    989         case -1:            /* failure */
    990             close(infd[0]);
    991             close(infd[1]);
    992             close(outfd[0]);
    993             close(outfd[1]);
    994             return 0;
    995         case 0:         /* child */
    996             dup2(infd[0], 0);
    997             dup2(outfd[1], 1);
    998             close(infd[0]);
    999             close(infd[1]);
    1000             close(outfd[0]);
    1001             close(outfd[1]);
    1002             execvp(command, argv);
    1003             exit(127);
    1004         default:            /* parent */
    1005             *in = fdopen(infd[1], "w");
    1006             *out = fdopen(outfd[0], "r");
    1007             close(infd[0]);
    1008             close(outfd[1]);
    1009             return pid;
     1024    case -1:            /* failure */
     1025        close(infd[0]);
     1026        close(infd[1]);
     1027        close(outfd[0]);
     1028        close(outfd[1]);
     1029        return 0;
     1030    case 0:         /* child */
     1031        dup2(infd[0], 0);
     1032        dup2(outfd[1], 1);
     1033        close(infd[0]);
     1034        close(infd[1]);
     1035        close(outfd[0]);
     1036        close(outfd[1]);
     1037        BB_EXECVP(command, argv);
     1038        exit(127);
     1039    default:            /* parent */
     1040        *in = fdopen(infd[1], "w");
     1041        *out = fdopen(outfd[0], "r");
     1042        close(infd[0]);
     1043        close(outfd[1]);
     1044        return pid;
    10101045    }
    10111046    /* unreached */
     
    10181053    pid_t pid;
    10191054
    1020     char *logical = bb_xstrdup(physical);
     1055    char *logical = xstrdup(physical);
    10211056
    10221057    /* Run the mapping script. */
     
    10381073         * grab a line of output and use that as the name of the
    10391074         * logical interface. */
    1040         char *new_logical = (char *)xmalloc(MAX_INTERFACE_LENGTH);
     1075        char *new_logical = xmalloc(MAX_INTERFACE_LENGTH);
    10411076
    10421077        if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) {
     
    10621097    return logical;
    10631098}
    1064 #endif /* CONFIG_FEATURE_IFUPDOWN_MAPPING */
     1099#endif /* FEATURE_IFUPDOWN_MAPPING */
    10651100
    10661101static llist_t *find_iface_state(llist_t *state_list, const char *iface)
     
    10701105
    10711106    while (search) {
    1072         if ((strncmp(search->data, iface, iface_len) == 0) &&
    1073                 (search->data[iface_len] == '=')) {
    1074             return(search);
     1107        if ((strncmp(search->data, iface, iface_len) == 0)
     1108         && (search->data[iface_len] == '=')) {
     1109            return search;
    10751110        }
    10761111        search = search->link;
    10771112    }
    1078     return(NULL);
    1079 }
    1080 
     1113    return NULL;
     1114}
     1115
     1116/* read the previous state from the state file */
     1117static llist_t *read_iface_state(void)
     1118{
     1119    llist_t *state_list = NULL;
     1120    FILE *state_fp = fopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "r");
     1121
     1122    if (state_fp) {
     1123        char *start, *end_ptr;
     1124        while ((start = xmalloc_fgets(state_fp)) != NULL) {
     1125            /* We should only need to check for a single character */
     1126            end_ptr = start + strcspn(start, " \t\n");
     1127            *end_ptr = '\0';
     1128            llist_add_to(&state_list, start);
     1129        }
     1130        fclose(state_fp);
     1131    }
     1132    return state_list;
     1133}
     1134
     1135
     1136int ifupdown_main(int argc, char **argv);
    10811137int ifupdown_main(int argc, char **argv)
    10821138{
    1083     int (*cmds) (struct interface_defn_t *) = NULL;
     1139    int (*cmds)(struct interface_defn_t *) = NULL;
    10841140    struct interfaces_file_t *defn;
    1085     llist_t *state_list = NULL;
    10861141    llist_t *target_list = NULL;
    10871142    const char *interfaces = "/etc/network/interfaces";
    1088     const char *statefile = "/var/run/ifstate";
    1089 
    1090 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1091     int run_mappings = 1;
    1092 #endif
    1093     int do_all = 0;
    1094     int force = 0;
    1095     int any_failures = 0;
    1096     int i;
    1097 
    1098     if (bb_applet_name[2] == 'u') {
     1143    bool any_failures = 0;
     1144
     1145    cmds = iface_down;
     1146    if (applet_name[2] == 'u') {
    10991147        /* ifup command */
    11001148        cmds = iface_up;
     1149    }
     1150
     1151    getopt32(argv, OPTION_STR, &interfaces);
     1152    if (argc - optind > 0) {
     1153        if (DO_ALL) bb_show_usage();
    11011154    } else {
    1102         /* ifdown command */
    1103         cmds = iface_down;
    1104     }
    1105 
    1106 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1107     while ((i = getopt(argc, argv, "i:hvnamf")) != -1)
    1108 #else
    1109         while ((i = getopt(argc, argv, "i:hvnaf")) != -1)
    1110 #endif
    1111         {
    1112             switch (i) {
    1113                 case 'i':   /* interfaces */
    1114                     interfaces = optarg;
    1115                     break;
    1116                 case 'v':   /* verbose */
    1117                     verbose = 1;
    1118                     break;
    1119                 case 'a':   /* all */
    1120                     do_all = 1;
    1121                     break;
    1122                 case 'n':   /* no-act */
    1123                     no_act = 1;
    1124                     break;
    1125 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1126                 case 'm':   /* no-mappings */
    1127                     run_mappings = 0;
    1128                     break;
    1129 #endif
    1130                 case 'f':   /* force */
    1131                     force = 1;
    1132                     break;
    1133                 default:
    1134                     bb_show_usage();
    1135                     break;
    1136             }
    1137         }
    1138 
    1139     if (argc - optind > 0) {
    1140         if (do_all) {
    1141             bb_show_usage();
    1142         }
    1143     } else {
    1144         if (!do_all) {
    1145             bb_show_usage();
    1146         }
     1155        if (!DO_ALL) bb_show_usage();
    11471156    }
    11481157
     
    11521161
    11531162    if (!defn) {
    1154         exit(EXIT_FAILURE);
    1155     }
     1163        return EXIT_FAILURE;
     1164    }
     1165
     1166    startup_PATH = getenv("PATH");
     1167    if (!startup_PATH) startup_PATH = "";
    11561168
    11571169    /* Create a list of interfaces to work on */
    1158     if (do_all) {
    1159         if (cmds == iface_up) {
    1160             target_list = defn->autointerfaces;
    1161         } else {
    1162             /* iface_down */
    1163             const llist_t *list = state_list;
    1164             while (list) {
    1165                 llist_add_to_end(&target_list, bb_xstrdup(list->data));
    1166                 list = list->link;
    1167             }
    1168             target_list = defn->autointerfaces;
    1169         }
     1170    if (DO_ALL) {
     1171        target_list = defn->autointerfaces;
    11701172    } else {
    11711173        llist_add_to_end(&target_list, argv[optind]);
    11721174    }
    1173 
    11741175
    11751176    /* Update the interfaces */
     
    11801181        char *liface;
    11811182        char *pch;
    1182         int okay = 0;
    1183         int cmds_ret;
    1184 
    1185         iface = bb_xstrdup(target_list->data);
     1183        bool okay = 0;
     1184        unsigned cmds_ret;
     1185
     1186        iface = xstrdup(target_list->data);
    11861187        target_list = target_list->link;
    11871188
     
    11891190        if (pch) {
    11901191            *pch = '\0';
    1191             liface = bb_xstrdup(pch + 1);
     1192            liface = xstrdup(pch + 1);
    11921193        } else {
    1193             liface = bb_xstrdup(iface);
    1194         }
    1195 
    1196         if (!force) {
     1194            liface = xstrdup(iface);
     1195        }
     1196
     1197        if (!FORCE) {
     1198            llist_t *state_list = read_iface_state();
    11971199            const llist_t *iface_state = find_iface_state(state_list, iface);
    11981200
     
    12051207            } else {
    12061208                /* ifdown */
    1207                 if (iface_state) {
     1209                if (!iface_state) {
    12081210                    bb_error_msg("interface %s not configured", iface);
    12091211                    continue;
    12101212                }
    12111213            }
    1212         }
    1213 
    1214 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1215         if ((cmds == iface_up) && run_mappings) {
     1214            llist_free(state_list, free);
     1215        }
     1216
     1217#if ENABLE_FEATURE_IFUPDOWN_MAPPING
     1218        if ((cmds == iface_up) && !NO_MAPPINGS) {
    12161219            struct mapping_defn_t *currmap;
    12171220
    12181221            for (currmap = defn->mappings; currmap; currmap = currmap->next) {
    1219 
     1222                int i;
    12201223                for (i = 0; i < currmap->n_matches; i++) {
    12211224                    if (fnmatch(currmap->match[i], liface, 0) != 0)
    12221225                        continue;
    1223                     if (verbose) {
     1226                    if (VERBOSE) {
    12241227                        printf("Running mapping script %s on %s\n", currmap->script, liface);
    12251228                    }
     
    12301233        }
    12311234#endif
    1232 
    12331235
    12341236        iface_list = defn->ifaces;
     
    12461248                cmds_ret = cmds(currif);
    12471249                if (cmds_ret == -1) {
    1248                     bb_error_msg("Don't seem to have all the variables for %s/%s.",
     1250                    bb_error_msg("don't seem to have all the variables for %s/%s",
    12491251                            liface, currif->address_family->name);
    1250                     any_failures += 1;
     1252                    any_failures = 1;
    12511253                } else if (cmds_ret == 0) {
    1252                     any_failures += 1;
     1254                    any_failures = 1;
    12531255                }
    12541256
     
    12571259            iface_list = iface_list->link;
    12581260        }
    1259         if (verbose) {
    1260             printf("\n");
    1261         }
    1262 
    1263         if (!okay && !force) {
    1264             bb_error_msg("Ignoring unknown interface %s", liface);
    1265             any_failures += 1;
    1266         } else {
     1261        if (VERBOSE) {
     1262            puts("");
     1263        }
     1264
     1265        if (!okay && !FORCE) {
     1266            bb_error_msg("ignoring unknown interface %s", liface);
     1267            any_failures = 1;
     1268        } else if (!NO_ACT) {
     1269            /* update the state file */
     1270            FILE *state_fp;
     1271            llist_t *state;
     1272            llist_t *state_list = read_iface_state();
    12671273            llist_t *iface_state = find_iface_state(state_list, iface);
    12681274
    12691275            if (cmds == iface_up) {
    1270                 char *newiface = bb_xasprintf("%s=%s", iface, liface);
     1276                char * const newiface = xasprintf("%s=%s", iface, liface);
    12711277                if (iface_state == NULL) {
    12721278                    llist_add_to_end(&state_list, newiface);
     
    12761282                }
    12771283            } else {
    1278                 /* Remove an interface from the linked list */
     1284                /* Remove an interface from state_list */
     1285                llist_unlink(&state_list, iface_state);
    12791286                free(llist_pop(&iface_state));
    12801287            }
    1281         }
    1282     }
    1283 
    1284     /* Actually write the new state */
    1285     if (!no_act) {
    1286         FILE *state_fp = NULL;
    1287 
    1288         state_fp = bb_xfopen(statefile, "w");
    1289         while (state_list) {
    1290             if (state_list->data) {
    1291                 fputs(state_list->data, state_fp);
    1292                 fputc('\n', state_fp);
    1293             }
    1294             state_list = state_list->link;
    1295         }
    1296         fclose(state_fp);
    1297     }
    1298 
    1299     if (any_failures)
    1300         return 1;
    1301     return 0;
    1302 }
     1288
     1289            /* Actually write the new state */
     1290            state_fp = xfopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "w");
     1291            state = state_list;
     1292            while (state) {
     1293                if (state->data) {
     1294                    fprintf(state_fp, "%s\n", state->data);
     1295                }
     1296                state = state->link;
     1297            }
     1298            fclose(state_fp);
     1299            llist_free(state_list, free);
     1300        }
     1301    }
     1302
     1303    return any_failures;
     1304}
  • branches/stable/mindi-busybox/networking/inetd.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*      $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $    */
    23/*      $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $      */
     
    2324 *    without specific prior written permission.
    2425 *
    25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
    2627 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    2728 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     
    3637 */
    3738
    38 /*
    39  * Inetd - Internet super-server
     39/* Inetd - Internet super-server
    4040 *
    4141 * This program invokes all internet services as needed.
     
    5050 * on file descriptor 0.  Datagram servers may either connect
    5151 * to their peer, freeing up the original socket for inetd
    52  * to receive further messages on, or ``take over the socket'',
     52 * to receive further messages on, or "take over the socket",
    5353 * processing all arriving datagrams and, eventually, timing
    54  * out.  The first type of server is said to be ``multi-threaded'';
    55  * the second type of server ``single-threaded''.
     54 * out.  The first type of server is said to be "multi-threaded";
     55 * the second type of server "single-threaded".
    5656 *
    5757 * Inetd uses a configuration file which is read at startup
    5858 * and, possibly, at some later time in response to a hangup signal.
    59  * The configuration file is ``free format'' with fields given in the
     59 * The configuration file is "free format" with fields given in the
    6060 * order shown below.  Continuation lines for an entry must begin with
    6161 * a space or tab.  All fields must be present in each entry.
     
    105105 */
    106106
    107 /*
    108  * Here's the scoop concerning the user[.:]group feature:
     107/* inetd rules for passing file descriptors to children
     108 * (http://www.freebsd.org/cgi/man.cgi?query=inetd):
     109 *
     110 * The wait/nowait entry specifies whether the server that is invoked by
     111 * inetd will take over the socket associated with the service access point,
     112 * and thus whether inetd should wait for the server to exit before listen-
     113 * ing for new service requests.  Datagram servers must use "wait", as
     114 * they are always invoked with the original datagram socket bound to the
     115 * specified service address.  These servers must read at least one datagram
     116 * from the socket before exiting.  If a datagram server connects to its
     117 * peer, freeing the socket so inetd can receive further messages on the
     118 * socket, it is said to be a "multi-threaded" server; it should read one
     119 * datagram from the socket and create a new socket connected to the peer.
     120 * It should fork, and the parent should then exit to allow inetd to check
     121 * for new service requests to spawn new servers.  Datagram servers which
     122 * process all incoming datagrams on a socket and eventually time out are
     123 * said to be "single-threaded".  The comsat(8), (biff(1)) and talkd(8)
     124 * utilities are both examples of the latter type of datagram server.  The
     125 * tftpd(8) utility is an example of a multi-threaded datagram server.
     126 *
     127 * Servers using stream sockets generally are multi-threaded and use the
     128 * "nowait" entry. Connection requests for these services are accepted by
     129 * inetd, and the server is given only the newly-accepted socket connected
     130 * to a client of the service.  Most stream-based services operate in this
     131 * manner.  Stream-based servers that use "wait" are started with the lis-
     132 * tening service socket, and must accept at least one connection request
     133 * before exiting.  Such a server would normally accept and process incoming
     134 * connection requests until a timeout.
     135 */
     136
     137/* Here's the scoop concerning the user[.:]group feature:
    109138 *
    110139 * 1) set-group-option off.
     
    125154 *                      initgroups(name, specified group)
    126155 *                      setuid()
    127  *
    128156 */
    129157
    130 #include <sys/param.h>
    131 #include <sys/stat.h>
    132 #include <sys/ioctl.h>
    133 #include <sys/socket.h>
     158#include "libbb.h"
     159#include <syslog.h>
    134160#include <sys/un.h>
    135 #include <sys/file.h>
    136 #include <sys/wait.h>
    137 #include <sys/resource.h>
    138 
    139 
    140 #include <netinet/in.h>
    141 #include <arpa/inet.h>
    142 
    143 #include <errno.h>
    144 #include <signal.h>
    145 #include <netdb.h>
    146 #include <syslog.h>
    147 #include <stdio.h>
    148 #include <stdlib.h>
    149 #include <unistd.h>
    150 #include <string.h>
    151 #include <ctype.h>
    152 #include <time.h>
    153 
    154 #include "busybox.h"
    155 
    156 //#define CONFIG_FEATURE_INETD_RPC
    157 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    158 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    159 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    160 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    161 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    162 //#define CONFIG_FEATURE_IPV6
    163 
    164 #ifdef CONFIG_FEATURE_INETD_RPC
     161
     162//#define ENABLE_FEATURE_INETD_RPC 1
     163//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1
     164//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1
     165//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1
     166//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1
     167//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1
     168//#define ENABLE_FEATURE_IPV6 1
     169
     170#if ENABLE_FEATURE_INETD_RPC
    165171#include <rpc/rpc.h>
    166172#include <rpc/pmap_clnt.h>
    167173#endif
    168174
    169 #define _PATH_INETDCONF "/etc/inetd.conf"
     175extern char **environ;
     176
     177
    170178#define _PATH_INETDPID  "/var/run/inetd.pid"
    171 
    172 
    173 #define TOOMANY         0               /* don't start more than TOOMANY */
    174179
    175180#define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
     
    185190
    186191/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
    187 #define FD_MARGIN       (8)
     192#define FD_MARGIN       8
    188193static rlim_t rlim_ofile_cur = OPEN_MAX;
    189194static struct rlimit rlim_ofile;
     
    191196
    192197/* Check unsupporting builtin */
    193 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    194     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    195     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
    196     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
    197     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     198#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     199    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
     200    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
     201    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
     202    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    198203# define INETD_FEATURE_ENABLED
    199204#endif
    200205
    201 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    202     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    203     defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     206#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     207    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
     208    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    204209# define INETD_SETPROCTITLE
    205210#endif
    206211
    207 typedef struct servtab
    208 {
    209   char *se_hostaddr;                    /* host address to listen on */
    210   char *se_service;                     /* name of service */
    211   int se_socktype;                      /* type of socket to use */
    212   int se_family;                        /* address family */
    213   char *se_proto;                       /* protocol used */
    214 #ifdef CONFIG_FEATURE_INETD_RPC
    215   int se_rpcprog;                       /* rpc program number */
    216   int se_rpcversl;                      /* rpc program lowest version */
    217   int se_rpcversh;                      /* rpc program highest version */
     212typedef struct servtab {
     213    char *se_hostaddr;                    /* host address to listen on */
     214    char *se_service;                     /* name of service */
     215    int se_socktype;                      /* type of socket to use */
     216    int se_family;                        /* address family */
     217    char *se_proto;                       /* protocol used */
     218#if ENABLE_FEATURE_INETD_RPC
     219    int se_rpcprog;                       /* rpc program number */
     220    int se_rpcversl;                      /* rpc program lowest version */
     221    int se_rpcversh;                      /* rpc program highest version */
    218222#define isrpcservice(sep)       ((sep)->se_rpcversl != 0)
    219223#else
    220224#define isrpcservice(sep)       0
    221225#endif
    222   pid_t se_wait;                        /* single threaded server */
    223   short se_checked;                     /* looked at during merge */
    224   char *se_user;                        /* user name to run as */
    225   char *se_group;                       /* group name to run as */
     226    pid_t se_wait;                        /* single threaded server */
     227    short se_checked;                     /* looked at during merge */
     228    char *se_user;                        /* user name to run as */
     229    char *se_group;                       /* group name to run as */
    226230#ifdef INETD_FEATURE_ENABLED
    227   const struct builtin *se_bi;                 /* if built-in, description */
    228 #endif
    229   char *se_server;                      /* server program */
     231    const struct builtin *se_bi;          /* if built-in, description */
     232#endif
     233    char *se_server;                      /* server program */
    230234#define MAXARGV 20
    231   char *se_argv[MAXARGV + 1];           /* program arguments */
    232   int se_fd;                            /* open descriptor */
    233   union
    234   {
    235     struct sockaddr se_un_ctrladdr;
    236     struct sockaddr_in se_un_ctrladdr_in;
    237 #ifdef CONFIG_FEATURE_IPV6
    238     struct sockaddr_in6 se_un_ctrladdr_in6;
    239 #endif
    240     struct sockaddr_un se_un_ctrladdr_un;
    241   } se_un;                              /* bound address */
     235    char *se_argv[MAXARGV + 1];           /* program arguments */
     236    int se_fd;                            /* open descriptor */
     237    union {
     238        struct sockaddr se_un_ctrladdr;
     239        struct sockaddr_in se_un_ctrladdr_in;
     240#if ENABLE_FEATURE_IPV6
     241        struct sockaddr_in6 se_un_ctrladdr_in6;
     242#endif
     243        struct sockaddr_un se_un_ctrladdr_un;
     244    } se_un;                              /* bound address */
    242245#define se_ctrladdr     se_un.se_un_ctrladdr
    243246#define se_ctrladdr_in  se_un.se_un_ctrladdr_in
    244247#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
    245248#define se_ctrladdr_un  se_un.se_un_ctrladdr_un
    246   int se_ctrladdr_size;
    247   int se_max;                           /* max # of instances of this service */
    248   int se_count;                         /* number started since se_time */
    249   struct timeval se_time;               /* start of se_count */
    250   struct servtab *se_next;
     249    int se_ctrladdr_size;
     250    int se_max;                           /* max # of instances of this service */
     251    int se_count;                         /* number started since se_time */
     252    struct timeval se_time;               /* start of se_count */
     253    struct servtab *se_next;
    251254} servtab_t;
    252255
     
    254257
    255258#ifdef INETD_FEATURE_ENABLED
    256 struct builtin
    257 {
    258   const char *bi_service;               /* internally provided service name */
    259   int bi_socktype;                      /* type of socket supported */
    260   short bi_fork;                        /* 1 if should fork before call */
    261   short bi_wait;                        /* 1 if should wait for child */
    262   void (*bi_fn) (int, servtab_t *);
     259struct builtin {
     260    const char *bi_service;               /* internally provided service name */
     261    int bi_socktype;                      /* type of socket supported */
     262    short bi_fork;                        /* 1 if should fork before call */
     263    short bi_wait;                        /* 1 if should wait for child */
     264    void (*bi_fn) (int, servtab_t *);
    263265};
    264266
     267        /* Echo received data */
     268#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     269static void echo_stream(int, servtab_t *);
     270static void echo_dg(int, servtab_t *);
     271#endif
     272        /* Internet /dev/null */
     273#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     274static void discard_stream(int, servtab_t *);
     275static void discard_dg(int, servtab_t *);
     276#endif
     277        /* Return 32 bit time since 1900 */
     278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     279static void machtime_stream(int, servtab_t *);
     280static void machtime_dg(int, servtab_t *);
     281#endif
     282        /* Return human-readable time */
     283#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     284static void daytime_stream(int, servtab_t *);
     285static void daytime_dg(int, servtab_t *);
     286#endif
     287        /* Familiar character generator */
     288#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     289static void chargen_stream(int, servtab_t *);
     290static void chargen_dg(int, servtab_t *);
     291#endif
     292
     293static const struct builtin builtins[] = {
     294#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    265295    /* Echo received data */
    266 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    267 static void echo_stream (int, servtab_t *);
    268 static void echo_dg (int, servtab_t *);
    269 #endif
     296    {"echo", SOCK_STREAM, 1, 0, echo_stream,},
     297    {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
     298#endif
     299#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    270300    /* Internet /dev/null */
    271 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    272 static void discard_stream (int, servtab_t *);
    273 static void discard_dg (int, servtab_t *);
    274 #endif
     301    {"discard", SOCK_STREAM, 1, 0, discard_stream,},
     302    {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
     303#endif
     304#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    275305    /* Return 32 bit time since 1900 */
    276 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    277 static void machtime_stream (int, servtab_t *);
    278 static void machtime_dg (int, servtab_t *);
    279 #endif
     306    {"time", SOCK_STREAM, 0, 0, machtime_stream,},
     307    {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
     308#endif
     309#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    280310    /* Return human-readable time */
    281 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    282 static void daytime_stream (int, servtab_t *);
    283 static void daytime_dg (int, servtab_t *);
    284 #endif
     311    {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
     312    {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
     313#endif
     314#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    285315    /* Familiar character generator */
    286 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    287 static void chargen_stream (int, servtab_t *);
    288 static void chargen_dg (int, servtab_t *);
    289 #endif
    290 
    291 static const struct builtin builtins[] = {
    292 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    293   /* Echo received data */
    294   {"echo", SOCK_STREAM, 1, 0, echo_stream,},
    295   {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
    296 #endif
    297 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    298   /* Internet /dev/null */
    299   {"discard", SOCK_STREAM, 1, 0, discard_stream,},
    300   {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
    301 #endif
    302 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    303   /* Return 32 bit time since 1900 */
    304   {"time", SOCK_STREAM, 0, 0, machtime_stream,},
    305   {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
    306 #endif
    307 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    308   /* Return human-readable time */
    309   {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
    310   {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
    311 #endif
    312 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    313   /* Familiar character generator */
    314   {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
    315   {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
    316 #endif
    317   {NULL, 0, 0, 0, NULL}
     316    {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
     317    {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
     318#endif
     319    {NULL, 0, 0, 0, NULL}
    318320};
    319321#endif /* INETD_FEATURE_ENABLED */
     
    322324static int nsock, maxsock;
    323325static fd_set allsock;
    324 static int toomany = TOOMANY;
     326static int toomany;
    325327static int timingout;
    326328static struct servent *sp;
    327329static uid_t uid;
    328330
    329 static char *CONFIG = _PATH_INETDCONF;
     331static const char *config_filename = "/etc/inetd.conf";
    330332
    331333static FILE *fconfig;
    332 static char line[1024];
    333334static char *defhost;
    334335
    335 static char *newstr (char *cp)
    336 {
    337   if ((cp = strdup (cp ? cp : "")))
    338     return (cp);
    339   syslog (LOG_ERR, "strdup: %m");
    340   exit (1);
    341 }
    342 
    343 static int setconfig (void)
    344 {
    345   free (defhost);
    346   defhost = newstr ("*");
    347   if (fconfig != NULL) {
    348     fseek (fconfig, 0L, SEEK_SET);
    349     return (1);
    350   }
    351   fconfig = fopen (CONFIG, "r");
    352   return (fconfig != NULL);
    353 }
    354 
    355 static void endconfig (void)
    356 {
    357   if (fconfig) {
    358     (void) fclose (fconfig);
    359     fconfig = NULL;
    360   }
    361   free (defhost);
    362   defhost = 0;
    363 }
    364 
    365 #ifdef CONFIG_FEATURE_INETD_RPC
    366 static void register_rpc (servtab_t *sep)
    367 {
    368   int n;
    369   struct sockaddr_in ir_sin;
    370   struct protoent *pp;
    371   socklen_t size;
    372 
    373   if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) {
    374     syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto);
    375     return;
    376   }
    377   size = sizeof ir_sin;
    378   if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
    379     syslog (LOG_ERR, "%s/%s: getsockname: %m",
    380             sep->se_service, sep->se_proto);
    381     return;
    382   }
    383 
    384   for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
    385     (void) pmap_unset (sep->se_rpcprog, n);
    386     if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)))
    387       syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
    388               sep->se_service, sep->se_proto,
    389               sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port));
    390   }
    391 }
    392 
    393 static void unregister_rpc (servtab_t *sep)
    394 {
    395   int n;
    396 
    397   for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
    398     if (!pmap_unset (sep->se_rpcprog, n))
    399       syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n);
    400   }
    401 }
    402 #endif /* CONFIG_FEATURE_INETD_RPC */
    403 
    404 static void freeconfig (servtab_t *cp)
    405 {
    406   int i;
    407 
    408   free (cp->se_hostaddr);
    409   free (cp->se_service);
    410   free (cp->se_proto);
    411   free (cp->se_user);
    412   free (cp->se_group);
    413   free (cp->se_server);
    414   for (i = 0; i < MAXARGV; i++)
    415     free (cp->se_argv[i]);
    416 }
    417 
    418 static int bump_nofile (void)
     336/* xstrdup(NULL) returns NULL, but this one
     337 * will return newly-allocated "" if called with NULL arg
     338 * TODO: audit whether this makes any real difference
     339 */
     340static char *xxstrdup(char *cp)
     341{
     342    return xstrdup(cp ? cp : "");
     343}
     344
     345static int setconfig(void)
     346{
     347    free(defhost);
     348    defhost = xstrdup("*");
     349    if (fconfig != NULL) {
     350        fseek(fconfig, 0L, SEEK_SET);
     351        return 1;
     352    }
     353    fconfig = fopen(config_filename, "r");
     354    return (fconfig != NULL);
     355}
     356
     357static void endconfig(void)
     358{
     359    if (fconfig) {
     360        (void) fclose(fconfig);
     361        fconfig = NULL;
     362    }
     363    free(defhost);
     364    defhost = 0;
     365}
     366
     367#if ENABLE_FEATURE_INETD_RPC
     368static void register_rpc(servtab_t *sep)
     369{
     370    int n;
     371    struct sockaddr_in ir_sin;
     372    struct protoent *pp;
     373    socklen_t size;
     374
     375    if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) {
     376        bb_perror_msg("%s: getproto", sep->se_proto);
     377        return;
     378    }
     379    size = sizeof ir_sin;
     380    if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
     381        bb_perror_msg("%s/%s: getsockname",
     382                sep->se_service, sep->se_proto);
     383        return;
     384    }
     385
     386    for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
     387        (void) pmap_unset(sep->se_rpcprog, n);
     388        if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port)))
     389            bb_perror_msg("%s %s: pmap_set: %u %u %u %u",
     390                    sep->se_service, sep->se_proto,
     391                    sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port));
     392    }
     393}
     394
     395static void unregister_rpc(servtab_t *sep)
     396{
     397    int n;
     398
     399    for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
     400        if (!pmap_unset(sep->se_rpcprog, n))
     401            bb_error_msg("pmap_unset(%u, %u)", sep->se_rpcprog, n);
     402    }
     403}
     404#endif /* FEATURE_INETD_RPC */
     405
     406static void freeconfig(servtab_t *cp)
     407{
     408    int i;
     409
     410    free(cp->se_hostaddr);
     411    free(cp->se_service);
     412    free(cp->se_proto);
     413    free(cp->se_user);
     414    free(cp->se_group);
     415    free(cp->se_server);
     416    for (i = 0; i < MAXARGV; i++)
     417        free(cp->se_argv[i]);
     418}
     419
     420static int bump_nofile(void)
    419421{
    420422#define FD_CHUNK        32
    421423
    422   struct rlimit rl;
    423 
    424   if (getrlimit (RLIMIT_NOFILE, &rl) < 0) {
    425     syslog (LOG_ERR, "getrlimit: %m");
    426     return -1;
    427   }
    428   rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK);
    429   rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
    430   if (rl.rlim_cur <= rlim_ofile_cur) {
    431     syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d",
    432             (int) rl.rlim_cur);
    433     return -1;
    434   }
    435 
    436   if (setrlimit (RLIMIT_NOFILE, &rl) < 0) {
    437     syslog (LOG_ERR, "setrlimit: %m");
    438     return -1;
    439   }
    440 
    441   rlim_ofile_cur = rl.rlim_cur;
    442   return 0;
    443 }
    444 
    445 static void setup (servtab_t *sep)
    446 {
    447   int on = 1;
    448   int r;
    449 
    450   if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) {
    451     syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto);
    452     return;
    453   }
    454 #define turnon(fd, opt) \
    455 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
    456   if (turnon (sep->se_fd, SO_REUSEADDR) < 0)
    457     syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
    458 #undef turnon
    459 
    460 #ifdef CONFIG_FEATURE_INETD_RPC
    461   if (isrpcservice (sep)) {
    462     struct passwd *pwd;
     424    struct rlimit rl;
     425
     426    if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
     427        bb_perror_msg("getrlimit");
     428        return -1;
     429    }
     430    rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
     431    rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
     432    if (rl.rlim_cur <= rlim_ofile_cur) {
     433        bb_error_msg("bump_nofile: cannot extend file limit, max = %d",
     434                        (int) rl.rlim_cur);
     435        return -1;
     436    }
     437
     438    if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
     439        bb_perror_msg("setrlimit");
     440        return -1;
     441    }
     442
     443    rlim_ofile_cur = rl.rlim_cur;
     444    return 0;
     445}
     446
     447static void setup(servtab_t *sep)
     448{
     449    int r;
     450
     451    sep->se_fd = socket(sep->se_family, sep->se_socktype, 0);
     452    if (sep->se_fd < 0) {
     453        bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto);
     454        return;
     455    }
     456    setsockopt_reuseaddr(sep->se_fd);
     457
     458#if ENABLE_FEATURE_INETD_RPC
     459    if (isrpcservice(sep)) {
     460        struct passwd *pwd;
     461
     462        /*
     463         * for RPC services, attempt to use a reserved port
     464         * if they are going to be running as root.
     465         *
     466         * Also, zero out the port for all RPC services; let bind()
     467         * find one.
     468         */
     469        sep->se_ctrladdr_in.sin_port = 0;
     470        if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
     471                pwd->pw_uid == 0 && uid == 0)
     472            r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
     473        else {
     474            r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
     475            if (r == 0) {
     476                socklen_t len = sep->se_ctrladdr_size;
     477                int saveerrno = errno;
     478
     479                /* update se_ctrladdr_in.sin_port */
     480                r = getsockname(sep->se_fd, &sep->se_ctrladdr, &len);
     481                if (r <= 0)
     482                    errno = saveerrno;
     483            }
     484        }
     485    } else
     486#endif
     487        r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
     488    if (r < 0) {
     489        bb_perror_msg("%s/%s (%d): bind",
     490                sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
     491        close(sep->se_fd);
     492        sep->se_fd = -1;
     493        if (!timingout) {
     494            timingout = 1;
     495            alarm(RETRYTIME);
     496        }
     497        return;
     498    }
     499    if (sep->se_socktype == SOCK_STREAM)
     500        listen(sep->se_fd, global_queuelen);
     501
     502    FD_SET(sep->se_fd, &allsock);
     503    nsock++;
     504    if (sep->se_fd > maxsock) {
     505        maxsock = sep->se_fd;
     506        if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
     507            bump_nofile();
     508    }
     509}
     510
     511static char *nextline(void)
     512{
     513#define line bb_common_bufsiz1
     514
     515    char *cp;
     516    FILE *fd = fconfig;
     517
     518    if (fgets(line, sizeof(line), fd) == NULL)
     519        return NULL;
     520    cp = strchr(line, '\n');
     521    if (cp)
     522        *cp = '\0';
     523    return line;
     524}
     525
     526static char *skip(char **cpp) /* int report; */
     527{
     528    char *cp = *cpp;
     529    char *start;
     530
     531/* erp: */
     532    if (*cpp == NULL) {
     533        /* if (report) */
     534        /* bb_error_msg("syntax error in inetd config file"); */
     535        return NULL;
     536    }
     537
     538 again:
     539    while (*cp == ' ' || *cp == '\t')
     540        cp++;
     541    if (*cp == '\0') {
     542        int c;
     543
     544        c = getc(fconfig);
     545        ungetc(c, fconfig);
     546        if (c == ' ' || c == '\t') {
     547            cp = nextline();
     548            if (cp)
     549                goto again;
     550        }
     551        *cpp = NULL;
     552        /* goto erp; */
     553        return NULL;
     554    }
     555    start = cp;
     556    while (*cp && *cp != ' ' && *cp != '\t')
     557        cp++;
     558    if (*cp != '\0')
     559        *cp++ = '\0';
     560    /* if ((*cpp = cp) == NULL) */
     561    /* goto erp; */
     562
     563    *cpp = cp;
     564    return start;
     565}
     566
     567static servtab_t *new_servtab(void)
     568{
     569    return xmalloc(sizeof(servtab_t));
     570}
     571
     572static servtab_t *dupconfig(servtab_t *sep)
     573{
     574    servtab_t *newtab;
     575    int argc;
     576
     577    newtab = new_servtab();
     578    memset(newtab, 0, sizeof(servtab_t));
     579    newtab->se_service = xstrdup(sep->se_service);
     580    newtab->se_socktype = sep->se_socktype;
     581    newtab->se_family = sep->se_family;
     582    newtab->se_proto = xstrdup(sep->se_proto);
     583#if ENABLE_FEATURE_INETD_RPC
     584    newtab->se_rpcprog = sep->se_rpcprog;
     585    newtab->se_rpcversl = sep->se_rpcversl;
     586    newtab->se_rpcversh = sep->se_rpcversh;
     587#endif
     588    newtab->se_wait = sep->se_wait;
     589    newtab->se_user = xstrdup(sep->se_user);
     590    newtab->se_group = xstrdup(sep->se_group);
     591#ifdef INETD_FEATURE_ENABLED
     592    newtab->se_bi = sep->se_bi;
     593#endif
     594    newtab->se_server = xstrdup(sep->se_server);
     595
     596    for (argc = 0; argc <= MAXARGV; argc++)
     597        newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]);
     598    newtab->se_max = sep->se_max;
     599
     600    return newtab;
     601}
     602
     603static servtab_t *getconfigent(void)
     604{
     605    servtab_t *sep;
     606    int argc;
     607    char *cp, *arg;
     608    char *hostdelim;
     609    servtab_t *nsep;
     610    servtab_t *psep;
     611
     612    sep = new_servtab();
     613
     614    /* memset(sep, 0, sizeof *sep); */
     615 more:
     616    /* freeconfig(sep); */
     617
     618    while ((cp = nextline()) && *cp == '#') /* skip comment line */;
     619    if (cp == NULL) {
     620        /* free(sep); */
     621        return NULL;
     622    }
     623
     624    memset((char *) sep, 0, sizeof *sep);
     625    arg = skip(&cp);
     626    if (arg == NULL) {
     627        /* A blank line. */
     628        goto more;
     629    }
     630
     631    /* Check for a host name. */
     632    hostdelim = strrchr(arg, ':');
     633    if (hostdelim) {
     634        *hostdelim = '\0';
     635        sep->se_hostaddr = xstrdup(arg);
     636        arg = hostdelim + 1;
     637        /*
     638         * If the line is of the form `host:', then just change the
     639         * default host for the following lines.
     640         */
     641        if (*arg == '\0') {
     642            arg = skip(&cp);
     643            if (cp == NULL) {
     644                free(defhost);
     645                defhost = sep->se_hostaddr;
     646                goto more;
     647            }
     648        }
     649    } else
     650        sep->se_hostaddr = xxstrdup(defhost);
     651
     652    sep->se_service = xxstrdup(arg);
     653    arg = skip(&cp);
     654
     655    if (strcmp(arg, "stream") == 0)
     656        sep->se_socktype = SOCK_STREAM;
     657    else if (strcmp(arg, "dgram") == 0)
     658        sep->se_socktype = SOCK_DGRAM;
     659    else if (strcmp(arg, "rdm") == 0)
     660        sep->se_socktype = SOCK_RDM;
     661    else if (strcmp(arg, "seqpacket") == 0)
     662        sep->se_socktype = SOCK_SEQPACKET;
     663    else if (strcmp(arg, "raw") == 0)
     664        sep->se_socktype = SOCK_RAW;
     665    else
     666        sep->se_socktype = -1;
     667
     668    sep->se_proto = xxstrdup(skip(&cp));
     669
     670    if (strcmp(sep->se_proto, "unix") == 0) {
     671        sep->se_family = AF_UNIX;
     672    } else {
     673        sep->se_family = AF_INET;
     674        if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
     675#if ENABLE_FEATURE_IPV6
     676            sep->se_family = AF_INET6;
     677#else
     678            bb_error_msg("%s: IPV6 not supported", sep->se_proto);
     679#endif
     680        if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
     681#if ENABLE_FEATURE_INETD_RPC
     682            char *p, *ccp;
     683            long l;
     684
     685            p = strchr(sep->se_service, '/');
     686            if (p == 0) {
     687                bb_error_msg("%s: no rpc version", sep->se_service);
     688                goto more;
     689            }
     690            *p++ = '\0';
     691            l = strtol(p, &ccp, 0);
     692            if (ccp == p || l < 0 || l > INT_MAX) {
     693 badafterall:
     694                bb_error_msg("%s/%s: bad rpc version", sep->se_service, p);
     695                goto more;
     696            }
     697            sep->se_rpcversl = sep->se_rpcversh = l;
     698            if (*ccp == '-') {
     699                p = ccp + 1;
     700                l = strtol(p, &ccp, 0);
     701                if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
     702                    goto badafterall;
     703                sep->se_rpcversh = l;
     704            } else if (*ccp != '\0')
     705                goto badafterall;
     706#else
     707            bb_error_msg("%s: rpc services not supported", sep->se_service);
     708#endif
     709        }
     710    }
     711    arg = skip(&cp);
     712    if (arg == NULL)
     713        goto more;
     714
     715    {
     716        char *s = strchr(arg, '.');
     717        if (s) {
     718            *s++ = '\0';
     719            sep->se_max = xatoi(s);
     720        } else
     721            sep->se_max = toomany;
     722    }
     723    sep->se_wait = strcmp(arg, "wait") == 0;
     724    /* if ((arg = skip(&cp, 1)) == NULL) */
     725    /* goto more; */
     726    sep->se_user = xxstrdup(skip(&cp));
     727    arg = strchr(sep->se_user, '.');
     728    if (arg == NULL)
     729        arg = strchr(sep->se_user, ':');
     730    if (arg) {
     731        *arg++ = '\0';
     732        sep->se_group = xstrdup(arg);
     733    }
     734    /* if ((arg = skip(&cp, 1)) == NULL) */
     735    /* goto more; */
     736
     737    sep->se_server = xxstrdup(skip(&cp));
     738    if (strcmp(sep->se_server, "internal") == 0) {
     739#ifdef INETD_FEATURE_ENABLED
     740        const struct builtin *bi;
     741
     742        for (bi = builtins; bi->bi_service; bi++)
     743            if (bi->bi_socktype == sep->se_socktype &&
     744                    strcmp(bi->bi_service, sep->se_service) == 0)
     745                break;
     746        if (bi->bi_service == 0) {
     747            bb_error_msg("internal service %s unknown", sep->se_service);
     748            goto more;
     749        }
     750        sep->se_bi = bi;
     751        sep->se_wait = bi->bi_wait;
     752#else
     753        bb_perror_msg("internal service %s unknown", sep->se_service);
     754        goto more;
     755#endif
     756    }
     757#ifdef INETD_FEATURE_ENABLED
     758        else
     759        sep->se_bi = NULL;
     760#endif
     761    argc = 0;
     762    for (arg = skip(&cp); cp; arg = skip(&cp)) {
     763        if (argc < MAXARGV)
     764            sep->se_argv[argc++] = xxstrdup(arg);
     765    }
     766    while (argc <= MAXARGV)
     767        sep->se_argv[argc++] = NULL;
    463768
    464769    /*
    465      * for RPC services, attempt to use a reserved port
    466      * if they are going to be running as root.
    467      *
    468      * Also, zero out the port for all RPC services; let bind()
    469      * find one.
     770     * Now that we've processed the entire line, check if the hostname
     771     * specifier was a comma separated list of hostnames. If so
     772     * we'll make new entries for each address.
    470773     */
    471     sep->se_ctrladdr_in.sin_port = 0;
    472     if (sep->se_user && (pwd = getpwnam (sep->se_user)) &&
    473         pwd->pw_uid == 0 && uid == 0)
    474       r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in);
    475     else {
    476       r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
    477       if (r == 0) {
    478         socklen_t len = sep->se_ctrladdr_size;
    479         int saveerrno = errno;
    480 
    481         /* update se_ctrladdr_in.sin_port */
    482         r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len);
    483         if (r <= 0)
    484           errno = saveerrno;
    485       }
    486     }
    487   } else
    488 #endif
    489     r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
    490   if (r < 0) {
    491     syslog (LOG_ERR, "%s/%s (%d): bind: %m",
    492             sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
    493     close (sep->se_fd);
     774    while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) {
     775        nsep = dupconfig(sep);
     776
     777        /*
     778         * NULL terminate the hostname field of the existing entry,
     779         * and make a dup for the new entry.
     780         */
     781        *hostdelim++ = '\0';
     782        nsep->se_hostaddr = xstrdup(hostdelim);
     783
     784        nsep->se_next = sep->se_next;
     785        sep->se_next = nsep;
     786    }
     787
     788    nsep = sep;
     789    while (nsep != NULL) {
     790        nsep->se_checked = 1;
     791        if (nsep->se_family == AF_INET) {
     792            if (LONE_CHAR(nsep->se_hostaddr, '*'))
     793                nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
     794            else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
     795                struct hostent *hp;
     796
     797                hp = gethostbyname(nsep->se_hostaddr);
     798                if (hp == 0) {
     799                    bb_error_msg("%s: unknown host", nsep->se_hostaddr);
     800                    nsep->se_checked = 0;
     801                    goto skip;
     802                } else if (hp->h_addrtype != AF_INET) {
     803                    bb_error_msg("%s: address isn't an Internet "
     804                                  "address", nsep->se_hostaddr);
     805                    nsep->se_checked = 0;
     806                    goto skip;
     807                } else {
     808                    int i = 1;
     809
     810                    memmove(&nsep->se_ctrladdr_in.sin_addr,
     811                                   hp->h_addr_list[0], sizeof(struct in_addr));
     812                    while (hp->h_addr_list[i] != NULL) {
     813                        psep = dupconfig(nsep);
     814                        psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
     815                        psep->se_checked = 1;
     816                        memmove(&psep->se_ctrladdr_in.sin_addr,
     817                                     hp->h_addr_list[i], sizeof(struct in_addr));
     818                        psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
     819                        i++;
     820                        /* Prepend to list, don't want to look up */
     821                        /* its hostname again. */
     822                        psep->se_next = sep;
     823                        sep = psep;
     824                    }
     825                }
     826            }
     827        }
     828/* XXX BUG?: is this skip: label supposed to remain? */
     829 skip:
     830        nsep = nsep->se_next;
     831    }
     832
     833    /*
     834     * Finally, free any entries which failed the gethostbyname
     835     * check.
     836     */
     837    psep = NULL;
     838    nsep = sep;
     839    while (nsep != NULL) {
     840        servtab_t *tsep;
     841
     842        if (nsep->se_checked == 0) {
     843            tsep = nsep;
     844            if (psep == NULL) {
     845                sep = nsep->se_next;
     846                nsep = sep;
     847            } else {
     848                nsep = nsep->se_next;
     849                psep->se_next = nsep;
     850            }
     851            freeconfig(tsep);
     852        } else {
     853            nsep->se_checked = 0;
     854            psep = nsep;
     855            nsep = nsep->se_next;
     856        }
     857    }
     858
     859    return sep;
     860}
     861
     862#define Block_Using_Signals(m) do { \
     863    sigemptyset(&m); \
     864    sigaddset(&m, SIGCHLD); \
     865    sigaddset(&m, SIGHUP); \
     866    sigaddset(&m, SIGALRM); \
     867    sigprocmask(SIG_BLOCK, &m, NULL); \
     868} while (0)
     869
     870static servtab_t *enter(servtab_t *cp)
     871{
     872    servtab_t *sep;
     873    sigset_t omask;
     874
     875    sep = new_servtab();
     876    *sep = *cp;
    494877    sep->se_fd = -1;
    495     if (!timingout) {
    496       timingout = 1;
    497       alarm (RETRYTIME);
    498     }
    499     return;
    500   }
    501   if (sep->se_socktype == SOCK_STREAM)
    502     listen (sep->se_fd, global_queuelen);
    503 
    504   FD_SET (sep->se_fd, &allsock);
    505   nsock++;
    506   if (sep->se_fd > maxsock) {
    507     maxsock = sep->se_fd;
    508     if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
    509       bump_nofile ();
    510   }
    511 }
    512 
    513 static char *nextline (void)
    514 {
    515   char *cp;
    516   FILE *fd = fconfig;
    517 
    518   if (fgets (line, sizeof (line), fd) == NULL)
    519     return (NULL);
    520   cp = strchr (line, '\n');
    521   if (cp)
    522     *cp = '\0';
    523   return (line);
    524 }
    525 
    526 static char *skip (char **cpp) /* int report; */
    527 {
    528   char *cp = *cpp;
    529   char *start;
    530 
    531 /* erp: */
    532   if (*cpp == NULL) {
    533     /* if (report) */
    534     /* syslog(LOG_ERR, "syntax error in inetd config file"); */
    535     return (NULL);
    536   }
    537 
    538 again:
    539   while (*cp == ' ' || *cp == '\t')
    540     cp++;
    541   if (*cp == '\0') {
    542     int c;
    543 
    544     c = getc (fconfig);
    545     (void) ungetc (c, fconfig);
    546     if (c == ' ' || c == '\t')
    547       if ((cp = nextline ()))
    548         goto again;
    549     *cpp = NULL;
    550     /* goto erp; */
    551     return (NULL);
    552   }
    553   start = cp;
    554   while (*cp && *cp != ' ' && *cp != '\t')
    555     cp++;
    556   if (*cp != '\0')
    557     *cp++ = '\0';
    558   /* if ((*cpp = cp) == NULL) */
    559   /* goto erp; */
    560 
    561   *cpp = cp;
    562   return (start);
    563 }
    564 
    565 static servtab_t *new_servtab(void)
    566 {
    567   servtab_t *sep;
    568 
    569   sep = (servtab_t *) malloc (sizeof (servtab_t));
    570   if (sep == NULL) {
    571     syslog (LOG_ERR, bb_msg_memory_exhausted);
    572     exit (1);
    573   }
    574   return sep;
    575 }
    576 
    577 static servtab_t *dupconfig (servtab_t *sep)
    578 {
    579   servtab_t *newtab;
    580   int argc;
    581 
    582   newtab = new_servtab();
    583   memset (newtab, 0, sizeof (servtab_t));
    584   newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL;
    585   newtab->se_socktype = sep->se_socktype;
    586   newtab->se_family = sep->se_family;
    587   newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL;
    588 #ifdef CONFIG_FEATURE_INETD_RPC
    589   newtab->se_rpcprog = sep->se_rpcprog;
    590   newtab->se_rpcversl = sep->se_rpcversl;
    591   newtab->se_rpcversh = sep->se_rpcversh;
    592 #endif
    593   newtab->se_wait = sep->se_wait;
    594   newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL;
    595   newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL;
     878#if ENABLE_FEATURE_INETD_RPC
     879    sep->se_rpcprog = -1;
     880#endif
     881    Block_Using_Signals(omask);
     882    sep->se_next = servtab;
     883    servtab = sep;
     884    sigprocmask(SIG_UNBLOCK, &omask, NULL);
     885    return sep;
     886}
     887
     888static int matchconf(servtab_t *old, servtab_t *new)
     889{
     890    if (strcmp(old->se_service, new->se_service) != 0)
     891        return 0;
     892
     893    if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
     894        return 0;
     895
     896    if (strcmp(old->se_proto, new->se_proto) != 0)
     897        return 0;
     898
     899    /*
     900     * If the new servtab is bound to a specific address, check that the
     901     * old servtab is bound to the same entry. If the new service is not
     902     * bound to a specific address then the check of se_hostaddr above
     903     * is sufficient.
     904     */
     905
     906    if (old->se_family == AF_INET && new->se_family == AF_INET &&
     907            memcmp(&old->se_ctrladdr_in.sin_addr,
     908                    &new->se_ctrladdr_in.sin_addr,
     909                    sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
     910        return 0;
     911
     912#if ENABLE_FEATURE_IPV6
     913    if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
     914            memcmp(&old->se_ctrladdr_in6.sin6_addr,
     915                    &new->se_ctrladdr_in6.sin6_addr,
     916                    sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
     917        return 0;
     918#endif
     919    return 1;
     920}
     921
     922static void config(int sig ATTRIBUTE_UNUSED)
     923{
     924    servtab_t *sep, *cp, **sepp;
     925    sigset_t omask;
     926    size_t n;
     927    char protoname[10];
     928
     929    if (!setconfig()) {
     930        bb_perror_msg("%s", config_filename);
     931        return;
     932    }
     933    for (sep = servtab; sep; sep = sep->se_next)
     934        sep->se_checked = 0;
     935    cp = getconfigent();
     936    while (cp != NULL) {
     937        for (sep = servtab; sep; sep = sep->se_next)
     938            if (matchconf(sep, cp))
     939                break;
     940
     941        if (sep != 0) {
     942            int i;
     943
     944#define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
     945
     946            Block_Using_Signals(omask);
     947            /*
     948             * sep->se_wait may be holding the pid of a daemon
     949             * that we're waiting for.  If so, don't overwrite
     950             * it unless the config file explicitly says don't
     951             * wait.
     952             */
     953            if (
    596954#ifdef INETD_FEATURE_ENABLED
    597   newtab->se_bi = sep->se_bi;
    598 #endif
    599   newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0;
    600 
    601   for (argc = 0; argc <= MAXARGV; argc++)
    602     newtab->se_argv[argc] = sep->se_argv[argc] ?
    603       newstr (sep->se_argv[argc]) : NULL;
    604   newtab->se_max = sep->se_max;
    605 
    606   return (newtab);
    607 }
    608 
    609 static servtab_t *getconfigent (void)
    610 {
    611   servtab_t *sep;
    612   int argc;
    613   char *cp, *arg;
    614   char *hostdelim;
    615   servtab_t *nsep;
    616   servtab_t *psep;
    617 
    618   sep = new_servtab();
    619 
    620   /* memset(sep, 0, sizeof *sep); */
    621 more:
    622   /* freeconfig(sep); */
    623 
    624   while ((cp = nextline ()) && *cp == '#');
    625   if (cp == NULL) {
    626     /* free(sep); */
    627     return (NULL);
    628   }
    629 
    630   memset ((char *) sep, 0, sizeof *sep);
    631   arg = skip (&cp);
    632   if (arg == NULL) {
    633     /* A blank line. */
    634     goto more;
    635   }
    636 
    637   /* Check for a host name. */
    638   hostdelim = strrchr (arg, ':');
    639   if (hostdelim) {
    640     *hostdelim = '\0';
    641     sep->se_hostaddr = newstr (arg);
    642     arg = hostdelim + 1;
     955                cp->se_bi == 0 &&
     956#endif
     957                (sep->se_wait == 1 || cp->se_wait == 0))
     958                sep->se_wait = cp->se_wait;
     959            SWAP(int, cp->se_max, sep->se_max);
     960            SWAP(char *, sep->se_user, cp->se_user);
     961            SWAP(char *, sep->se_group, cp->se_group);
     962            SWAP(char *, sep->se_server, cp->se_server);
     963            for (i = 0; i < MAXARGV; i++)
     964                SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
     965#undef SWAP
     966
     967#if ENABLE_FEATURE_INETD_RPC
     968            if (isrpcservice(sep))
     969                unregister_rpc(sep);
     970            sep->se_rpcversl = cp->se_rpcversl;
     971            sep->se_rpcversh = cp->se_rpcversh;
     972#endif
     973            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     974            freeconfig(cp);
     975        } else {
     976            sep = enter(cp);
     977        }
     978        sep->se_checked = 1;
     979
     980        switch (sep->se_family) {
     981        case AF_UNIX:
     982            if (sep->se_fd != -1)
     983                break;
     984            (void) unlink(sep->se_service);
     985            n = strlen(sep->se_service);
     986            if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
     987                n = sizeof sep->se_ctrladdr_un.sun_path - 1;
     988            safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
     989            sep->se_ctrladdr_un.sun_family = AF_UNIX;
     990            sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
     991            setup(sep);
     992            break;
     993        case AF_INET:
     994            sep->se_ctrladdr_in.sin_family = AF_INET;
     995            /* se_ctrladdr_in was set in getconfigent */
     996            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
     997
     998#if ENABLE_FEATURE_INETD_RPC
     999            if (isrpcservice(sep)) {
     1000                struct rpcent *rp;
     1001                // FIXME: atoi_or_else(str, 0) would be handy here
     1002                sep->se_rpcprog = atoi(sep->se_service);
     1003                if (sep->se_rpcprog == 0) {
     1004                    rp = getrpcbyname(sep->se_service);
     1005                    if (rp == 0) {
     1006                        bb_error_msg("%s: unknown rpc service", sep->se_service);
     1007                        goto serv_unknown;
     1008                    }
     1009                    sep->se_rpcprog = rp->r_number;
     1010                }
     1011                if (sep->se_fd == -1)
     1012                    setup(sep);
     1013                if (sep->se_fd != -1)
     1014                    register_rpc(sep);
     1015            } else
     1016#endif
     1017            {
     1018                uint16_t port = htons(atoi(sep->se_service));
     1019                // FIXME: atoi_or_else(str, 0) would be handy here
     1020                if (!port) {
     1021                     /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
     1022                    if (isdigit(protoname[strlen(protoname) - 1]))
     1023                        protoname[strlen(protoname) - 1] = '\0';
     1024                    sp = getservbyname(sep->se_service, protoname);
     1025                    if (sp == 0) {
     1026                        bb_error_msg("%s/%s: unknown service",
     1027                                sep->se_service, sep->se_proto);
     1028                        goto serv_unknown;
     1029                    }
     1030                    port = sp->s_port;
     1031                }
     1032                if (port != sep->se_ctrladdr_in.sin_port) {
     1033                    sep->se_ctrladdr_in.sin_port = port;
     1034                    if (sep->se_fd != -1) {
     1035                        FD_CLR(sep->se_fd, &allsock);
     1036                        nsock--;
     1037                        (void) close(sep->se_fd);
     1038                    }
     1039                    sep->se_fd = -1;
     1040                }
     1041                if (sep->se_fd == -1)
     1042                    setup(sep);
     1043            }
     1044            break;
     1045#if ENABLE_FEATURE_IPV6
     1046        case AF_INET6:
     1047            sep->se_ctrladdr_in6.sin6_family = AF_INET6;
     1048            /* se_ctrladdr_in was set in getconfigent */
     1049            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
     1050
     1051#if ENABLE_FEATURE_INETD_RPC
     1052            if (isrpcservice(sep)) {
     1053                struct rpcent *rp;
     1054
     1055                sep->se_rpcprog = atoi(sep->se_service);
     1056                if (sep->se_rpcprog == 0) {
     1057                    rp = getrpcbyname(sep->se_service);
     1058                    if (rp == 0) {
     1059                        bb_error_msg("%s: unknown rpc service", sep->se_service);
     1060                        goto serv_unknown;
     1061                    }
     1062                    sep->se_rpcprog = rp->r_number;
     1063                }
     1064                if (sep->se_fd == -1)
     1065                    setup(sep);
     1066                if (sep->se_fd != -1)
     1067                    register_rpc(sep);
     1068            } else
     1069#endif
     1070            {
     1071                uint16_t port = htons(atoi(sep->se_service));
     1072
     1073                if (!port) {
     1074                     /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
     1075                    if (isdigit(protoname[strlen(protoname) - 1]))
     1076                        protoname[strlen(protoname) - 1] = '\0';
     1077                    sp = getservbyname(sep->se_service, protoname);
     1078                    if (sp == 0) {
     1079                        bb_error_msg("%s/%s: unknown service",
     1080                                sep->se_service, sep->se_proto);
     1081                        goto serv_unknown;
     1082                    }
     1083                    port = sp->s_port;
     1084                }
     1085                if (port != sep->se_ctrladdr_in6.sin6_port) {
     1086                    sep->se_ctrladdr_in6.sin6_port = port;
     1087                    if (sep->se_fd != -1) {
     1088                        FD_CLR(sep->se_fd, &allsock);
     1089                        nsock--;
     1090                        (void) close(sep->se_fd);
     1091                    }
     1092                    sep->se_fd = -1;
     1093                }
     1094                if (sep->se_fd == -1)
     1095                    setup(sep);
     1096            }
     1097            break;
     1098#endif /* FEATURE_IPV6 */
     1099        }
     1100 serv_unknown:
     1101        if (cp->se_next != NULL) {
     1102            servtab_t *tmp = cp;
     1103
     1104            cp = cp->se_next;
     1105            free(tmp);
     1106        } else {
     1107            free(cp);
     1108            cp = getconfigent();
     1109        }
     1110    }
     1111    endconfig();
    6431112    /*
    644      * If the line is of the form `host:', then just change the
    645      * default host for the following lines.
     1113     * Purge anything not looked at above.
    6461114     */
    647     if (*arg == '\0') {
    648       arg = skip (&cp);
    649       if (cp == NULL) {
    650         free (defhost);
    651         defhost = sep->se_hostaddr;
    652         goto more;
    653       }
    654     }
    655   } else
    656     sep->se_hostaddr = newstr (defhost);
    657 
    658   sep->se_service = newstr (arg);
    659   arg = skip (&cp);
    660 
    661   if (strcmp (arg, "stream") == 0)
    662     sep->se_socktype = SOCK_STREAM;
    663   else if (strcmp (arg, "dgram") == 0)
    664     sep->se_socktype = SOCK_DGRAM;
    665   else if (strcmp (arg, "rdm") == 0)
    666     sep->se_socktype = SOCK_RDM;
    667   else if (strcmp (arg, "seqpacket") == 0)
    668     sep->se_socktype = SOCK_SEQPACKET;
    669   else if (strcmp (arg, "raw") == 0)
    670     sep->se_socktype = SOCK_RAW;
    671   else
    672     sep->se_socktype = -1;
    673 
    674   sep->se_proto = newstr (skip (&cp));
    675 
    676   if (strcmp (sep->se_proto, "unix") == 0) {
    677     sep->se_family = AF_UNIX;
    678   } else {
    679     sep->se_family = AF_INET;
    680     if (sep->se_proto[strlen (sep->se_proto) - 1] == '6')
    681 #ifdef CONFIG_FEATURE_IPV6
    682       sep->se_family = AF_INET6;
    683 #else
    684       syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto);
    685 #endif
    686     if (strncmp (sep->se_proto, "rpc/", 4) == 0) {
    687 #ifdef CONFIG_FEATURE_INETD_RPC
    688       char *p, *ccp;
    689       long l;
    690 
    691       p = strchr (sep->se_service, '/');
    692       if (p == 0) {
    693         syslog (LOG_ERR, "%s: no rpc version", sep->se_service);
    694         goto more;
    695       }
    696       *p++ = '\0';
    697       l = strtol (p, &ccp, 0);
    698       if (ccp == p || l < 0 || l > INT_MAX) {
    699       badafterall:
    700         syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p);
    701         goto more;
    702       }
    703       sep->se_rpcversl = sep->se_rpcversh = l;
    704       if (*ccp == '-') {
    705         p = ccp + 1;
    706         l = strtol (p, &ccp, 0);
    707         if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
    708           goto badafterall;
    709         sep->se_rpcversh = l;
    710       } else if (*ccp != '\0')
    711         goto badafterall;
    712 #else
    713     syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service);
    714 #endif
    715     }
    716   }
    717   arg = skip (&cp);
    718   if (arg == NULL)
    719     goto more;
    720 
    721   {
    722     char *s = strchr (arg, '.');
    723     if (s) {
    724       *s++ = '\0';
    725       sep->se_max = atoi (s);
    726     } else
    727       sep->se_max = toomany;
    728   }
    729   sep->se_wait = strcmp (arg, "wait") == 0;
    730   /* if ((arg = skip(&cp, 1)) == NULL) */
    731   /* goto more; */
    732   sep->se_user = newstr (skip (&cp));
    733   arg = strchr (sep->se_user, '.');
    734   if (arg == NULL)
    735     arg = strchr (sep->se_user, ':');
    736   if (arg) {
    737     *arg++ = '\0';
    738     sep->se_group = newstr (arg);
    739   }
    740   /* if ((arg = skip(&cp, 1)) == NULL) */
    741   /* goto more; */
    742 
    743   sep->se_server = newstr (skip (&cp));
    744   if (strcmp (sep->se_server, "internal") == 0) {
    745 #ifdef INETD_FEATURE_ENABLED
    746     const struct builtin *bi;
    747 
    748     for (bi = builtins; bi->bi_service; bi++)
    749       if (bi->bi_socktype == sep->se_socktype &&
    750           strcmp (bi->bi_service, sep->se_service) == 0)
    751         break;
    752     if (bi->bi_service == 0) {
    753       syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
    754       goto more;
    755     }
    756     sep->se_bi = bi;
    757     sep->se_wait = bi->bi_wait;
    758 #else
    759     syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
    760     goto more;
    761 #endif
    762   }
    763 #ifdef INETD_FEATURE_ENABLED
    764     else
    765     sep->se_bi = NULL;
    766 #endif
    767   argc = 0;
    768   for (arg = skip (&cp); cp; arg = skip (&cp)) {
    769     if (argc < MAXARGV)
    770       sep->se_argv[argc++] = newstr (arg);
    771   }
    772   while (argc <= MAXARGV)
    773     sep->se_argv[argc++] = NULL;
    774 
    775   /*
    776    * Now that we've processed the entire line, check if the hostname
    777    * specifier was a comma separated list of hostnames. If so
    778    * we'll make new entries for each address.
    779    */
    780   while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) {
    781     nsep = dupconfig (sep);
    782 
    783     /*
    784      * NULL terminate the hostname field of the existing entry,
    785      * and make a dup for the new entry.
    786      */
    787     *hostdelim++ = '\0';
    788     nsep->se_hostaddr = newstr (hostdelim);
    789 
    790     nsep->se_next = sep->se_next;
    791     sep->se_next = nsep;
    792   }
    793 
    794   nsep = sep;
    795   while (nsep != NULL) {
    796     nsep->se_checked = 1;
    797     if (nsep->se_family == AF_INET) {
    798       if (!strcmp (nsep->se_hostaddr, "*"))
    799         nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
    800       else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
    801         struct hostent *hp;
    802 
    803         hp = gethostbyname (nsep->se_hostaddr);
    804         if (hp == 0) {
    805           syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr);
    806           nsep->se_checked = 0;
    807           goto skip;
    808         } else if (hp->h_addrtype != AF_INET) {
    809           syslog (LOG_ERR,
    810                   "%s: address isn't an Internet "
    811                   "address", nsep->se_hostaddr);
    812           nsep->se_checked = 0;
    813           goto skip;
    814         } else {
    815           int i = 1;
    816 
    817           memmove (&nsep->se_ctrladdr_in.sin_addr,
    818                    hp->h_addr_list[0], sizeof (struct in_addr));
    819           while (hp->h_addr_list[i] != NULL) {
    820             psep = dupconfig (nsep);
    821             psep->se_hostaddr = newstr (nsep->se_hostaddr);
    822             psep->se_checked = 1;
    823             memmove (&psep->se_ctrladdr_in.sin_addr,
    824                      hp->h_addr_list[i], sizeof (struct in_addr));
    825             psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in);
    826             i++;
    827             /* Prepend to list, don't want to look up its */
    828             /* hostname again. */
    829             psep->se_next = sep;
    830             sep = psep;
    831           }
     1115    Block_Using_Signals(omask);
     1116    sepp = &servtab;
     1117    while ((sep = *sepp)) {
     1118        if (sep->se_checked) {
     1119            sepp = &sep->se_next;
     1120            continue;
    8321121        }
    833       }
    834     }
    835 /* XXX BUG?: is this skip: label supposed to remain? */
    836   skip:
    837     nsep = nsep->se_next;
    838   }
    839 
    840   /*
    841    * Finally, free any entries which failed the gethostbyname
    842    * check.
    843    */
    844   psep = NULL;
    845   nsep = sep;
    846   while (nsep != NULL) {
    847     servtab_t *tsep;
    848 
    849     if (nsep->se_checked == 0) {
    850       tsep = nsep;
    851       if (psep == NULL) {
    852         sep = nsep->se_next;
    853         nsep = sep;
    854       } else {
    855         nsep = nsep->se_next;
    856         psep->se_next = nsep;
    857       }
    858       freeconfig (tsep);
    859     } else {
    860       nsep->se_checked = 0;
    861       psep = nsep;
    862       nsep = nsep->se_next;
    863     }
    864   }
    865 
    866   return (sep);
    867 }
    868 
    869 #define Block_Using_Signals(m) do {     sigemptyset(&m); \
    870                     sigaddset(&m, SIGCHLD); \
    871                     sigaddset(&m, SIGHUP); \
    872                     sigaddset(&m, SIGALRM); \
    873                     sigprocmask(SIG_BLOCK, &m, NULL); \
    874                 } while(0)
    875 
    876 
    877 static servtab_t *enter (servtab_t *cp)
    878 {
    879   servtab_t *sep;
    880   sigset_t omask;
    881 
    882   sep = new_servtab();
    883   *sep = *cp;
    884   sep->se_fd = -1;
    885 #ifdef CONFIG_FEATURE_INETD_RPC
    886   sep->se_rpcprog = -1;
    887 #endif
    888   Block_Using_Signals(omask);
    889   sep->se_next = servtab;
    890   servtab = sep;
    891   sigprocmask(SIG_UNBLOCK, &omask, NULL);
    892   return (sep);
    893 }
    894 
    895 static int matchconf (servtab_t *old, servtab_t *new)
    896 {
    897   if (strcmp (old->se_service, new->se_service) != 0)
    898     return (0);
    899 
    900   if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0)
    901     return (0);
    902 
    903   if (strcmp (old->se_proto, new->se_proto) != 0)
    904     return (0);
    905 
    906   /*
    907    * If the new servtab is bound to a specific address, check that the
    908    * old servtab is bound to the same entry. If the new service is not
    909    * bound to a specific address then the check of se_hostaddr above
    910    * is sufficient.
    911    */
    912 
    913   if (old->se_family == AF_INET && new->se_family == AF_INET &&
    914       memcmp (&old->se_ctrladdr_in.sin_addr,
    915               &new->se_ctrladdr_in.sin_addr,
    916               sizeof (new->se_ctrladdr_in.sin_addr)) != 0)
    917     return (0);
    918 
    919 #ifdef CONFIG_FEATURE_IPV6
    920   if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
    921       memcmp (&old->se_ctrladdr_in6.sin6_addr,
    922               &new->se_ctrladdr_in6.sin6_addr,
    923               sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0)
    924     return (0);
    925 #endif
    926   return (1);
    927 }
    928 
    929 static void config (int sig ATTRIBUTE_UNUSED)
    930 {
    931   servtab_t *sep, *cp, **sepp;
    932   sigset_t omask;
    933   int add;
    934   size_t n;
    935   char protoname[10];
    936 
    937   if (!setconfig ()) {
    938     syslog (LOG_ERR, "%s: %m", CONFIG);
    939     return;
    940   }
    941   for (sep = servtab; sep; sep = sep->se_next)
    942     sep->se_checked = 0;
    943   cp = getconfigent ();
    944   while (cp != NULL) {
    945     for (sep = servtab; sep; sep = sep->se_next)
    946       if (matchconf (sep, cp))
    947         break;
    948     add = 0;
    949     if (sep != 0) {
    950       int i;
    951 
    952 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
    953 
    954       Block_Using_Signals(omask);
    955       /*
    956        * sep->se_wait may be holding the pid of a daemon
    957        * that we're waiting for.  If so, don't overwrite
    958        * it unless the config file explicitly says don't
    959        * wait.
    960        */
    961       if (
    962 #ifdef INETD_FEATURE_ENABLED
    963            cp->se_bi == 0 &&
    964 #endif
    965         (sep->se_wait == 1 || cp->se_wait == 0))
    966         sep->se_wait = cp->se_wait;
    967       SWAP (int, cp->se_max, sep->se_max);
    968       SWAP (char *, sep->se_user, cp->se_user);
    969       SWAP (char *, sep->se_group, cp->se_group);
    970       SWAP (char *, sep->se_server, cp->se_server);
    971       for (i = 0; i < MAXARGV; i++)
    972         SWAP (char *, sep->se_argv[i], cp->se_argv[i]);
    973 #undef SWAP
    974 
    975 #ifdef CONFIG_FEATURE_INETD_RPC
    976       if (isrpcservice (sep))
    977         unregister_rpc (sep);
    978       sep->se_rpcversl = cp->se_rpcversl;
    979       sep->se_rpcversh = cp->se_rpcversh;
    980 #endif
    981       sigprocmask(SIG_UNBLOCK, &omask, NULL);
    982       freeconfig (cp);
    983       add = 1;
    984     } else {
    985       sep = enter (cp);
    986     }
    987     sep->se_checked = 1;
    988 
    989     switch (sep->se_family) {
    990     case AF_UNIX:
    991       if (sep->se_fd != -1)
    992         break;
    993       (void) unlink (sep->se_service);
    994       n = strlen (sep->se_service);
    995       if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
    996         n = sizeof sep->se_ctrladdr_un.sun_path - 1;
    997       safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
    998       sep->se_ctrladdr_un.sun_family = AF_UNIX;
    999       sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
    1000       setup (sep);
    1001       break;
    1002     case AF_INET:
    1003       sep->se_ctrladdr_in.sin_family = AF_INET;
    1004       /* se_ctrladdr_in was set in getconfigent */
    1005       sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
    1006 
    1007 #ifdef CONFIG_FEATURE_INETD_RPC
    1008       if (isrpcservice (sep)) {
    1009         struct rpcent *rp;
    1010 
    1011         sep->se_rpcprog = atoi (sep->se_service);
    1012         if (sep->se_rpcprog == 0) {
    1013           rp = getrpcbyname (sep->se_service);
    1014           if (rp == 0) {
    1015             syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
    1016             goto serv_unknown;
    1017           }
    1018           sep->se_rpcprog = rp->r_number;
     1122        *sepp = sep->se_next;
     1123        if (sep->se_fd != -1) {
     1124            FD_CLR(sep->se_fd, &allsock);
     1125            nsock--;
     1126            (void) close(sep->se_fd);
    10191127        }
     1128#if ENABLE_FEATURE_INETD_RPC
     1129        if (isrpcservice(sep))
     1130            unregister_rpc(sep);
     1131#endif
     1132        if (sep->se_family == AF_UNIX)
     1133            (void) unlink(sep->se_service);
     1134        freeconfig(sep);
     1135        free(sep);
     1136    }
     1137    sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1138}
     1139
     1140
     1141static void reapchild(int sig ATTRIBUTE_UNUSED)
     1142{
     1143    pid_t pid;
     1144    int save_errno = errno, status;
     1145    servtab_t *sep;
     1146
     1147    for (;;) {
     1148        pid = wait3(&status, WNOHANG, NULL);
     1149        if (pid <= 0)
     1150            break;
     1151        for (sep = servtab; sep; sep = sep->se_next)
     1152            if (sep->se_wait == pid) {
     1153                if (WIFEXITED(status) && WEXITSTATUS(status))
     1154                    bb_error_msg("%s: exit status 0x%x",
     1155                            sep->se_server, WEXITSTATUS(status));
     1156                else if (WIFSIGNALED(status))
     1157                    bb_error_msg("%s: exit signal 0x%x",
     1158                            sep->se_server, WTERMSIG(status));
     1159                sep->se_wait = 1;
     1160                FD_SET(sep->se_fd, &allsock);
     1161                nsock++;
     1162            }
     1163    }
     1164    errno = save_errno;
     1165}
     1166
     1167static void retry(int sig ATTRIBUTE_UNUSED)
     1168{
     1169    servtab_t *sep;
     1170
     1171    timingout = 0;
     1172    for (sep = servtab; sep; sep = sep->se_next) {
     1173        if (sep->se_fd == -1) {
     1174            switch (sep->se_family) {
     1175            case AF_UNIX:
     1176            case AF_INET:
     1177#if ENABLE_FEATURE_IPV6
     1178            case AF_INET6:
     1179#endif
     1180                setup(sep);
     1181#if ENABLE_FEATURE_INETD_RPC
     1182                if (sep->se_fd != -1 && isrpcservice(sep))
     1183                    register_rpc(sep);
     1184#endif
     1185                break;
     1186            }
     1187        }
     1188    }
     1189}
     1190
     1191static void goaway(int sig ATTRIBUTE_UNUSED)
     1192{
     1193    servtab_t *sep;
     1194
     1195    /* XXX signal race walking sep list */
     1196    for (sep = servtab; sep; sep = sep->se_next) {
    10201197        if (sep->se_fd == -1)
    1021           setup (sep);
    1022         if (sep->se_fd != -1)
    1023           register_rpc (sep);
    1024       } else
    1025 #endif
    1026          {
    1027         u_short port = htons (atoi (sep->se_service));
    1028 
    1029         if (!port) {
    1030            /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
    1031           if (isdigit (protoname[strlen (protoname) - 1]))
    1032             protoname[strlen (protoname) - 1] = '\0';
    1033           sp = getservbyname (sep->se_service, protoname);
    1034           if (sp == 0) {
    1035             syslog (LOG_ERR,
    1036                     "%s/%s: unknown service", sep->se_service, sep->se_proto);
    1037             goto serv_unknown;
    1038           }
    1039           port = sp->s_port;
     1198            continue;
     1199
     1200        switch (sep->se_family) {
     1201        case AF_UNIX:
     1202            (void) unlink(sep->se_service);
     1203            break;
     1204        case AF_INET:
     1205#if ENABLE_FEATURE_IPV6
     1206        case AF_INET6:
     1207#endif
     1208#if ENABLE_FEATURE_INETD_RPC
     1209            if (sep->se_wait == 1 && isrpcservice(sep))
     1210                unregister_rpc(sep);   /* XXX signal race */
     1211#endif
     1212            break;
    10401213        }
    1041         if (port != sep->se_ctrladdr_in.sin_port) {
    1042           sep->se_ctrladdr_in.sin_port = port;
    1043           if (sep->se_fd != -1) {
    1044             FD_CLR (sep->se_fd, &allsock);
    1045             nsock--;
    1046             (void) close (sep->se_fd);
    1047           }
    1048           sep->se_fd = -1;
    1049         }
    1050         if (sep->se_fd == -1)
    1051           setup (sep);
    1052       }
    1053       break;
    1054 #ifdef CONFIG_FEATURE_IPV6
    1055     case AF_INET6:
    1056       sep->se_ctrladdr_in6.sin6_family = AF_INET6;
    1057       /* se_ctrladdr_in was set in getconfigent */
    1058       sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
    1059 
    1060 #ifdef CONFIG_FEATURE_INETD_RPC
    1061       if (isrpcservice (sep)) {
    1062         struct rpcent *rp;
    1063 
    1064         sep->se_rpcprog = atoi (sep->se_service);
    1065         if (sep->se_rpcprog == 0) {
    1066           rp = getrpcbyname (sep->se_service);
    1067           if (rp == 0) {
    1068             syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
    1069             goto serv_unknown;
    1070           }
    1071           sep->se_rpcprog = rp->r_number;
    1072         }
    1073         if (sep->se_fd == -1)
    1074           setup (sep);
    1075         if (sep->se_fd != -1)
    1076           register_rpc (sep);
    1077       } else
    1078 #endif
    1079         {
    1080         u_short port = htons (atoi (sep->se_service));
    1081 
    1082         if (!port) {
    1083            /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
    1084           if (isdigit (protoname[strlen (protoname) - 1]))
    1085             protoname[strlen (protoname) - 1] = '\0';
    1086           sp = getservbyname (sep->se_service, protoname);
    1087           if (sp == 0) {
    1088             syslog (LOG_ERR,
    1089                     "%s/%s: unknown service", sep->se_service, sep->se_proto);
    1090             goto serv_unknown;
    1091           }
    1092           port = sp->s_port;
    1093         }
    1094         if (port != sep->se_ctrladdr_in6.sin6_port) {
    1095           sep->se_ctrladdr_in6.sin6_port = port;
    1096           if (sep->se_fd != -1) {
    1097             FD_CLR (sep->se_fd, &allsock);
    1098             nsock--;
    1099             (void) close (sep->se_fd);
    1100           }
    1101           sep->se_fd = -1;
    1102         }
    1103         if (sep->se_fd == -1)
    1104           setup (sep);
    1105       }
    1106       break;
    1107 #endif /* CONFIG_FEATURE_IPV6 */
    1108     }
    1109   serv_unknown:
    1110     if (cp->se_next != NULL) {
    1111       servtab_t *tmp = cp;
    1112 
    1113       cp = cp->se_next;
    1114       free (tmp);
    1115     } else {
    1116       free (cp);
    1117       cp = getconfigent ();
    1118     }
    1119   }
    1120   endconfig ();
    1121   /*
    1122    * Purge anything not looked at above.
    1123    */
    1124   Block_Using_Signals(omask);
    1125   sepp = &servtab;
    1126   while ((sep = *sepp)) {
    1127     if (sep->se_checked) {
    1128       sepp = &sep->se_next;
    1129       continue;
    1130     }
    1131     *sepp = sep->se_next;
    1132     if (sep->se_fd != -1) {
    1133       FD_CLR (sep->se_fd, &allsock);
    1134       nsock--;
    1135       (void) close (sep->se_fd);
    1136     }
    1137 #ifdef CONFIG_FEATURE_INETD_RPC
    1138     if (isrpcservice (sep))
    1139       unregister_rpc (sep);
    1140 #endif
    1141     if (sep->se_family == AF_UNIX)
    1142       (void) unlink (sep->se_service);
    1143     freeconfig (sep);
    1144     free (sep);
    1145   }
    1146   sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1147 }
    1148 
    1149 
    1150 static void reapchild (int sig ATTRIBUTE_UNUSED)
    1151 {
    1152   pid_t pid;
    1153   int save_errno = errno, status;
    1154   servtab_t *sep;
    1155 
    1156   for (;;) {
    1157     pid = wait3 (&status, WNOHANG, NULL);
    1158     if (pid <= 0)
    1159       break;
    1160     for (sep = servtab; sep; sep = sep->se_next)
    1161       if (sep->se_wait == pid) {
    1162         if (WIFEXITED (status) && WEXITSTATUS (status))
    1163           syslog (LOG_WARNING,
    1164                   "%s: exit status 0x%x",
    1165                   sep->se_server, WEXITSTATUS (status));
    1166         else if (WIFSIGNALED (status))
    1167           syslog (LOG_WARNING,
    1168                   "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status));
    1169         sep->se_wait = 1;
    1170         FD_SET (sep->se_fd, &allsock);
    1171         nsock++;
    1172       }
    1173   }
    1174   errno = save_errno;
    1175 }
    1176 
    1177 static void retry (int sig ATTRIBUTE_UNUSED)
    1178 {
    1179   servtab_t *sep;
    1180 
    1181   timingout = 0;
    1182   for (sep = servtab; sep; sep = sep->se_next) {
    1183     if (sep->se_fd == -1) {
    1184       switch (sep->se_family) {
    1185       case AF_UNIX:
    1186       case AF_INET:
    1187 #ifdef CONFIG_FEATURE_IPV6
    1188       case AF_INET6:
    1189 #endif
    1190         setup (sep);
    1191 #ifdef CONFIG_FEATURE_INETD_RPC
    1192         if (sep->se_fd != -1 && isrpcservice (sep))
    1193           register_rpc (sep);
    1194 #endif
    1195         break;
    1196       }
    1197     }
    1198   }
    1199 }
    1200 
    1201 static void goaway (int sig ATTRIBUTE_UNUSED)
    1202 {
    1203   servtab_t *sep;
    1204 
    1205   /* XXX signal race walking sep list */
    1206   for (sep = servtab; sep; sep = sep->se_next) {
    1207     if (sep->se_fd == -1)
    1208       continue;
    1209 
    1210     switch (sep->se_family) {
    1211     case AF_UNIX:
    1212       (void) unlink (sep->se_service);
    1213       break;
    1214     case AF_INET:
    1215 #ifdef CONFIG_FEATURE_IPV6
    1216     case AF_INET6:
    1217 #endif
    1218 #ifdef CONFIG_FEATURE_INETD_RPC
    1219       if (sep->se_wait == 1 && isrpcservice (sep))
    1220         unregister_rpc (sep);   /* XXX signal race */
    1221 #endif
    1222       break;
    1223     }
    1224     (void) close (sep->se_fd);
    1225   }
    1226   (void) unlink (_PATH_INETDPID);
    1227   exit (0);
     1214        (void) close(sep->se_fd);
     1215    }
     1216    remove_pidfile(_PATH_INETDPID);
     1217    exit(0);
    12281218}
    12291219
     
    12341224
    12351225static void
    1236 inetd_setproctitle (char *a, int s)
    1237 {
    1238   socklen_t size;
    1239   char *cp;
    1240   struct sockaddr_in prt_sin;
    1241   char buf[80];
    1242 
    1243   cp = Argv[0];
    1244   size = sizeof (prt_sin);
    1245   (void) snprintf (buf, sizeof buf, "-%s", a);
    1246   if (getpeername (s, (struct sockaddr *) &prt_sin, &size) == 0) {
    1247     char *sa = inet_ntoa (prt_sin.sin_addr);
    1248 
    1249     buf[sizeof (buf) - 1 - strlen (sa) - 3] = '\0';
    1250     strcat (buf, " [");
    1251     strcat (buf, sa);
    1252     strcat (buf, "]");
    1253   }
    1254   strncpy (cp, buf, LastArg - cp);
    1255   cp += strlen (cp);
    1256   while (cp < LastArg)
    1257     *cp++ = ' ';
    1258 }
    1259 #endif
    1260 
    1261 
    1262 int
    1263 inetd_main (int argc, char *argv[])
    1264 {
    1265   servtab_t *sep;
    1266   struct passwd *pwd;
    1267   struct group *grp = NULL;
    1268   int tmpint;
    1269   struct sigaction sa, sapipe;
    1270   int opt;
    1271   pid_t pid;
    1272   char buf[50];
    1273   char *stoomany;
    1274   sigset_t omask, wait_mask;
     1226inetd_setproctitle(char *a, int s)
     1227{
     1228    socklen_t size;
     1229    char *cp;
     1230    struct sockaddr_in prt_sin;
     1231    char buf[80];
     1232
     1233    cp = Argv[0];
     1234    size = sizeof(prt_sin);
     1235    (void) snprintf(buf, sizeof buf, "-%s", a);
     1236    if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {
     1237        char *sa = inet_ntoa(prt_sin.sin_addr);
     1238
     1239        buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0';
     1240        strcat(buf, " [");
     1241        strcat(buf, sa);
     1242        strcat(buf, "]");
     1243    }
     1244    strncpy(cp, buf, LastArg - cp);
     1245    cp += strlen(cp);
     1246    while (cp < LastArg)
     1247        *cp++ = ' ';
     1248}
     1249#endif
     1250
     1251
     1252int inetd_main(int argc, char **argv);
     1253int inetd_main(int argc, char **argv)
     1254{
     1255    servtab_t *sep;
     1256    struct passwd *pwd;
     1257    struct group *grp = NULL;
     1258    int tmpint;
     1259    struct sigaction sa, sapipe;
     1260    int opt;
     1261    pid_t pid;
     1262    char buf[50];
     1263    char *stoomany;
     1264    sigset_t omask, wait_mask;
    12751265
    12761266#ifdef INETD_SETPROCTITLE
    1277   extern char **environ;
    1278   char **envp = environ;
    1279 
    1280   Argv = argv;
    1281   if (envp == 0 || *envp == 0)
    1282     envp = argv;
    1283   while (*envp)
    1284     envp++;
    1285   LastArg = envp[-1] + strlen (envp[-1]);
    1286 #endif
    1287 
    1288   openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
    1289 
    1290   opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany);
    1291   if(opt & 1) {
    1292     char *e;
    1293 
    1294     toomany = strtoul (stoomany, &e, 0);
    1295     if (!(toomany >= 0 && *e == '\0')) {
    1296         toomany = TOOMANY;
    1297         syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany);
    1298     }
    1299   }
    1300   argc -= optind;
    1301   argv += optind;
    1302 
    1303   uid = getuid ();
    1304   if (uid != 0)
    1305     CONFIG = NULL;
    1306   if (argc > 0)
    1307     CONFIG = argv[0];
    1308   if (CONFIG == NULL)
    1309     bb_error_msg_and_die ("non-root must specify a config file");
    1310 
    1311   if (!(opt & 2)) {
    1312 #ifdef BB_NOMMU
    1313     /* reexec for vfork() do continue parent */
    1314     vfork_daemon_rexec (0, 0, argc, argv, "-f");
    1315 #else
    1316     bb_xdaemon (0, 0);
    1317 #endif
    1318   } else {
    1319     setsid ();
    1320   }
    1321 
    1322   if (uid == 0) {
    1323     gid_t gid = getgid ();
    1324 
    1325     /* If run by hand, ensure groups vector gets trashed */
    1326     setgroups (1, &gid);
    1327   }
    1328 
    1329   {
    1330     FILE *fp;
    1331 
    1332     if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) {
    1333         fprintf (fp, "%u\n", getpid ());
    1334         (void) fclose (fp);
    1335     }
    1336   }
    1337 
    1338   if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) {
    1339     syslog (LOG_ERR, "getrlimit: %m");
    1340   } else {
    1341     rlim_ofile_cur = rlim_ofile.rlim_cur;
    1342     if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
    1343       rlim_ofile_cur = OPEN_MAX;
    1344   }
    1345 
    1346   memset ((char *) &sa, 0, sizeof (sa));
    1347   sigemptyset (&sa.sa_mask);
    1348   sigaddset (&sa.sa_mask, SIGALRM);
    1349   sigaddset (&sa.sa_mask, SIGCHLD);
    1350   sigaddset (&sa.sa_mask, SIGHUP);
    1351   sa.sa_handler = retry;
    1352   sigaction (SIGALRM, &sa, NULL);
    1353   /* doconfig(); */
    1354   config (SIGHUP);
    1355   sa.sa_handler = config;
    1356   sigaction (SIGHUP, &sa, NULL);
    1357   sa.sa_handler = reapchild;
    1358   sigaction (SIGCHLD, &sa, NULL);
    1359   sa.sa_handler = goaway;
    1360   sigaction (SIGTERM, &sa, NULL);
    1361   sa.sa_handler = goaway;
    1362   sigaction (SIGINT, &sa, NULL);
    1363   sa.sa_handler = SIG_IGN;
    1364   sigaction (SIGPIPE, &sa, &sapipe);
    1365   memset(&wait_mask, 0, sizeof(wait_mask));
    1366   {
    1367     /* space for daemons to overwrite environment for ps */
     1267    char **envp = environ;
     1268
     1269    Argv = argv;
     1270    if (envp == 0 || *envp == 0)
     1271        envp = argv;
     1272    while (*envp)
     1273        envp++;
     1274    LastArg = envp[-1] + strlen(envp[-1]);
     1275#endif
     1276
     1277    uid = getuid();
     1278    if (uid != 0)
     1279        config_filename = NULL;
     1280
     1281    opt = getopt32(argv, "R:f", &stoomany);
     1282    if (opt & 1)
     1283        toomany = xatoi_u(stoomany);
     1284    argv += optind;
     1285    argc -= optind;
     1286    if (argc)
     1287        config_filename = argv[0];
     1288    if (config_filename == NULL)
     1289        bb_error_msg_and_die("non-root must specify a config file");
     1290
     1291    if (!(opt & 2))
     1292        bb_daemonize_or_rexec(0, argv - optind);
     1293    else
     1294        bb_sanitize_stdio();
     1295    openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
     1296    logmode = LOGMODE_SYSLOG;
     1297
     1298    if (uid == 0) {
     1299        /* If run by hand, ensure groups vector gets trashed */
     1300        gid_t gid = getgid();
     1301        setgroups(1, &gid);
     1302    }
     1303
     1304    write_pidfile(_PATH_INETDPID);
     1305
     1306    if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
     1307        bb_perror_msg("getrlimit");
     1308    } else {
     1309        rlim_ofile_cur = rlim_ofile.rlim_cur;
     1310        if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
     1311            rlim_ofile_cur = OPEN_MAX;
     1312    }
     1313
     1314    memset((char *) &sa, 0, sizeof(sa));
     1315    sigemptyset(&sa.sa_mask);
     1316    sigaddset(&sa.sa_mask, SIGALRM);
     1317    sigaddset(&sa.sa_mask, SIGCHLD);
     1318    sigaddset(&sa.sa_mask, SIGHUP);
     1319    sa.sa_handler = retry;
     1320    sigaction(SIGALRM, &sa, NULL);
     1321    config(SIGHUP);
     1322    sa.sa_handler = config;
     1323    sigaction(SIGHUP, &sa, NULL);
     1324    sa.sa_handler = reapchild;
     1325    sigaction(SIGCHLD, &sa, NULL);
     1326    sa.sa_handler = goaway;
     1327    sigaction(SIGTERM, &sa, NULL);
     1328    sa.sa_handler = goaway;
     1329    sigaction(SIGINT, &sa, NULL);
     1330    sa.sa_handler = SIG_IGN;
     1331    sigaction(SIGPIPE, &sa, &sapipe);
     1332    memset(&wait_mask, 0, sizeof(wait_mask));
     1333    {
     1334        /* space for daemons to overwrite environment for ps */
    13681335#define DUMMYSIZE       100
    1369     char dummy[DUMMYSIZE];
    1370 
    1371     (void) memset (dummy, 'x', DUMMYSIZE - 1);
    1372     dummy[DUMMYSIZE - 1] = '\0';
    1373 
    1374     (void) setenv ("inetd_dummy", dummy, 1);
    1375   }
    1376 
    1377   for (;;) {
    1378     int n, ctrl = -1;
    1379     fd_set readable;
    1380 
    1381     if (nsock == 0) {
    1382       Block_Using_Signals(omask);
    1383       while (nsock == 0)
    1384         sigsuspend (&wait_mask);
    1385       sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1386     }
    1387 
    1388     readable = allsock;
    1389     if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) {
    1390       if (n < 0 && errno != EINTR) {
    1391         syslog (LOG_WARNING, "select: %m");
    1392         sleep (1);
    1393       }
    1394       continue;
    1395     }
    1396     for (sep = servtab; n && sep; sep = sep->se_next)
    1397       if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) {
    1398         n--;
    1399         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
    1400           ctrl = accept (sep->se_fd, NULL, NULL);
    1401           if (ctrl < 0) {
    1402             if (errno == EINTR)
    1403               continue;
    1404             syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service);
     1336        char dummy[DUMMYSIZE];
     1337
     1338        (void) memset(dummy, 'x', DUMMYSIZE - 1);
     1339        dummy[DUMMYSIZE - 1] = '\0';
     1340
     1341        (void) setenv("inetd_dummy", dummy, 1);
     1342    }
     1343
     1344    for (;;) {
     1345        int n, ctrl = -1;
     1346        fd_set readable;
     1347
     1348        if (nsock == 0) {
     1349            Block_Using_Signals(omask);
     1350            while (nsock == 0)
     1351                sigsuspend(&wait_mask);
     1352            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1353        }
     1354
     1355        readable = allsock;
     1356        n = select(maxsock + 1, &readable, NULL, NULL, NULL);
     1357        if (n <= 0) {
     1358            if (n < 0 && errno != EINTR) {
     1359                bb_perror_msg("select");
     1360                sleep(1);
     1361            }
    14051362            continue;
    1406           }
    1407           if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
    1408             struct sockaddr_in peer;
    1409             socklen_t plen = sizeof (peer);
    1410 
    1411             if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) {
    1412               syslog (LOG_WARNING, "could not getpeername");
    1413               close (ctrl);
    1414               continue;
     1363        }
     1364
     1365        for (sep = servtab; n && sep; sep = sep->se_next) {
     1366            if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
     1367                continue;
     1368
     1369            n--;
     1370            if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
     1371                ctrl = accept(sep->se_fd, NULL, NULL);
     1372                if (ctrl < 0) {
     1373                    if (errno == EINTR)
     1374                        continue;
     1375                    bb_perror_msg("accept (for %s)", sep->se_service);
     1376                    continue;
     1377                }
     1378                if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
     1379                    struct sockaddr_in peer;
     1380                    socklen_t plen = sizeof(peer);
     1381
     1382                    if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) {
     1383                        bb_error_msg("cannot getpeername");
     1384                        close(ctrl);
     1385                        continue;
     1386                    }
     1387                    if (ntohs(peer.sin_port) == 20) {
     1388                        /* XXX ftp bounce */
     1389                        close(ctrl);
     1390                        continue;
     1391                    }
     1392                }
     1393            } else
     1394                ctrl = sep->se_fd;
     1395
     1396            Block_Using_Signals(omask);
     1397            pid = 0;
     1398#ifdef INETD_FEATURE_ENABLED
     1399            if (sep->se_bi == 0 || sep->se_bi->bi_fork)
     1400#endif
     1401            {
     1402                if (sep->se_count++ == 0)
     1403                    (void) gettimeofday(&sep->se_time, NULL);
     1404                else if (toomany > 0 && sep->se_count >= sep->se_max) {
     1405                    struct timeval now;
     1406
     1407                    (void) gettimeofday(&now, NULL);
     1408                    if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
     1409                        sep->se_time = now;
     1410                        sep->se_count = 1;
     1411                    } else {
     1412                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1413                            close(ctrl);
     1414                        if (sep->se_family == AF_INET &&
     1415                              ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
     1416                            /*
     1417                             * Cannot close it -- there are
     1418                             * thieves on the system.
     1419                             * Simply ignore the connection.
     1420                             */
     1421                            --sep->se_count;
     1422                            continue;
     1423                        }
     1424                        bb_error_msg("%s/%s server failing (looping), service terminated",
     1425                                  sep->se_service, sep->se_proto);
     1426                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1427                            close(ctrl);
     1428                        FD_CLR(sep->se_fd, &allsock);
     1429                        (void) close(sep->se_fd);
     1430                        sep->se_fd = -1;
     1431                        sep->se_count = 0;
     1432                        nsock--;
     1433                        sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1434                        if (!timingout) {
     1435                            timingout = 1;
     1436                            alarm(RETRYTIME);
     1437                        }
     1438                        continue;
     1439                    }
     1440                }
     1441                pid = fork();
    14151442            }
    1416             if (ntohs (peer.sin_port) == 20) {
    1417               /* XXX ftp bounce */
    1418               close (ctrl);
    1419               continue;
     1443            if (pid < 0) {
     1444                bb_perror_msg("fork");
     1445                if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1446                    close(ctrl);
     1447                sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1448                sleep(1);
     1449                continue;
    14201450            }
    1421           }
    1422         } else
    1423           ctrl = sep->se_fd;
    1424         Block_Using_Signals(omask);
    1425         pid = 0;
     1451            if (pid && sep->se_wait) {
     1452                sep->se_wait = pid;
     1453                FD_CLR(sep->se_fd, &allsock);
     1454                nsock--;
     1455            }
     1456            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1457            if (pid == 0) {
    14261458#ifdef INETD_FEATURE_ENABLED
    1427         if (sep->se_bi == 0 || sep->se_bi->bi_fork)
    1428 #endif
    1429         {
    1430           if (sep->se_count++ == 0)
    1431             (void) gettimeofday (&sep->se_time, NULL);
    1432           else if (toomany > 0 && sep->se_count >= sep->se_max) {
    1433             struct timeval now;
    1434 
    1435             (void) gettimeofday (&now, NULL);
    1436             if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
    1437               sep->se_time = now;
    1438               sep->se_count = 1;
    1439             } else {
    1440               if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1441                 close (ctrl);
    1442               if (sep->se_family == AF_INET &&
    1443                   ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
    1444                 /*
    1445                  * Cannot close it -- there are
    1446                  * thieves on the system.
    1447                  * Simply ignore the connection.
    1448                  */
    1449                 --sep->se_count;
    1450                 continue;
    1451               }
    1452               syslog (LOG_ERR,
    1453                       "%s/%s server failing (looping), service terminated",
    1454                       sep->se_service, sep->se_proto);
    1455               if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1456                 close (ctrl);
    1457               FD_CLR (sep->se_fd, &allsock);
    1458               (void) close (sep->se_fd);
    1459               sep->se_fd = -1;
    1460               sep->se_count = 0;
    1461               nsock--;
    1462               sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1463               if (!timingout) {
    1464                 timingout = 1;
    1465                 alarm (RETRYTIME);
    1466               }
    1467               continue;
     1459                if (sep->se_bi) {
     1460                    (*sep->se_bi->bi_fn)(ctrl, sep);
     1461                } else
     1462#endif
     1463                {
     1464                    pwd = getpwnam(sep->se_user);
     1465                    if (pwd == NULL) {
     1466                        bb_error_msg("getpwnam: %s: no such user", sep->se_user);
     1467                        goto do_exit1;
     1468                    }
     1469                    if (setsid() < 0)
     1470                        bb_perror_msg("%s: setsid", sep->se_service);
     1471                    if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
     1472                        bb_error_msg("getgrnam: %s: no such group", sep->se_group);
     1473                        goto do_exit1;
     1474                    }
     1475                    if (uid != 0) {
     1476                        /* a user running private inetd */
     1477                        if (uid != pwd->pw_uid)
     1478                            _exit(1);
     1479                    } else if (pwd->pw_uid) {
     1480                        if (sep->se_group)
     1481                            pwd->pw_gid = grp->gr_gid;
     1482                        xsetgid((gid_t) pwd->pw_gid);
     1483                        initgroups(pwd->pw_name, pwd->pw_gid);
     1484                        xsetuid((uid_t) pwd->pw_uid);
     1485                    } else if (sep->se_group) {
     1486                        xsetgid(grp->gr_gid);
     1487                        setgroups(1, &grp->gr_gid);
     1488                    }
     1489                    dup2(ctrl, 0);
     1490                    if (ctrl) close(ctrl);
     1491                    dup2(0, 1);
     1492                    dup2(0, 2);
     1493                    if (rlim_ofile.rlim_cur != rlim_ofile_cur)
     1494                        if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
     1495                            bb_perror_msg("setrlimit");
     1496                    closelog();
     1497                    for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
     1498                        (void) close(tmpint);
     1499                    sigaction(SIGPIPE, &sapipe, NULL);
     1500                    execv(sep->se_server, sep->se_argv);
     1501                    bb_perror_msg("execv %s", sep->se_server);
     1502 do_exit1:
     1503                    if (sep->se_socktype != SOCK_STREAM)
     1504                        recv(0, buf, sizeof(buf), 0);
     1505                    _exit(1);
     1506                }
    14681507            }
    1469           }
    1470           pid = fork ();
    1471         }
    1472         if (pid < 0) {
    1473           syslog (LOG_ERR, "fork: %m");
    1474           if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1475             close (ctrl);
    1476           sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1477           sleep (1);
    1478           continue;
    1479         }
    1480         if (pid && sep->se_wait) {
    1481           sep->se_wait = pid;
    1482           FD_CLR (sep->se_fd, &allsock);
    1483           nsock--;
    1484         }
    1485         sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1486         if (pid == 0) {
    1487 #ifdef INETD_FEATURE_ENABLED
    1488           if (sep->se_bi) {
    1489             (*sep->se_bi->bi_fn) (ctrl, sep);
    1490           } else
    1491 #endif
    1492             {
    1493             if ((pwd = getpwnam (sep->se_user)) == NULL) {
    1494               syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user);
    1495               if (sep->se_socktype != SOCK_STREAM)
    1496                 recv (0, buf, sizeof (buf), 0);
    1497               _exit (1);
    1498             }
    1499             if (setsid () < 0)
    1500               syslog (LOG_ERR, "%s: setsid: %m", sep->se_service);
    1501             if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) {
    1502               syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group);
    1503               if (sep->se_socktype != SOCK_STREAM)
    1504                 recv (0, buf, sizeof (buf), 0);
    1505               _exit (1);
    1506             }
    1507             if (uid != 0) {
    1508               /* a user running private inetd */
    1509               if (uid != pwd->pw_uid)
    1510                 _exit (1);
    1511             } else if (pwd->pw_uid) {
    1512               if (sep->se_group) {
    1513                 pwd->pw_gid = grp->gr_gid;
    1514               }
    1515               xsetgid ((gid_t) pwd->pw_gid);
    1516               initgroups (pwd->pw_name, pwd->pw_gid);
    1517               xsetuid((uid_t) pwd->pw_uid);
    1518             } else if (sep->se_group) {
    1519               xsetgid(grp->gr_gid);
    1520               setgroups (1, &grp->gr_gid);
    1521             }
    1522             dup2 (ctrl, 0);
    1523             close (ctrl);
    1524             dup2 (0, 1);
    1525             dup2 (0, 2);
    1526             if (rlim_ofile.rlim_cur != rlim_ofile_cur)
    1527               if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0)
    1528                 syslog (LOG_ERR, "setrlimit: %m");
    1529             closelog ();
    1530             for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
    1531               (void) close (tmpint);
    1532             sigaction (SIGPIPE, &sapipe, NULL);
    1533             execv (sep->se_server, sep->se_argv);
    1534             if (sep->se_socktype != SOCK_STREAM)
    1535               recv (0, buf, sizeof (buf), 0);
    1536             syslog (LOG_ERR, "execv %s: %m", sep->se_server);
    1537             _exit (1);
    1538           }
    1539         }
    1540         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1541           close (ctrl);
    1542       }
    1543   }
     1508            if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1509                close(ctrl);
     1510        } /* for (sep = servtab...) */
     1511    } /* for (;;) */
    15441512}
    15451513
     
    15491517#define BUFSIZE 4096
    15501518
    1551 #if defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO) || \
    1552     defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN) || \
    1553     defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME)
    1554 static int dg_badinput (struct sockaddr_in *dg_sin)
    1555 {
    1556   if (ntohs (dg_sin->sin_port) < IPPORT_RESERVED)
    1557     return (1);
    1558   if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST))
    1559     return (1);
    1560   /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
    1561   return (0);
    1562 }
    1563 #endif
    1564 
    1565 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     1519#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     1520    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
     1521    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     1522static int dg_badinput(struct sockaddr_in *dg_sin)
     1523{
     1524    if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
     1525        return 1;
     1526    if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))
     1527        return 1;
     1528    /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
     1529    return 0;
     1530}
     1531#endif
     1532
     1533#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    15661534/* Echo service -- echo data back */
    15671535/* ARGSUSED */
    15681536static void
    1569 echo_stream (int s, servtab_t *sep)
    1570 {
    1571   char buffer[BUFSIZE];
    1572   int i;
    1573 
    1574   inetd_setproctitle (sep->se_service, s);
    1575   while ((i = read (s, buffer, sizeof (buffer))) > 0 &&
    1576          write (s, buffer, i) > 0);
    1577   exit (0);
     1537echo_stream(int s, servtab_t *sep)
     1538{
     1539    char buffer[BUFSIZE];
     1540    int i;
     1541
     1542    inetd_setproctitle(sep->se_service, s);
     1543    while (1) {
     1544        i = read(s, buffer, sizeof(buffer));
     1545        if (i <= 0) break;
     1546        /* FIXME: this isnt correct - safe_write()? */
     1547        if (write(s, buffer, i) <= 0) break;
     1548    }
     1549    exit(0);
    15781550}
    15791551
     
    15811553/* ARGSUSED */
    15821554static void
    1583 echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1584 {
    1585   char buffer[BUFSIZE];
    1586   int i;
    1587   socklen_t size;
    1588   /* struct sockaddr_storage ss; */
    1589   struct sockaddr sa;
    1590 
    1591   size = sizeof (sa);
    1592   if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0)
    1593     return;
    1594   if (dg_badinput ((struct sockaddr_in *) &sa))
    1595     return;
    1596   (void) sendto (s, buffer, i, 0, &sa, sizeof (sa));
    1597 }
    1598 #endif  /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
    1599 
    1600 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     1555echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1556{
     1557    char buffer[BUFSIZE];
     1558    int i;
     1559    socklen_t size;
     1560    /* struct sockaddr_storage ss; */
     1561    struct sockaddr sa;
     1562
     1563    size = sizeof(sa);
     1564    i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size);
     1565    if (i < 0)
     1566        return;
     1567    if (dg_badinput((struct sockaddr_in *) &sa))
     1568        return;
     1569    (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
     1570}
     1571#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
     1572
     1573#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    16011574/* Discard service -- ignore data */
    16021575/* ARGSUSED */
    16031576static void
    1604 discard_stream (int s, servtab_t *sep)
    1605 {
    1606   char buffer[BUFSIZE];
    1607 
    1608   inetd_setproctitle (sep->se_service, s);
    1609   while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) ||
    1610          errno == EINTR);
    1611   exit (0);
     1577discard_stream(int s, servtab_t *sep)
     1578{
     1579    char buffer[BUFSIZE];
     1580
     1581    inetd_setproctitle(sep->se_service, s);
     1582    while (1) {
     1583        errno = 0;
     1584        if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR)
     1585            exit(0);
     1586    }
    16121587}
    16131588
     
    16151590/* ARGSUSED */
    16161591static void
    1617 discard_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1618 {
    1619   char buffer[BUFSIZE];
    1620 
    1621   (void) read (s, buffer, sizeof (buffer));
    1622 }
    1623 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
    1624 
    1625 
    1626 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     1592discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1593{
     1594    char buffer[BUFSIZE];
     1595
     1596    (void) read(s, buffer, sizeof(buffer));
     1597}
     1598#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
     1599
     1600
     1601#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    16271602#define LINESIZ 72
    16281603static char ring[128];
     
    16301605
    16311606static void
    1632 initring (void)
    1633 {
    1634   int i;
    1635 
    1636   endring = ring;
    1637 
    1638   for (i = 0; i <= 128; ++i)
    1639     if (isprint (i))
    1640       *endring++ = i;
     1607initring(void)
     1608{
     1609    int i;
     1610
     1611    endring = ring;
     1612
     1613    for (i = 0; i <= 128; ++i)
     1614        if (isprint(i))
     1615            *endring++ = i;
    16411616}
    16421617
     
    16441619/* ARGSUSED */
    16451620static void
    1646 chargen_stream (int s, servtab_t *sep)
    1647 {
    1648   char *rs;
    1649   int len;
    1650   char text[LINESIZ + 2];
    1651 
    1652   inetd_setproctitle (sep->se_service, s);
    1653 
    1654   if (!endring) {
    1655     initring ();
     1621chargen_stream(int s, servtab_t *sep)
     1622{
     1623    char *rs;
     1624    int len;
     1625    char text[LINESIZ + 2];
     1626
     1627    inetd_setproctitle(sep->se_service, s);
     1628
     1629    if (!endring) {
     1630        initring();
     1631        rs = ring;
     1632    }
     1633
     1634    text[LINESIZ] = '\r';
     1635    text[LINESIZ + 1] = '\n';
    16561636    rs = ring;
    1657   }
    1658 
    1659   text[LINESIZ] = '\r';
    1660   text[LINESIZ + 1] = '\n';
    1661   for (rs = ring;;) {
    1662     if ((len = endring - rs) >= LINESIZ)
    1663       memmove (text, rs, LINESIZ);
    1664     else {
    1665       memmove (text, rs, len);
    1666       memmove (text + len, ring, LINESIZ - len);
    1667     }
    1668     if (++rs == endring)
    1669       rs = ring;
    1670     if (write (s, text, sizeof (text)) != sizeof (text))
    1671       break;
    1672   }
    1673   exit (0);
     1637    for (;;) {
     1638        len = endring - rs;
     1639        if (len >= LINESIZ)
     1640            memmove(text, rs, LINESIZ);
     1641        else {
     1642            memmove(text, rs, len);
     1643            memmove(text + len, ring, LINESIZ - len);
     1644        }
     1645        if (++rs == endring)
     1646            rs = ring;
     1647        if (write(s, text, sizeof(text)) != sizeof(text))
     1648            break;
     1649    }
     1650    exit(0);
    16741651}
    16751652
     
    16771654/* ARGSUSED */
    16781655static void
    1679 chargen_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1680 {
    1681   /* struct sockaddr_storage ss; */
    1682   struct sockaddr sa;
    1683   static char *rs;
    1684   int len;
    1685   char text[LINESIZ + 2];
    1686   socklen_t size;
    1687 
    1688   if (endring == 0) {
    1689     initring ();
    1690     rs = ring;
    1691   }
    1692 
    1693   size = sizeof (sa);
    1694   if (recvfrom (s, text, sizeof (text), 0, &sa, &size) < 0)
    1695     return;
    1696   if (dg_badinput ((struct sockaddr_in *) &sa))
    1697     return;
    1698 
    1699   if ((len = endring - rs) >= LINESIZ)
    1700     memmove (text, rs, LINESIZ);
    1701   else {
    1702     memmove (text, rs, len);
    1703     memmove (text + len, ring, LINESIZ - len);
    1704   }
    1705   if (++rs == endring)
    1706     rs = ring;
    1707   text[LINESIZ] = '\r';
    1708   text[LINESIZ + 1] = '\n';
    1709   (void) sendto (s, text, sizeof (text), 0, &sa, sizeof (sa));
    1710 }
    1711 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
    1712 
    1713 
    1714 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     1656chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1657{
     1658    /* struct sockaddr_storage ss; */
     1659    struct sockaddr sa;
     1660    static char *rs;
     1661    int len;
     1662    char text[LINESIZ + 2];
     1663    socklen_t size;
     1664
     1665    if (endring == 0) {
     1666        initring();
     1667        rs = ring;
     1668    }
     1669
     1670    size = sizeof(sa);
     1671    if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
     1672        return;
     1673    if (dg_badinput((struct sockaddr_in *) &sa))
     1674        return;
     1675
     1676    if ((len = endring - rs) >= LINESIZ)
     1677        memmove(text, rs, LINESIZ);
     1678    else {
     1679        memmove(text, rs, len);
     1680        memmove(text + len, ring, LINESIZ - len);
     1681    }
     1682    if (++rs == endring)
     1683        rs = ring;
     1684    text[LINESIZ] = '\r';
     1685    text[LINESIZ + 1] = '\n';
     1686    (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
     1687}
     1688#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
     1689
     1690
     1691#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    17151692/*
    17161693 * Return a machine readable date and time, in the form of the
     
    17211698 */
    17221699
    1723 static u_int machtime (void)
    1724 {
    1725   struct timeval tv;
    1726 
    1727   if (gettimeofday (&tv, NULL) < 0) {
    1728     fprintf (stderr, "Unable to get time of day\n");
    1729     return (0L);
    1730   }
    1731   return (htonl ((u_int) tv.tv_sec + 2208988800UL));
     1700static unsigned machtime(void)
     1701{
     1702    struct timeval tv;
     1703
     1704    if (gettimeofday(&tv, NULL) < 0) {
     1705        fprintf(stderr, "Unable to get time of day\n");
     1706        return 0L;
     1707    }
     1708    return htonl((unsigned) tv.tv_sec + 2208988800UL);
    17321709}
    17331710
    17341711/* ARGSUSED */
    17351712static void
    1736 machtime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1737 {
    1738   u_int result;
    1739 
    1740   result = machtime ();
    1741   (void) write (s, (char *) &result, sizeof (result));
     1713machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1714{
     1715    unsigned result;
     1716
     1717    result = machtime();
     1718    (void) write(s, (char *) &result, sizeof(result));
    17421719}
    17431720
    17441721/* ARGSUSED */
    17451722static void
    1746 machtime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1747 {
    1748   u_int result;
    1749   /* struct sockaddr_storage ss; */
    1750   struct sockaddr sa;
    1751   struct sockaddr_in *dg_sin;
    1752   socklen_t size;
    1753 
    1754   size = sizeof (sa);
    1755   if (recvfrom (s, (char *) &result, sizeof (result), 0, &sa, &size) < 0)
    1756     return;
    1757   /* if (dg_badinput((struct sockaddr *)&ss)) */
    1758   dg_sin = (struct sockaddr_in *) &sa;
    1759   if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST) ||
    1760       ntohs (dg_sin->sin_port) < IPPORT_RESERVED / 2)
    1761     return;
    1762   result = machtime ();
    1763   (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof (sa));
    1764 }
    1765 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME */
    1766 
    1767 
    1768 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     1723machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1724{
     1725    unsigned result;
     1726    /* struct sockaddr_storage ss; */
     1727    struct sockaddr sa;
     1728    struct sockaddr_in *dg_sin;
     1729    socklen_t size;
     1730
     1731    size = sizeof(sa);
     1732    if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)
     1733        return;
     1734    /* if (dg_badinput((struct sockaddr *)&ss)) */
     1735    dg_sin = (struct sockaddr_in *) &sa;
     1736    if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
     1737            ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)
     1738        return;
     1739    result = machtime();
     1740    (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
     1741}
     1742#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
     1743
     1744
     1745#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    17691746/* Return human-readable time of day */
    17701747/* ARGSUSED */
    1771 static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1772 {
    1773   char buffer[256];
    1774   time_t t;
    1775 
    1776   t = time (NULL);
    1777 
    1778   (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
    1779   (void) write (s, buffer, strlen (buffer));
     1748static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1749{
     1750    char buffer[32];
     1751    time_t t;
     1752
     1753    t = time(NULL);
     1754
     1755// fdprintf instead?
     1756    (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
     1757    (void) write(s, buffer, strlen(buffer));
    17801758}
    17811759
     
    17831761/* ARGSUSED */
    17841762void
    1785 daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1786 {
    1787   char buffer[256];
    1788   time_t t;
    1789   /* struct sockaddr_storage ss; */
    1790   struct sockaddr sa;
    1791   socklen_t size;
    1792 
    1793   t = time ((time_t *) 0);
    1794 
    1795   size = sizeof (sa);
    1796   if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0)
    1797     return;
    1798   if (dg_badinput ((struct sockaddr_in *) &sa))
    1799     return;
    1800   (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
    1801   (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa));
    1802 }
    1803 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
    1804 /* vi: set sw=4 ts=4: */
     1763daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1764{
     1765    char buffer[256];
     1766    time_t t;
     1767    /* struct sockaddr_storage ss; */
     1768    struct sockaddr sa;
     1769    socklen_t size;
     1770
     1771    t = time(NULL);
     1772
     1773    size = sizeof(sa);
     1774    if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
     1775        return;
     1776    if (dg_badinput((struct sockaddr_in *) &sa))
     1777        return;
     1778    (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
     1779    (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
     1780}
     1781#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
  • branches/stable/mindi-busybox/networking/interface.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * stolen from net-tools-1.59 and stripped down for busybox by
     
    1516 *              one or more of the system's networking interfaces.
    1617 *
    17  * Version:     $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $
    1818 *
    1919 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
     
    3232 */
    3333
    34 #include "inet_common.h"
    35 #include <stdio.h>
    36 #include <errno.h>
    37 #include <stdlib.h>
    38 #include <string.h>
    39 #include <unistd.h>
    40 #include <fcntl.h>
    41 #include <ctype.h>
    42 #include <sys/ioctl.h>
    43 #include <sys/types.h>
    4434#include <net/if.h>
    4535#include <net/if_arp.h>
    46 #include "busybox.h"
    47 
    48 #ifdef CONFIG_FEATURE_IPV6
     36#include "inet_common.h"
     37#include "libbb.h"
     38
     39#if ENABLE_FEATURE_IPV6
    4940# define HAVE_AFINET6 1
    5041#else
     
    5546#define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
    5647
    57 #if HAVE_AFINET6
     48#ifdef HAVE_AFINET6
    5849
    5950#ifndef _LINUX_IN6_H
     
    7061#endif
    7162
    72 #endif                          /* HAVE_AFINET6 */
     63#endif /* HAVE_AFINET6 */
    7364
    7465/* Defines for glibc2.0 users. */
     
    9182#endif
    9283
    93 /* This structure defines protocol families and their handlers. */
    94 struct aftype {
    95     const char *name;
    96     const char *title;
    97     int af;
    98     int alen;
    99     char *(*print) (unsigned char *);
    100     char *(*sprint) (struct sockaddr *, int numeric);
    101     int (*input) (int type, char *bufp, struct sockaddr *);
    102     void (*herror) (char *text);
    103     int (*rprint) (int options);
    104     int (*rinput) (int typ, int ext, char **argv);
    105 
    106     /* may modify src */
    107     int (*getmask) (char *src, struct sockaddr * mask, char *name);
    108 
    109     int fd;
    110     char *flag_file;
    111 };
    112 
    11384/* Display an Internet socket address. */
    114 static char *INET_sprint(struct sockaddr *sap, int numeric)
    115 {
    116     static char buff[128];
    117 
     85static const char *INET_sprint(struct sockaddr *sap, int numeric)
     86{
     87    static char *buff;
     88
     89    free(buff);
    11890    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
    119         return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
    120 
    121     if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
    122                       numeric, 0xffffff00) != 0)
    123         return (NULL);
    124 
    125     return (buff);
    126 }
    127 
    128 static struct aftype inet_aftype = {
     91        return "[NONE SET]";
     92    buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00);
     93    return buff;
     94}
     95
     96#ifdef UNUSED_AND_BUGGY
     97static int INET_getsock(char *bufp, struct sockaddr *sap)
     98{
     99    char *sp = bufp, *bp;
     100    unsigned int i;
     101    unsigned val;
     102    struct sockaddr_in *sock_in;
     103
     104    sock_in = (struct sockaddr_in *) sap;
     105    sock_in->sin_family = AF_INET;
     106    sock_in->sin_port = 0;
     107
     108    val = 0;
     109    bp = (char *) &val;
     110    for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
     111        *sp = toupper(*sp);
     112
     113        if ((unsigned)(*sp - 'A') <= 5)
     114            bp[i] |= (int) (*sp - ('A' - 10));
     115        else if (isdigit(*sp))
     116            bp[i] |= (int) (*sp - '0');
     117        else
     118            return -1;
     119
     120        bp[i] <<= 4;
     121        sp++;
     122        *sp = toupper(*sp);
     123
     124        if ((unsigned)(*sp - 'A') <= 5)
     125            bp[i] |= (int) (*sp - ('A' - 10));
     126        else if (isdigit(*sp))
     127            bp[i] |= (int) (*sp - '0');
     128        else
     129            return -1;
     130
     131        sp++;
     132    }
     133    sock_in->sin_addr.s_addr = htonl(val);
     134
     135    return (sp - bufp);
     136}
     137#endif
     138
     139static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
     140{
     141    return INET_resolve(bufp, (struct sockaddr_in *) sap, 0);
     142/*
     143    switch (type) {
     144    case 1:
     145        return (INET_getsock(bufp, sap));
     146    case 256:
     147        return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
     148    default:
     149        return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
     150    }
     151*/
     152}
     153
     154static const struct aftype inet_aftype = {
    129155    .name =     "inet",
    130156    .title =    "DARPA Internet",
     
    132158    .alen =     4,
    133159    .sprint =   INET_sprint,
    134     .fd =       -1
    135 };
    136 
    137 #if HAVE_AFINET6
     160    .input =    INET_input,
     161};
     162
     163#ifdef HAVE_AFINET6
    138164
    139165/* Display an Internet socket address. */
    140166/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
    141 static char *INET6_sprint(struct sockaddr *sap, int numeric)
    142 {
    143     static char buff[128];
    144 
     167static const char *INET6_sprint(struct sockaddr *sap, int numeric)
     168{
     169    static char *buff;
     170
     171    free(buff);
    145172    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
    146         return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
    147     if (INET6_rresolve
    148         (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
    149         return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
    150     return (buff);
    151 }
    152 
    153 static struct aftype inet6_aftype = {
     173        return "[NONE SET]";
     174    buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric);
     175    return buff;
     176}
     177
     178#ifdef UNUSED
     179static int INET6_getsock(char *bufp, struct sockaddr *sap)
     180{
     181    struct sockaddr_in6 *sin6;
     182
     183    sin6 = (struct sockaddr_in6 *) sap;
     184    sin6->sin6_family = AF_INET6;
     185    sin6->sin6_port = 0;
     186
     187    if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
     188        return -1;
     189
     190    return 16;          /* ?;) */
     191}
     192#endif
     193
     194static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
     195{
     196    return INET6_resolve(bufp, (struct sockaddr_in6 *) sap);
     197/*
     198    switch (type) {
     199    case 1:
     200        return (INET6_getsock(bufp, sap));
     201    default:
     202        return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
     203    }
     204*/
     205}
     206
     207static const struct aftype inet6_aftype = {
    154208    .name =     "inet6",
    155209    .title =    "IPv6",
     
    157211    .alen =     sizeof(struct in6_addr),
    158212    .sprint =   INET6_sprint,
    159     .fd =       -1
    160 };
    161 
    162 #endif                          /* HAVE_AFINET6 */
     213    .input =    INET6_input,
     214};
     215
     216#endif /* HAVE_AFINET6 */
    163217
    164218/* Display an UNSPEC address. */
    165219static char *UNSPEC_print(unsigned char *ptr)
    166220{
    167     static char buff[sizeof(struct sockaddr) * 3 + 1];
     221    static char *buff;
     222
    168223    char *pos;
    169224    unsigned int i;
    170225
     226    if (!buff);
     227        buff = xmalloc(sizeof(struct sockaddr) * 3 + 1);
    171228    pos = buff;
    172229    for (i = 0; i < sizeof(struct sockaddr); i++) {
     
    177234    /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
    178235    *--pos = '\0';
    179     return (buff);
     236    return buff;
    180237}
    181238
    182239/* Display an UNSPEC socket address. */
    183 static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
    184 {
    185     static char buf[64];
    186 
     240static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
     241{
    187242    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
    188         return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
    189     return (UNSPEC_print((unsigned char *)sap->sa_data));
    190 }
    191 
    192 static struct aftype unspec_aftype = {
    193     "unspec", "UNSPEC", AF_UNSPEC, 0,
    194     UNSPEC_print, UNSPEC_sprint, NULL, NULL,
    195     NULL,
    196 };
    197 
    198 static struct aftype * const aftypes[] = {
     243        return "[NONE SET]";
     244    return UNSPEC_print((unsigned char *)sap->sa_data);
     245}
     246
     247static const struct aftype unspec_aftype = {
     248    .name   = "unspec",
     249    .title  = "UNSPEC",
     250    .af     = AF_UNSPEC,
     251    .alen    = 0,
     252    .print  = UNSPEC_print,
     253    .sprint = UNSPEC_sprint,
     254};
     255
     256static const struct aftype *const aftypes[] = {
    199257    &inet_aftype,
    200 #if HAVE_AFINET6
     258#ifdef HAVE_AFINET6
    201259    &inet6_aftype,
    202260#endif
     
    206264
    207265/* Check our protocol family table for this family. */
    208 static struct aftype *get_afntype(int af)
    209 {
    210     struct aftype * const *afp;
     266const struct aftype *get_aftype(const char *name)
     267{
     268    const struct aftype *const *afp;
     269
     270    afp = aftypes;
     271    while (*afp != NULL) {
     272        if (!strcmp((*afp)->name, name))
     273            return (*afp);
     274        afp++;
     275    }
     276    return NULL;
     277}
     278
     279/* Check our protocol family table for this family. */
     280static const struct aftype *get_afntype(int af)
     281{
     282    const struct aftype *const *afp;
    211283
    212284    afp = aftypes;
    213285    while (*afp != NULL) {
    214286        if ((*afp)->af == af)
    215             return (*afp);
     287            return *afp;
    216288        afp++;
    217289    }
    218     return (NULL);
    219 }
    220 
    221 /* Check our protocol family table for this family and return its socket */
    222 static int get_socket_for_af(int af)
    223 {
    224     struct aftype * const *afp;
    225 
    226     afp = aftypes;
    227     while (*afp != NULL) {
    228         if ((*afp)->af == af)
    229             return (*afp)->fd;
    230         afp++;
    231     }
    232     return -1;
     290    return NULL;
    233291}
    234292
     
    284342
    285343
    286 int interface_opt_a = 0;    /* show all interfaces          */
     344smallint interface_opt_a;   /* show all interfaces */
    287345
    288346static struct interface *int_list, *int_last;
    289 static int skfd = -1;   /* generic raw socket desc.     */
    290 
    291 
    292 static int sockets_open(int family)
    293 {
    294     struct aftype * const *aft;
    295     int sfd = -1;
    296     static int force = -1;
    297 
    298     if (force < 0) {
    299         force = 0;
    300         if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
    301             force = 1;
    302         if (access("/proc/net", R_OK))
    303             force = 1;
    304     }
    305     for (aft = aftypes; *aft; aft++) {
    306         struct aftype *af = *aft;
    307         int type = SOCK_DGRAM;
    308 
    309         if (af->af == AF_UNSPEC)
    310             continue;
    311         if (family && family != af->af)
    312             continue;
    313         if (af->fd != -1) {
    314             sfd = af->fd;
    315             continue;
    316         }
    317         /* Check some /proc file first to not stress kmod */
    318         if (!family && !force && af->flag_file) {
    319             if (access(af->flag_file, R_OK))
    320                 continue;
    321         }
    322         af->fd = socket(af->af, type, 0);
    323         if (af->fd >= 0)
    324             sfd = af->fd;
    325     }
    326     if (sfd < 0) {
    327         bb_error_msg("No usable address families found.");
    328     }
    329     return sfd;
    330 }
    331 
    332 #ifdef CONFIG_FEATURE_CLEAN_UP
    333 static void sockets_close(void)
    334 {
    335     struct aftype * const *aft;
    336     for (aft = aftypes; *aft != NULL; aft++) {
    337         struct aftype *af = *aft;
    338         if( af->fd != -1 ) {
    339             close(af->fd);
    340             af->fd = -1;
    341         }
    342     }
    343 }
    344 #endif
    345 
     347
     348
     349#if 0
    346350/* like strcmp(), but knows about numbers */
     351except that the freshly added calls to xatoul() brf on ethernet aliases with
     352uClibc with e.g.: ife->name='lo'  name='eth0:1'
    347353static int nstrcmp(const char *a, const char *b)
    348354{
     
    363369
    364370    if (isdigit(*a) && isdigit(*b)) {
    365         return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
     371        return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
    366372    }
    367373    return *a - *b;
    368374}
     375#endif
    369376
    370377static struct interface *add_interface(char *name)
     
    373380
    374381    for (ife = int_last; ife; ife = ife->prev) {
    375         int n = nstrcmp(ife->name, name);
     382        int n = /*n*/strcmp(ife->name, name);
    376383
    377384        if (n == 0)
     
    392399    *nextp = new;
    393400    return new;
    394 }
    395 
    396 
    397 static int if_readconf(void)
    398 {
    399     int numreqs = 30;
    400     struct ifconf ifc;
    401     struct ifreq *ifr;
    402     int n, err = -1;
    403     int skfd2;
    404 
    405     /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
    406        (as of 2.1.128) */
    407     skfd2 = get_socket_for_af(AF_INET);
    408     if (skfd2 < 0) {
    409         bb_perror_msg(("warning: no inet socket available"));
    410         /* Try to soldier on with whatever socket we can get hold of.  */
    411         skfd2 = sockets_open(0);
    412         if (skfd2 < 0)
    413             return -1;
    414     }
    415 
    416     ifc.ifc_buf = NULL;
    417     for (;;) {
    418         ifc.ifc_len = sizeof(struct ifreq) * numreqs;
    419         ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
    420 
    421         if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
    422             perror("SIOCGIFCONF");
    423             goto out;
    424         }
    425         if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
    426             /* assume it overflowed and try again */
    427             numreqs += 10;
    428             continue;
    429         }
    430         break;
    431     }
    432 
    433     ifr = ifc.ifc_req;
    434     for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
    435         add_interface(ifr->ifr_name);
    436         ifr++;
    437     }
    438     err = 0;
    439 
    440   out:
    441     free(ifc.ifc_buf);
    442     return err;
    443401}
    444402
     
    477435 * args. */
    478436
    479 /* static const char * const ss_fmt[] = { */
     437/* static const char *const ss_fmt[] = { */
    480438/*  "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
    481439/*  "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
     
    485443    /* Lie about the size of the int pointed to for %n. */
    486444#if INT_MAX == LONG_MAX
    487 static const char * const ss_fmt[] = {
     445static const char *const ss_fmt[] = {
    488446    "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
    489447    "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
     
    491449};
    492450#else
    493 static const char * const ss_fmt[] = {
     451static const char *const ss_fmt[] = {
    494452    "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
    495453    "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
     
    542500}
    543501
     502static int if_readconf(void)
     503{
     504    int numreqs = 30;
     505    struct ifconf ifc;
     506    struct ifreq *ifr;
     507    int n, err = -1;
     508    int skfd;
     509
     510    ifc.ifc_buf = NULL;
     511
     512    /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
     513       (as of 2.1.128) */
     514    skfd = socket(AF_INET, SOCK_DGRAM, 0);
     515    if (skfd < 0) {
     516        bb_perror_msg("error: no inet socket available");
     517        return -1;
     518    }
     519
     520    for (;;) {
     521        ifc.ifc_len = sizeof(struct ifreq) * numreqs;
     522        ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
     523
     524        if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) {
     525            goto out;
     526        }
     527        if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
     528            /* assume it overflowed and try again */
     529            numreqs += 10;
     530            continue;
     531        }
     532        break;
     533    }
     534
     535    ifr = ifc.ifc_req;
     536    for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
     537        add_interface(ifr->ifr_name);
     538        ifr++;
     539    }
     540    err = 0;
     541
     542 out:
     543    close(skfd);
     544    free(ifc.ifc_buf);
     545    return err;
     546}
     547
    544548static int if_readlist_proc(char *target)
    545549{
    546     static int proc_read;
     550    static smallint proc_read;
     551
    547552    FILE *fh;
    548553    char buf[512];
     
    557562    fh = fopen(_PATH_PROCNET_DEV, "r");
    558563    if (!fh) {
    559         bb_perror_msg("Warning: cannot open %s. Limited output.", _PATH_PROCNET_DEV);
     564        bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
    560565        return if_readconf();
    561566    }
     
    577582    }
    578583    if (ferror(fh)) {
    579         perror(_PATH_PROCNET_DEV);
     584        bb_perror_msg(_PATH_PROCNET_DEV);
    580585        err = -1;
    581586        proc_read = 0;
     
    588593{
    589594    int err = if_readlist_proc(NULL);
    590 
     595    /* Needed in order to get ethN:M aliases */
    591596    if (!err)
    592597        err = if_readconf();
     
    594599}
    595600
    596 static int for_all_interfaces(int (*doit) (struct interface *, void *),
    597                               void *cookie)
    598 {
    599     struct interface *ife;
    600 
    601     if (!int_list && (if_readlist() < 0))
    602         return -1;
    603     for (ife = int_list; ife; ife = ife->next) {
    604         int err = doit(ife, cookie);
    605 
    606         if (err)
    607             return err;
    608     }
    609     return 0;
    610 }
    611 
    612601/* Fetch the interface configuration from the kernel. */
    613602static int if_fetch(struct interface *ife)
    614603{
    615604    struct ifreq ifr;
    616     int fd;
    617605    char *ifname = ife->name;
    618 
    619     strcpy(ifr.ifr_name, ifname);
    620     if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
    621         return (-1);
     606    int skfd;
     607
     608    skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
     609
     610    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     611    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
     612        close(skfd);
     613        return -1;
     614    }
    622615    ife->flags = ifr.ifr_flags;
    623616
    624     strcpy(ifr.ifr_name, ifname);
    625     if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
    626         memset(ife->hwaddr, 0, 32);
    627     else
     617    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     618    memset(ife->hwaddr, 0, 32);
     619    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
    628620        memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
    629621
    630622    ife->type = ifr.ifr_hwaddr.sa_family;
    631623
    632     strcpy(ifr.ifr_name, ifname);
    633     if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
    634         ife->metric = 0;
    635     else
     624    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     625    ife->metric = 0;
     626    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
    636627        ife->metric = ifr.ifr_metric;
    637628
    638     strcpy(ifr.ifr_name, ifname);
    639     if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
    640         ife->mtu = 0;
    641     else
     629    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     630    ife->mtu = 0;
     631    if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
    642632        ife->mtu = ifr.ifr_mtu;
    643633
     634    memset(&ife->map, 0, sizeof(struct ifmap));
    644635#ifdef SIOCGIFMAP
    645     strcpy(ifr.ifr_name, ifname);
     636    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    646637    if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
    647638        ife->map = ifr.ifr_map;
    648     else
    649 #endif
    650         memset(&ife->map, 0, sizeof(struct ifmap));
     639#endif
    651640
    652641#ifdef HAVE_TXQUEUELEN
    653     strcpy(ifr.ifr_name, ifname);
    654     if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
    655         ife->tx_queue_len = -1; /* unknown value */
    656     else
     642    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     643    ife->tx_queue_len = -1; /* unknown value */
     644    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
    657645        ife->tx_queue_len = ifr.ifr_qlen;
    658646#else
     
    660648#endif
    661649
    662     /* IPv4 address? */
    663     fd = get_socket_for_af(AF_INET);
    664     if (fd >= 0) {
    665         strcpy(ifr.ifr_name, ifname);
    666         ifr.ifr_addr.sa_family = AF_INET;
    667         if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
    668             ife->has_ip = 1;
    669             ife->addr = ifr.ifr_addr;
    670             strcpy(ifr.ifr_name, ifname);
    671             if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
    672                 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
    673             else
    674                 ife->dstaddr = ifr.ifr_dstaddr;
    675 
    676             strcpy(ifr.ifr_name, ifname);
    677             if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
    678                 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
    679             else
    680                 ife->broadaddr = ifr.ifr_broadaddr;
    681 
    682             strcpy(ifr.ifr_name, ifname);
    683             if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
    684                 memset(&ife->netmask, 0, sizeof(struct sockaddr));
    685             else
    686                 ife->netmask = ifr.ifr_netmask;
    687         } else
    688             memset(&ife->addr, 0, sizeof(struct sockaddr));
    689     }
    690 
     650    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     651    ifr.ifr_addr.sa_family = AF_INET;
     652    memset(&ife->addr, 0, sizeof(struct sockaddr));
     653    if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
     654        ife->has_ip = 1;
     655        ife->addr = ifr.ifr_addr;
     656        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     657        memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
     658        if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
     659            ife->dstaddr = ifr.ifr_dstaddr;
     660
     661        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     662        memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
     663        if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
     664            ife->broadaddr = ifr.ifr_broadaddr;
     665
     666        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     667        memset(&ife->netmask, 0, sizeof(struct sockaddr));
     668        if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
     669            ife->netmask = ifr.ifr_netmask;
     670    }
     671
     672    close(skfd);
    691673    return 0;
    692674}
     
    696678{
    697679    if (if_fetch(ife) < 0) {
    698         char *errmsg;
     680        const char *errmsg;
    699681
    700682        if (errno == ENODEV) {
     
    711693}
    712694
    713 /* This structure defines hardware protocols and their handlers. */
    714 struct hwtype {
    715     const char * const name;
    716     const char *title;
    717     int type;
    718     int alen;
    719     char *(*print) (unsigned char *);
    720     int (*input) (char *, struct sockaddr *);
    721     int (*activate) (int fd);
    722     int suppress_null_addr;
    723 };
    724 
    725695static const struct hwtype unspec_hwtype = {
    726696    .name =     "unspec",
     
    738708#include <net/if_arp.h>
    739709
    740 #if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
     710#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
    741711#include <net/ethernet.h>
    742712#else
     
    747717static char *pr_ether(unsigned char *ptr)
    748718{
    749     static char buff[64];
    750 
    751     snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
     719    static char *buff;
     720
     721    free(buff);
     722    buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
    752723             (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
    753724             (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
    754725        );
    755     return (buff);
    756 }
     726    return buff;
     727}
     728
     729static int in_ether(const char *bufp, struct sockaddr *sap);
    757730
    758731static const struct hwtype ether_hwtype = {
     
    761734    .type =     ARPHRD_ETHER,
    762735    .alen =     ETH_ALEN,
    763     .print =    pr_ether
    764 };
     736    .print =    pr_ether,
     737    .input =    in_ether
     738};
     739
     740static unsigned hexchar2int(char c)
     741{
     742    if (isdigit(c))
     743        return c - '0';
     744    c &= ~0x20; /* a -> A */
     745    if ((unsigned)(c - 'A') <= 5)
     746        return c - ('A' - 10);
     747    return ~0U;
     748}
     749
     750/* Input an Ethernet address and convert to binary. */
     751static int in_ether(const char *bufp, struct sockaddr *sap)
     752{
     753    unsigned char *ptr;
     754    char c;
     755    int i;
     756    unsigned val;
     757
     758    sap->sa_family = ether_hwtype.type;
     759    ptr = (unsigned char*) sap->sa_data;
     760
     761    i = 0;
     762    while ((*bufp != '\0') && (i < ETH_ALEN)) {
     763        val = hexchar2int(*bufp++) * 0x10;
     764        if (val > 0xff) {
     765            errno = EINVAL;
     766            return -1;
     767        }
     768        c = *bufp;
     769        if (c == ':' || c == 0)
     770            val >>= 4;
     771        else {
     772            val |= hexchar2int(c);
     773            if (val > 0xff) {
     774                errno = EINVAL;
     775                return -1;
     776            }
     777        }
     778        if (c != 0)
     779            bufp++;
     780        *ptr++ = (unsigned char) val;
     781        i++;
     782
     783        /* We might get a semicolon here - not required. */
     784        if (*bufp == ':') {
     785            bufp++;
     786        }
     787    }
     788    return 0;
     789}
    765790
    766791#include <net/if_arp.h>
     
    772797};
    773798
    774 #ifdef CONFIG_FEATURE_IPV6
     799#if ENABLE_FEATURE_IPV6
    775800static const struct hwtype sit_hwtype = {
    776801    .name =         "sit",
     
    779804    .print =        UNSPEC_print,
    780805    .suppress_null_addr =   1
    781 } ;
    782 #endif
    783 
    784 static const struct hwtype * const hwtypes[] = {
     806};
     807#endif
     808
     809static const struct hwtype *const hwtypes[] = {
    785810    &loop_hwtype,
    786811    &ether_hwtype,
    787812    &ppp_hwtype,
    788813    &unspec_hwtype,
    789 #ifdef CONFIG_FEATURE_IPV6
     814#if ENABLE_FEATURE_IPV6
    790815    &sit_hwtype,
    791816#endif
     
    794819
    795820#ifdef IFF_PORTSEL
    796 static const char * const if_port_text[] = {
     821static const char *const if_port_text[] = {
    797822    /* Keep in step with <linux/netdevice.h> */
    798823    "unknown",
     
    808833
    809834/* Check our hardware type table for this type. */
    810 static const struct hwtype *get_hwntype(int type)
    811 {
    812     const struct hwtype * const *hwp;
     835const struct hwtype *get_hwtype(const char *name)
     836{
     837    const struct hwtype *const *hwp;
     838
     839    hwp = hwtypes;
     840    while (*hwp != NULL) {
     841        if (!strcmp((*hwp)->name, name))
     842            return (*hwp);
     843        hwp++;
     844    }
     845    return NULL;
     846}
     847
     848/* Check our hardware type table for this type. */
     849const struct hwtype *get_hwntype(int type)
     850{
     851    const struct hwtype *const *hwp;
    813852
    814853    hwp = hwtypes;
    815854    while (*hwp != NULL) {
    816855        if ((*hwp)->type == type)
    817             return (*hwp);
     856            return *hwp;
    818857        hwp++;
    819858    }
    820     return (NULL);
     859    return NULL;
    821860}
    822861
     
    833872}
    834873
    835 static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
     874static const char TRext[] ALIGN1 = "\0\0\0Ki\0Mi\0Gi\0Ti";
    836875
    837876static void print_bytes_scaled(unsigned long long ull, const char *end)
     
    858897}
    859898
    860 static const char * const ife_print_flags_strs[] = {
    861     "UP ",
    862     "BROADCAST ",
    863     "DEBUG ",
    864     "LOOPBACK ",
    865     "POINTOPOINT ",
    866     "NOTRAILERS ",
    867     "RUNNING ",
    868     "NOARP ",
    869     "PROMISC ",
    870     "ALLMULTI ",
    871     "SLAVE ",
    872     "MASTER ",
    873     "MULTICAST ",
    874 #ifdef HAVE_DYNAMIC
    875     "DYNAMIC "
    876 #endif
    877 };
    878 
    879 static const unsigned short ife_print_flags_mask[] = {
    880     IFF_UP,
    881     IFF_BROADCAST,
    882     IFF_DEBUG,
    883     IFF_LOOPBACK,
    884     IFF_POINTOPOINT,
    885     IFF_NOTRAILERS,
    886     IFF_RUNNING,
    887     IFF_NOARP,
    888     IFF_PROMISC,
    889     IFF_ALLMULTI,
    890     IFF_SLAVE,
    891     IFF_MASTER,
    892     IFF_MULTICAST,
    893 #ifdef HAVE_DYNAMIC
    894     IFF_DYNAMIC
    895 #endif
    896     0
    897 };
    898 
    899899static void ife_print(struct interface *ptr)
    900900{
    901     struct aftype *ap;
     901    const struct aftype *ap;
    902902    const struct hwtype *hw;
    903903    int hf;
    904904    int can_compress = 0;
    905905
    906 #if HAVE_AFINET6
     906#ifdef HAVE_AFINET6
    907907    FILE *f;
    908908    char addr6[40], devname[20];
     
    938938    }
    939939#endif
    940     printf("\n");
     940    puts("");
    941941
    942942    if (ptr->has_ip) {
     
    952952    }
    953953
    954 #if HAVE_AFINET6
     954#ifdef HAVE_AFINET6
    955955
    956956#define IPV6_ADDR_ANY           0x0000U
     
    971971#define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
    972972
    973     if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
     973    f = fopen(_PATH_PROCNET_IFINET6, "r");
     974    if (f != NULL) {
    974975        while (fscanf
    975                (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
     976               (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
    976977                addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
    977978                addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
    978                 &dad_status, devname) != EOF) {
     979                &dad_status, devname) != EOF
     980        ) {
    979981            if (!strcmp(devname, ptr->name)) {
    980982                sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
     
    985987                sap.sin6_family = AF_INET6;
    986988                printf("          inet6 addr: %s/%d",
    987                        inet6_aftype.sprint((struct sockaddr *) &sap, 1),
     989                       INET6_sprint((struct sockaddr *) &sap, 1),
    988990                       plen);
    989991                printf(" Scope:");
    990992                switch (scope & IPV6_ADDR_SCOPE_MASK) {
    991993                case 0:
    992                     printf("Global");
     994                    puts("Global");
    993995                    break;
    994996                case IPV6_ADDR_LINKLOCAL:
    995                     printf("Link");
     997                    puts("Link");
    996998                    break;
    997999                case IPV6_ADDR_SITELOCAL:
    998                     printf("Site");
     1000                    puts("Site");
    9991001                    break;
    10001002                case IPV6_ADDR_COMPATv4:
    1001                     printf("Compat");
     1003                    puts("Compat");
    10021004                    break;
    10031005                case IPV6_ADDR_LOOPBACK:
    1004                     printf("Host");
     1006                    puts("Host");
    10051007                    break;
    10061008                default:
    1007                     printf("Unknown");
     1009                    puts("Unknown");
    10081010                }
    1009                 printf("\n");
    10101011            }
    10111012        }
     
    10201021        printf("[NO FLAGS] ");
    10211022    } else {
    1022         int i = 0;
     1023        static const char ife_print_flags_strs[] ALIGN1 =
     1024            "UP\0"
     1025            "BROADCAST\0"
     1026            "DEBUG\0"
     1027            "LOOPBACK\0"
     1028            "POINTOPOINT\0"
     1029            "NOTRAILERS\0"
     1030            "RUNNING\0"
     1031            "NOARP\0"
     1032            "PROMISC\0"
     1033            "ALLMULTI\0"
     1034            "SLAVE\0"
     1035            "MASTER\0"
     1036            "MULTICAST\0"
     1037#ifdef HAVE_DYNAMIC
     1038            "DYNAMIC\0"
     1039#endif
     1040            ;
     1041        static const unsigned short ife_print_flags_mask[] ALIGN2 = {
     1042            IFF_UP,
     1043            IFF_BROADCAST,
     1044            IFF_DEBUG,
     1045            IFF_LOOPBACK,
     1046            IFF_POINTOPOINT,
     1047            IFF_NOTRAILERS,
     1048            IFF_RUNNING,
     1049            IFF_NOARP,
     1050            IFF_PROMISC,
     1051            IFF_ALLMULTI,
     1052            IFF_SLAVE,
     1053            IFF_MASTER,
     1054            IFF_MULTICAST
     1055#ifdef HAVE_DYNAMIC
     1056            ,IFF_DYNAMIC
     1057#endif
     1058        };
     1059        const unsigned short *mask = ife_print_flags_mask;
     1060        const char *str = ife_print_flags_strs;
    10231061        do {
    1024             if (ptr->flags & ife_print_flags_mask[i]) {
    1025                 printf(ife_print_flags_strs[i]);
     1062            if (ptr->flags & *mask) {
     1063                printf("%s ", str);
    10261064            }
    1027         } while (ife_print_flags_mask[++i]);
     1065            mask++;
     1066            str += strlen(str) + 1;
     1067        } while (*str);
    10281068    }
    10291069
     
    10341074        printf("  Outfill:%d  Keepalive:%d", ptr->outfill, ptr->keepalive);
    10351075#endif
    1036     printf("\n");
     1076    puts("");
    10371077
    10381078    /* If needed, display the interface statistics. */
     
    10831123        if (ptr->map.dma)
    10841124            printf("DMA chan:%x ", ptr->map.dma);
    1085         printf("\n");
    1086     }
    1087     printf("\n");
    1088 }
    1089 
    1090 
    1091 static int do_if_print(struct interface *ife, void *cookie)
    1092 {
    1093     int *opt_a = (int *) cookie;
     1125        puts("");
     1126    }
     1127    puts("");
     1128}
     1129
     1130
     1131static int do_if_print(struct interface *ife) /*, int *opt_a)*/
     1132{
    10941133    int res;
    10951134
    10961135    res = do_if_fetch(ife);
    10971136    if (res >= 0) {
    1098         if ((ife->flags & IFF_UP) || *opt_a)
     1137        if ((ife->flags & IFF_UP) || interface_opt_a)
    10991138            ife_print(ife);
    11001139    }
     
    11121151}
    11131152
     1153#ifdef UNUSED
     1154static int for_all_interfaces(int (*doit) (struct interface *, void *),
     1155                              void *cookie)
     1156{
     1157    struct interface *ife;
     1158
     1159    if (!int_list && (if_readlist() < 0))
     1160        return -1;
     1161    for (ife = int_list; ife; ife = ife->next) {
     1162        int err = doit(ife, cookie);
     1163
     1164        if (err)
     1165            return err;
     1166    }
     1167    return 0;
     1168}
     1169#endif
     1170
    11141171/* for ipv4 add/del modes */
    11151172static int if_print(char *ifname)
    11161173{
     1174    struct interface *ife;
    11171175    int res;
    11181176
    11191177    if (!ifname) {
    1120         res = for_all_interfaces(do_if_print, &interface_opt_a);
    1121     } else {
    1122         struct interface *ife;
    1123 
    1124         ife = lookup_interface(ifname);
    1125         res = do_if_fetch(ife);
    1126         if (res >= 0)
    1127             ife_print(ife);
    1128     }
     1178        /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
     1179        if (!int_list && (if_readlist() < 0))
     1180            return -1;
     1181        for (ife = int_list; ife; ife = ife->next) {
     1182            int err = do_if_print(ife); /*, &interface_opt_a);*/
     1183            if (err)
     1184                return err;
     1185        }
     1186        return 0;
     1187    }
     1188    ife = lookup_interface(ifname);
     1189    res = do_if_fetch(ife);
     1190    if (res >= 0)
     1191        ife_print(ife);
    11291192    return res;
    11301193}
    11311194
    1132 int display_interfaces(char *ifname);
    11331195int display_interfaces(char *ifname)
    11341196{
    11351197    int status;
    11361198
    1137     /* Create a channel to the NET kernel. */
    1138     if ((skfd = sockets_open(0)) < 0) {
    1139         bb_perror_msg_and_die("socket");
    1140     }
    1141 
    1142     /* Do we have to show the current setup? */
    11431199    status = if_print(ifname);
    1144 #ifdef CONFIG_FEATURE_CLEAN_UP
    1145     sockets_close();
    1146 #endif
    1147     exit(status < 0);
    1148 }
     1200
     1201    return (status < 0); /* status < 0 == 1 -- error */
     1202}
  • branches/stable/mindi-busybox/networking/ip.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ip.c     "ip" utility frontend.
     
    1011 *
    1112 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     13 * Bernhard Fischer rewrote to use index_in_substr_array
    1214 */
    1315
    14 #include <stdio.h>
    15 #include <stdlib.h>
    16 #include <unistd.h>
    17 #include <syslog.h>
    18 #include <fcntl.h>
    19 #include <sys/socket.h>
    20 #include <netinet/in.h>
    21 #include <string.h>
     16#include "libbb.h"
    2217
    2318#include "libiproute/utils.h"
    2419#include "libiproute/ip_common.h"
    2520
    26 #include "busybox.h"
     21#if ENABLE_FEATURE_IP_ADDRESS \
     22 || ENABLE_FEATURE_IP_ROUTE \
     23 || ENABLE_FEATURE_IP_LINK \
     24 || ENABLE_FEATURE_IP_TUNNEL \
     25 || ENABLE_FEATURE_IP_RULE
    2726
    28 #if 0
    29 int preferred_family = AF_UNSPEC;
    30 int oneline = 0;
    31 char * _SL_ = NULL;
     27static int ATTRIBUTE_NORETURN ip_print_help(int ATTRIBUTE_UNUSED ac, char ATTRIBUTE_UNUSED **av)
     28{
     29    bb_show_usage();
     30}
    3231
    33 void ip_parse_common_args(int *argcp, char ***argvp)
     32static int (*ip_func)(int argc, char **argv) = ip_print_help;
     33
     34static int ip_do(int argc, char **argv)
    3435{
    35     int argc = *argcp;
    36     char **argv = *argvp;
     36    ip_parse_common_args(&argc, &argv);
     37    return ip_func(argc-1, argv+1);
     38}
    3739
    38     while (argc > 1) {
    39         char *opt = argv[1];
    40 
    41         if (strcmp(opt,"--") == 0) {
    42             argc--; argv++;
    43             break;
    44         }
    45 
    46         if (opt[0] != '-')
    47             break;
    48 
    49         if (opt[1] == '-')
    50             opt++;
    51 
    52         if (matches(opt, "-family") == 0) {
    53             argc--;
    54             argv++;
    55             if (strcmp(argv[1], "inet") == 0)
    56                 preferred_family = AF_INET;
    57             else if (strcmp(argv[1], "inet6") == 0)
    58                 preferred_family = AF_INET6;
    59             else if (strcmp(argv[1], "link") == 0)
    60                 preferred_family = AF_PACKET;
    61             else
    62                 invarg(bb_msg_invalid_arg, argv[1], "-family");
    63         } else if (strcmp(opt, "-4") == 0) {
    64             preferred_family = AF_INET;
    65         } else if (strcmp(opt, "-6") == 0) {
    66             preferred_family = AF_INET6;
    67         } else if (strcmp(opt, "-0") == 0) {
    68             preferred_family = AF_PACKET;
    69         } else if (matches(opt, "-oneline") == 0) {
    70             ++oneline;
    71         } else {
    72             bb_show_usage();
    73         }
    74         argc--; argv++;
    75     }
    76     _SL_ = oneline ? "\\" : "\n" ;
     40#if ENABLE_FEATURE_IP_ADDRESS
     41int ipaddr_main(int argc, char **argv);
     42int ipaddr_main(int argc, char **argv)
     43{
     44    ip_func = do_ipaddr;
     45    return ip_do(argc, argv);
     46}
     47#endif
     48#if ENABLE_FEATURE_IP_LINK
     49int iplink_main(int argc, char **argv);
     50int iplink_main(int argc, char **argv)
     51{
     52    ip_func = do_iplink;
     53    return ip_do(argc, argv);
     54}
     55#endif
     56#if ENABLE_FEATURE_IP_ROUTE
     57int iproute_main(int argc, char **argv);
     58int iproute_main(int argc, char **argv)
     59{
     60    ip_func = do_iproute;
     61    return ip_do(argc, argv);
     62}
     63#endif
     64#if ENABLE_FEATURE_IP_RULE
     65int iprule_main(int argc, char **argv);
     66int iprule_main(int argc, char **argv)
     67{
     68    ip_func = do_iprule;
     69    return ip_do(argc, argv);
     70}
     71#endif
     72#if ENABLE_FEATURE_IP_TUNNEL
     73int iptunnel_main(int argc, char **argv);
     74int iptunnel_main(int argc, char **argv)
     75{
     76    ip_func = do_iptunnel;
     77    return ip_do(argc, argv);
    7778}
    7879#endif
    7980
     81
     82int ip_main(int argc, char **argv);
    8083int ip_main(int argc, char **argv)
    8184{
    82     int ret = EXIT_FAILURE;
     85    static const char keywords[] ALIGN1 =
     86        USE_FEATURE_IP_ADDRESS("address\0")
     87        USE_FEATURE_IP_ROUTE("route\0")
     88        USE_FEATURE_IP_LINK("link\0")
     89        USE_FEATURE_IP_TUNNEL("tunnel\0" "tunl\0")
     90        USE_FEATURE_IP_RULE("rule\0")
     91        ;
     92    enum {
     93        USE_FEATURE_IP_ADDRESS(IP_addr,)
     94        USE_FEATURE_IP_ROUTE(IP_route,)
     95        USE_FEATURE_IP_LINK(IP_link,)
     96        USE_FEATURE_IP_TUNNEL(IP_tunnel, IP_tunl,)
     97        USE_FEATURE_IP_RULE(IP_rule,)
     98        IP_none
     99    };
    83100
    84101    ip_parse_common_args(&argc, &argv);
    85 
    86102    if (argc > 1) {
    87 #ifdef CONFIG_FEATURE_IP_ADDRESS
    88         if (matches(argv[1], "address") == 0) {
    89             ret = do_ipaddr(argc-2, argv+2);
    90         }
     103        int key = index_in_substrings(keywords, argv[1]);
     104        argc -= 2;
     105        argv += 2;
     106#if ENABLE_FEATURE_IP_ADDRESS
     107        if (key == IP_addr)
     108            ip_func = do_ipaddr;
    91109#endif
    92 #ifdef CONFIG_FEATURE_IP_ROUTE
    93         if (matches(argv[1], "route") == 0) {
    94             ret = do_iproute(argc-2, argv+2);
    95         }
     110#if ENABLE_FEATURE_IP_ROUTE
     111        if (key == IP_route)
     112            ip_func = do_iproute;
    96113#endif
    97 #ifdef CONFIG_FEATURE_IP_LINK
    98         if (matches(argv[1], "link") == 0) {
    99             ret = do_iplink(argc-2, argv+2);
    100         }
     114#if ENABLE_FEATURE_IP_LINK
     115        if (key == IP_link)
     116            ip_func = do_iplink;
    101117#endif
    102 #ifdef CONFIG_FEATURE_IP_TUNNEL
    103         if (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0) {
    104             ret = do_iptunnel(argc-2, argv+2);
    105         }
     118#if ENABLE_FEATURE_IP_TUNNEL
     119        if (key == IP_tunnel || key == IP_tunl)
     120            ip_func = do_iptunnel;
     121#endif
     122#if ENABLE_FEATURE_IP_RULE
     123        if (key == IP_rule)
     124            ip_func = do_iprule;
    106125#endif
    107126    }
    108     if (ret) {
    109         bb_show_usage();
    110     }
    111     return(EXIT_SUCCESS);
     127    return ip_func(argc, argv);
    112128}
     129
     130#endif /* any of ENABLE_FEATURE_IP_xxx is 1 */
  • branches/stable/mindi-busybox/networking/ipcalc.c

    r821 r1770  
    1 /* vi: set sw=4 ts=4 ai: */
     1/* vi: set sw=4 ts=4: */
    22/*
    33 * Mini ipcalc implementation for busybox
     
    1313 */
    1414
    15 #include "busybox.h"
    16 #include <ctype.h>
    1715#include <getopt.h>
    1816#include <sys/socket.h>
    1917#include <arpa/inet.h>
    2018
    21 #define IPCALC_MSG(CMD,ALTCMD) if (mode & SILENT) {ALTCMD;} else {CMD;}
     19#include "libbb.h"
    2220
    2321#define CLASS_A_NETMASK ntohl(0xFF000000)
     
    3937}
    4038
    41 #ifdef CONFIG_FEATURE_IPCALC_FANCY
     39#if ENABLE_FEATURE_IPCALC_FANCY
    4240static int get_prefix(unsigned long netmask)
    4341{
     
    4644
    4745    netmask = htonl(netmask);
    48     while(msk) {
     46    while (msk) {
    4947        if (netmask & msk)
    5048            ret++;
     
    5755#endif
    5856
     57
    5958#define NETMASK   0x01
    6059#define BROADCAST 0x02
     
    6564
    6665#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
    67     static const struct option long_options[] = {
    68         {"netmask",     no_argument, NULL, 'm'},
    69         {"broadcast",   no_argument, NULL, 'b'},
    70         {"network",     no_argument, NULL, 'n'},
    71 #ifdef CONFIG_FEATURE_IPCALC_FANCY
    72         {"prefix",      no_argument, NULL, 'p'},
    73         {"hostname",    no_argument, NULL, 'h'},
    74         {"silent",      no_argument, NULL, 's'},
    75 #endif
    76         {NULL, 0, NULL, 0}
    77     };
    78 #else
    79 #define long_options 0
     66    static const char ipcalc_longopts[] ALIGN1 =
     67        "netmask\0"   No_argument "m"
     68        "broadcast\0" No_argument "b"
     69        "network\0"   No_argument "n"
     70# if ENABLE_FEATURE_IPCALC_FANCY
     71        "prefix\0"    No_argument "p"
     72        "hostname\0"  No_argument "h"
     73        "silent\0"    No_argument "s"
     74# endif
     75        ;
    8076#endif
    8177
    82 
    83 
     78int ipcalc_main(int argc, char **argv);
    8479int ipcalc_main(int argc, char **argv)
    8580{
    86     unsigned long mode;
     81    unsigned opt;
    8782    int have_netmask = 0;
    8883    in_addr_t netmask, broadcast, network, ipaddr;
     
    9085    char *ipstr;
    9186
    92     if (ENABLE_FEATURE_IPCALC_LONG_OPTIONS)
    93         bb_applet_long_options = long_options;
    94 
    95     mode = bb_getopt_ulflags(argc, argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs"));
    96 
     87#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
     88    applet_long_options = ipcalc_longopts;
     89#endif
     90    opt = getopt32(argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs"));
    9791    argc -= optind;
    9892    argv += optind;
    99     if (mode & (BROADCAST | NETWORK | NETPREFIX)) {
     93    if (opt & (BROADCAST | NETWORK | NETPREFIX)) {
    10094        if (argc > 2 || argc <= 0)
    10195            bb_show_usage();
     
    10498            bb_show_usage();
    10599    }
     100    if (opt & SILENT)
     101        logmode = LOGMODE_NONE; /* Suppress error_msg() output */
    106102
    107103    ipstr = argv[0];
     
    112108        prefixstr = ipstr;
    113109
    114         while(*prefixstr) {
     110        while (*prefixstr) {
    115111            if (*prefixstr == '/') {
    116112                *prefixstr = (char)0;
    117113                prefixstr++;
    118114                if (*prefixstr) {
    119                     unsigned int msk;
    120 
    121                     if (safe_strtoul(prefixstr, &netprefix) || netprefix > 32) {
    122                         IPCALC_MSG(bb_error_msg_and_die("bad IP prefix: %s\n", prefixstr),
    123                                 exit(EXIT_FAILURE));
    124                     }
     115                    unsigned msk;
     116                    netprefix = xatoul_range(prefixstr, 0, 32);
    125117                    netmask = 0;
    126118                    msk = 0x80000000;
     
    143135
    144136    if (ipaddr == 0) {
    145         IPCALC_MSG(bb_error_msg_and_die("bad IP address: %s", argv[0]),
    146                 exit(EXIT_FAILURE));
     137        bb_error_msg_and_die("bad IP address: %s", argv[0]);
    147138    }
    148139    ipaddr = a.s_addr;
     
    150141    if (argc == 2) {
    151142        if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) {
    152             IPCALC_MSG(bb_error_msg_and_die("Use prefix or netmask, not both.\n"),
    153                     exit(EXIT_FAILURE));
     143            bb_error_msg_and_die("use prefix or netmask, not both");
    154144        }
    155145
    156146        netmask = inet_aton(argv[1], &a);
    157147        if (netmask == 0) {
    158             IPCALC_MSG(bb_error_msg_and_die("bad netmask: %s", argv[1]),
    159                     exit(EXIT_FAILURE));
     148            bb_error_msg_and_die("bad netmask: %s", argv[1]);
    160149        }
    161150        netmask = a.s_addr;
     
    167156    }
    168157
    169     if (mode & NETMASK) {
     158    if (opt & NETMASK) {
    170159        printf("NETMASK=%s\n", inet_ntoa((*(struct in_addr *) &netmask)));
    171160    }
    172161
    173     if (mode & BROADCAST) {
     162    if (opt & BROADCAST) {
    174163        broadcast = (ipaddr & netmask) | ~netmask;
    175164        printf("BROADCAST=%s\n", inet_ntoa((*(struct in_addr *) &broadcast)));
    176165    }
    177166
    178     if (mode & NETWORK) {
     167    if (opt & NETWORK) {
    179168        network = ipaddr & netmask;
    180169        printf("NETWORK=%s\n", inet_ntoa((*(struct in_addr *) &network)));
     
    182171
    183172    if (ENABLE_FEATURE_IPCALC_FANCY) {
    184         if (mode & NETPREFIX) {
     173        if (opt & NETPREFIX) {
    185174            printf("PREFIX=%i\n", get_prefix(netmask));
    186175        }
    187176
    188         if (mode & HOSTNAME) {
     177        if (opt & HOSTNAME) {
    189178            struct hostent *hostinfo;
    190179            int x;
     
    192181            hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET);
    193182            if (!hostinfo) {
    194                 IPCALC_MSG(bb_herror_msg_and_die(
    195                             "cannot find hostname for %s", argv[0]),);
    196                 exit(EXIT_FAILURE);
     183                bb_herror_msg_and_die("cannot find hostname for %s", argv[0]);
    197184            }
    198185            for (x = 0; hostinfo->h_name[x]; x++) {
  • branches/stable/mindi-busybox/networking/libiproute/ip_common.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12#ifndef _IP_COMMON_H
    23#define _IP_COMMON_H 1
    34
    4 #include "busybox.h"
     5#include "libbb.h"
    56#include <asm/types.h>
    67#include <linux/netlink.h>
    78#include <linux/rtnetlink.h>
    8 
    9 
    10 extern int preferred_family;
    11 extern char * _SL_;
     9#if !defined IFA_RTA
     10#include <linux/if_addr.h>
     11#endif
     12#if !defined IFLA_RTA
     13#include <linux/if_link.h>
     14#endif
    1215
    1316extern void ip_parse_common_args(int *argcp, char ***argvp);
     
    1720extern void iplink_usage(void) ATTRIBUTE_NORETURN;
    1821extern void ipneigh_reset_filter(void);
     22
    1923extern int do_ipaddr(int argc, char **argv);
    2024extern int do_iproute(int argc, char **argv);
  • branches/stable/mindi-busybox/networking/libiproute/ip_parse_common_args.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ip.c     "ip" utility frontend.
     
    1516 */
    1617
    17 #include <string.h>
    18 
    19 #include "libbb.h"
     18#include "ip_common.h"  /* #include "libbb.h" is inside */
    2019#include "utils.h"
    21 #include "ip_common.h"
    22 
    2320
    2421int preferred_family = AF_UNSPEC;
    25 int oneline = 0;
    26 char * _SL_ = NULL;
     22smallint oneline;
     23char _SL_;
    2724
    2825void ip_parse_common_args(int *argcp, char ***argvp)
     
    3027    int argc = *argcp;
    3128    char **argv = *argvp;
     29    static const char ip_common_commands[] ALIGN1 =
     30        "-family\0""inet\0""inet6\0""link\0"
     31        "-4\0""-6\0""-0\0""-oneline\0";
     32    enum {
     33        ARG_family = 1,
     34        ARG_inet,
     35        ARG_inet6,
     36        ARG_link,
     37        ARG_IPv4,
     38        ARG_IPv6,
     39        ARG_packet,
     40        ARG_oneline
     41    };
     42    smalluint arg;
    3243
    3344    while (argc > 1) {
     
    3546
    3647        if (strcmp(opt,"--") == 0) {
    37             argc--; argv++;
     48            argc--;
     49            argv++;
    3850            break;
    3951        }
    40 
    4152        if (opt[0] != '-')
    4253            break;
    43 
    4454        if (opt[1] == '-')
    4555            opt++;
    46 
    47         if (matches(opt, "-family") == 0) {
     56        arg = index_in_strings(ip_common_commands, opt) + 1;
     57        if (arg == ARG_family) {
    4858            argc--;
    4959            argv++;
    50             if (! argv[1])
    51                 bb_show_usage();
    52             if (strcmp(argv[1], "inet") == 0)
     60            if (!argv[1])
     61                bb_show_usage();
     62            arg = index_in_strings(ip_common_commands, argv[1]) + 1;
     63            if (arg == ARG_inet)
    5364                preferred_family = AF_INET;
    54             else if (strcmp(argv[1], "inet6") == 0)
     65            else if (arg == ARG_inet6)
    5566                preferred_family = AF_INET6;
    56             else if (strcmp(argv[1], "link") == 0)
     67            else if (arg == ARG_link)
    5768                preferred_family = AF_PACKET;
    5869            else
    5970                invarg(argv[1], "protocol family");
    60         } else if (strcmp(opt, "-4") == 0) {
     71        } else if (arg == ARG_IPv4) {
    6172            preferred_family = AF_INET;
    62         } else if (strcmp(opt, "-6") == 0) {
     73        } else if (arg == ARG_IPv6) {
    6374            preferred_family = AF_INET6;
    64         } else if (strcmp(opt, "-0") == 0) {
     75        } else if (arg == ARG_packet) {
    6576            preferred_family = AF_PACKET;
    66         } else if (matches(opt, "-oneline") == 0) {
     77        } else if (arg == ARG_oneline) {
    6778            ++oneline;
    6879        } else {
    6980            bb_show_usage();
    7081        }
    71         argc--; argv++;
     82        argc--;
     83        argv++;
    7284    }
    73     _SL_ = oneline ? "\\" : "\n" ;
     85    _SL_ = oneline ? '\\' : '\n';
    7486    *argcp = argc;
    7587    *argvp = argv;
  • branches/stable/mindi-busybox/networking/libiproute/ipaddress.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ipaddress.c      "ip address".
     
    1011 */
    1112
    12 #include "libbb.h"
    13 #include <sys/socket.h>
    14 #include <sys/ioctl.h>
    15 
     13//#include <sys/socket.h>
     14//#include <sys/ioctl.h>
    1615#include <fnmatch.h>
    17 #include <string.h>
    18 #include <unistd.h>
    19 
    2016#include <net/if.h>
    2117#include <net/if_arp.h>
    2218
     19#include "ip_common.h"  /* #include "libbb.h" is inside */
    2320#include "rt_names.h"
    2421#include "utils.h"
    25 #include "ip_common.h"
    26 
    27 
    28 static struct
    29 {
     22
     23
     24typedef struct filter_t {
    3025    int ifindex;
    3126    int family;
     
    4237    int flushe;
    4338    struct rtnl_handle *rth;
    44 } filter;
     39} filter_t;
     40
     41#define filter (*(filter_t*)&bb_common_bufsiz1)
     42
    4543
    4644static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
     
    4947    flags &= ~IFF_RUNNING;
    5048#define _PF(f) if (flags&IFF_##f) { \
    51           flags &= ~IFF_##f ; \
     49          flags &= ~IFF_##f; \
    5250          fprintf(fp, #f "%s", flags ? "," : ""); }
    5351    _PF(LOOPBACK);
     
    8684
    8785    memset(&ifr, 0, sizeof(ifr));
    88     strcpy(ifr.ifr_name, name);
    89     if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
    90         perror("SIOCGIFXQLEN");
     86    strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
     87    if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) {
    9188        close(s);
    9289        return;
     
    9996
    10097static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
    101         struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
     98        const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
    10299{
    103100    FILE *fp = (FILE*)arg;
     
    125122        return -1;
    126123    }
    127     if (filter.label &&
    128         (!filter.family || filter.family == AF_PACKET) &&
    129         fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
    130         return 0;
     124    if (filter.label
     125     && (!filter.family || filter.family == AF_PACKET)
     126     && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)
     127    ) {
     128        return 0;
     129    }
    131130
    132131    if (n->nlmsg_type == RTM_DELLINK)
     
    166165    if (!filter.family || filter.family == AF_PACKET) {
    167166        SPRINT_BUF(b1);
    168         fprintf(fp, "%s", _SL_);
    169         fprintf(fp, "    link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
     167        fprintf(fp, "%c    link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
    170168
    171169        if (tb[IFLA_ADDRESS]) {
     
    186184        }
    187185    }
    188     fprintf(fp, "\n");
     186    fputc('\n', fp);
    189187    fflush(fp);
    190188    return 0;
     
    194192{
    195193    if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
    196         perror("Failed to send flush request\n");
     194        bb_perror_msg("failed to send flush request");
    197195        return -1;
    198196    }
     
    341339        struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
    342340        char buf[128];
    343         fprintf(fp, "%s", _SL_);
     341        fputc(_SL_, fp);
    344342        if (ci->ifa_valid == 0xFFFFFFFFU)
    345343            sprintf(buf, "valid_lft forever");
     
    352350        fprintf(fp, "       %s", buf);
    353351    }
    354     fprintf(fp, "\n");
     352    fputc('\n', fp);
    355353    fflush(fp);
    356354    return 0;
     
    366364static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
    367365{
    368     for ( ;ainfo ; ainfo = ainfo->next) {
     366    for (; ainfo; ainfo = ainfo->next) {
    369367        struct nlmsghdr *n = &ainfo->h;
    370368        struct ifaddrmsg *ifa = NLMSG_DATA(n);
     
    412410}
    413411
     412/* Return value becomes exitcode. It's okay to not return at all */
    414413int ipaddr_list_or_flush(int argc, char **argv, int flush)
    415414{
    416     static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 };
     415    static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0";
    417416
    418417    struct nlmsg_list *linfo = NULL;
     
    431430    if (flush) {
    432431        if (argc <= 0) {
    433             bb_error_msg(bb_msg_requires_arg, "flush");
    434             return -1;
     432            bb_error_msg_and_die(bb_msg_requires_arg, "flush");
    435433        }
    436434        if (filter.family == AF_PACKET) {
    437             bb_error_msg("Cannot flush link addresses.");
    438             return -1;
     435            bb_error_msg_and_die("cannot flush link addresses");
    439436        }
    440437    }
    441438
    442439    while (argc > 0) {
    443         const int option_num = compare_string_array(option, *argv);
     440        const int option_num = index_in_strings(option, *argv);
    444441        switch (option_num) {
    445442            case 0: /* to */
     
    484481    }
    485482
    486     if (rtnl_open(&rth, 0) < 0)
    487         exit(1);
    488 
    489     if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
    490         bb_perror_msg_and_die("Cannot send dump request");
    491     }
    492 
    493     if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
    494         bb_error_msg_and_die("Dump terminated");
    495     }
     483    xrtnl_open(&rth);
     484
     485    xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK);
     486    xrtnl_dump_filter(&rth, store_nlmsg, &linfo);
    496487
    497488    if (filter_dev) {
    498         filter.ifindex = ll_name_to_index(filter_dev);
    499         if (filter.ifindex <= 0) {
    500             bb_error_msg("Device \"%s\" does not exist", filter_dev);
    501             return -1;
    502         }
     489        filter.ifindex = xll_name_to_index(filter_dev);
    503490    }
    504491
     
    512499
    513500        for (;;) {
    514             if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
    515                 perror("Cannot send dump request");
    516                 exit(1);
    517             }
     501            xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR);
    518502            filter.flushed = 0;
    519             if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
    520                 fprintf(stderr, "Flush terminated\n");
    521                 exit(1);
    522             }
     503            xrtnl_dump_filter(&rth, print_addrinfo, stdout);
    523504            if (filter.flushed == 0) {
    524                 fflush(stdout);
    525505                return 0;
    526506            }
    527507            if (flush_update() < 0)
    528                 exit(1);
     508                return 1;
    529509        }
    530510    }
    531511
    532512    if (filter.family != AF_PACKET) {
    533         if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
    534             bb_perror_msg_and_die("Cannot send dump request");
    535         }
    536 
    537         if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) {
    538             bb_error_msg_and_die("Dump terminated");
    539         }
     513        xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR);
     514        xrtnl_dump_filter(&rth, store_nlmsg, &ainfo);
    540515    }
    541516
     
    601576    }
    602577
    603     for (l=linfo; l; l = l->next) {
     578    for (l = linfo; l; l = l->next) {
    604579        if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
    605580            struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
     
    607582                print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
    608583        }
    609         fflush(stdout);
    610     }
    611 
    612     exit(0);
     584        fflush(stdout); /* why? */
     585    }
     586
     587    return 0;
    613588}
    614589
     
    616591{
    617592    if (lcl->family == AF_INET) {
    618         if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
     593        if (lcl->bytelen >= 1 && *(uint8_t*)&lcl->data == 127)
    619594            return RT_SCOPE_HOST;
    620595    }
     
    622597}
    623598
     599/* Return value becomes exitcode. It's okay to not return at all */
    624600static int ipaddr_modify(int cmd, int argc, char **argv)
    625601{
    626     static const char *const option[] = {
    627         "peer", "remote", "broadcast", "brd",
    628         "anycast", "scope", "dev", "label", "local", 0
    629     };
    630 
     602    static const char option[] ALIGN1 =
     603        "peer\0""remote\0""broadcast\0""brd\0"
     604        "anycast\0""scope\0""dev\0""label\0""local\0";
    631605    struct rtnl_handle rth;
    632606    struct {
    633         struct nlmsghdr     n;
    634         struct ifaddrmsg    ifa;
    635         char            buf[256];
     607        struct nlmsghdr  n;
     608        struct ifaddrmsg ifa;
     609        char             buf[256];
    636610    } req;
    637     char  *d = NULL;
    638     char  *l = NULL;
     611    char *d = NULL;
     612    char *l = NULL;
    639613    inet_prefix lcl;
    640614    inet_prefix peer;
     
    643617    int brd_len = 0;
    644618    int any_len = 0;
    645     int scoped = 0;
     619    bool scoped = 0;
    646620
    647621    memset(&req, 0, sizeof(req));
     
    653627
    654628    while (argc > 0) {
    655         const int option_num = compare_string_array(option, *argv);
     629        const int option_num = index_in_strings(option, *argv);
    656630        switch (option_num) {
    657631            case 0: /* peer */
     
    678652                    duparg("broadcast", *argv);
    679653                }
    680                 if (strcmp(*argv, "+") == 0) {
     654                if (LONE_CHAR(*argv, '+')) {
    681655                    brd_len = -1;
    682656                }
    683                 else if (strcmp(*argv, "-") == 0) {
     657                else if (LONE_DASH(*argv)) {
    684658                    brd_len = -2;
    685659                } else {
     
    748722        return -1;
    749723    }
    750     if (l && matches(d, l) != 0) {
     724    if (l && strncmp(d, l, strlen(d)) != 0) {
    751725        bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l);
    752726    }
     
    763737        int i;
    764738        if (req.ifa.ifa_family != AF_INET) {
    765             bb_error_msg("Broadcast can be set only for IPv4 addresses");
    766             return -1;
     739            bb_error_msg_and_die("broadcast can be set only for IPv4 addresses");
    767740        }
    768741        brd = peer;
     
    781754        req.ifa.ifa_scope = default_scope(&lcl);
    782755
    783     if (rtnl_open(&rth, 0) < 0)
    784         exit(1);
     756    xrtnl_open(&rth);
    785757
    786758    ll_init_map(&rth);
    787759
    788     if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
    789         bb_error_msg("Cannot find device \"%s\"", d);
    790         return -1;
    791     }
     760    req.ifa.ifa_index = xll_name_to_index(d);
    792761
    793762    if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
    794         exit(2);
    795 
    796     exit(0);
    797 }
    798 
     763        return 2;
     764
     765    return 0;
     766}
     767
     768/* Return value becomes exitcode. It's okay to not return at all */
    799769int do_ipaddr(int argc, char **argv)
    800770{
    801     static const char *const commands[] = {
    802         "add", "delete", "list", "show", "lst", "flush", 0
    803     };
    804 
    805     int command_num = 2;
     771    static const char commands[] ALIGN1 =
     772        "add\0""delete\0""list\0""show\0""lst\0""flush\0";
     773
     774    int command_num = 2; /* default command is list */
    806775
    807776    if (*argv) {
    808         command_num = compare_string_array(commands, *argv);
    809     }
    810     switch (command_num) {
    811         case 0: /* add */
    812             return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1);
    813         case 1: /* delete */
    814             return ipaddr_modify(RTM_DELADDR, argc-1, argv+1);
    815         case 2: /* list */
    816         case 3: /* show */
    817         case 4: /* lst */
    818             return ipaddr_list_or_flush(argc-1, argv+1, 0);
    819         case 5: /* flush */
    820             return ipaddr_list_or_flush(argc-1, argv+1, 1);
    821     }
    822     bb_error_msg_and_die("Unknown command %s", *argv);
    823 }
     777        command_num = index_in_substrings(commands, *argv);
     778    }
     779    if (command_num < 0 || command_num > 5)
     780        bb_error_msg_and_die("unknown command %s", *argv);
     781    --argc;
     782    ++argv;
     783    if (command_num == 0) /* add */
     784        return ipaddr_modify(RTM_NEWADDR, argc, argv);
     785    else if (command_num == 1) /* delete */
     786        return ipaddr_modify(RTM_DELADDR, argc, argv);
     787    else if (command_num == 5) /* flush */
     788        return ipaddr_list_or_flush(argc, argv, 1);
     789    else /* 2 == list, 3 == show, 4 == lst */
     790        return ipaddr_list_or_flush(argc, argv, 0);
     791}
  • branches/stable/mindi-busybox/networking/libiproute/iplink.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    2  * iplink.c     "ip link".
     3 * iplink.c "ip link".
    34 *
    4  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    56 *
    67 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    78 */
    89
    9 #include "libbb.h"
    10 
    11 #include <sys/ioctl.h>
    12 #include <sys/socket.h>
    13 
    14 #include <errno.h>
    15 #include <string.h>
    16 #include <unistd.h>
    17 
     10//#include <sys/ioctl.h>
     11//#include <sys/socket.h>
    1812#include <net/if.h>
    1913#include <net/if_packet.h>
    2014#include <netpacket/packet.h>
    21 
    2215#include <net/ethernet.h>
    2316
     17#include "ip_common.h"  /* #include "libbb.h" is inside */
    2418#include "rt_names.h"
    2519#include "utils.h"
    26 #include "ip_common.h"
    27 
    28 /* take from linux/sockios.h */
     20
     21/* taken from linux/sockios.h */
    2922#define SIOCSIFNAME 0x8923      /* set interface name */
    3023
    31 static int do_link;
    32 
    33 static int on_off(char *msg)
    34 {
    35     bb_error_msg("Error: argument of \"%s\" must be \"on\" or \"off\"", msg);
    36     return -1;
    37 }
    38 
     24static void on_off(const char *msg) ATTRIBUTE_NORETURN;
     25static void on_off(const char *msg)
     26{
     27    bb_error_msg_and_die("error: argument of \"%s\" must be \"on\" or \"off\"", msg);
     28}
     29
     30/* Exits on error */
    3931static int get_ctl_fd(void)
    4032{
    41     int s_errno;
    4233    int fd;
    4334
     
    4536    if (fd >= 0)
    4637        return fd;
    47     s_errno = errno;
    4838    fd = socket(PF_PACKET, SOCK_DGRAM, 0);
    4939    if (fd >= 0)
    5040        return fd;
    51     fd = socket(PF_INET6, SOCK_DGRAM, 0);
    52     if (fd >= 0)
    53         return fd;
    54     errno = s_errno;
    55     perror("Cannot create control socket");
    56     return -1;
    57 }
    58 
    59 static int do_chflags(char *dev, __u32 flags, __u32 mask)
     41    return xsocket(PF_INET6, SOCK_DGRAM, 0);
     42}
     43
     44/* Exits on error */
     45static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
    6046{
    6147    struct ifreq ifr;
    6248    int fd;
    63     int err;
    64 
    65     strcpy(ifr.ifr_name, dev);
     49
     50    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
    6651    fd = get_ctl_fd();
    67     if (fd < 0)
    68         return -1;
    69     err = ioctl(fd, SIOCGIFFLAGS, &ifr);
    70     if (err) {
    71         perror("SIOCGIFFLAGS");
    72         close(fd);
    73         return -1;
    74     }
    75     if ((ifr.ifr_flags^flags)&mask) {
     52    xioctl(fd, SIOCGIFFLAGS, &ifr);
     53    if ((ifr.ifr_flags ^ flags) & mask) {
    7654        ifr.ifr_flags &= ~mask;
    77         ifr.ifr_flags |= mask&flags;
    78         err = ioctl(fd, SIOCSIFFLAGS, &ifr);
    79         if (err)
    80             perror("SIOCSIFFLAGS");
     55        ifr.ifr_flags |= mask & flags;
     56        xioctl(fd, SIOCSIFFLAGS, &ifr);
    8157    }
    8258    close(fd);
    83     return err;
    84 }
    85 
    86 static int do_changename(char *dev, char *newdev)
     59}
     60
     61/* Exits on error */
     62static void do_changename(char *dev, char *newdev)
    8763{
    8864    struct ifreq ifr;
    8965    int fd;
    90     int err;
    91 
    92     strcpy(ifr.ifr_name, dev);
    93     strcpy(ifr.ifr_newname, newdev);
     66
     67    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     68    strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));
    9469    fd = get_ctl_fd();
    95     if (fd < 0)
    96         return -1;
    97     err = ioctl(fd, SIOCSIFNAME, &ifr);
    98     if (err) {
    99         perror("SIOCSIFNAME");
    100         close(fd);
    101         return -1;
    102     }
     70    xioctl(fd, SIOCSIFNAME, &ifr);
    10371    close(fd);
    104     return err;
    105 }
    106 
    107 static int set_qlen(char *dev, int qlen)
     72}
     73
     74/* Exits on error */
     75static void set_qlen(char *dev, int qlen)
    10876{
    10977    struct ifreq ifr;
     
    11179
    11280    s = get_ctl_fd();
    113     if (s < 0)
    114         return -1;
    115 
    11681    memset(&ifr, 0, sizeof(ifr));
    117     strcpy(ifr.ifr_name, dev);
     82    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
    11883    ifr.ifr_qlen = qlen;
    119     if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
    120         perror("SIOCSIFXQLEN");
    121         close(s);
    122         return -1;
    123     }
    124     close(s);
    125 
    126     return 0;
    127 }
    128 
    129 static int set_mtu(char *dev, int mtu)
     84    xioctl(s, SIOCSIFTXQLEN, &ifr);
     85    close(s);
     86}
     87
     88/* Exits on error */
     89static void set_mtu(char *dev, int mtu)
    13090{
    13191    struct ifreq ifr;
     
    13393
    13494    s = get_ctl_fd();
    135     if (s < 0)
    136         return -1;
    137 
    13895    memset(&ifr, 0, sizeof(ifr));
    139     strcpy(ifr.ifr_name, dev);
     96    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
    14097    ifr.ifr_mtu = mtu;
    141     if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
    142         perror("SIOCSIFMTU");
    143         close(s);
    144         return -1;
    145     }
    146     close(s);
    147 
    148     return 0;
    149 }
    150 
     98    xioctl(s, SIOCSIFMTU, &ifr);
     99    close(s);
     100}
     101
     102/* Exits on error */
    151103static int get_address(char *dev, int *htype)
    152104{
     
    156108    int s;
    157109
    158     s = socket(PF_PACKET, SOCK_DGRAM, 0);
    159     if (s < 0) {
    160         perror("socket(PF_PACKET)");
    161         return -1;
    162     }
     110    s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
    163111
    164112    memset(&ifr, 0, sizeof(ifr));
    165     strcpy(ifr.ifr_name, dev);
    166     if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
    167         perror("SIOCGIFINDEX");
    168         close(s);
    169         return -1;
    170     }
     113    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     114    xioctl(s, SIOCGIFINDEX, &ifr);
    171115
    172116    memset(&me, 0, sizeof(me));
     
    174118    me.sll_ifindex = ifr.ifr_ifindex;
    175119    me.sll_protocol = htons(ETH_P_LOOP);
    176     if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
    177         perror("bind");
    178         close(s);
    179         return -1;
    180     }
     120    xbind(s, (struct sockaddr*)&me, sizeof(me));
    181121
    182122    alen = sizeof(me);
    183123    if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
    184         perror("getsockname");
    185         close(s);
    186         return -1;
     124        bb_perror_msg_and_die("getsockname");
    187125    }
    188126    close(s);
     
    191129}
    192130
    193 static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
     131/* Exits on error */
     132static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
    194133{
    195134    int alen;
    196135
    197136    memset(ifr, 0, sizeof(*ifr));
    198     strcpy(ifr->ifr_name, dev);
     137    strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name));
    199138    ifr->ifr_hwaddr.sa_family = hatype;
    200139    alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla);
    201140    if (alen < 0)
    202         return -1;
     141        exit(1);
    203142    if (alen != halen) {
    204         bb_error_msg("Wrong address (%s) length: expected %d bytes", lla, halen);
    205         return -1;
    206     }
    207     return 0;
    208 }
    209 
    210 static int set_address(struct ifreq *ifr, int brd)
     143        bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
     144    }
     145}
     146
     147/* Exits on error */
     148static void set_address(struct ifreq *ifr, int brd)
    211149{
    212150    int s;
    213151
    214152    s = get_ctl_fd();
    215     if (s < 0)
    216         return -1;
    217     if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
    218         perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
    219         close(s);
    220         return -1;
    221     }
    222     close(s);
    223     return 0;
    224 }
    225 
    226 
     153    if (brd)
     154        xioctl(s, SIOCSIFHWBROADCAST, ifr);
     155    else
     156        xioctl(s, SIOCSIFHWADDR, ifr);
     157    close(s);
     158}
     159
     160
     161/* Return value becomes exitcode. It's okay to not return at all */
    227162static int do_set(int argc, char **argv)
    228163{
    229164    char *dev = NULL;
    230     __u32 mask = 0;
    231     __u32 flags = 0;
     165    uint32_t mask = 0;
     166    uint32_t flags = 0;
    232167    int qlen = -1;
    233168    int mtu = -1;
     
    237172    char *newname = NULL;
    238173    int htype, halen;
     174    static const char keywords[] ALIGN1 =
     175        "up\0""down\0""name\0""mtu\0""multicast\0""arp\0""addr\0""dev\0"
     176        "on\0""off\0";
     177    enum { ARG_up = 1, ARG_down, ARG_name, ARG_mtu, ARG_multicast, ARG_arp,
     178        ARG_addr, ARG_dev, PARM_on, PARM_off };
     179    smalluint key;
    239180
    240181    while (argc > 0) {
    241         if (strcmp(*argv, "up") == 0) {
     182        key = index_in_strings(keywords, *argv) + 1;
     183        if (key == ARG_up) {
    242184            mask |= IFF_UP;
    243185            flags |= IFF_UP;
    244         } else if (strcmp(*argv, "down") == 0) {
     186        } else if (key == ARG_down) {
    245187            mask |= IFF_UP;
    246188            flags &= ~IFF_UP;
    247         } else if (strcmp(*argv, "name") == 0) {
     189        } else if (key == ARG_name) {
    248190            NEXT_ARG();
    249191            newname = *argv;
    250         } else if (strcmp(*argv, "mtu") == 0) {
     192        } else if (key == ARG_mtu) {
    251193            NEXT_ARG();
    252194            if (mtu != -1)
     
    254196            if (get_integer(&mtu, *argv, 0))
    255197                invarg(*argv, "mtu");
    256         } else if (strcmp(*argv, "multicast") == 0) {
     198        } else if (key == ARG_multicast) {
    257199            NEXT_ARG();
    258200            mask |= IFF_MULTICAST;
    259             if (strcmp(*argv, "on") == 0) {
     201            key = index_in_strings(keywords, *argv) + 1;
     202            if (key == PARM_on) {
    260203                flags |= IFF_MULTICAST;
    261             } else if (strcmp(*argv, "off") == 0) {
     204            } else if (key == PARM_off) {
    262205                flags &= ~IFF_MULTICAST;
    263206            } else
    264                 return on_off("multicast");
    265         } else if (strcmp(*argv, "arp") == 0) {
     207                on_off("multicast");
     208        } else if (key == ARG_arp) {
    266209            NEXT_ARG();
    267210            mask |= IFF_NOARP;
    268             if (strcmp(*argv, "on") == 0) {
     211            key = index_in_strings(keywords, *argv) + 1;
     212            if (key == PARM_on) {
    269213                flags &= ~IFF_NOARP;
    270             } else if (strcmp(*argv, "off") == 0) {
     214            } else if (key == PARM_off) {
    271215                flags |= IFF_NOARP;
    272216            } else
    273                 return on_off("noarp");
    274         } else if (strcmp(*argv, "addr") == 0) {
     217                on_off("arp");
     218        } else if (key == ARG_addr) {
    275219            NEXT_ARG();
    276220            newaddr = *argv;
    277221        } else {
    278             if (strcmp(*argv, "dev") == 0) {
     222            if (key == ARG_dev) {
    279223                NEXT_ARG();
    280224            }
     
    287231
    288232    if (!dev) {
    289         bb_error_msg(bb_msg_requires_arg, "\"dev\"");
    290         exit(-1);
     233        bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
    291234    }
    292235
    293236    if (newaddr || newbrd) {
    294237        halen = get_address(dev, &htype);
    295         if (halen < 0)
    296             return -1;
    297238        if (newaddr) {
    298             if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
    299                 return -1;
     239            parse_address(dev, htype, halen, newaddr, &ifr0);
    300240        }
    301241        if (newbrd) {
    302             if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
    303                 return -1;
     242            parse_address(dev, htype, halen, newbrd, &ifr1);
    304243        }
    305244    }
    306245
    307246    if (newname && strcmp(dev, newname)) {
    308         if (do_changename(dev, newname) < 0)
    309             return -1;
     247        do_changename(dev, newname);
    310248        dev = newname;
    311249    }
    312250    if (qlen != -1) {
    313         if (set_qlen(dev, qlen) < 0)
    314             return -1;
     251        set_qlen(dev, qlen);
    315252    }
    316253    if (mtu != -1) {
    317         if (set_mtu(dev, mtu) < 0)
    318             return -1;
     254        set_mtu(dev, mtu);
    319255    }
    320256    if (newaddr || newbrd) {
    321257        if (newbrd) {
    322             if (set_address(&ifr1, 1) < 0)
    323                 return -1;
     258            set_address(&ifr1, 1);
    324259        }
    325260        if (newaddr) {
    326             if (set_address(&ifr0, 0) < 0)
    327                 return -1;
     261            set_address(&ifr0, 0);
    328262        }
    329263    }
    330264    if (mask)
    331         return do_chflags(dev, flags, mask);
     265        do_chflags(dev, flags, mask);
    332266    return 0;
    333267}
     
    336270{
    337271    preferred_family = AF_PACKET;
    338     do_link = 1;
    339272    return ipaddr_list_or_flush(argc, argv, 0);
    340273}
    341274
     275/* Return value becomes exitcode. It's okay to not return at all */
    342276int do_iplink(int argc, char **argv)
    343277{
    344     if (argc > 0) {
    345         if (matches(*argv, "set") == 0)
    346             return do_set(argc-1, argv+1);
    347         if (matches(*argv, "show") == 0 ||
    348             matches(*argv, "lst") == 0 ||
    349             matches(*argv, "list") == 0)
    350             return ipaddr_list_link(argc-1, argv+1);
    351     } else
     278    static const char keywords[] ALIGN1 =
     279        "set\0""show\0""lst\0""list\0";
     280    smalluint key;
     281    if (argc <= 0)
    352282        return ipaddr_list_link(0, NULL);
    353 
    354     bb_error_msg("Command \"%s\" is unknown.", *argv);
    355     exit(-1);
    356 }
     283    key = index_in_substrings(keywords, *argv) + 1;
     284    if (key == 0)
     285        bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
     286    argc--; argv++;
     287    if (key == 1) /* set */
     288        return do_set(argc, argv);
     289    else /* show, lst, list */
     290        return ipaddr_list_link(argc, argv);
     291}
  • branches/stable/mindi-busybox/networking/libiproute/iproute.c

    r821 r1770  
    1414 */
    1515
    16 #include "libbb.h"
    17 
    18 #include <sys/socket.h>
    19 
    20 #include <string.h>
    21 #include <fcntl.h>
    22 #include <unistd.h>
    23 
     16#include "ip_common.h"  /* #include "libbb.h" is inside */
    2417#include "rt_names.h"
    2518#include "utils.h"
    26 #include "ip_common.h"
    2719
    2820#ifndef RTAX_RTTVAR
     
    3123
    3224
    33 static struct
    34 {
     25typedef struct filter_t {
    3526    int tb;
    3627    int flushed;
     
    5243    inet_prefix rsrc;
    5344    inet_prefix msrc;
    54 } filter;
     45} filter_t;
     46
     47#define filter (*(filter_t*)&bb_common_bufsiz1)
    5548
    5649static int flush_update(void)
    5750{
    5851    if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
    59         perror("Failed to send flush request\n");
     52        bb_perror_msg("failed to send flush request");
    6053        return -1;
    6154    }
    6255    filter.flushp = 0;
    6356    return 0;
     57}
     58
     59static unsigned get_hz(void)
     60{
     61    static unsigned hz_internal;
     62    FILE *fp;
     63
     64    if (hz_internal)
     65        return hz_internal;
     66
     67    fp = fopen("/proc/net/psched", "r");
     68    if (fp) {
     69        unsigned nom, denom;
     70
     71        if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
     72            if (nom == 1000000)
     73                hz_internal = denom;
     74        fclose(fp);
     75    }
     76    if (!hz_internal)
     77        hz_internal = sysconf(_SC_CLK_TCK);
     78    return hz_internal;
    6479}
    6580
     
    86101        return 0;
    87102    len -= NLMSG_LENGTH(sizeof(*r));
    88     if (len < 0) {
    89         bb_error_msg("wrong nlmsg len %d", len);
    90         return -1;
    91     }
     103    if (len < 0)
     104        bb_error_msg_and_die("wrong nlmsg len %d", len);
    92105
    93106    if (r->rtm_family == AF_INET6)
     
    170183        if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
    171184            if (flush_update())
    172                 return -1;
     185                bb_error_msg_and_die("flush");
    173186        }
    174187        fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
     
    249262    }
    250263    if (tb[RTA_PRIORITY]) {
    251         fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
     264        fprintf(fp, " metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
    252265    }
    253266    if (r->rtm_family == AF_INET6) {
     
    257270        }
    258271        if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
    259             static int hz;
    260             if (!hz) {
    261                 hz = get_hz();
    262             }
    263272            if (r->rtm_flags & RTM_F_CLONED) {
    264                 fprintf(fp, "%s    cache ", _SL_);
     273                fprintf(fp, "%c    cache ", _SL_);
    265274            }
    266275            if (ci->rta_expires) {
    267                 fprintf(fp, " expires %dsec", ci->rta_expires/hz);
     276                fprintf(fp, " expires %dsec", ci->rta_expires / get_hz());
    268277            }
    269278            if (ci->rta_error != 0) {
     
    278287        fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
    279288    }
    280     fprintf(fp, "\n");
     289    fputc('\n', fp);
    281290    fflush(fp);
    282291    return 0;
    283292}
    284293
     294/* Return value becomes exitcode. It's okay to not return at all */
    285295static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
    286296{
     297    static const char keywords[] ALIGN1 =
     298        "src\0""via\0""mtu\0""lock\0""protocol\0"USE_FEATURE_IP_RULE("table\0")
     299        "dev\0""oif\0""to\0";
     300    enum {
     301        ARG_src,
     302        ARG_via,
     303        ARG_mtu, PARM_lock,
     304        ARG_protocol,
     305USE_FEATURE_IP_RULE(ARG_table,)
     306        ARG_dev,
     307        ARG_oif,
     308        ARG_to
     309    };
     310    enum {
     311        gw_ok = 1 << 0,
     312        dst_ok = 1 << 1,
     313        proto_ok = 1 << 2,
     314        type_ok = 1 << 3
     315    };
    287316    struct rtnl_handle rth;
    288317    struct {
     
    291320        char            buf[1024];
    292321    } req;
    293     char  mxbuf[256];
     322    char mxbuf[256];
    294323    struct rtattr * mxrta = (void*)mxbuf;
    295324    unsigned mxlock = 0;
    296     char  *d = NULL;
    297     int gw_ok = 0;
    298     int dst_ok = 0;
    299     int proto_ok = 0;
    300     int type_ok = 0;
     325    char *d = NULL;
     326    smalluint ok = 0;
     327    int arg;
    301328
    302329    memset(&req, 0, sizeof(req));
     
    319346
    320347    while (argc > 0) {
    321         if (strcmp(*argv, "src") == 0) {
     348        arg = index_in_substrings(keywords, *argv);
     349        if (arg == ARG_src) {
    322350            inet_prefix addr;
     351            NEXT_ARG();
     352            get_addr(&addr, *argv, req.r.rtm_family);
     353            if (req.r.rtm_family == AF_UNSPEC)
     354                req.r.rtm_family = addr.family;
     355            addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
     356        } else if (arg == ARG_via) {
     357            inet_prefix addr;
     358            ok |= gw_ok;
    323359            NEXT_ARG();
    324360            get_addr(&addr, *argv, req.r.rtm_family);
     
    326362                req.r.rtm_family = addr.family;
    327363            }
    328             addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
    329         } else if (strcmp(*argv, "via") == 0) {
    330             inet_prefix addr;
    331             gw_ok = 1;
    332             NEXT_ARG();
    333             get_addr(&addr, *argv, req.r.rtm_family);
    334             if (req.r.rtm_family == AF_UNSPEC) {
    335                 req.r.rtm_family = addr.family;
    336             }
    337364            addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
    338         } else if (strcmp(*argv, "mtu") == 0) {
     365        } else if (arg == ARG_mtu) {
    339366            unsigned mtu;
    340367            NEXT_ARG();
    341             if (strcmp(*argv, "lock") == 0) {
     368            if (index_in_strings(keywords, *argv) == PARM_lock) {
    342369                mxlock |= (1<<RTAX_MTU);
    343370                NEXT_ARG();
    344371            }
    345             if (get_unsigned(&mtu, *argv, 0)) {
     372            if (get_unsigned(&mtu, *argv, 0))
    346373                invarg(*argv, "mtu");
    347             }
    348374            rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
    349         } else if (matches(*argv, "protocol") == 0) {
     375        } else if (arg == ARG_protocol) {
    350376            uint32_t prot;
    351377            NEXT_ARG();
     
    353379                invarg(*argv, "protocol");
    354380            req.r.rtm_protocol = prot;
    355             proto_ok =1;
    356         } else if (strcmp(*argv, "dev") == 0 ||
    357                strcmp(*argv, "oif") == 0) {
     381            ok |= proto_ok;
     382#if ENABLE_FEATURE_IP_RULE
     383        } else if (arg == ARG_table) {
     384            uint32_t tid;
     385            NEXT_ARG();
     386            if (rtnl_rttable_a2n(&tid, *argv))
     387                invarg(*argv, "table");
     388            req.r.rtm_table = tid;
     389#endif
     390        } else if (arg == ARG_dev || arg == ARG_oif) {
    358391            NEXT_ARG();
    359392            d = *argv;
     
    362395            inet_prefix dst;
    363396
    364             if (strcmp(*argv, "to") == 0) {
    365                 NEXT_ARG();
    366             }
    367             if ((**argv < '0' || **argv > '9') &&
    368                 rtnl_rtntype_a2n(&type, *argv) == 0) {
     397            if (arg == ARG_to) {
     398                NEXT_ARG();
     399            }
     400            if ((**argv < '0' || **argv > '9')
     401                && rtnl_rtntype_a2n(&type, *argv) == 0) {
    369402                NEXT_ARG();
    370403                req.r.rtm_type = type;
    371                 type_ok = 1;
    372             }
    373 
    374             if (dst_ok) {
     404                ok |= type_ok;
     405            }
     406
     407            if (ok & dst_ok) {
    375408                duparg2("to", *argv);
    376409            }
     
    380413            }
    381414            req.r.rtm_dst_len = dst.bitlen;
    382             dst_ok = 1;
     415            ok |= dst_ok;
    383416            if (dst.bytelen) {
    384417                addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
     
    388421    }
    389422
    390     if (rtnl_open(&rth, 0) < 0) {
    391         exit(1);
    392     }
     423    xrtnl_open(&rth);
    393424
    394425    if (d)  {
     
    398429
    399430        if (d) {
    400             if ((idx = ll_name_to_index(d)) == 0) {
    401                 bb_error_msg("Cannot find device \"%s\"", d);
    402                 return -1;
    403             }
     431            idx = xll_name_to_index(d);
    404432            addattr32(&req.n, sizeof(req), RTA_OIF, idx);
    405433        }
     
    413441    }
    414442
     443    if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
     444        req.r.rtm_scope = RT_SCOPE_HOST;
     445    else if (req.r.rtm_type == RTN_BROADCAST ||
     446            req.r.rtm_type == RTN_MULTICAST ||
     447            req.r.rtm_type == RTN_ANYCAST)
     448        req.r.rtm_scope = RT_SCOPE_LINK;
     449    else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
     450        if (cmd == RTM_DELROUTE)
     451            req.r.rtm_scope = RT_SCOPE_NOWHERE;
     452        else if (!(ok & gw_ok))
     453            req.r.rtm_scope = RT_SCOPE_LINK;
     454    }
     455
    415456    if (req.r.rtm_family == AF_UNSPEC) {
    416457        req.r.rtm_family = AF_INET;
     
    418459
    419460    if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
    420         exit(2);
     461        return 2;
    421462    }
    422463
     
    444485    req.rtm.rtm_flags |= RTM_F_CLONED;
    445486
    446     return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
    447 }
    448 
    449 static int iproute_flush_cache(void)
    450 {
    451 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
    452 
    453     int len;
    454     int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY);
    455     char *buffer = "-1";
     487    return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
     488}
     489
     490static void iproute_flush_cache(void)
     491{
     492    static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
     493    int flush_fd = open_or_warn(fn, O_WRONLY);
    456494
    457495    if (flush_fd < 0) {
    458         fprintf (stderr, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH);
    459         return -1;
    460     }
    461 
    462     len = strlen (buffer);
    463 
    464     if ((write (flush_fd, (void *)buffer, len)) < len) {
    465         fprintf (stderr, "Cannot flush routing cache\n");
    466         return -1;
     496        return;
     497    }
     498
     499    if (write(flush_fd, "-1", 2) < 2) {
     500        bb_perror_msg("cannot flush routing cache");
     501        return;
    467502    }
    468503    close(flush_fd);
    469     return 0;
    470504}
    471505
     
    477511}
    478512
     513/* Return value becomes exitcode. It's okay to not return at all */
    479514static int iproute_list_or_flush(int argc, char **argv, int flush)
    480515{
     
    483518    char *id = NULL;
    484519    char *od = NULL;
    485 
     520    static const char keywords[] ALIGN1 =
     521        "protocol\0""all\0""dev\0""oif\0""iif\0""via\0""table\0""cache\0" /*all*/
     522        "from\0""root\0""match\0""exact\0""to\0"/*root match exact*/;
     523    enum {
     524        ARG_proto, PARM_all,
     525        ARG_dev,
     526        ARG_oif,
     527        ARG_iif,
     528        ARG_via,
     529        ARG_table, PARM_cache, /*PARM_all,*/
     530        ARG_from, PARM_root, PARM_match, PARM_exact,
     531        ARG_to  /*PARM_root, PARM_match, PARM_exact*/
     532    };
     533    int arg, parm;
    486534    iproute_reset_filter();
    487535    filter.tb = RT_TABLE_MAIN;
    488536
    489     if (flush && argc <= 0) {
    490         bb_error_msg(bb_msg_requires_arg, "\"ip route flush\"");
    491         return -1;
    492     }
     537    if (flush && argc <= 0)
     538        bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
    493539
    494540    while (argc > 0) {
    495         if (matches(*argv, "protocol") == 0) {
     541        arg = index_in_substrings(keywords, *argv);
     542        if (arg == ARG_proto) {
    496543            uint32_t prot = 0;
    497544            NEXT_ARG();
    498545            filter.protocolmask = -1;
    499546            if (rtnl_rtprot_a2n(&prot, *argv)) {
    500                 if (strcmp(*argv, "all") != 0) {
     547                if (index_in_strings(keywords, *argv) != PARM_all)
    501548                    invarg(*argv, "protocol");
    502                 }
    503549                prot = 0;
    504550                filter.protocolmask = 0;
    505551            }
    506552            filter.protocol = prot;
    507         } else if (strcmp(*argv, "dev") == 0 ||
    508                strcmp(*argv, "oif") == 0) {
     553        } else if (arg == ARG_dev || arg == ARG_oif) {
    509554            NEXT_ARG();
    510555            od = *argv;
    511         } else if (strcmp(*argv, "iif") == 0) {
     556        } else if (arg == ARG_iif) {
    512557            NEXT_ARG();
    513558            id = *argv;
    514         } else if (matches(*argv, "from") == 0) {
    515             NEXT_ARG();
    516             if (matches(*argv, "root") == 0) {
     559        } else if (arg == ARG_via) {
     560            NEXT_ARG();
     561            get_prefix(&filter.rvia, *argv, do_ipv6);
     562        } else if (arg == ARG_table) {
     563            NEXT_ARG();
     564            parm = index_in_substrings(keywords, *argv);
     565            if (parm == PARM_cache)
     566                filter.tb = -1;
     567            else if (parm == PARM_all)
     568                filter.tb = 0;
     569            else
     570                invarg(*argv, "table");
     571        } else if (arg == ARG_from) {
     572            NEXT_ARG();
     573            parm = index_in_substrings(keywords, *argv);
     574            if (parm == PARM_root) {
    517575                NEXT_ARG();
    518576                get_prefix(&filter.rsrc, *argv, do_ipv6);
    519             } else if (matches(*argv, "match") == 0) {
     577            } else if (parm == PARM_match) {
    520578                NEXT_ARG();
    521579                get_prefix(&filter.msrc, *argv, do_ipv6);
    522580            } else {
    523                 if (matches(*argv, "exact") == 0) {
     581                if (parm == PARM_exact)
    524582                    NEXT_ARG();
    525                 }
    526583                get_prefix(&filter.msrc, *argv, do_ipv6);
    527584                filter.rsrc = filter.msrc;
    528585            }
    529586        } else {
    530             if (matches(*argv, "to") == 0) {
    531                 NEXT_ARG();
    532             }
    533             if (matches(*argv, "root") == 0) {
     587            /* parm = arg; // would be more plausible, we reuse arg here */
     588            if (arg == ARG_to) {
     589                NEXT_ARG();
     590                arg = index_in_substrings(keywords, *argv);
     591            }
     592            if (arg == PARM_root) {
    534593                NEXT_ARG();
    535594                get_prefix(&filter.rdst, *argv, do_ipv6);
    536             } else if (matches(*argv, "match") == 0) {
     595            } else if (arg == PARM_match) {
    537596                NEXT_ARG();
    538597                get_prefix(&filter.mdst, *argv, do_ipv6);
    539             } else if (matches(*argv, "table") == 0) {
    540                 NEXT_ARG();
    541                 if (matches(*argv, "cache") == 0) {
    542                     filter.tb = -1;
    543                 } else if (matches(*argv, "main") != 0) {
    544                     invarg(*argv, "table");
    545                 }
    546             } else if (matches(*argv, "cache") == 0) {
    547                 filter.tb = -1;
    548598            } else {
    549                 if (matches(*argv, "exact") == 0) {
     599                if (arg == PARM_exact)
    550600                    NEXT_ARG();
    551                 }
    552601                get_prefix(&filter.mdst, *argv, do_ipv6);
    553602                filter.rdst = filter.mdst;
    554603            }
    555604        }
    556         argc--; argv++;
     605        argc--;
     606        argv++;
    557607    }
    558608
     
    561611    }
    562612
    563     if (rtnl_open(&rth, 0) < 0) {
    564         exit(1);
    565     }
     613    xrtnl_open(&rth);
    566614
    567615    ll_init_map(&rth);
     
    571619
    572620        if (id) {
    573             if ((idx = ll_name_to_index(id)) == 0) {
    574                 bb_error_msg("Cannot find device \"%s\"", id);
    575                 return -1;
    576             }
     621            idx = xll_name_to_index(id);
    577622            filter.iif = idx;
    578623            filter.iifmask = -1;
    579624        }
    580625        if (od) {
    581             if ((idx = ll_name_to_index(od)) == 0) {
    582                 bb_error_msg("Cannot find device \"%s\"", od);
    583             }
     626            idx = xll_name_to_index(od);
    584627            filter.oif = idx;
    585628            filter.oifmask = -1;
     
    603646
    604647        for (;;) {
    605             if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
    606                 perror("Cannot send dump request");
    607                 return -1;
    608             }
     648            xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
    609649            filter.flushed = 0;
    610             if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
    611                 bb_error_msg("Flush terminated\n");
    612                 return -1;
    613             }
    614             if (filter.flushed == 0) {
    615                 fflush(stdout);
     650            xrtnl_dump_filter(&rth, print_route, stdout);
     651            if (filter.flushed == 0)
    616652                return 0;
    617             }
    618             if (flush_update() < 0)
    619                 exit(1);
     653            if (flush_update())
     654                return 1;
    620655        }
    621656    }
    622657
    623658    if (filter.tb != -1) {
    624         if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
    625             bb_perror_msg_and_die("Cannot send dump request");
    626         }
    627     } else {
    628         if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
    629             bb_perror_msg_and_die("Cannot send dump request");
    630         }
    631     }
    632 
    633     if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
    634         bb_error_msg_and_die("Dump terminated");
    635     }
    636 
    637     exit(0);
    638 }
    639 
    640 
     659        xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
     660    } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
     661        bb_perror_msg_and_die("cannot send dump request");
     662    }
     663    xrtnl_dump_filter(&rth, print_route, stdout);
     664
     665    return 0;
     666}
     667
     668
     669/* Return value becomes exitcode. It's okay to not return at all */
    641670static int iproute_get(int argc, char **argv)
    642671{
    643672    struct rtnl_handle rth;
    644673    struct {
    645         struct nlmsghdr     n;
    646         struct rtmsg        r;
    647         char            buf[1024];
     674        struct nlmsghdr n;
     675        struct rtmsg    r;
     676        char            buf[1024];
    648677    } req;
    649     char  *idev = NULL;
    650     char  *odev = NULL;
    651     int connected = 0;
    652     int from_ok = 0;
    653     static const char * const options[] =
    654         { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };
     678    char *idev = NULL;
     679    char *odev = NULL;
     680    bool connected = 0;
     681    bool from_ok = 0;
     682    static const char options[] ALIGN1 =
     683        "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
    655684
    656685    memset(&req, 0, sizeof(req));
     
    671700
    672701    while (argc > 0) {
    673         switch (compare_string_array(options, *argv)) {
     702        switch (index_in_strings(options, *argv)) {
    674703            case 0: /* from */
    675704            {
     
    724753    }
    725754
    726     if (rtnl_open(&rth, 0) < 0)
    727         exit(1);
     755    xrtnl_open(&rth);
    728756
    729757    ll_init_map(&rth);
     
    733761
    734762        if (idev) {
    735             if ((idx = ll_name_to_index(idev)) == 0) {
    736                 bb_error_msg("Cannot find device \"%s\"", idev);
    737                 return -1;
    738             }
     763            idx = xll_name_to_index(idev);
    739764            addattr32(&req.n, sizeof(req), RTA_IIF, idx);
    740765        }
    741766        if (odev) {
    742             if ((idx = ll_name_to_index(odev)) == 0) {
    743                 bb_error_msg("Cannot find device \"%s\"", odev);
    744                 return -1;
    745             }
     767            idx = xll_name_to_index(odev);
    746768            addattr32(&req.n, sizeof(req), RTA_OIF, idx);
    747769        }
     
    753775
    754776    if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
    755         exit(2);
     777        return 2;
    756778    }
    757779
     
    761783        struct rtattr * tb[RTA_MAX+1];
    762784
    763         if (print_route(NULL, &req.n, (void*)stdout) < 0) {
    764             bb_error_msg_and_die("An error :-)");
    765         }
     785        print_route(NULL, &req.n, (void*)stdout);
    766786
    767787        if (req.n.nlmsg_type != RTM_NEWROUTE) {
    768             bb_error_msg("Not a route?");
    769             return -1;
     788            bb_error_msg_and_die("not a route?");
    770789        }
    771790        len -= NLMSG_LENGTH(sizeof(*r));
    772791        if (len < 0) {
    773             bb_error_msg("Wrong len %d", len);
    774             return -1;
     792            bb_error_msg_and_die("wrong len %d", len);
    775793        }
    776794
     
    782800            r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
    783801        } else if (!tb[RTA_SRC]) {
    784             bb_error_msg("Failed to connect the route");
    785             return -1;
     802            bb_error_msg_and_die("failed to connect the route");
    786803        }
    787804        if (!odev && tb[RTA_OIF]) {
     
    798815
    799816        if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
    800             exit(2);
    801         }
    802     }
    803 
    804     if (print_route(NULL, &req.n, (void*)stdout) < 0) {
    805         bb_error_msg_and_die("An error :-)");
    806     }
    807 
    808     exit(0);
    809 }
    810 
     817            return 2;
     818        }
     819    }
     820    print_route(NULL, &req.n, (void*)stdout);
     821    return 0;
     822}
     823
     824/* Return value becomes exitcode. It's okay to not return at all */
    811825int do_iproute(int argc, char **argv)
    812826{
    813     static const char * const ip_route_commands[] =
    814         { "add", "append", "change", "chg", "delete", "del", "get",
    815         "list", "show", "prepend", "replace", "test", "flush", 0 };
    816     int command_num = 7;
    817     unsigned int flags = 0;
     827    static const char ip_route_commands[] ALIGN1 =
     828    /*0-3*/ "add\0""append\0""change\0""chg\0"
     829    /*4-7*/ "delete\0""get\0""list\0""show\0"
     830    /*8..*/ "prepend\0""replace\0""test\0""flush\0";
     831    int command_num = 6;
     832    unsigned flags = 0;
    818833    int cmd = RTM_NEWROUTE;
    819834
     835    /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
     836    /* It probably means that it is using "first match" rule */
    820837    if (*argv) {
    821         command_num = compare_string_array(ip_route_commands, *argv);
    822     }
    823     switch(command_num) {
    824         case 0: /* add*/
     838        command_num = index_in_substrings(ip_route_commands, *argv);
     839    }
     840    switch (command_num) {
     841        case 0: /* add */
    825842            flags = NLM_F_CREATE|NLM_F_EXCL;
    826843            break;
     
    833850            break;
    834851        case 4: /* delete */
    835         case 5: /* del */
    836852            cmd = RTM_DELROUTE;
    837853            break;
    838         case 6: /* get */
     854        case 5: /* get */
    839855            return iproute_get(argc-1, argv+1);
    840         case 7: /* list */
    841         case 8: /* show */
     856        case 6: /* list */
     857        case 7: /* show */
    842858            return iproute_list_or_flush(argc-1, argv+1, 0);
    843         case 9: /* prepend */
     859        case 8: /* prepend */
    844860            flags = NLM_F_CREATE;
    845         case 10: /* replace */
     861        case 9: /* replace */
    846862            flags = NLM_F_CREATE|NLM_F_REPLACE;
    847         case 11: /* test */
     863        case 10: /* test */
    848864            flags = NLM_F_EXCL;
    849         case 12: /* flush */
     865        case 11: /* flush */
    850866            return iproute_list_or_flush(argc-1, argv+1, 1);
    851867        default:
    852             bb_error_msg_and_die("Unknown command %s", *argv);
     868            bb_error_msg_and_die("unknown command %s", *argv);
    853869    }
    854870
  • branches/stable/mindi-busybox/networking/libiproute/iptunnel.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * iptunnel.c          "ip tunnel"
     
    1415 */
    1516
    16 #include "libbb.h"
    17 #include <sys/socket.h>
    18 #include <sys/ioctl.h>
    19 
    20 #include <string.h>
    21 #include <unistd.h>
    22 
    2317#include <netinet/ip.h>
    24 
    2518#include <net/if.h>
    2619#include <net/if_arp.h>
    27 
    2820#include <asm/types.h>
    2921#ifndef __constant_htons
     
    3224#include <linux/if_tunnel.h>
    3325
     26#include "ip_common.h"  /* #include "libbb.h" is inside */
    3427#include "rt_names.h"
    3528#include "utils.h"
    36 #include "ip_common.h"
    37 
    38 
     29
     30
     31/* Dies on error */
    3932static int do_ioctl_get_ifindex(char *dev)
    4033{
     
    4235    int fd;
    4336
    44     strcpy(ifr.ifr_name, dev);
    45     fd = socket(AF_INET, SOCK_DGRAM, 0);
    46     if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
    47         bb_perror_msg("ioctl");
    48         return 0;
    49     }
     37    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     38    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     39    xioctl(fd, SIOCGIFINDEX, &ifr);
    5040    close(fd);
    5141    return ifr.ifr_ifindex;
     
    5343
    5444static int do_ioctl_get_iftype(char *dev)
    55 {
    56     struct ifreq ifr;
    57     int fd;
    58 
    59     strcpy(ifr.ifr_name, dev);
    60     fd = socket(AF_INET, SOCK_DGRAM, 0);
    61     if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {
    62         bb_perror_msg("ioctl");
    63         return -1;
    64     }
    65     close(fd);
    66     return ifr.ifr_addr.sa_family;
    67 }
    68 
    69 
    70 static char *do_ioctl_get_ifname(int idx)
    71 {
    72     static struct ifreq ifr;
    73     int fd;
    74 
    75     ifr.ifr_ifindex = idx;
    76     fd = socket(AF_INET, SOCK_DGRAM, 0);
    77     if (ioctl(fd, SIOCGIFNAME, &ifr)) {
    78         bb_perror_msg("ioctl");
    79         return NULL;
    80     }
    81     close(fd);
    82     return ifr.ifr_name;
    83 }
    84 
    85 
    86 
    87 static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p)
    8845{
    8946    struct ifreq ifr;
     
    9148    int err;
    9249
    93     strcpy(ifr.ifr_name, basedev);
    94     ifr.ifr_ifru.ifru_data = (void*)p;
    95     fd = socket(AF_INET, SOCK_DGRAM, 0);
    96     err = ioctl(fd, SIOCGETTUNNEL, &ifr);
    97     if (err) {
    98         bb_perror_msg("ioctl");
    99     }
     50    strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     51    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     52    err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr);
    10053    close(fd);
    101     return err;
    102 }
    103 
    104 static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p)
     54    return err ? -1 : ifr.ifr_addr.sa_family;
     55}
     56
     57static char *do_ioctl_get_ifname(int idx)
    10558{
    10659    struct ifreq ifr;
     
    10861    int err;
    10962
    110     if (cmd == SIOCCHGTUNNEL && p->name[0]) {
    111         strcpy(ifr.ifr_name, p->name);
    112     } else {
    113         strcpy(ifr.ifr_name, basedev);
    114     }
    115     ifr.ifr_ifru.ifru_data = (void*)p;
    116     fd = socket(AF_INET, SOCK_DGRAM, 0);
    117     err = ioctl(fd, cmd, &ifr);
    118     if (err) {
    119         bb_perror_msg("ioctl");
    120     }
     63    ifr.ifr_ifindex = idx;
     64    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     65    err = ioctl_or_warn(fd, SIOCGIFNAME, &ifr);
    12166    close(fd);
    122     return err;
    123 }
    124 
    125 static int do_del_ioctl(char *basedev, struct ip_tunnel_parm *p)
     67    return err ? NULL : xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name));
     68}
     69
     70static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
    12671{
    12772    struct ifreq ifr;
     
    12974    int err;
    13075
    131     if (p->name[0]) {
    132         strcpy(ifr.ifr_name, p->name);
    133     } else {
    134         strcpy(ifr.ifr_name, basedev);
    135     }
     76    strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
    13677    ifr.ifr_ifru.ifru_data = (void*)p;
    137     fd = socket(AF_INET, SOCK_DGRAM, 0);
    138     err = ioctl(fd, SIOCDELTUNNEL, &ifr);
    139     if (err) {
    140         bb_perror_msg("ioctl");
    141     }
     78    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     79    err = ioctl_or_warn(fd, SIOCGETTUNNEL, &ifr);
    14280    close(fd);
    14381    return err;
    14482}
    14583
    146 static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
    147 {
     84/* Dies on error, otherwise returns 0 */
     85static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
     86{
     87    struct ifreq ifr;
     88    int fd;
     89
     90    if (cmd == SIOCCHGTUNNEL && p->name[0]) {
     91        strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
     92    } else {
     93        strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
     94    }
     95    ifr.ifr_ifru.ifru_data = (void*)p;
     96    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     97#if ENABLE_IOCTL_HEX2STR_ERROR
     98    /* #define magic will turn ioctl# into string */
     99    if (cmd == SIOCCHGTUNNEL)
     100        xioctl(fd, SIOCCHGTUNNEL, &ifr);
     101    else
     102        xioctl(fd, SIOCADDTUNNEL, &ifr);
     103#else
     104    xioctl(fd, cmd, &ifr);
     105#endif
     106    close(fd);
     107    return 0;
     108}
     109
     110/* Dies on error, otherwise returns 0 */
     111static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
     112{
     113    struct ifreq ifr;
     114    int fd;
     115
     116    if (p->name[0]) {
     117        strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
     118    } else {
     119        strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
     120    }
     121    ifr.ifr_ifru.ifru_data = (void*)p;
     122    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     123    xioctl(fd, SIOCDELTUNNEL, &ifr);
     124    close(fd);
     125    return 0;
     126}
     127
     128/* Dies on error */
     129static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
     130{
     131    static const char keywords[] ALIGN1 =
     132        "mode\0""ipip\0""ip/ip\0""gre\0""gre/ip\0""sit\0""ipv6/ip\0"
     133        "key\0""ikey\0""okey\0""seq\0""iseq\0""oseq\0"
     134        "csum\0""icsum\0""ocsum\0""nopmtudisc\0""pmtudisc\0"
     135        "remote\0""any\0""local\0""dev\0"
     136        "ttl\0""inherit\0""tos\0""dsfield\0"
     137        "name\0";
     138    enum {
     139        ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip,
     140        ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq,
     141        ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc,
     142        ARG_remote, ARG_any, ARG_local, ARG_dev,
     143        ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield,
     144        ARG_name
     145    };
    148146    int count = 0;
    149147    char medium[IFNAMSIZ];
     148    int key;
     149
    150150    memset(p, 0, sizeof(*p));
    151151    memset(&medium, 0, sizeof(medium));
     
    154154    p->iph.ihl = 5;
    155155#ifndef IP_DF
    156 #define IP_DF       0x4000      /* Flag: "Don't Fragment"   */
     156#define IP_DF 0x4000  /* Flag: "Don't Fragment" */
    157157#endif
    158158    p->iph.frag_off = htons(IP_DF);
    159159
    160160    while (argc > 0) {
    161         if (strcmp(*argv, "mode") == 0) {
    162             NEXT_ARG();
    163             if (strcmp(*argv, "ipip") == 0 ||
    164                 strcmp(*argv, "ip/ip") == 0) {
     161        key = index_in_strings(keywords, *argv);
     162        if (key == ARG_mode) {
     163            NEXT_ARG();
     164            key = index_in_strings(keywords, *argv);
     165            if (key == ARG_ipip ||
     166                key == ARG_ip_ip) {
    165167                if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
    166                     bb_error_msg("You managed to ask for more than one tunnel mode.");
    167                     exit(-1);
     168                    bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
    168169                }
    169170                p->iph.protocol = IPPROTO_IPIP;
    170             } else if (strcmp(*argv, "gre") == 0 ||
    171                    strcmp(*argv, "gre/ip") == 0) {
     171            } else if (key == ARG_gre ||
     172                   key == ARG_gre_ip) {
    172173                if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
    173                     bb_error_msg("You managed to ask for more than one tunnel mode.");
    174                     exit(-1);
     174                    bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
    175175                }
    176176                p->iph.protocol = IPPROTO_GRE;
    177             } else if (strcmp(*argv, "sit") == 0 ||
    178                    strcmp(*argv, "ipv6/ip") == 0) {
     177            } else if (key == ARG_sit ||
     178                   key == ARG_ip6_ip) {
    179179                if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
    180                     bb_error_msg("You managed to ask for more than one tunnel mode.");
    181                     exit(-1);
     180                    bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
    182181                }
    183182                p->iph.protocol = IPPROTO_IPV6;
    184183            } else {
    185                 bb_error_msg("Cannot guess tunnel mode.");
    186                 exit(-1);
    187             }
    188         } else if (strcmp(*argv, "key") == 0) {
     184                bb_error_msg_and_die("cannot guess tunnel mode");
     185            }
     186        } else if (key == ARG_key) {
    189187            unsigned uval;
    190188            NEXT_ARG();
     
    195193            else {
    196194                if (get_unsigned(&uval, *argv, 0)<0) {
    197                     bb_error_msg("invalid value of \"key\"");
    198                     exit(-1);
     195                    bb_error_msg_and_die("invalid value of \"key\"");
    199196                }
    200197                p->i_key = p->o_key = htonl(uval);
    201198            }
    202         } else if (strcmp(*argv, "ikey") == 0) {
     199        } else if (key == ARG_ikey) {
    203200            unsigned uval;
    204201            NEXT_ARG();
     
    208205            else {
    209206                if (get_unsigned(&uval, *argv, 0)<0) {
    210                     bb_error_msg("invalid value of \"ikey\"");
    211                     exit(-1);
     207                    bb_error_msg_and_die("invalid value of \"ikey\"");
    212208                }
    213209                p->i_key = htonl(uval);
    214210            }
    215         } else if (strcmp(*argv, "okey") == 0) {
     211        } else if (key == ARG_okey) {
    216212            unsigned uval;
    217213            NEXT_ARG();
     
    221217            else {
    222218                if (get_unsigned(&uval, *argv, 0)<0) {
    223                     bb_error_msg("invalid value of \"okey\"");
    224                     exit(-1);
     219                    bb_error_msg_and_die("invalid value of \"okey\"");
    225220                }
    226221                p->o_key = htonl(uval);
    227222            }
    228         } else if (strcmp(*argv, "seq") == 0) {
     223        } else if (key == ARG_seq) {
    229224            p->i_flags |= GRE_SEQ;
    230225            p->o_flags |= GRE_SEQ;
    231         } else if (strcmp(*argv, "iseq") == 0) {
     226        } else if (key == ARG_iseq) {
    232227            p->i_flags |= GRE_SEQ;
    233         } else if (strcmp(*argv, "oseq") == 0) {
     228        } else if (key == ARG_oseq) {
    234229            p->o_flags |= GRE_SEQ;
    235         } else if (strcmp(*argv, "csum") == 0) {
     230        } else if (key == ARG_csum) {
    236231            p->i_flags |= GRE_CSUM;
    237232            p->o_flags |= GRE_CSUM;
    238         } else if (strcmp(*argv, "icsum") == 0) {
     233        } else if (key == ARG_icsum) {
    239234            p->i_flags |= GRE_CSUM;
    240         } else if (strcmp(*argv, "ocsum") == 0) {
     235        } else if (key == ARG_ocsum) {
    241236            p->o_flags |= GRE_CSUM;
    242         } else if (strcmp(*argv, "nopmtudisc") == 0) {
     237        } else if (key == ARG_nopmtudisc) {
    243238            p->iph.frag_off = 0;
    244         } else if (strcmp(*argv, "pmtudisc") == 0) {
     239        } else if (key == ARG_pmtudisc) {
    245240            p->iph.frag_off = htons(IP_DF);
    246         } else if (strcmp(*argv, "remote") == 0) {
    247             NEXT_ARG();
    248             if (strcmp(*argv, "any"))
     241        } else if (key == ARG_remote) {
     242            NEXT_ARG();
     243            key = index_in_strings(keywords, *argv);
     244            if (key == ARG_any)
    249245                p->iph.daddr = get_addr32(*argv);
    250         } else if (strcmp(*argv, "local") == 0) {
    251             NEXT_ARG();
    252             if (strcmp(*argv, "any"))
     246        } else if (key == ARG_local) {
     247            NEXT_ARG();
     248            key = index_in_strings(keywords, *argv);
     249            if (key == ARG_any)
    253250                p->iph.saddr = get_addr32(*argv);
    254         } else if (strcmp(*argv, "dev") == 0) {
     251        } else if (key == ARG_dev) {
    255252            NEXT_ARG();
    256253            strncpy(medium, *argv, IFNAMSIZ-1);
    257         } else if (strcmp(*argv, "ttl") == 0) {
     254        } else if (key == ARG_ttl) {
    258255            unsigned uval;
    259256            NEXT_ARG();
    260             if (strcmp(*argv, "inherit") != 0) {
     257            key = index_in_strings(keywords, *argv);
     258            if (key != ARG_inherit) {
    261259                if (get_unsigned(&uval, *argv, 0))
    262260                    invarg(*argv, "TTL");
     
    265263                p->iph.ttl = uval;
    266264            }
    267         } else if (strcmp(*argv, "tos") == 0 ||
    268                matches(*argv, "dsfield") == 0) {
    269             __u32 uval;
    270             NEXT_ARG();
    271             if (strcmp(*argv, "inherit") != 0) {
     265        } else if (key == ARG_tos ||
     266               key == ARG_dsfield) {
     267            uint32_t uval;
     268            NEXT_ARG();
     269            key = index_in_strings(keywords, *argv);
     270            if (key != ARG_inherit) {
    272271                if (rtnl_dsfield_a2n(&uval, *argv))
    273272                    invarg(*argv, "TOS");
     
    276275                p->iph.tos = 1;
    277276        } else {
    278             if (strcmp(*argv, "name") == 0) {
     277            if (key == ARG_name) {
    279278                NEXT_ARG();
    280279            }
     
    286285                memset(&old_p, 0, sizeof(old_p));
    287286                if (do_get_ioctl(*argv, &old_p))
    288                     return -1;
     287                    exit(1);
    289288                *p = old_p;
    290289            }
    291290        }
    292291        count++;
    293         argc--; argv++;
    294     }
    295 
     292        argc--;
     293        argv++;
     294    }
    296295
    297296    if (p->iph.protocol == 0) {
     
    306305    if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
    307306        if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
    308             bb_error_msg("Keys are not allowed with ipip and sit.");
    309             return -1;
     307            bb_error_msg_and_die("keys are not allowed with ipip and sit");
    310308        }
    311309    }
     
    313311    if (medium[0]) {
    314312        p->link = do_ioctl_get_ifindex(medium);
    315         if (p->link == 0)
    316             return -1;
    317313    }
    318314
     
    326322    }
    327323    if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
    328         bb_error_msg("Broadcast tunnel requires a source address.");
    329         return -1;
    330     }
    331     return 0;
    332 }
    333 
    334 
     324        bb_error_msg_and_die("broadcast tunnel requires a source address");
     325    }
     326}
     327
     328
     329/* Return value becomes exitcode. It's okay to not return at all */
    335330static int do_add(int cmd, int argc, char **argv)
    336331{
    337332    struct ip_tunnel_parm p;
    338333
    339     if (parse_args(argc, argv, cmd, &p) < 0)
    340         return -1;
     334    parse_args(argc, argv, cmd, &p);
    341335
    342336    if (p.iph.ttl && p.iph.frag_off == 0) {
    343         bb_error_msg("ttl != 0 and noptmudisc are incompatible");
    344         return -1;
     337        bb_error_msg_and_die("ttl != 0 and noptmudisc are incompatible");
    345338    }
    346339
     
    353346        return do_add_ioctl(cmd, "sit0", &p);
    354347    default:
    355         bb_error_msg("cannot determine tunnel mode (ipip, gre or sit)");
    356         return -1;
    357     }
    358     return -1;
    359 }
    360 
     348        bb_error_msg_and_die("cannot determine tunnel mode (ipip, gre or sit)");
     349    }
     350}
     351
     352/* Return value becomes exitcode. It's okay to not return at all */
    361353static int do_del(int argc, char **argv)
    362354{
    363355    struct ip_tunnel_parm p;
    364356
    365     if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
    366         return -1;
     357    parse_args(argc, argv, SIOCDELTUNNEL, &p);
    367358
    368359    switch (p.iph.protocol) {
     
    376367        return do_del_ioctl(p.name, &p);
    377368    }
    378     return -1;
    379369}
    380370
     
    399389    if (p->link) {
    400390        char *n = do_ioctl_get_ifname(p->link);
    401         if (n)
     391        if (n) {
    402392            printf(" dev %s ", n);
     393            free(n);
     394        }
    403395    }
    404396    if (p->iph.ttl)
     
    409401        SPRINT_BUF(b1);
    410402        printf(" tos");
    411         if (p->iph.tos&1)
     403        if (p->iph.tos & 1)
    412404            printf(" inherit");
    413         if (p->iph.tos&~1)
    414             printf("%c%s ", p->iph.tos&1 ? '/' : ' ',
    415                    rtnl_dsfield_n2a(p->iph.tos&~1, b1, sizeof(b1)));
    416     }
    417     if (!(p->iph.frag_off&htons(IP_DF)))
     405        if (p->iph.tos & ~1)
     406            printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
     407                   rtnl_dsfield_n2a(p->iph.tos & ~1, b1, sizeof(b1)));
     408    }
     409    if (!(p->iph.frag_off & htons(IP_DF)))
    418410        printf(" nopmtudisc");
    419411
    420     if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
     412    if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key)
    421413        printf(" key %s", s3);
    422     else if ((p->i_flags|p->o_flags)&GRE_KEY) {
    423         if (p->i_flags&GRE_KEY)
     414    else if ((p->i_flags | p->o_flags) & GRE_KEY) {
     415        if (p->i_flags & GRE_KEY)
    424416            printf(" ikey %s ", s3);
    425         if (p->o_flags&GRE_KEY)
     417        if (p->o_flags & GRE_KEY)
    426418            printf(" okey %s ", s4);
    427419    }
    428420
    429     if (p->i_flags&GRE_SEQ)
    430         printf("%s  Drop packets out of sequence.\n", _SL_);
    431     if (p->i_flags&GRE_CSUM)
    432         printf("%s  Checksum in received packet is required.", _SL_);
    433     if (p->o_flags&GRE_SEQ)
    434         printf("%s  Sequence packets on output.", _SL_);
    435     if (p->o_flags&GRE_CSUM)
    436         printf("%s  Checksum output packets.", _SL_);
    437 }
    438 
    439 static int do_tunnels_list(struct ip_tunnel_parm *p)
     421    if (p->i_flags & GRE_SEQ)
     422        printf("%c  Drop packets out of sequence.\n", _SL_);
     423    if (p->i_flags & GRE_CSUM)
     424        printf("%c  Checksum in received packet is required.", _SL_);
     425    if (p->o_flags & GRE_SEQ)
     426        printf("%c  Sequence packets on output.", _SL_);
     427    if (p->o_flags & GRE_CSUM)
     428        printf("%c  Checksum output packets.", _SL_);
     429}
     430
     431static void do_tunnels_list(struct ip_tunnel_parm *p)
    440432{
    441433    char name[IFNAMSIZ];
    442     unsigned long  rx_bytes, rx_packets, rx_errs, rx_drops,
    443     rx_fifo, rx_frame,
    444     tx_bytes, tx_packets, tx_errs, tx_drops,
    445     tx_fifo, tx_colls, tx_carrier, rx_multi;
     434    unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
     435        rx_fifo, rx_frame,
     436        tx_bytes, tx_packets, tx_errs, tx_drops,
     437        tx_fifo, tx_colls, tx_carrier, rx_multi;
    446438    int type;
    447439    struct ip_tunnel_parm p1;
    448 
    449440    char buf[512];
    450     FILE *fp = fopen("/proc/net/dev", "r");
     441    FILE *fp = fopen_or_warn("/proc/net/dev", "r");
     442
    451443    if (fp == NULL) {
    452         perror("fopen");
    453         return -1;
     444        return;
    454445    }
    455446
     
    459450    while (fgets(buf, sizeof(buf), fp) != NULL) {
    460451        char *ptr;
    461         buf[sizeof(buf) - 1] = 0;
    462         if ((ptr = strchr(buf, ':')) == NULL ||
     452
     453        /*buf[sizeof(buf) - 1] = 0; - fgets is safe anyway */
     454        ptr = strchr(buf, ':');
     455        if (ptr == NULL ||
    463456            (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
    464             bb_error_msg("Wrong format of /proc/net/dev. Sorry.");
    465             return -1;
     457            bb_error_msg("wrong format of /proc/net/dev");
     458            return;
    466459        }
    467460        if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
     
    475468        type = do_ioctl_get_iftype(name);
    476469        if (type == -1) {
    477             bb_error_msg("Failed to get type of [%s]", name);
     470            bb_error_msg("cannot get type of [%s]", name);
    478471            continue;
    479472        }
     
    490483            continue;
    491484        print_tunnel(&p1);
    492         printf("\n");
    493     }
    494     return 0;
    495 }
    496 
     485        puts("");
     486    }
     487}
     488
     489/* Return value becomes exitcode. It's okay to not return at all */
    497490static int do_show(int argc, char **argv)
    498491{
     
    500493    struct ip_tunnel_parm p;
    501494
    502     if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
    503         return -1;
     495    parse_args(argc, argv, SIOCGETTUNNEL, &p);
    504496
    505497    switch (p.iph.protocol) {
     
    521513
    522514    print_tunnel(&p);
    523     printf("\n");
     515    puts("");
    524516    return 0;
    525517}
    526518
     519/* Return value becomes exitcode. It's okay to not return at all */
    527520int do_iptunnel(int argc, char **argv)
    528521{
    529     if (argc > 0) {
    530         if (matches(*argv, "add") == 0)
    531             return do_add(SIOCADDTUNNEL, argc-1, argv+1);
    532         if (matches(*argv, "change") == 0)
    533             return do_add(SIOCCHGTUNNEL, argc-1, argv+1);
    534         if (matches(*argv, "del") == 0)
    535             return do_del(argc-1, argv+1);
    536         if (matches(*argv, "show") == 0 ||
    537             matches(*argv, "lst") == 0 ||
    538             matches(*argv, "list") == 0)
    539             return do_show(argc-1, argv+1);
    540     } else
    541         return do_show(0, NULL);
    542 
    543     bb_error_msg("Command \"%s\" is unknown.", *argv);
    544     exit(-1);
    545 }
     522    static const char keywords[] ALIGN1 =
     523        "add\0""change\0""delete\0""show\0""list\0""lst\0";
     524    enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst };
     525    int key;
     526
     527    if (argc) {
     528        key = index_in_substrings(keywords, *argv);
     529        if (key < 0)
     530            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
     531        --argc;
     532        ++argv;
     533        if (key == ARG_add)
     534            return do_add(SIOCADDTUNNEL, argc, argv);
     535        if (key == ARG_change)
     536            return do_add(SIOCCHGTUNNEL, argc, argv);
     537        if (key == ARG_del)
     538            return do_del(argc, argv);
     539    }
     540    return do_show(argc, argv);
     541}
  • branches/stable/mindi-busybox/networking/libiproute/libnetlink.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * libnetlink.c RTnetlink service routines.
     
    1112 */
    1213
     14#include <sys/socket.h>
     15#include <sys/uio.h>
     16
    1317#include "libbb.h"
    14 #include <sys/socket.h>
    15 
    16 #include <errno.h>
    17 #include <string.h>
    18 #include <time.h>
    19 #include <unistd.h>
    20 
    21 #include <sys/uio.h>
    22 
    2318#include "libnetlink.h"
    2419
     
    2823}
    2924
    30 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
     25int xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
    3126{
    3227    socklen_t addr_len;
     
    3429    memset(rth, 0, sizeof(rth));
    3530
    36     rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    37     if (rth->fd < 0) {
    38         bb_perror_msg("Cannot open netlink socket");
    39         return -1;
    40     }
     31    rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    4132
    4233    memset(&rth->local, 0, sizeof(rth->local));
    4334    rth->local.nl_family = AF_NETLINK;
    44     rth->local.nl_groups = subscriptions;
    45 
    46     if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
    47         bb_perror_msg("Cannot bind netlink socket");
    48         return -1;
    49     }
     35    /*rth->local.nl_groups = subscriptions;*/
     36
     37    xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
    5038    addr_len = sizeof(rth->local);
    51     if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
    52         bb_perror_msg("Cannot getsockname");
    53         return -1;
    54     }
    55     if (addr_len != sizeof(rth->local)) {
    56         bb_error_msg("Wrong address length %d", addr_len);
    57         return -1;
    58     }
    59     if (rth->local.nl_family != AF_NETLINK) {
    60         bb_error_msg("Wrong address family %d", rth->local.nl_family);
    61         return -1;
    62     }
     39    if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
     40        bb_perror_msg_and_die("cannot getsockname");
     41    if (addr_len != sizeof(rth->local))
     42        bb_error_msg_and_die("wrong address length %d", addr_len);
     43    if (rth->local.nl_family != AF_NETLINK)
     44        bb_error_msg_and_die("wrong address family %d", rth->local.nl_family);
    6345    rth->seq = time(NULL);
    6446    return 0;
    6547}
    6648
    67 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
     49int xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
    6850{
    6951    struct {
     
    8365    req.g.rtgen_family = family;
    8466
    85     return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
     67    return xsendto(rth->fd, (void*)&req, sizeof(req),
     68                 (struct sockaddr*)&nladdr, sizeof(nladdr));
    8669}
    8770
     
    9376    nladdr.nl_family = AF_NETLINK;
    9477
    95     return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
     78    return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
    9679}
    9780
     
    120103}
    121104
    122 int rtnl_dump_filter(struct rtnl_handle *rth,
    123              int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
    124              void *arg1,
    125              int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
    126              void *arg2)
    127 {
    128     char    buf[8192];
     105static int rtnl_dump_filter(struct rtnl_handle *rth,
     106        int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
     107        void *arg1/*,
     108        int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
     109        void *arg2*/)
     110{
     111    char buf[8192];
    129112    struct sockaddr_nl nladdr;
    130113    struct iovec iov = { buf, sizeof(buf) };
     
    164147                h->nlmsg_pid != rth->local.nl_pid ||
    165148                h->nlmsg_seq != rth->dump) {
    166                 if (junk) {
     149/*              if (junk) {
    167150                    err = junk(&nladdr, h, arg2);
    168                     if (err < 0) {
     151                    if (err < 0)
    169152                        return err;
    170                     }
    171                 }
     153                } */
    172154                goto skip_it;
    173155            }
     
    187169            }
    188170            err = filter(&nladdr, h, arg1);
    189             if (err < 0) {
     171            if (err < 0)
    190172                return err;
    191             }
    192173
    193174skip_it:
     
    195176        }
    196177        if (msg.msg_flags & MSG_TRUNC) {
    197             bb_error_msg("Message truncated");
     178            bb_error_msg("message truncated");
    198179            continue;
    199180        }
    200181        if (status) {
    201             bb_error_msg_and_die("!!!Remnant of size %d", status);
    202         }
    203     }
     182            bb_error_msg_and_die("remnant of size %d!", status);
     183        }
     184    }
     185}
     186
     187int xrtnl_dump_filter(struct rtnl_handle *rth,
     188        int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
     189        void *arg1)
     190{
     191    int ret = rtnl_dump_filter(rth, filter, arg1/*, NULL, NULL*/);
     192    if (ret < 0)
     193        bb_error_msg_and_die("dump terminated");
     194    return ret;
    204195}
    205196
     
    234225
    235226    if (status < 0) {
    236         bb_perror_msg("Cannot talk to rtnetlink");
     227        bb_perror_msg("cannot talk to rtnetlink");
    237228        return -1;
    238229    }
     
    265256            if (l<0 || len>status) {
    266257                if (msg.msg_flags & MSG_TRUNC) {
    267                     bb_error_msg("Truncated message");
     258                    bb_error_msg("truncated message");
    268259                    return -1;
    269260                }
    270                 bb_error_msg_and_die("!!!malformed message: len=%d", len);
     261                bb_error_msg_and_die("malformed message: len=%d!", len);
    271262            }
    272263
     
    304295            }
    305296
    306             bb_error_msg("Unexpected reply!!!");
     297            bb_error_msg("unexpected reply!");
    307298
    308299            status -= NLMSG_ALIGN(len);
     
    310301        }
    311302        if (msg.msg_flags & MSG_TRUNC) {
    312             bb_error_msg("Message truncated");
     303            bb_error_msg("message truncated");
    313304            continue;
    314305        }
    315306        if (status) {
    316             bb_error_msg_and_die("!!!Remnant of size %d", status);
    317         }
    318     }
    319 }
    320 
    321 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
     307            bb_error_msg_and_die("remnant of size %d!", status);
     308        }
     309    }
     310}
     311
     312int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
    322313{
    323314    int len = RTA_LENGTH(4);
     
    348339}
    349340
    350 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
     341int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
    351342{
    352343    int len = RTA_LENGTH(4);
     
    390381    }
    391382    if (len) {
    392         bb_error_msg("!!!Deficit %d, rta_len=%d", len, rta->rta_len);
    393     }
    394     return 0;
    395 }
     383        bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len);
     384    }
     385    return 0;
     386}
  • branches/stable/mindi-busybox/networking/libiproute/libnetlink.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12#ifndef __LIBNETLINK_H__
    23#define __LIBNETLINK_H__ 1
    34
    4 #include <asm/types.h>
     5#include <linux/types.h>
     6/* We need linux/types.h because older kernels use __u32 etc
     7 * in linux/[rt]netlink.h. 2.6.19 seems to be ok, though */
    58#include <linux/netlink.h>
    69#include <linux/rtnetlink.h>
     
    1114    struct sockaddr_nl  local;
    1215    struct sockaddr_nl  peer;
    13     __u32           seq;
    14     __u32           dump;
     16    uint32_t        seq;
     17    uint32_t        dump;
    1518};
    1619
    17 extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions);
     20extern int xrtnl_open(struct rtnl_handle *rth);
    1821extern void rtnl_close(struct rtnl_handle *rth);
    19 extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
     22extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
    2023extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
    21 extern int rtnl_dump_filter(struct rtnl_handle *rth,
    22                 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
    23                 void *arg1,
    24                 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
    25                 void *arg2);
     24extern int xrtnl_dump_filter(struct rtnl_handle *rth,
     25            int (*filter)(struct sockaddr_nl*, struct nlmsghdr *n, void*),
     26            void *arg1);
    2627extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
    27              unsigned groups, struct nlmsghdr *answer,
    28              int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
    29              void *jarg);
     28            unsigned groups, struct nlmsghdr *answer,
     29            int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
     30            void *jarg);
    3031extern int rtnl_send(struct rtnl_handle *rth, char *buf, int);
    3132
    3233
    33 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data);
     34extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data);
    3435extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen);
    35 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data);
     36extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data);
    3637extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen);
    3738
    3839extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
    3940
    40 
    4141#endif /* __LIBNETLINK_H__ */
    42 
  • branches/stable/mindi-busybox/networking/libiproute/ll_addr.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ll_addr.c
     
    1011 */
    1112
    12 #include "libbb.h"
    13 
    14 #include <string.h>
    1513#include <net/if_arp.h>
    1614
     15#include "libbb.h"
    1716#include "rt_names.h"
    1817#include "utils.h"
     
    3130    for (i=0; i<alen; i++) {
    3231        if (i==0) {
    33             snprintf(buf+l, blen, "%02x", addr[i]);
     32            snprintf(buf+l, blen, ":%02x"+1, addr[i]);
    3433            blen -= 2;
    3534            l += 2;
     
    4847        inet_prefix pfx;
    4948        if (get_addr_1(&pfx, arg, AF_INET)) {
    50             bb_error_msg("\"%s\" is invalid lladdr.", arg);
     49            bb_error_msg("\"%s\" is invalid lladdr", arg);
    5150            return -1;
    5251        }
     
    6766            }
    6867            if (sscanf(arg, "%x", &temp) != 1) {
    69                 bb_error_msg("\"%s\" is invalid lladdr.", arg);
     68                bb_error_msg("\"%s\" is invalid lladdr", arg);
    7069                return -1;
    7170            }
    7271            if (temp < 0 || temp > 255) {
    73                 bb_error_msg("\"%s\" is invalid lladdr.", arg);
     72                bb_error_msg("\"%s\" is invalid lladdr", arg);
    7473                return -1;
    7574            }
  • branches/stable/mindi-busybox/networking/libiproute/ll_map.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ll_map.c
     
    1112 */
    1213
     14#include <net/if.h> /* struct ifreq and co. */
     15
    1316#include "libbb.h"
    14 #include <string.h>
    15 
    1617#include "libnetlink.h"
    1718#include "ll_map.h"
    1819
    19 struct idxmap
    20 {
    21     struct idxmap * next;
    22     int     index;
    23     int     type;
    24     int     alen;
    25     unsigned    flags;
    26     unsigned char   addr[8];
    27     char        name[16];
     20struct idxmap {
     21    struct idxmap *next;
     22    int            index;
     23    int            type;
     24    int            alen;
     25    unsigned       flags;
     26    unsigned char  addr[8];
     27    char           name[16];
    2828};
    2929
    3030static struct idxmap *idxmap[16];
     31
     32static struct idxmap *find_by_index(int idx)
     33{
     34    struct idxmap *im;
     35
     36    for (im = idxmap[idx & 0xF]; im; im = im->next)
     37        if (im->index == idx)
     38            return im;
     39    return NULL;
     40}
    3141
    3242int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
     
    4353        return -1;
    4454
    45 
    4655    memset(tb, 0, sizeof(tb));
    4756    parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
     
    4958        return 0;
    5059
    51     h = ifi->ifi_index&0xF;
     60    h = ifi->ifi_index & 0xF;
    5261
    53     for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next)
     62    for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next)
    5463        if (im->index == ifi->ifi_index)
    55             break;
     64            goto found;
    5665
    57     if (im == NULL) {
    58         im = xmalloc(sizeof(*im));
    59         im->next = *imp;
    60         im->index = ifi->ifi_index;
    61         *imp = im;
    62     }
    63 
     66    im = xmalloc(sizeof(*im));
     67    im->next = *imp;
     68    im->index = ifi->ifi_index;
     69    *imp = im;
     70 found:
    6471    im->type = ifi->ifi_type;
    6572    im->flags = ifi->ifi_flags;
     
    8491    if (idx == 0)
    8592        return "*";
    86     for (im = idxmap[idx&0xF]; im; im = im->next)
    87         if (im->index == idx)
    88             return im->name;
     93    im = find_by_index(idx);
     94    if (im)
     95        return im->name;
    8996    snprintf(buf, 16, "if%d", idx);
    9097    return buf;
     
    99106}
    100107
     108#ifdef UNUSED
    101109int ll_index_to_type(int idx)
    102110{
     
    105113    if (idx == 0)
    106114        return -1;
    107     for (im = idxmap[idx&0xF]; im; im = im->next)
    108         if (im->index == idx)
    109             return im->type;
     115    im = find_by_index(idx);
     116    if (im)
     117        return im->type;
    110118    return -1;
    111119}
     120#endif
    112121
    113122unsigned ll_index_to_flags(int idx)
     
    117126    if (idx == 0)
    118127        return 0;
    119 
    120     for (im = idxmap[idx&0xF]; im; im = im->next)
    121         if (im->index == idx)
    122             return im->flags;
     128    im = find_by_index(idx);
     129    if (im)
     130        return im->flags;
    123131    return 0;
    124132}
    125133
    126 int ll_name_to_index(char *name)
     134int xll_name_to_index(const char *const name)
    127135{
     136    int ret = 0;
     137    int sock_fd;
     138
     139/* caching is not warranted - no users which repeatedly call it */
     140#ifdef UNUSED
    128141    static char ncache[16];
    129142    static int icache;
     143
    130144    struct idxmap *im;
    131145    int i;
    132146
    133147    if (name == NULL)
    134         return 0;
    135     if (icache && strcmp(name, ncache) == 0)
    136         return icache;
    137     for (i=0; i<16; i++) {
     148        goto out;
     149    if (icache && strcmp(name, ncache) == 0) {
     150        ret = icache;
     151        goto out;
     152    }
     153    for (i = 0; i < 16; i++) {
    138154        for (im = idxmap[i]; im; im = im->next) {
    139155            if (strcmp(im->name, name) == 0) {
    140156                icache = im->index;
    141157                strcpy(ncache, name);
    142                 return im->index;
     158                ret = im->index;
     159                goto out;
    143160            }
    144161        }
    145162    }
    146     return 0;
     163    /* We have not found the interface in our cache, but the kernel
     164     * may still know about it. One reason is that we may be using
     165     * module on-demand loading, which means that the kernel will
     166     * load the module and make the interface exist only when
     167     * we explicitely request it (check for dev_load() in net/core/dev.c).
     168     * I can think of other similar scenario, but they are less common...
     169     * Jean II */
     170#endif
     171
     172    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
     173    if (sock_fd) {
     174        struct ifreq ifr;
     175        int tmp;
     176
     177        strncpy(ifr.ifr_name, name, IFNAMSIZ);
     178        ifr.ifr_ifindex = -1;
     179        tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr);
     180        close(sock_fd);
     181        if (tmp >= 0)
     182            /* In theory, we should redump the interface list
     183             * to update our cache, this is left as an exercise
     184             * to the reader... Jean II */
     185            ret = ifr.ifr_ifindex;
     186    }
     187/* out:*/
     188    if (ret <= 0)
     189        bb_error_msg_and_die("cannot find device \"%s\"", name);
     190    return ret;
    147191}
    148192
    149193int ll_init_map(struct rtnl_handle *rth)
    150194{
    151     if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) {
    152         perror("Cannot send dump request");
    153         exit(1);
    154     }
    155 
    156     if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) {
    157         fprintf(stderr, "Dump terminated\n");
    158         exit(1);
    159     }
     195    xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK);
     196    xrtnl_dump_filter(rth, ll_remember_index, &idxmap);
    160197    return 0;
    161198}
  • branches/stable/mindi-busybox/networking/libiproute/ll_map.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12#ifndef __LL_MAP_H__
    23#define __LL_MAP_H__ 1
    34
    4 extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
    5 extern int ll_init_map(struct rtnl_handle *rth);
    6 extern int ll_name_to_index(char *name);
    7 extern const char *ll_index_to_name(int idx);
    8 extern const char *ll_idx_n2a(int idx, char *buf);
    9 extern int ll_index_to_type(int idx);
    10 extern unsigned ll_index_to_flags(int idx);
     5int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
     6int ll_init_map(struct rtnl_handle *rth);
     7int xll_name_to_index(const char *const name);
     8const char *ll_index_to_name(int idx);
     9const char *ll_idx_n2a(int idx, char *buf);
     10/* int ll_index_to_type(int idx); */
     11unsigned ll_index_to_flags(int idx);
    1112
    1213#endif /* __LL_MAP_H__ */
  • branches/stable/mindi-busybox/networking/libiproute/ll_proto.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ll_proto.c
     
    1112
    1213#include "libbb.h"
    13 #include <string.h>
    14 
    1514#include "rt_names.h"
    1615#include "utils.h"
    1716
    18 #if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
     17#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1
    1918#include <net/ethernet.h>
    2019#else
     
    2524static struct {
    2625    int id;
    27     char *name;
     26    const char *name;
    2827} llproto_names[] = {
    2928__PF(LOOP,loop)
     
    9897    id = ntohs(id);
    9998
    100     for (i=0; i<sizeof(llproto_names)/sizeof(llproto_names[0]); i++) {
     99    for (i=0; i < ARRAY_SIZE(llproto_names); i++) {
    101100         if (llproto_names[i].id == id)
    102101            return llproto_names[i].name;
     
    109108{
    110109    int i;
    111     for (i=0; i<sizeof(llproto_names)/sizeof(llproto_names[0]); i++) {
     110    for (i=0; i < ARRAY_SIZE(llproto_names); i++) {
    112111         if (strcasecmp(llproto_names[i].name, buf) == 0) {
    113112             *id = htons(llproto_names[i].id);
  • branches/stable/mindi-busybox/networking/libiproute/ll_types.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * ll_types.c
     
    910 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    1011 */
    11 #include <stdio.h>
    1212#include <arpa/inet.h>
    13 
    1413#include <linux/if_arp.h>
    1514
     15#include "libbb.h"
    1616#include "rt_names.h"
    1717
    18 const char * ll_type_n2a(int type, char *buf, int len)
     18const char* ll_type_n2a(int type, char *buf, int len)
    1919{
    2020#define __PF(f,n) { ARPHRD_##f, #n },
    21 static struct {
     21static const struct {
    2222    int type;
    23     char *name;
     23    const char *name;
    2424} arphrd_names[] = {
    2525{ 0, "generic" },
     
    109109
    110110    int i;
    111     for (i=0; i<sizeof(arphrd_names)/sizeof(arphrd_names[0]); i++) {
     111    for (i = 0; i < ARRAY_SIZE(arphrd_names); i++) {
    112112         if (arphrd_names[i].type == type)
    113113            return arphrd_names[i].name;
  • branches/stable/mindi-busybox/networking/libiproute/rt_names.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * rt_names.c       rtnetlink names DB.
     
    910 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    1011 */
    11 #include <stdio.h>
    12 #include <stdlib.h>
    13 #include <string.h>
    14 
    15 #include <stdint.h>
     12
     13#include "libbb.h"
    1614#include "rt_names.h"
    1715
    18 static void rtnl_tab_initialize(char *file, char **tab, int size)
     16static void rtnl_tab_initialize(const char *file, const char **tab, int size)
    1917{
    2018    char buf[512];
     
    3331        if (*p == '#' || *p == '\n' || *p == 0)
    3432            continue;
    35         if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 &&
    36             sscanf(p, "0x%x %s #", &id, namebuf) != 2 &&
    37             sscanf(p, "%d %s\n", &id, namebuf) != 2 &&
    38             sscanf(p, "%d %s #", &id, namebuf) != 2) {
    39             fprintf(stderr, "Database %s is corrupted at %s\n",
     33        if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2
     34         && sscanf(p, "0x%x %s #", &id, namebuf) != 2
     35         && sscanf(p, "%d %s\n", &id, namebuf) != 2
     36         && sscanf(p, "%d %s #", &id, namebuf) != 2
     37        ) {
     38            bb_error_msg("database %s is corrupted at %s",
    4039                file, p);
    4140            return;
    4241        }
    4342
    44         if (id<0 || id>size)
     43        if (id < 0 || id > size)
    4544            continue;
    4645
    47         tab[id] = strdup(namebuf);
     46        tab[id] = xstrdup(namebuf);
    4847    }
    4948    fclose(fp);
     
    5150
    5251
    53 static char * rtnl_rtprot_tab[256] = {
    54     "none",
    55     "redirect",
    56     "kernel",
    57     "boot",
    58     "static",
    59     NULL,
    60     NULL,
    61     NULL,
    62     "gated",
    63     "ra",
    64     "mrt",
    65     "zebra",
    66     "bird",
    67 };
    68 
    69 
    70 
    71 static int rtnl_rtprot_init;
     52static const char **rtnl_rtprot_tab; /* [256] */
    7253
    7354static void rtnl_rtprot_initialize(void)
    7455{
    75     rtnl_rtprot_init = 1;
     56    static const char *const init_tab[] = {
     57        "none",
     58        "redirect",
     59        "kernel",
     60        "boot",
     61        "static",
     62        NULL,
     63        NULL,
     64        NULL,
     65        "gated",
     66        "ra",
     67        "mrt",
     68        "zebra",
     69        "bird",
     70    };
     71    if (rtnl_rtprot_tab) return;
     72    rtnl_rtprot_tab = xzalloc(256 * sizeof(rtnl_rtprot_tab[0]));
     73    memcpy(rtnl_rtprot_tab, init_tab, sizeof(init_tab));
    7674    rtnl_tab_initialize("/etc/iproute2/rt_protos",
    7775                rtnl_rtprot_tab, 256);
    7876}
    7977
    80 const char * rtnl_rtprot_n2a(int id, char *buf, int len)
    81 {
    82     if (id<0 || id>=256) {
    83         snprintf(buf, len, "%d", id);
    84         return buf;
    85     }
    86     if (!rtnl_rtprot_tab[id]) {
    87         if (!rtnl_rtprot_init)
    88             rtnl_rtprot_initialize();
    89     }
     78
     79const char* rtnl_rtprot_n2a(int id, char *buf, int len)
     80{
     81    if (id < 0 || id >= 256) {
     82        snprintf(buf, len, "%d", id);
     83        return buf;
     84    }
     85
     86    rtnl_rtprot_initialize();
     87
    9088    if (rtnl_rtprot_tab[id])
    9189        return rtnl_rtprot_tab[id];
     
    9694int rtnl_rtprot_a2n(uint32_t *id, char *arg)
    9795{
    98     static char *cache = NULL;
    99     static unsigned long res;
    100     char *end;
    101     int i;
    102 
    103     if (cache && strcmp(cache, arg) == 0) {
    104         *id = res;
    105         return 0;
    106     }
    107 
    108     if (!rtnl_rtprot_init)
    109         rtnl_rtprot_initialize();
    110 
    111     for (i=0; i<256; i++) {
     96    static const char *cache = NULL;
     97    static unsigned long res;
     98    int i;
     99
     100    if (cache && strcmp(cache, arg) == 0) {
     101        *id = res;
     102        return 0;
     103    }
     104
     105    rtnl_rtprot_initialize();
     106
     107    for (i = 0; i < 256; i++) {
    112108        if (rtnl_rtprot_tab[i] &&
    113109            strcmp(rtnl_rtprot_tab[i], arg) == 0) {
     
    119115    }
    120116
    121     res = strtoul(arg, &end, 0);
    122     if (!end || end == arg || *end || res > 255)
     117    res = bb_strtoul(arg, NULL, 0);
     118    if (errno || res > 255)
    123119        return -1;
    124120    *id = res;
     
    127123
    128124
    129 
    130 static char * rtnl_rtscope_tab[256] = {
    131     "global",
    132 };
    133 
    134 static int rtnl_rtscope_init;
     125static const char **rtnl_rtscope_tab; /* [256] */
    135126
    136127static void rtnl_rtscope_initialize(void)
    137128{
    138     rtnl_rtscope_init = 1;
     129    if (rtnl_rtscope_tab) return;
     130    rtnl_rtscope_tab = xzalloc(256 * sizeof(rtnl_rtscope_tab[0]));
     131    rtnl_rtscope_tab[0] = "global";
    139132    rtnl_rtscope_tab[255] = "nowhere";
    140133    rtnl_rtscope_tab[254] = "host";
     
    145138}
    146139
    147 const char * rtnl_rtscope_n2a(int id, char *buf, int len)
    148 {
    149     if (id<0 || id>=256) {
    150         snprintf(buf, len, "%d", id);
    151         return buf;
    152     }
    153     if (!rtnl_rtscope_tab[id]) {
    154         if (!rtnl_rtscope_init)
    155             rtnl_rtscope_initialize();
    156     }
     140
     141const char* rtnl_rtscope_n2a(int id, char *buf, int len)
     142{
     143    if (id < 0 || id >= 256) {
     144        snprintf(buf, len, "%d", id);
     145        return buf;
     146    }
     147
     148    rtnl_rtscope_initialize();
     149
    157150    if (rtnl_rtscope_tab[id])
    158151        return rtnl_rtscope_tab[id];
     
    163156int rtnl_rtscope_a2n(uint32_t *id, char *arg)
    164157{
    165     static char *cache = NULL;
    166     static unsigned long res;
    167     char *end;
    168     int i;
    169 
    170     if (cache && strcmp(cache, arg) == 0) {
    171         *id = res;
    172         return 0;
    173     }
    174 
    175     if (!rtnl_rtscope_init)
    176         rtnl_rtscope_initialize();
    177 
    178     for (i=0; i<256; i++) {
     158    static const char *cache = NULL;
     159    static unsigned long res;
     160    int i;
     161
     162    if (cache && strcmp(cache, arg) == 0) {
     163        *id = res;
     164        return 0;
     165    }
     166
     167    rtnl_rtscope_initialize();
     168
     169    for (i = 0; i < 256; i++) {
    179170        if (rtnl_rtscope_tab[i] &&
    180171            strcmp(rtnl_rtscope_tab[i], arg) == 0) {
     
    186177    }
    187178
    188     res = strtoul(arg, &end, 0);
    189     if (!end || end == arg || *end || res > 255)
     179    res = bb_strtoul(arg, NULL, 0);
     180    if (errno || res > 255)
    190181        return -1;
    191182    *id = res;
     
    194185
    195186
    196 
    197 static char * rtnl_rtrealm_tab[256] = {
    198     "unknown",
    199 };
    200 
    201 static int rtnl_rtrealm_init;
     187static const char **rtnl_rtrealm_tab; /* [256] */
    202188
    203189static void rtnl_rtrealm_initialize(void)
    204190{
    205     rtnl_rtrealm_init = 1;
     191    if (rtnl_rtrealm_tab) return;
     192    rtnl_rtrealm_tab = xzalloc(256 * sizeof(rtnl_rtrealm_tab[0]));
     193    rtnl_rtrealm_tab[0] = "unknown";
    206194    rtnl_tab_initialize("/etc/iproute2/rt_realms",
    207195                rtnl_rtrealm_tab, 256);
    208196}
    209197
     198
    210199int rtnl_rtrealm_a2n(uint32_t *id, char *arg)
    211200{
    212     static char *cache = NULL;
    213     static unsigned long res;
    214     char *end;
    215     int i;
    216 
    217     if (cache && strcmp(cache, arg) == 0) {
    218         *id = res;
    219         return 0;
    220     }
    221 
    222     if (!rtnl_rtrealm_init)
    223         rtnl_rtrealm_initialize();
    224 
    225     for (i=0; i<256; i++) {
     201    static const char *cache = NULL;
     202    static unsigned long res;
     203    int i;
     204
     205    if (cache && strcmp(cache, arg) == 0) {
     206        *id = res;
     207        return 0;
     208    }
     209
     210    rtnl_rtrealm_initialize();
     211
     212    for (i = 0; i < 256; i++) {
    226213        if (rtnl_rtrealm_tab[i] &&
    227214            strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
     
    233220    }
    234221
    235     res = strtoul(arg, &end, 0);
    236     if (!end || end == arg || *end || res > 255)
     222    res = bb_strtoul(arg, NULL, 0);
     223    if (errno || res > 255)
    237224        return -1;
    238225    *id = res;
     
    240227}
    241228
    242 
    243 
    244 static char * rtnl_rtdsfield_tab[256] = {
    245     "0",
    246 };
    247 
    248 static int rtnl_rtdsfield_init;
     229#if ENABLE_FEATURE_IP_RULE
     230const char* rtnl_rtrealm_n2a(int id, char *buf, int len)
     231{
     232    if (id < 0 || id >= 256) {
     233        snprintf(buf, len, "%d", id);
     234        return buf;
     235    }
     236
     237    rtnl_rtrealm_initialize();
     238
     239    if (rtnl_rtrealm_tab[id])
     240        return rtnl_rtrealm_tab[id];
     241    snprintf(buf, len, "%d", id);
     242    return buf;
     243}
     244#endif
     245
     246
     247static const char **rtnl_rtdsfield_tab; /* [256] */
    249248
    250249static void rtnl_rtdsfield_initialize(void)
    251250{
    252     rtnl_rtdsfield_init = 1;
     251    if (rtnl_rtdsfield_tab) return;
     252    rtnl_rtdsfield_tab = xzalloc(256 * sizeof(rtnl_rtdsfield_tab[0]));
     253    rtnl_rtdsfield_tab[0] = "0";
    253254    rtnl_tab_initialize("/etc/iproute2/rt_dsfield",
    254255                rtnl_rtdsfield_tab, 256);
    255256}
    256257
     258
    257259const char * rtnl_dsfield_n2a(int id, char *buf, int len)
    258260{
    259     if (id<0 || id>=256) {
    260         snprintf(buf, len, "%d", id);
    261         return buf;
    262     }
    263     if (!rtnl_rtdsfield_tab[id]) {
    264         if (!rtnl_rtdsfield_init)
    265             rtnl_rtdsfield_initialize();
    266     }
     261    if (id < 0 || id >= 256) {
     262        snprintf(buf, len, "%d", id);
     263        return buf;
     264    }
     265
     266    rtnl_rtdsfield_initialize();
     267
    267268    if (rtnl_rtdsfield_tab[id])
    268269        return rtnl_rtdsfield_tab[id];
     
    274275int rtnl_dsfield_a2n(uint32_t *id, char *arg)
    275276{
    276     static char *cache = NULL;
    277     static unsigned long res;
    278     char *end;
    279     int i;
    280 
    281     if (cache && strcmp(cache, arg) == 0) {
    282         *id = res;
    283         return 0;
    284     }
    285 
    286     if (!rtnl_rtdsfield_init)
    287         rtnl_rtdsfield_initialize();
    288 
    289     for (i=0; i<256; i++) {
     277    static const char *cache = NULL;
     278    static unsigned long res;
     279    int i;
     280
     281    if (cache && strcmp(cache, arg) == 0) {
     282        *id = res;
     283        return 0;
     284    }
     285
     286    rtnl_rtdsfield_initialize();
     287
     288    for (i = 0; i < 256; i++) {
    290289        if (rtnl_rtdsfield_tab[i] &&
    291290            strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
     
    297296    }
    298297
    299     res = strtoul(arg, &end, 16);
    300     if (!end || end == arg || *end || res > 255)
     298    res = bb_strtoul(arg, NULL, 16);
     299    if (errno || res > 255)
    301300        return -1;
    302301    *id = res;
     
    304303}
    305304
     305
     306#if ENABLE_FEATURE_IP_RULE
     307static const char **rtnl_rttable_tab; /* [256] */
     308
     309static void rtnl_rttable_initialize(void)
     310{
     311    if (rtnl_rtdsfield_tab) return;
     312    rtnl_rttable_tab = xzalloc(256 * sizeof(rtnl_rttable_tab[0]));
     313    rtnl_rttable_tab[0] = "unspec";
     314    rtnl_rttable_tab[255] = "local";
     315    rtnl_rttable_tab[254] = "main";
     316    rtnl_rttable_tab[253] = "default";
     317    rtnl_tab_initialize("/etc/iproute2/rt_tables", rtnl_rttable_tab, 256);
     318}
     319
     320
     321const char *rtnl_rttable_n2a(int id, char *buf, int len)
     322{
     323    if (id < 0 || id >= 256) {
     324        snprintf(buf, len, "%d", id);
     325        return buf;
     326    }
     327
     328    rtnl_rttable_initialize();
     329
     330    if (rtnl_rttable_tab[id])
     331        return rtnl_rttable_tab[id];
     332    snprintf(buf, len, "%d", id);
     333    return buf;
     334}
     335
     336int rtnl_rttable_a2n(uint32_t * id, char *arg)
     337{
     338    static char *cache = NULL;
     339    static unsigned long res;
     340    int i;
     341
     342    if (cache && strcmp(cache, arg) == 0) {
     343        *id = res;
     344        return 0;
     345    }
     346
     347    rtnl_rttable_initialize();
     348
     349    for (i = 0; i < 256; i++) {
     350        if (rtnl_rttable_tab[i] && strcmp(rtnl_rttable_tab[i], arg) == 0) {
     351            cache = (char*)rtnl_rttable_tab[i];
     352            res = i;
     353            *id = res;
     354            return 0;
     355        }
     356    }
     357
     358    i = bb_strtoul(arg, NULL, 0);
     359    if (errno || i > 255)
     360        return -1;
     361    *id = i;
     362    return 0;
     363}
     364
     365#endif
  • branches/stable/mindi-busybox/networking/libiproute/rt_names.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12#ifndef RT_NAMES_H_
    23#define RT_NAMES_H_ 1
     
    67extern const char* rtnl_rtprot_n2a(int id, char *buf, int len);
    78extern const char* rtnl_rtscope_n2a(int id, char *buf, int len);
     9extern const char* rtnl_rtrealm_n2a(int id, char *buf, int len);
    810extern const char* rtnl_dsfield_n2a(int id, char *buf, int len);
     11extern const char* rtnl_rttable_n2a(int id, char *buf, int len);
    912extern int rtnl_rtprot_a2n(uint32_t *id, char *arg);
    1013extern int rtnl_rtscope_a2n(uint32_t *id, char *arg);
    1114extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg);
    1215extern int rtnl_dsfield_a2n(uint32_t *id, char *arg);
     16extern int rtnl_rttable_a2n(uint32_t *id, char *arg);
    1317
    1418
    15 extern const char * ll_type_n2a(int type, char *buf, int len);
     19extern const char* ll_type_n2a(int type, char *buf, int len);
    1620
    17 extern const char *ll_addr_n2a(unsigned char *addr, int alen, int type,
     21extern const char* ll_addr_n2a(unsigned char *addr, int alen, int type,
    1822                char *buf, int blen);
    1923extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg);
    2024
    21 extern const char * ll_proto_n2a(unsigned short id, char *buf, int len);
     25extern const char* ll_proto_n2a(unsigned short id, char *buf, int len);
    2226extern int ll_proto_a2n(unsigned short *id, char *buf);
    2327
    24 
    2528#endif
  • branches/stable/mindi-busybox/networking/libiproute/rtm_map.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * rtm_map.c
     
    1112 */
    1213
    13 #include <stdlib.h>
    14 #include <string.h>
    15 
     14#include "libbb.h"
    1615#include "rt_names.h"
    1716#include "utils.h"
    1817
    19 char *rtnl_rtntype_n2a(int id, char *buf, int len)
     18const char *rtnl_rtntype_n2a(int id, char *buf, int len)
    2019{
    2120    switch (id) {
     
    5352int rtnl_rtntype_a2n(int *id, char *arg)
    5453{
     54    static const char keywords[] ALIGN1 =
     55        "local\0""nat\0""broadcast\0""brd\0""anycast\0"
     56        "multicast\0""prohibit\0""unreachable\0""blackhole\0"
     57        "xresolve\0""unicast\0""throw\0";
     58    enum {
     59        ARG_local = 1, ARG_nat, ARG_broadcast, ARG_brd, ARG_anycast,
     60        ARG_multicast, ARG_prohibit, ARG_unreachable, ARG_blackhole,
     61        ARG_xresolve, ARG_unicast, ARG_throw
     62    };
     63    const smalluint key = index_in_substrings(keywords, arg) + 1;
    5564    char *end;
    5665    unsigned long res;
    5766
    58     if (strcmp(arg, "local") == 0)
     67    if (key == ARG_local)
    5968        res = RTN_LOCAL;
    60     else if (strcmp(arg, "nat") == 0)
     69    else if (key == ARG_nat)
    6170        res = RTN_NAT;
    62     else if (matches(arg, "broadcast") == 0 ||
    63          strcmp(arg, "brd") == 0)
     71    else if (key == ARG_broadcast || key == ARG_brd)
    6472        res = RTN_BROADCAST;
    65     else if (matches(arg, "anycast") == 0)
     73    else if (key == ARG_anycast)
    6674        res = RTN_ANYCAST;
    67     else if (matches(arg, "multicast") == 0)
     75    else if (key == ARG_multicast)
    6876        res = RTN_MULTICAST;
    69     else if (matches(arg, "prohibit") == 0)
     77    else if (key == ARG_prohibit)
    7078        res = RTN_PROHIBIT;
    71     else if (matches(arg, "unreachable") == 0)
     79    else if (key == ARG_unreachable)
    7280        res = RTN_UNREACHABLE;
    73     else if (matches(arg, "blackhole") == 0)
     81    else if (key == ARG_blackhole)
    7482        res = RTN_BLACKHOLE;
    75     else if (matches(arg, "xresolve") == 0)
     83    else if (key == ARG_xresolve)
    7684        res = RTN_XRESOLVE;
    77     else if (matches(arg, "unicast") == 0)
     85    else if (key == ARG_unicast)
    7886        res = RTN_UNICAST;
    79     else if (strcmp(arg, "throw") == 0)
     87    else if (key == ARG_throw)
    8088        res = RTN_THROW;
    8189    else {
     
    8896}
    8997
    90 int get_rt_realms(__u32 *realms, char *arg)
     98int get_rt_realms(uint32_t *realms, char *arg)
    9199{
    92     __u32 realm = 0;
     100    uint32_t realm = 0;
    93101    char *p = strchr(arg, '/');
    94102
  • branches/stable/mindi-busybox/networking/libiproute/rtm_map.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12#ifndef __RTM_MAP_H__
    23#define __RTM_MAP_H__ 1
    34
    4 char *rtnl_rtntype_n2a(int id, char *buf, int len);
     5const char *rtnl_rtntype_n2a(int id, char *buf, int len);
    56int rtnl_rtntype_a2n(int *id, char *arg);
    67
    7 int get_rt_realms(__u32 *realms, char *arg);
     8int get_rt_realms(uint32_t *realms, char *arg);
    89
    910
  • branches/stable/mindi-busybox/networking/libiproute/utils.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * utils.c
     
    1213
    1314#include "libbb.h"
    14 
    15 #include <string.h>
    16 #include <unistd.h>
    17 
    1815#include "utils.h"
    1916#include "inet_common.h"
     
    3229    return 0;
    3330}
    34 
     31//XXX: FIXME: use some libbb function instead
    3532int get_unsigned(unsigned *val, char *arg, int base)
    3633{
     
    4744}
    4845
    49 int get_u32(__u32 * val, char *arg, int base)
     46int get_u32(uint32_t * val, char *arg, int base)
    5047{
    5148    unsigned long res;
     
    6158}
    6259
    63 int get_u16(__u16 * val, char *arg, int base)
     60int get_u16(uint16_t * val, char *arg, int base)
    6461{
    6562    unsigned long res;
     
    7572}
    7673
    77 int get_u8(__u8 * val, char *arg, int base)
     74int get_u8(uint8_t * val, char *arg, int base)
    7875{
    7976    unsigned long res;
     
    8986}
    9087
    91 int get_s16(__s16 * val, char *arg, int base)
     88int get_s16(int16_t * val, char *arg, int base)
    9289{
    9390    long res;
     
    103100}
    104101
    105 int get_s8(__s8 * val, char *arg, int base)
     102int get_s8(int8_t * val, char *arg, int base)
    106103{
    107104    long res;
     
    125122    memset(addr, 0, sizeof(*addr));
    126123
    127     if (strcmp(name, bb_INET_default) == 0 ||
     124    if (strcmp(name, bb_str_default) == 0 ||
    128125        strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
    129126        addr->family = family;
     
    169166    memset(dst, 0, sizeof(*dst));
    170167
    171     if (strcmp(arg, bb_INET_default) == 0 || strcmp(arg, "any") == 0) {
     168    if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) {
    172169        dst->family = family;
    173170        dst->bytelen = 0;
     
    178175    slash = strchr(arg, '/');
    179176    if (slash)
    180         *slash = 0;
     177        *slash = '\0';
    181178    err = get_addr_1(dst, arg, family);
    182179    if (err == 0) {
     
    197194        }
    198195    }
    199   done:
     196 done:
    200197    if (slash)
    201198        *slash = '/';
     
    206203{
    207204    if (family == AF_PACKET) {
    208         bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
     205        bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg);
    209206    }
    210207    if (get_addr_1(dst, arg, family)) {
    211         bb_error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
     208        bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg);
    212209    }
    213210    return 0;
     
    217214{
    218215    if (family == AF_PACKET) {
    219         bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
     216        bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg);
    220217    }
    221218    if (get_prefix_1(dst, arg, family)) {
    222         bb_error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
    223     }
    224     return 0;
    225 }
    226 
    227 __u32 get_addr32(char *name)
     219        bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg);
     220    }
     221    return 0;
     222}
     223
     224uint32_t get_addr32(char *name)
    228225{
    229226    inet_prefix addr;
     
    237234void incomplete_command(void)
    238235{
    239     bb_error_msg("Command line is not complete. Try option \"help\"");
    240     exit(-1);
    241 }
    242 
    243 void invarg(const char * const arg, const char * const opt)
    244 {
    245     bb_error_msg(bb_msg_invalid_arg, arg, opt);
    246     exit(-1);
    247 }
    248 
    249 void duparg(char *key, char *arg)
    250 {
    251     bb_error_msg("duplicate \"%s\": \"%s\" is the second value.", key, arg);
    252     exit(-1);
    253 }
    254 
    255 void duparg2(char *key, char *arg)
    256 {
    257     bb_error_msg("either \"%s\" is duplicate, or \"%s\" is a garbage.", key, arg);
    258     exit(-1);
    259 }
    260 
    261 int matches(char *cmd, char *pattern)
    262 {
    263     int len = strlen(cmd);
    264 
    265     if (len > strlen(pattern)) {
    266         return -1;
    267     }
    268     return memcmp(pattern, cmd, len);
     236    bb_error_msg_and_die("command line is not complete, try option \"help\"");
     237}
     238
     239void invarg(const char *arg, const char *opt)
     240{
     241    bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt);
     242}
     243
     244void duparg(const char *key, const char *arg)
     245{
     246    bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg);
     247}
     248
     249void duparg2(const char *key, const char *arg)
     250{
     251    bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg);
    269252}
    270253
    271254int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
    272255{
    273     __u32 *a1 = a->data;
    274     __u32 *a2 = b->data;
     256    uint32_t *a1 = a->data;
     257    uint32_t *a2 = b->data;
    275258    int words = bits >> 0x05;
    276259
     
    282265
    283266    if (bits) {
    284         __u32 w1, w2;
    285         __u32 mask;
     267        uint32_t w1, w2;
     268        uint32_t mask;
    286269
    287270        w1 = a1[words];
     
    295278
    296279    return 0;
    297 }
    298 
    299 int __iproute2_hz_internal;
    300 
    301 int __get_hz(void)
    302 {
    303     int hz = 0;
    304     FILE *fp = fopen("/proc/net/psched", "r");
    305 
    306     if (fp) {
    307         unsigned nom, denom;
    308 
    309         if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
    310             if (nom == 1000000)
    311                 hz = denom;
    312         fclose(fp);
    313     }
    314     if (hz)
    315         return hz;
    316     return sysconf(_SC_CLK_TCK);
    317280}
    318281
     
    347310            }
    348311        }
    349         if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) {
    350             snprintf(buf, buflen - 1, "%s", h_ent->h_name);
    351             return buf;
     312        if (len > 0) {
     313            h_ent = gethostbyaddr(addr, len, af);
     314            if (h_ent != NULL) {
     315                safe_strncpy(buf, h_ent->h_name, buflen);
     316                return buf;
     317            }
    352318        }
    353319    }
  • branches/stable/mindi-busybox/networking/libiproute/utils.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12#ifndef __UTILS_H__
    23#define __UTILS_H__ 1
    3 
    4 #include "libbb.h"
    5 #include <asm/types.h>
    6 #include <resolv.h>
    74
    85#include "libnetlink.h"
     
    118
    129extern int preferred_family;
    13 extern int show_stats;
    14 extern int show_details;
    15 extern int show_raw;
    16 extern int resolve_hosts;
    17 extern int oneline;
    18 extern char * _SL_;
     10extern smallint show_stats;    /* UNUSED */
     11extern smallint show_details;  /* UNUSED */
     12extern smallint show_raw;      /* UNUSED */
     13extern smallint resolve_hosts; /* UNUSED */
     14extern smallint oneline;
     15extern char _SL_;
    1916
    2017#ifndef IPPROTO_ESP
     
    3027extern void incomplete_command(void) ATTRIBUTE_NORETURN;
    3128
    32 #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0)
     29#define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while (0)
    3330
    3431typedef struct
    3532{
    36     __u8 family;
    37     __u8 bytelen;
    38     __s16 bitlen;
    39     __u32 data[4];
     33    uint8_t family;
     34    uint8_t bytelen;
     35    int16_t bitlen;
     36    uint32_t data[4];
    4037} inet_prefix;
    4138
     
    4542#endif
    4643
    47 struct dn_naddr
    48 {
     44struct dn_naddr {
    4945    unsigned short          a_len;
    5046    unsigned char a_addr[DN_MAXADDL];
     
    5854};
    5955
    60 extern __u32 get_addr32(char *name);
     56extern uint32_t get_addr32(char *name);
    6157extern int get_addr_1(inet_prefix *dst, char *arg, int family);
    6258extern int get_prefix_1(inet_prefix *dst, char *arg, int family);
     
    6965#define get_ushort get_u16
    7066#define get_short get_s16
    71 extern int get_u32(__u32 *val, char *arg, int base);
    72 extern int get_u16(__u16 *val, char *arg, int base);
    73 extern int get_s16(__s16 *val, char *arg, int base);
    74 extern int get_u8(__u8 *val, char *arg, int base);
    75 extern int get_s8(__s8 *val, char *arg, int base);
     67extern int get_u32(uint32_t *val, char *arg, int base);
     68extern int get_u16(uint16_t *val, char *arg, int base);
     69extern int get_s16(int16_t *val, char *arg, int base);
     70extern int get_u8(uint8_t *val, char *arg, int base);
     71extern int get_s8(int8_t *val, char *arg, int base);
    7672
    7773extern const char *format_host(int af, int len, void *addr, char *buf, int buflen);
    7874extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen);
    7975
    80 void invarg(const char * const, const char * const) ATTRIBUTE_NORETURN;
    81 void duparg(char *, char *) ATTRIBUTE_NORETURN;
    82 void duparg2(char *, char *) ATTRIBUTE_NORETURN;
    83 int matches(char *arg, char *pattern);
    84 extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits);
     76void invarg(const char *, const char *) ATTRIBUTE_NORETURN;
     77void duparg(const char *, const char *) ATTRIBUTE_NORETURN;
     78void duparg2(const char *, const char *) ATTRIBUTE_NORETURN;
     79int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits);
    8580
    8681const char *dnet_ntop(int af, const void *addr, char *str, size_t len);
     
    9085int ipx_pton(int af, const char *src, void *addr);
    9186
    92 extern int __iproute2_hz_internal;
    93 extern int __get_hz(void);
    94 
    95 static __inline__ int get_hz(void)
    96 {
    97     if (__iproute2_hz_internal == 0)
    98         __iproute2_hz_internal = __get_hz();
    99     return __iproute2_hz_internal;
    100 }
    101 
    10287#endif /* __UTILS_H__ */
  • branches/stable/mindi-busybox/networking/nameif.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * nameif.c - Naming Interfaces based on MAC address for busybox.
     
    910 */
    1011
    11 #include "busybox.h"
    12 
    13 #include <sys/syslog.h>
    14 #include <sys/socket.h>
    15 #include <sys/ioctl.h>
    16 #include <errno.h>
    17 #include <string.h>
    18 #include <unistd.h>
     12#include "libbb.h"
     13#include <syslog.h>
    1914#include <net/if.h>
    2015#include <netinet/ether.h>
     
    4742} mactable_t;
    4843
    49 static unsigned long flags;
    50 
    51 static void serror(const char *s, ...) ATTRIBUTE_NORETURN;
    52 
    53 static void serror(const char *s, ...)
    54 {
    55     va_list ap;
    56 
    57     va_start(ap, s);
    58 
    59     if (flags & 1) {
    60         openlog(bb_applet_name, 0, LOG_LOCAL0);
    61         vsyslog(LOG_ERR, s, ap);
    62         closelog();
    63     } else {
    64         bb_verror_msg(s, ap);
    65         putc('\n', stderr);
    66     }
    67     va_end(ap);
    68 
    69     exit(EXIT_FAILURE);
    70 }
    71 
    7244/* Check ascii str_macaddr, convert and copy to *mac */
    7345static struct ether_addr *cc_macaddr(const char *str_macaddr)
     
    7749    lmac = ether_aton(str_macaddr);
    7850    if (lmac == NULL)
    79         serror("cannot parse MAC %s", str_macaddr);
     51        bb_error_msg_and_die("cannot parse MAC %s", str_macaddr);
    8052    mac = xmalloc(ETH_ALEN);
    8153    memcpy(mac, lmac, ETH_ALEN);
     
    8456}
    8557
     58int nameif_main(int argc, char **argv);
    8659int nameif_main(int argc, char **argv)
    8760{
     
    9467    mactable_t *ch;
    9568
    96     flags = bb_getopt_ulflags(argc, argv, "sc:", &fname);
     69    if (1 & getopt32(argv, "sc:", &fname)) {
     70        openlog(applet_name, 0, LOG_LOCAL0);
     71        logmode = LOGMODE_SYSLOG;
     72    }
    9773
    9874    if ((argc - optind) & 1)
     
    10379
    10480        while (*a) {
    105 
    10681            if (strlen(*a) > IF_NAMESIZE)
    107                 serror("interface name `%s' too long", *a);
     82                bb_error_msg_and_die("interface name '%s' "
     83                        "too long", *a);
    10884            ch = xzalloc(sizeof(mactable_t));
    109             ch->ifname = bb_xstrdup(*a++);
     85            ch->ifname = xstrdup(*a++);
    11086            ch->mac = cc_macaddr(*a++);
    11187            if (clist)
     
    11591        }
    11692    } else {
    117         ifh = bb_xfopen(fname, "r");
     93        ifh = xfopen(fname, "r");
    11894
    119         while ((line = bb_get_line_from_file(ifh)) != NULL) {
     95        while ((line = xmalloc_fgets(ifh)) != NULL) {
    12096            char *line_ptr;
    12197            size_t name_length;
     
    128104            name_length = strcspn(line_ptr, " \t");
    129105            ch = xzalloc(sizeof(mactable_t));
    130             ch->ifname = bb_xstrndup(line_ptr, name_length);
     106            ch->ifname = xstrndup(line_ptr, name_length);
    131107            if (name_length > IF_NAMESIZE)
    132                 serror("interface name `%s' too long", ch->ifname);
     108                bb_error_msg_and_die("interface name '%s' "
     109                        "too long", ch->ifname);
    133110            line_ptr += name_length;
    134111            line_ptr += strspn(line_ptr, " \t");
     
    145122    }
    146123
    147     if ((ctl_sk = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
    148         serror("socket: %m");
     124    ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0);
    149125
    150126    while (clist) {
     
    173149
    174150        strcpy(ifr.ifr_newname, ch->ifname);
    175         if (ioctl(ctl_sk, SIOCSIFNAME, &ifr) < 0)
    176             serror("cannot change ifname %s to %s: %m",
    177                    ifr.ifr_name, ch->ifname);
     151        ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr,
     152                    "cannot change ifname %s to %s",
     153                    ifr.ifr_name, ch->ifname);
    178154
    179155        /* Remove list entry of renamed interface */
  • branches/stable/mindi-busybox/networking/nc.c

    r821 r1770  
    11/* vi: set sw=4 ts=4: */
    22/*  nc: mini-netcat - built from the ground up for LRP
    3     Copyright (C) 1998  Charles P. Wright
    4 
    5     0.0.1   6K      It works.
    6     0.0.2   5K      Smaller and you can also check the exit condition if you wish.
    7     0.0.3           Uses select()
    8 
    9     19980918 Busy Boxed! Dave Cinege
    10     19990512 Uses Select. Charles P. Wright
    11     19990513 Fixes stdin stupidity and uses buffers.  Charles P. Wright
    12 
    13     Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    14 */
    15 
    16 #include <stdio.h>
    17 #include <stdlib.h>
    18 #include <string.h>
    19 #include <unistd.h>
    20 #include <signal.h>
    21 
    22 #include <sys/types.h>
    23 #include <sys/socket.h>
    24 #include <netinet/in.h>
    25 #include <arpa/inet.h>
    26 #include <netdb.h>
    27 #include <sys/ioctl.h>
    28 #include "busybox.h"
     3 *
     4 *  Copyright (C) 1998, 1999  Charles P. Wright
     5 *  Copyright (C) 1998  Dave Cinege
     6 *
     7 *  Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 */
     9
     10#include "libbb.h"
     11
     12#if ENABLE_DESKTOP
     13#include "nc_bloaty.c"
     14#else
     15
     16/* Lots of small differences in features
     17 * when compared to "standard" nc
     18 */
    2919
    3020static void timeout(int signum)
    3121{
    32     bb_error_msg_and_die("Timed out");
     22    bb_error_msg_and_die("timed out");
    3323}
    3424
     25int nc_main(int argc, char **argv);
    3526int nc_main(int argc, char **argv)
    3627{
    37     int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x;
    38 
    39 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
    40     char *pr00gie = NULL;
    41 #endif
    42 
    43     struct sockaddr_in address;
    44     struct hostent *hostinfo;
    45 
     28    /* sfd sits _here_ only because of "repeat" option (-l -l). */
     29    int sfd = sfd; /* for gcc */
     30    int cfd = 0;
     31    unsigned lport = 0;
     32    SKIP_NC_SERVER(const) unsigned do_listen = 0;
     33    SKIP_NC_EXTRA (const) unsigned wsecs = 0;
     34    SKIP_NC_EXTRA (const) unsigned delay = 0;
     35    SKIP_NC_EXTRA (const int execparam = 0;)
     36    USE_NC_EXTRA  (char **execparam = NULL;)
     37    len_and_sockaddr *lsa;
    4638    fd_set readfds, testfds;
    47 
    48     while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) {
    49         switch (opt) {
    50             case 'l':
    51                 do_listen++;
    52                 break;
    53             case 'p':
    54                 lport = bb_lookup_port(optarg, "tcp", 0);
    55                 break;
    56             case 'i':
    57                 delay = atoi(optarg);
    58                 break;
    59 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
    60             case 'e':
    61                 pr00gie = optarg;
    62                 break;
    63 #endif
    64             case 'w':
    65                 wsecs = atoi(optarg);
    66                 break;
    67             default:
    68                 bb_show_usage();
    69         }
    70     }
    71 
    72     if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
    73         bb_show_usage();
    74 
    75     sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
    76     x = 1;
    77     if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
    78         bb_perror_msg_and_die("reuseaddr");
    79     address.sin_family = AF_INET;
     39    int opt; /* must be signed (getopt returns -1) */
     40
     41    if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
     42        /* getopt32 is _almost_ usable:
     43        ** it cannot handle "... -e prog -prog-opt" */
     44        while ((opt = getopt(argc, argv,
     45                "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0
     46        ) {
     47            if (ENABLE_NC_SERVER && opt=='l')      USE_NC_SERVER(do_listen++);
     48            else if (ENABLE_NC_SERVER && opt=='p') {
     49                USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
     50            }
     51            else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg));
     52            else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg));
     53            else if (ENABLE_NC_EXTRA && opt=='f') USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
     54            else if (ENABLE_NC_EXTRA && opt=='e' && optind<=argc) {
     55                /* We cannot just 'break'. We should let getopt finish.
     56                ** Or else we won't be able to find where
     57                ** 'host' and 'port' params are
     58                ** (think "nc -w 60 host port -e prog"). */
     59                USE_NC_EXTRA(
     60                    char **p;
     61                    // +2: one for progname (optarg) and one for NULL
     62                    execparam = xzalloc(sizeof(char*) * (argc - optind + 2));
     63                    p = execparam;
     64                    *p++ = optarg;
     65                    while (optind < argc) {
     66                        *p++ = argv[optind++];
     67                    }
     68                )
     69                /* optind points to argv[arvc] (NULL) now.
     70                ** FIXME: we assume that getopt will not count options
     71                ** possibly present on "-e prog args" and will not
     72                ** include them into final value of optind
     73                ** which is to be used ...  */
     74            } else bb_show_usage();
     75        }
     76        argv += optind; /* ... here! */
     77        argc -= optind;
     78        // -l and -f don't mix
     79        if (do_listen && cfd) bb_show_usage();
     80        // Listen or file modes need zero arguments, client mode needs 2
     81        if (do_listen || cfd) {
     82            if (argc) bb_show_usage();
     83        } else {
     84            if (!argc || argc > 2) bb_show_usage();
     85        }
     86    } else {
     87        if (argc != 3) bb_show_usage();
     88        argc--;
     89        argv++;
     90    }
    8091
    8192    if (wsecs) {
     
    8495    }
    8596
    86     if (lport != 0) {
    87         memset(&address.sin_addr, 0, sizeof(address.sin_addr));
    88         address.sin_port = lport;
    89 
    90         bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
    91     }
    92 
    93     if (do_listen) {
    94         socklen_t addrlen = sizeof(address);
    95 
    96         bb_xlisten(sfd, 1);
    97         if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
    98             bb_perror_msg_and_die("accept");
    99 
    100         close(sfd);
    101         sfd = tmpfd;
    102     } else {
    103         hostinfo = xgethostbyname(argv[optind]);
    104 
    105         address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
    106         address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
    107 
    108         if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
    109             bb_perror_msg_and_die("connect");
     97    if (!cfd) {
     98        if (do_listen) {
     99            /* create_and_bind_stream_or_die(NULL, lport)
     100             * would've work wonderfully, but we need
     101             * to know lsa */
     102            sfd = xsocket_stream(&lsa);
     103            if (lport)
     104                set_nport(lsa, htons(lport));
     105            setsockopt_reuseaddr(sfd);
     106            xbind(sfd, &lsa->sa, lsa->len);
     107            xlisten(sfd, do_listen); /* can be > 1 */
     108            /* If we didn't specify a port number,
     109             * query and print it after listen() */
     110            if (!lport) {
     111                socklen_t addrlen = lsa->len;
     112                getsockname(sfd, &lsa->sa, &addrlen);
     113                lport = get_nport(&lsa->sa);
     114                fdprintf(2, "%d\n", ntohs(lport));
     115            }
     116            fcntl(sfd, F_SETFD, FD_CLOEXEC);
     117 accept_again:
     118            cfd = accept(sfd, NULL, 0);
     119            if (cfd < 0)
     120                bb_perror_msg_and_die("accept");
     121            if (!execparam)
     122                close(sfd);
     123        } else {
     124            cfd = create_and_connect_stream_or_die(argv[0],
     125                argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0);
     126        }
    110127    }
    111128
     
    115132    }
    116133
    117 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
    118134    /* -e given? */
    119     if (pr00gie) {
    120         dup2(sfd, 0);
    121         close(sfd);
     135    if (execparam) {
     136        signal(SIGCHLD, SIG_IGN);
     137        // With more than one -l, repeatedly act as server.
     138        if (do_listen > 1 && vfork()) {
     139            /* parent */
     140            // This is a bit weird as cleanup goes, since we wind up with no
     141            // stdin/stdout/stderr.  But it's small and shouldn't hurt anything.
     142            // We check for cfd == 0 above.
     143            logmode = LOGMODE_NONE;
     144            close(0);
     145            close(1);
     146            close(2);
     147            goto accept_again;
     148        }
     149        /* child (or main thread if no multiple -l) */
     150        if (cfd) {
     151            dup2(cfd, 0);
     152            close(cfd);
     153        }
    122154        dup2(0, 1);
    123155        dup2(0, 2);
    124         execl(pr00gie, pr00gie, NULL);
     156        USE_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
    125157        /* Don't print stuff or it will go over the wire.... */
    126         _exit(-1);
    127     }
    128 #endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
     158        _exit(127);
     159    }
     160
     161    // Select loop copying stdin to cfd, and cfd to stdout.
    129162
    130163    FD_ZERO(&readfds);
    131     FD_SET(sfd, &readfds);
     164    FD_SET(cfd, &readfds);
    132165    FD_SET(STDIN_FILENO, &readfds);
    133166
    134     while (1) {
     167    for (;;) {
    135168        int fd;
    136169        int ofd;
     
    142175            bb_perror_msg_and_die("select");
    143176
     177#define iobuf bb_common_bufsiz1
    144178        for (fd = 0; fd < FD_SETSIZE; fd++) {
    145179            if (FD_ISSET(fd, &testfds)) {
    146                 if ((nread = safe_read(fd, bb_common_bufsiz1,
    147                     sizeof(bb_common_bufsiz1))) < 0)
    148                 {
    149                     bb_perror_msg_and_die(bb_msg_read_error);
    150                 }
    151 
    152                 if (fd == sfd) {
    153                     if (nread == 0)
     180                nread = safe_read(fd, iobuf, sizeof(iobuf));
     181                if (fd == cfd) {
     182                    if (nread < 1)
    154183                        exit(0);
    155184                    ofd = STDOUT_FILENO;
    156185                } else {
    157                     if (nread <= 0) {
    158                         shutdown(sfd, 1 /* send */ );
    159                         close(STDIN_FILENO);
     186                    if (nread<1) {
     187                        // Close outgoing half-connection so they get EOF, but
     188                        // leave incoming alone so we can see response.
     189                        shutdown(cfd, 1);
    160190                        FD_CLR(STDIN_FILENO, &readfds);
    161191                    }
    162                     ofd = sfd;
     192                    ofd = cfd;
    163193                }
    164 
    165                 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0)
    166                     bb_perror_msg_and_die(bb_msg_write_error);
    167                 if (delay > 0) {
    168                     sleep(delay);
    169                 }
     194                xwrite(ofd, iobuf, nread);
     195                if (delay > 0) sleep(delay);
    170196            }
    171197        }
    172198    }
    173199}
     200#endif
  • branches/stable/mindi-busybox/networking/netstat.c

    r821 r1770  
    66 * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
    77 *
    8  * This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    16  * General Public License for more details.
    17  *
    18  * You should have received a copy of the GNU General Public License
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    21  *
    228 * 2002-04-20
    239 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
     10 *
     11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    2412 */
    2513
    26 #include <stdio.h>
    27 #include <stdlib.h>
    28 #include <string.h>
    29 #include <stdarg.h>
    30 #include <signal.h>
    31 #include <errno.h>
    32 #include <sys/stat.h>
    33 #include <dirent.h>
    34 #include <unistd.h>
     14#include "libbb.h"
    3515#include "inet_common.h"
    36 #include "busybox.h"
    37 #include "pwd_.h"
    38 
    39 #ifdef CONFIG_ROUTE
    40 extern void displayroutes(int noresolve, int netstatfmt);
    41 #endif
    42 
    43 #define NETSTAT_CONNECTED   0x01
    44 #define NETSTAT_LISTENING   0x02
    45 #define NETSTAT_NUMERIC     0x04
    46 #define NETSTAT_TCP         0x10
    47 #define NETSTAT_UDP         0x20
    48 #define NETSTAT_RAW         0x40
    49 #define NETSTAT_UNIX        0x80
    50 
    51 static int flags = NETSTAT_CONNECTED |
    52             NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
    53 
    54 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
    55 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
    56 #define PROGNAME_WIDTH2(s) #s
    57 
    58 #define PRG_HASH_SIZE 211
    5916
    6017enum {
    61     TCP_ESTABLISHED = 1,
    62     TCP_SYN_SENT,
    63     TCP_SYN_RECV,
    64     TCP_FIN_WAIT1,
    65     TCP_FIN_WAIT2,
    66     TCP_TIME_WAIT,
    67     TCP_CLOSE,
    68     TCP_CLOSE_WAIT,
    69     TCP_LAST_ACK,
    70     TCP_LISTEN,
    71     TCP_CLOSING         /* now a valid state */
     18    OPT_extended = 0x4,
     19    OPT_showroute = 0x100,
     20    OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE,
    7221};
    73 
    74 static const char * const tcp_state[] =
    75 {
    76     "",
    77     "ESTABLISHED",
    78     "SYN_SENT",
    79     "SYN_RECV",
    80     "FIN_WAIT1",
    81     "FIN_WAIT2",
    82     "TIME_WAIT",
    83     "CLOSE",
    84     "CLOSE_WAIT",
    85     "LAST_ACK",
    86     "LISTEN",
    87     "CLOSING"
     22# define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")
     23
     24#define NETSTAT_CONNECTED 0x01
     25#define NETSTAT_LISTENING 0x02
     26#define NETSTAT_NUMERIC   0x04
     27/* Must match getopt32 option string */
     28#define NETSTAT_TCP       0x10
     29#define NETSTAT_UDP       0x20
     30#define NETSTAT_RAW       0x40
     31#define NETSTAT_UNIX      0x80
     32#define NETSTAT_ALLPROTO  (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX)
     33
     34static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;
     35
     36enum {
     37    TCP_ESTABLISHED = 1,
     38    TCP_SYN_SENT,
     39    TCP_SYN_RECV,
     40    TCP_FIN_WAIT1,
     41    TCP_FIN_WAIT2,
     42    TCP_TIME_WAIT,
     43    TCP_CLOSE,
     44    TCP_CLOSE_WAIT,
     45    TCP_LAST_ACK,
     46    TCP_LISTEN,
     47    TCP_CLOSING /* now a valid state */
    8848};
    8949
     50static const char *const tcp_state[] = {
     51    "",
     52    "ESTABLISHED",
     53    "SYN_SENT",
     54    "SYN_RECV",
     55    "FIN_WAIT1",
     56    "FIN_WAIT2",
     57    "TIME_WAIT",
     58    "CLOSE",
     59    "CLOSE_WAIT",
     60    "LAST_ACK",
     61    "LISTEN",
     62    "CLOSING"
     63};
     64
    9065typedef enum {
    91     SS_FREE = 0,        /* not allocated                */
    92     SS_UNCONNECTED,     /* unconnected to any socket    */
    93     SS_CONNECTING,      /* in process of connecting     */
    94     SS_CONNECTED,       /* connected to socket          */
    95     SS_DISCONNECTING        /* in process of disconnecting  */
     66    SS_FREE = 0,     /* not allocated                */
     67    SS_UNCONNECTED,  /* unconnected to any socket    */
     68    SS_CONNECTING,   /* in process of connecting     */
     69    SS_CONNECTED,    /* connected to socket          */
     70    SS_DISCONNECTING /* in process of disconnecting  */
    9671} socket_state;
    9772
    98 #define SO_ACCEPTCON    (1<<16) /* performed a listen           */
    99 #define SO_WAITDATA     (1<<17) /* wait data to read            */
    100 #define SO_NOSPACE      (1<<18) /* no space to write            */
    101 
    102 static char *itoa(unsigned int i)
    103 {
    104     /* 21 digits plus null terminator, good for 64-bit or smaller ints */
    105     static char local[22];
    106     char *p = &local[21];
    107     *p-- = '\0';
    108     do {
    109         *p-- = '0' + i % 10;
    110         i /= 10;
    111     } while (i > 0);
    112     return p + 1;
    113 }
    114 
    115 static char *get_sname(int port, const char *proto, int num)
    116 {
    117     char *str=itoa(ntohs(port));
    118     if (num) {
     73#define SO_ACCEPTCON (1<<16)    /* performed a listen           */
     74#define SO_WAITDATA  (1<<17)    /* wait data to read            */
     75#define SO_NOSPACE   (1<<18)    /* no space to write            */
     76
     77/* Standard printout size */
     78#define PRINT_IP_MAX_SIZE           23
     79#define PRINT_NET_CONN              "%s   %6ld %6ld %-23s %-23s %-12s\n"
     80#define PRINT_NET_CONN_HEADER       "\nProto Recv-Q Send-Q %-23s %-23s State\n"
     81
     82/* When there are IPv6 connections the IPv6 addresses will be
     83 * truncated to none-recognition. The '-W' option makes the
     84 * address columns wide enough to accomodate for longest possible
     85 * IPv6 addresses, i.e. addresses of the form
     86 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd
     87 */
     88#define PRINT_IP_MAX_SIZE_WIDE      51  /* INET6_ADDRSTRLEN + 5 for the port number */
     89#define PRINT_NET_CONN_WIDE         "%s   %6ld %6ld %-51s %-51s %-12s\n"
     90#define PRINT_NET_CONN_HEADER_WIDE  "\nProto Recv-Q Send-Q %-51s %-51s State\n"
     91
     92static const char *net_conn_line = PRINT_NET_CONN;
     93
     94
     95#if ENABLE_FEATURE_IPV6
     96static void build_ipv6_addr(char* local_addr, struct sockaddr_in6* localaddr)
     97{
     98    char addr6[INET6_ADDRSTRLEN];
     99    struct in6_addr in6;
     100
     101    sscanf(local_addr, "%08X%08X%08X%08X",
     102           &in6.s6_addr32[0], &in6.s6_addr32[1],
     103           &in6.s6_addr32[2], &in6.s6_addr32[3]);
     104    inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
     105    inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr->sin6_addr);
     106
     107    localaddr->sin6_family = AF_INET6;
     108}
     109#endif
     110
     111#if ENABLE_FEATURE_IPV6
     112static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr)
     113#else
     114static void build_ipv4_addr(char* local_addr, struct sockaddr_in* localaddr)
     115#endif
     116{
     117    sscanf(local_addr, "%X",
     118           &((struct sockaddr_in *) localaddr)->sin_addr.s_addr);
     119    ((struct sockaddr *) localaddr)->sa_family = AF_INET;
     120}
     121
     122static const char *get_sname(int port, const char *proto, int numeric)
     123{
     124    if (!port)
     125        return "*";
     126    if (!numeric) {
     127        struct servent *se = getservbyport(port, proto);
     128        if (se)
     129            return se->s_name;
     130    }
     131    /* hummm, we may return static buffer here!! */
     132    return itoa(ntohs(port));
     133}
     134
     135static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric)
     136{
     137    enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) };
     138    char *host, *host_port;
     139
     140    /* Code which used "*" for INADDR_ANY is removed: it's ambiguous in IPv6,
     141     * while "0.0.0.0" is not. */
     142
     143    host = numeric ? xmalloc_sockaddr2dotted_noport(addr)
     144                   : xmalloc_sockaddr2host_noport(addr);
     145
     146    host_port = xasprintf("%s:%s", host, get_sname(htons(port), proto, numeric));
     147    free(host);
     148    return host_port;
     149}
     150
     151static void tcp_do_one(int lnr, const char *line)
     152{
     153    char local_addr[64], rem_addr[64];
     154    char more[512];
     155    int num, local_port, rem_port, d, state, timer_run, uid, timeout;
     156#if ENABLE_FEATURE_IPV6
     157    struct sockaddr_in6 localaddr, remaddr;
     158#else
     159    struct sockaddr_in localaddr, remaddr;
     160#endif
     161    unsigned long rxq, txq, time_len, retr, inode;
     162
     163    if (lnr == 0)
     164        return;
     165
     166    more[0] = '\0';
     167    num = sscanf(line,
     168            "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
     169            &d, local_addr, &local_port,
     170            rem_addr, &rem_port, &state,
     171            &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
     172
     173    if (strlen(local_addr) > 8) {
     174#if ENABLE_FEATURE_IPV6
     175        build_ipv6_addr(local_addr, &localaddr);
     176        build_ipv6_addr(rem_addr, &remaddr);
     177#endif
    119178    } else {
    120         struct servent *se=getservbyport(port,proto);
    121         if (se)
    122             str=se->s_name;
    123     }
    124     if (!port) {
    125         str="*";
    126     }
    127     return str;
    128 }
    129 
    130 static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
    131 {
    132     char *port_name;
    133 
    134 #ifdef CONFIG_FEATURE_IPV6
    135     if (addr->sa_family == AF_INET6) {
    136         INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
    137                        (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
    138     } else
    139 #endif
    140     {
    141     INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
    142         0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
    143         0xffffffff);
    144     }
    145     port_name=get_sname(htons(port), proto, numeric);
    146     if ((strlen(ip_port) + strlen(port_name)) > 22)
    147         ip_port[22 - strlen(port_name)] = '\0';
    148     ip_port+=strlen(ip_port);
    149     strcat(ip_port, ":");
    150     strcat(ip_port, port_name);
    151 }
    152 
    153 static void tcp_do_one(int lnr, const char *line)
     179        build_ipv4_addr(local_addr, &localaddr);
     180        build_ipv4_addr(rem_addr, &remaddr);
     181    }
     182
     183    if (num < 10) {
     184        bb_error_msg("warning, got bogus tcp line");
     185        return;
     186    }
     187
     188    if ((rem_port && (flags & NETSTAT_CONNECTED))
     189     || (!rem_port && (flags & NETSTAT_LISTENING))
     190    ) {
     191        char *l = ip_port_str(
     192                (struct sockaddr *) &localaddr, local_port,
     193                "tcp", flags & NETSTAT_NUMERIC);
     194        char *r = ip_port_str(
     195                (struct sockaddr *) &remaddr, rem_port,
     196                "tcp", flags & NETSTAT_NUMERIC);
     197        printf(net_conn_line,
     198            "tcp", rxq, txq, l, r, tcp_state[state]);
     199        free(l);
     200        free(r);
     201    }
     202}
     203
     204static void udp_do_one(int lnr, const char *line)
    154205{
    155206    char local_addr[64], rem_addr[64];
     
    157208    char more[512];
    158209    int num, local_port, rem_port, d, state, timer_run, uid, timeout;
    159 #ifdef CONFIG_FEATURE_IPV6
     210#if ENABLE_FEATURE_IPV6
    160211    struct sockaddr_in6 localaddr, remaddr;
    161     char addr6[INET6_ADDRSTRLEN];
    162     struct in6_addr in6;
    163212#else
    164213    struct sockaddr_in localaddr, remaddr;
     
    171220    more[0] = '\0';
    172221    num = sscanf(line,
    173                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
    174                  &d, local_addr, &local_port,
    175                  rem_addr, &rem_port, &state,
    176                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
     222            "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
     223            &d, local_addr, &local_port,
     224            rem_addr, &rem_port, &state,
     225            &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
    177226
    178227    if (strlen(local_addr) > 8) {
    179 #ifdef CONFIG_FEATURE_IPV6
    180         sscanf(local_addr, "%08X%08X%08X%08X",
    181                &in6.s6_addr32[0], &in6.s6_addr32[1],
    182                &in6.s6_addr32[2], &in6.s6_addr32[3]);
    183         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    184         inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
    185         sscanf(rem_addr, "%08X%08X%08X%08X",
    186                &in6.s6_addr32[0], &in6.s6_addr32[1],
    187                &in6.s6_addr32[2], &in6.s6_addr32[3]);
    188         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    189         inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
    190         localaddr.sin6_family = AF_INET6;
    191         remaddr.sin6_family = AF_INET6;
     228#if ENABLE_FEATURE_IPV6
     229        /* Demangle what the kernel gives us */
     230        build_ipv6_addr(local_addr, &localaddr);
     231        build_ipv6_addr(rem_addr, &remaddr);
    192232#endif
    193233    } else {
    194         sscanf(local_addr, "%X",
    195                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
    196         sscanf(rem_addr, "%X",
    197                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
    198         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
    199         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
     234        build_ipv4_addr(local_addr, &localaddr);
     235        build_ipv4_addr(rem_addr, &remaddr);
    200236    }
    201237
    202238    if (num < 10) {
    203         bb_error_msg("warning, got bogus tcp line.");
    204         return;
    205     }
    206     state_str = tcp_state[state];
    207     if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
    208         (!rem_port && (flags&NETSTAT_LISTENING)))
    209     {
    210         snprint_ip_port(local_addr, sizeof(local_addr),
    211                         (struct sockaddr *) &localaddr, local_port,
    212                         "tcp", flags&NETSTAT_NUMERIC);
    213 
    214         snprint_ip_port(rem_addr, sizeof(rem_addr),
    215                         (struct sockaddr *) &remaddr, rem_port,
    216                         "tcp", flags&NETSTAT_NUMERIC);
    217 
    218         printf("tcp   %6ld %6ld %-23s %-23s %-12s\n",
    219                rxq, txq, local_addr, rem_addr, state_str);
    220 
    221     }
    222 }
    223 
    224 static void udp_do_one(int lnr, const char *line)
    225 {
    226     char local_addr[64], rem_addr[64];
    227     char *state_str, more[512];
    228     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
    229 #ifdef CONFIG_FEATURE_IPV6
    230     struct sockaddr_in6 localaddr, remaddr;
    231     char addr6[INET6_ADDRSTRLEN];
    232     struct in6_addr in6;
    233 #else
    234     struct sockaddr_in localaddr, remaddr;
    235 #endif
    236     unsigned long rxq, txq, time_len, retr, inode;
    237 
    238     if (lnr == 0)
    239         return;
    240 
    241     more[0] = '\0';
    242     num = sscanf(line,
    243                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
    244                  &d, local_addr, &local_port,
    245                  rem_addr, &rem_port, &state,
    246                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
    247 
    248     if (strlen(local_addr) > 8) {
    249 #ifdef CONFIG_FEATURE_IPV6
    250     /* Demangle what the kernel gives us */
    251         sscanf(local_addr, "%08X%08X%08X%08X",
    252                &in6.s6_addr32[0], &in6.s6_addr32[1],
    253                &in6.s6_addr32[2], &in6.s6_addr32[3]);
    254         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    255         inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
    256         sscanf(rem_addr, "%08X%08X%08X%08X",
    257                &in6.s6_addr32[0], &in6.s6_addr32[1],
    258                &in6.s6_addr32[2], &in6.s6_addr32[3]);
    259         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    260         inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
    261         localaddr.sin6_family = AF_INET6;
    262         remaddr.sin6_family = AF_INET6;
    263 #endif
    264     } else {
    265         sscanf(local_addr, "%X",
    266                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
    267         sscanf(rem_addr, "%X",
    268                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
    269         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
    270         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
    271     }
    272 
    273     if (num < 10) {
    274         bb_error_msg("warning, got bogus udp line.");
     239        bb_error_msg("warning, got bogus udp line");
    275240        return;
    276241    }
     
    279244            state_str = "ESTABLISHED";
    280245            break;
    281 
    282246        case TCP_CLOSE:
    283247            state_str = "";
    284248            break;
    285 
    286249        default:
    287250            state_str = "UNKNOWN";
     
    289252    }
    290253
    291 #ifdef CONFIG_FEATURE_IPV6
    292 # define notnull(A) (((A.sin6_family == AF_INET6) &&            \
    293                      ((A.sin6_addr.s6_addr32[0]) ||            \
    294                       (A.sin6_addr.s6_addr32[1]) ||            \
    295                       (A.sin6_addr.s6_addr32[2]) ||            \
    296                       (A.sin6_addr.s6_addr32[3]))) ||          \
    297                     ((A.sin6_family == AF_INET) &&             \
    298                      ((struct sockaddr_in *) &A)->sin_addr.s_addr))
     254#if ENABLE_FEATURE_IPV6
     255# define notnull(A) ( \
     256    ( (A.sin6_family == AF_INET6)                               \
     257      && (A.sin6_addr.s6_addr32[0] | A.sin6_addr.s6_addr32[1] | \
     258          A.sin6_addr.s6_addr32[2] | A.sin6_addr.s6_addr32[3])  \
     259    ) || (                                                      \
     260      (A.sin6_family == AF_INET)                                \
     261      && ((struct sockaddr_in*)&A)->sin_addr.s_addr             \
     262    )                                                           \
     263)
    299264#else
    300265# define notnull(A) (A.sin_addr.s_addr)
    301266#endif
    302     if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
    303         (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
    304267    {
    305         snprint_ip_port(local_addr, sizeof(local_addr),
    306                         (struct sockaddr *) &localaddr, local_port,
    307                         "udp", flags&NETSTAT_NUMERIC);
    308 
    309         snprint_ip_port(rem_addr, sizeof(rem_addr),
    310                         (struct sockaddr *) &remaddr, rem_port,
    311                         "udp", flags&NETSTAT_NUMERIC);
    312 
    313         printf("udp   %6ld %6ld %-23s %-23s %-12s\n",
    314                rxq, txq, local_addr, rem_addr, state_str);
    315 
     268        int have_remaddr = notnull(remaddr);
     269        if ((have_remaddr && (flags & NETSTAT_CONNECTED))
     270         || (!have_remaddr && (flags & NETSTAT_LISTENING))
     271        ) {
     272            char *l = ip_port_str(
     273                (struct sockaddr *) &localaddr, local_port,
     274                "udp", flags & NETSTAT_NUMERIC);
     275            char *r = ip_port_str(
     276                (struct sockaddr *) &remaddr, rem_port,
     277                "udp", flags & NETSTAT_NUMERIC);
     278            printf(net_conn_line,
     279                "udp", rxq, txq, l, r, state_str);
     280            free(l);
     281            free(r);
     282        }
    316283    }
    317284}
     
    320287{
    321288    char local_addr[64], rem_addr[64];
    322     char *state_str, more[512];
     289    char more[512];
    323290    int num, local_port, rem_port, d, state, timer_run, uid, timeout;
    324 #ifdef CONFIG_FEATURE_IPV6
     291#if ENABLE_FEATURE_IPV6
    325292    struct sockaddr_in6 localaddr, remaddr;
    326     char addr6[INET6_ADDRSTRLEN];
    327     struct in6_addr in6;
    328293#else
    329294    struct sockaddr_in localaddr, remaddr;
     
    336301    more[0] = '\0';
    337302    num = sscanf(line,
    338                  "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
    339                  &d, local_addr, &local_port,
    340                  rem_addr, &rem_port, &state,
    341                  &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
     303            "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
     304            &d, local_addr, &local_port,
     305            rem_addr, &rem_port, &state,
     306            &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
    342307
    343308    if (strlen(local_addr) > 8) {
    344 #ifdef CONFIG_FEATURE_IPV6
    345         sscanf(local_addr, "%08X%08X%08X%08X",
    346                &in6.s6_addr32[0], &in6.s6_addr32[1],
    347                &in6.s6_addr32[2], &in6.s6_addr32[3]);
    348         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    349         inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
    350         sscanf(rem_addr, "%08X%08X%08X%08X",
    351                &in6.s6_addr32[0], &in6.s6_addr32[1],
    352                &in6.s6_addr32[2], &in6.s6_addr32[3]);
    353         inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    354         inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
    355         localaddr.sin6_family = AF_INET6;
    356         remaddr.sin6_family = AF_INET6;
     309#if ENABLE_FEATURE_IPV6
     310        build_ipv6_addr(local_addr, &localaddr);
     311        build_ipv6_addr(rem_addr, &remaddr);
    357312#endif
    358313    } else {
    359         sscanf(local_addr, "%X",
    360                &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
    361         sscanf(rem_addr, "%X",
    362                &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
    363         ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
    364         ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
     314        build_ipv4_addr(local_addr, &localaddr);
     315        build_ipv4_addr(rem_addr, &remaddr);
    365316    }
    366317
    367318    if (num < 10) {
    368         bb_error_msg("warning, got bogus raw line.");
    369         return;
    370     }
    371     state_str=itoa(state);
    372 
    373 #ifdef CONFIG_FEATURE_IPV6
    374 # define notnull(A) (((A.sin6_family == AF_INET6) &&            \
    375                      ((A.sin6_addr.s6_addr32[0]) ||            \
    376                       (A.sin6_addr.s6_addr32[1]) ||            \
    377                       (A.sin6_addr.s6_addr32[2]) ||            \
    378                       (A.sin6_addr.s6_addr32[3]))) ||          \
    379                     ((A.sin6_family == AF_INET) &&             \
    380                      ((struct sockaddr_in *) &A)->sin_addr.s_addr))
    381 #else
    382 # define notnull(A) (A.sin_addr.s_addr)
    383 #endif
    384     if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
    385         (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
     319        bb_error_msg("warning, got bogus raw line");
     320        return;
     321    }
     322
    386323    {
    387         snprint_ip_port(local_addr, sizeof(local_addr),
    388                         (struct sockaddr *) &localaddr, local_port,
    389                         "raw", flags&NETSTAT_NUMERIC);
    390 
    391         snprint_ip_port(rem_addr, sizeof(rem_addr),
    392                         (struct sockaddr *) &remaddr, rem_port,
    393                         "raw", flags&NETSTAT_NUMERIC);
    394 
    395         printf("raw   %6ld %6ld %-23s %-23s %-12s\n",
    396                rxq, txq, local_addr, rem_addr, state_str);
    397 
    398     }
    399 }
    400 
    401 #define HAS_INODE 1
     324        int have_remaddr = notnull(remaddr);
     325        if ((have_remaddr && (flags & NETSTAT_CONNECTED))
     326         || (!have_remaddr && (flags & NETSTAT_LISTENING))
     327        ) {
     328            char *l = ip_port_str(
     329                (struct sockaddr *) &localaddr, local_port,
     330                "raw", flags & NETSTAT_NUMERIC);
     331            char *r = ip_port_str(
     332                (struct sockaddr *) &remaddr, rem_port,
     333                "raw", flags & NETSTAT_NUMERIC);
     334            printf(net_conn_line,
     335                "raw", rxq, txq, l, r, itoa(state));
     336            free(l);
     337            free(r);
     338        }
     339    }
     340}
    402341
    403342static void unix_do_one(int nr, const char *line)
    404343{
    405     static int has = 0;
     344    static smallint has_inode = 0;
     345
    406346    char path[PATH_MAX], ss_flags[32];
    407     char *ss_proto, *ss_state, *ss_type;
     347    const char *ss_proto, *ss_state, *ss_type;
    408348    int num, state, type, inode;
    409349    void *d;
     
    412352    if (nr == 0) {
    413353        if (strstr(line, "Inode"))
    414             has |= HAS_INODE;
     354            has_inode = 1;
    415355        return;
    416356    }
    417357    path[0] = '\0';
    418358    num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
    419                  &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
     359            &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
    420360    if (num < 6) {
    421         bb_error_msg("warning, got bogus unix line.");
    422         return;
    423     }
    424     if (!(has & HAS_INODE))
    425         snprintf(path,sizeof(path),"%d",inode);
    426 
    427     if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
     361        bb_error_msg("warning, got bogus unix line");
     362        return;
     363    }
     364    if (!has_inode)
     365        sprintf(path, "%d", inode);
     366
     367    if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
    428368        if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
    429             if (!(flags&NETSTAT_LISTENING))
     369            if (!(flags & NETSTAT_LISTENING))
    430370                return;
    431371        } else {
    432             if (!(flags&NETSTAT_CONNECTED))
     372            if (!(flags & NETSTAT_CONNECTED))
    433373                return;
    434374        }
     
    439379            ss_proto = "unix";
    440380            break;
    441 
    442381        default:
    443382            ss_proto = "??";
     
    448387            ss_type = "STREAM";
    449388            break;
    450 
    451389        case SOCK_DGRAM:
    452390            ss_type = "DGRAM";
    453391            break;
    454 
    455392        case SOCK_RAW:
    456393            ss_type = "RAW";
    457394            break;
    458 
    459395        case SOCK_RDM:
    460396            ss_type = "RDM";
    461397            break;
    462 
    463398        case SOCK_SEQPACKET:
    464399            ss_type = "SEQPACKET";
    465400            break;
    466 
    467401        default:
    468402            ss_type = "UNKNOWN";
     
    473407            ss_state = "FREE";
    474408            break;
    475 
    476409        case SS_UNCONNECTED:
    477410            /*
     
    485418            }
    486419            break;
    487 
    488420        case SS_CONNECTING:
    489421            ss_state = "CONNECTING";
    490422            break;
    491 
    492423        case SS_CONNECTED:
    493424            ss_state = "CONNECTED";
    494425            break;
    495 
    496426        case SS_DISCONNECTING:
    497427            ss_state = "DISCONNECTING";
    498428            break;
    499 
    500429        default:
    501430            ss_state = "UNKNOWN";
     
    509438    if (unix_flags & SO_NOSPACE)
    510439        strcat(ss_flags, "N ");
    511 
    512440    strcat(ss_flags, "]");
    513441
    514442    printf("%-5s %-6ld %-11s %-10s %-13s ",
    515443           ss_proto, refcnt, ss_flags, ss_type, ss_state);
    516     if (has & HAS_INODE)
    517         printf("%-6d ",inode);
     444    if (has_inode)
     445        printf("%-6d ", inode);
    518446    else
    519447        printf("-      ");
     
    531459static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
    532460{
    533     char buffer[8192];
    534461    int lnr = 0;
    535462    FILE *procinfo;
     
    538465    if (procinfo == NULL) {
    539466        if (errno != ENOENT) {
    540             perror(file);
     467            bb_perror_msg("%s", file);
    541468        } else {
    542         bb_error_msg("no support for `%s' on this system.", name);
     469            bb_error_msg("no support for '%s' on this system", name);
    543470        }
    544     } else {
    545         do {
    546             if (fgets(buffer, sizeof(buffer), procinfo))
    547                 (proc)(lnr++, buffer);
    548         } while (!feof(procinfo));
    549         fclose(procinfo);
    550     }
     471        return;
     472    }
     473    do {
     474        char *buffer = xmalloc_fgets(procinfo);
     475        if (buffer) {
     476            (proc)(lnr++, buffer);
     477            free(buffer);
     478        }
     479    } while (!feof(procinfo));
     480    fclose(procinfo);
    551481}
    552482
     
    555485 */
    556486
     487int netstat_main(int argc, char **argv);
    557488int netstat_main(int argc, char **argv)
    558489{
    559     int opt;
    560     int new_flags=0;
    561     int showroute = 0, extended = 0;
    562 #ifdef CONFIG_FEATURE_IPV6
    563     int inet=1;
    564     int inet6=1;
    565 #else
    566 # define inet 1
    567 # define inet6 0
    568 #endif
    569     while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
    570         switch (opt) {
    571         case 'l':
    572             flags &= ~NETSTAT_CONNECTED;
    573             flags |= NETSTAT_LISTENING;
    574             break;
    575         case 'a':
    576             flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
    577             break;
    578         case 'n':
    579             flags |= NETSTAT_NUMERIC;
    580             break;
    581         case 'r':
    582             showroute = 1;
    583             break;
    584         case 'e':
    585             extended = 1;
    586             break;
    587         case 't':
    588             new_flags |= NETSTAT_TCP;
    589             break;
    590         case 'u':
    591             new_flags |= NETSTAT_UDP;
    592             break;
    593         case 'w':
    594             new_flags |= NETSTAT_RAW;
    595             break;
    596         case 'x':
    597             new_flags |= NETSTAT_UNIX;
    598             break;
    599         default:
    600             bb_show_usage();
    601         }
    602     if ( showroute ) {
    603 #ifdef CONFIG_ROUTE
    604         displayroutes ( flags & NETSTAT_NUMERIC, !extended );
     490    const char *net_conn_line_header = PRINT_NET_CONN_HEADER;
     491    unsigned opt;
     492#if ENABLE_FEATURE_IPV6
     493    smallint inet = 1;
     494    smallint inet6 = 1;
     495#else
     496    enum { inet = 1, inet6 = 0 };
     497#endif
     498
     499    /* Option string must match NETSTAT_xxx constants */
     500    opt = getopt32(argv, NETSTAT_OPTS);
     501    if (opt & 0x1) { // -l
     502        flags &= ~NETSTAT_CONNECTED;
     503        flags |= NETSTAT_LISTENING;
     504    }
     505    if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a
     506    //if (opt & 0x4) // -e
     507    if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n
     508    //if (opt & 0x10) // -t: NETSTAT_TCP
     509    //if (opt & 0x20) // -u: NETSTAT_UDP
     510    //if (opt & 0x40) // -w: NETSTAT_RAW
     511    //if (opt & 0x80) // -x: NETSTAT_UNIX
     512    if (opt & OPT_showroute) { // -r
     513#if ENABLE_ROUTE
     514        bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended));
    605515        return 0;
    606516#else
    607         bb_error_msg_and_die( "-r (display routing table) is not compiled in." );
    608 #endif
    609     }
    610 
    611     if (new_flags) {
    612         flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
    613         flags |= new_flags;
    614     }
    615     if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
     517        bb_show_usage();
     518#endif
     519    }
     520
     521    if (opt & OPT_widedisplay) { // -W
     522        net_conn_line = PRINT_NET_CONN_WIDE;
     523        net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE;
     524    }
     525
     526    opt &= NETSTAT_ALLPROTO;
     527    if (opt) {
     528        flags &= ~NETSTAT_ALLPROTO;
     529        flags |= opt;
     530    }
     531    if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
    616532        printf("Active Internet connections "); /* xxx */
    617533
    618         if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
     534        if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED))
    619535            printf("(servers and established)");
    620         else {
    621             if (flags&NETSTAT_LISTENING)
    622                 printf("(only servers)");
    623             else
    624                 printf("(w/o servers)");
    625         }
    626         printf("\nProto Recv-Q Send-Q Local Address           Foreign Address         State      \n");
    627     }
    628     if (inet && flags&NETSTAT_TCP)
    629         do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
    630 #ifdef CONFIG_FEATURE_IPV6
    631     if (inet6 && flags&NETSTAT_TCP)
    632         do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
    633 #endif
    634     if (inet && flags&NETSTAT_UDP)
    635         do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
    636 #ifdef CONFIG_FEATURE_IPV6
    637     if (inet6 && flags&NETSTAT_UDP)
    638         do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
    639 #endif
    640     if (inet && flags&NETSTAT_RAW)
    641         do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
    642 #ifdef CONFIG_FEATURE_IPV6
    643     if (inet6 && flags&NETSTAT_RAW)
    644         do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
    645 #endif
    646     if (flags&NETSTAT_UNIX) {
     536        else if (flags & NETSTAT_LISTENING)
     537            printf("(only servers)");
     538        else
     539            printf("(w/o servers)");
     540        printf(net_conn_line_header, "Local Address", "Foreign Address");
     541    }
     542    if (inet && flags & NETSTAT_TCP)
     543        do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one);
     544#if ENABLE_FEATURE_IPV6
     545    if (inet6 && flags & NETSTAT_TCP)
     546        do_info(_PATH_PROCNET_TCP6, "AF INET6 (tcp)", tcp_do_one);
     547#endif
     548    if (inet && flags & NETSTAT_UDP)
     549        do_info(_PATH_PROCNET_UDP, "AF INET (udp)", udp_do_one);
     550#if ENABLE_FEATURE_IPV6
     551    if (inet6 && flags & NETSTAT_UDP)
     552        do_info(_PATH_PROCNET_UDP6, "AF INET6 (udp)", udp_do_one);
     553#endif
     554    if (inet && flags & NETSTAT_RAW)
     555        do_info(_PATH_PROCNET_RAW, "AF INET (raw)", raw_do_one);
     556#if ENABLE_FEATURE_IPV6
     557    if (inet6 && flags & NETSTAT_RAW)
     558        do_info(_PATH_PROCNET_RAW6, "AF INET6 (raw)", raw_do_one);
     559#endif
     560    if (flags & NETSTAT_UNIX) {
    647561        printf("Active UNIX domain sockets ");
    648         if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
     562        if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED))
    649563            printf("(servers and established)");
    650         else {
    651             if (flags&NETSTAT_LISTENING)
    652                 printf("(only servers)");
    653             else
    654                 printf("(w/o servers)");
    655         }
    656 
     564        else if (flags & NETSTAT_LISTENING)
     565            printf("(only servers)");
     566        else
     567            printf("(w/o servers)");
    657568        printf("\nProto RefCnt Flags       Type       State         I-Node Path\n");
    658         do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);
     569        do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
    659570    }
    660571    return 0;
  • branches/stable/mindi-busybox/networking/nslookup.c

    r821 r1770  
    99 * added by Ben Zeckel <bzeckel@hmc.edu> June 2001
    1010 *
    11  * This program is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 2 of the License, or
    14  * (at your option) any later version.
    15  *
    16  * This program is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    19  * General Public License for more details.
    20  *
    21  * You should have received a copy of the GNU General Public License
    22  * along with this program; if not, write to the Free Software
    23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    24  *
     11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    2512 */
    2613
    27 #include <ctype.h>
    28 #include <errno.h>
    29 #include <stdio.h>
    30 #include <string.h>
    31 #include <stdlib.h>
    32 
    33 #include <stdint.h>
    34 #include <netdb.h>
    35 #include <sys/socket.h>
    36 #include <sys/types.h>
    37 #include <netinet/in.h>
    3814#include <resolv.h>
    39 #include <arpa/inet.h>
    40 #include "busybox.h"
     15#include "libbb.h"
    4116
    4217/*
    43  |  I'm only implementing non-interactive mode;
    44  |  I totally forgot nslookup even had an interactive mode.
     18 *  I'm only implementing non-interactive mode;
     19 *  I totally forgot nslookup even had an interactive mode.
    4520 */
    4621
    47 /* only works for IPv4 */
    48 static int addr_fprint(char *addr)
     22/* Examples of 'standard' nslookup output
     23 * $ nslookup yahoo.com
     24 * Server:         128.193.0.10
     25 * Address:        128.193.0.10#53
     26 *
     27 * Non-authoritative answer:
     28 * Name:   yahoo.com
     29 * Address: 216.109.112.135
     30 * Name:   yahoo.com
     31 * Address: 66.94.234.13
     32 *
     33 * $ nslookup 204.152.191.37
     34 * Server:         128.193.4.20
     35 * Address:        128.193.4.20#53
     36 *
     37 * Non-authoritative answer:
     38 * 37.191.152.204.in-addr.arpa     canonical name = 37.32-27.191.152.204.in-addr.arpa.
     39 * 37.32-27.191.152.204.in-addr.arpa       name = zeus-pub2.kernel.org.
     40 *
     41 * Authoritative answers can be found from:
     42 * 32-27.191.152.204.in-addr.arpa  nameserver = ns1.kernel.org.
     43 * 32-27.191.152.204.in-addr.arpa  nameserver = ns2.kernel.org.
     44 * 32-27.191.152.204.in-addr.arpa  nameserver = ns3.kernel.org.
     45 * ns1.kernel.org  internet address = 140.211.167.34
     46 * ns2.kernel.org  internet address = 204.152.191.4
     47 * ns3.kernel.org  internet address = 204.152.191.36
     48 */
     49
     50static int print_host(const char *hostname, const char *header)
    4951{
    50     uint8_t split[4];
    51     uint32_t ip;
    52     uint32_t *x = (uint32_t *) addr;
     52    /* We can't use xhost2sockaddr() - we want to get ALL addresses,
     53     * not just one */
    5354
    54     ip = ntohl(*x);
    55     split[0] = (ip & 0xff000000) >> 24;
    56     split[1] = (ip & 0x00ff0000) >> 16;
    57     split[2] = (ip & 0x0000ff00) >> 8;
    58     split[3] = (ip & 0x000000ff);
    59     printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]);
    60     return 0;
    61 }
     55    struct addrinfo *result = NULL;
     56    int rc;
     57    struct addrinfo hint;
    6258
    63 /* takes the NULL-terminated array h_addr_list, and
    64  * prints its contents appropriately
    65  */
    66 static int addr_list_fprint(char **h_addr_list)
    67 {
    68     int i, j;
    69     char *addr_string = (h_addr_list[1])
    70         ? "Addresses: " : "Address:   ";
     59    memset(&hint, 0 , sizeof(hint));
     60    /* hint.ai_family = AF_UNSPEC; - zero anyway */
     61    /* Needed. Or else we will get each address thrice (or more)
     62     * for each possible socket type (tcp,udp,raw...): */
     63    hint.ai_socktype = SOCK_STREAM;
     64    // hint.ai_flags = AI_CANONNAME;
     65    rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
    7166
    72     printf("%s ", addr_string);
    73     for (i = 0, j = 0; h_addr_list[i]; i++, j++) {
    74         addr_fprint(h_addr_list[i]);
     67    if (!rc) {
     68        struct addrinfo *cur = result;
     69        unsigned cnt = 0;
    7570
    76         /* real nslookup does this */
    77         if (j == 4) {
    78             if (h_addr_list[i + 1]) {
    79                 printf("\n          ");
     71        printf("%-10s %s\n", header, hostname);
     72        // printf("%s\n", cur->ai_canonname); ?
     73        while (cur) {
     74            char *dotted, *revhost;
     75            dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr);
     76            revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr);
     77
     78            printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n');
     79            if (revhost) {
     80                puts(revhost);
     81                if (ENABLE_FEATURE_CLEAN_UP)
     82                    free(revhost);
    8083            }
    81             j = 0;
    82         } else {
    83             if (h_addr_list[i + 1]) {
    84                 printf(", ");
    85             }
     84            if (ENABLE_FEATURE_CLEAN_UP)
     85                free(dotted);
     86            cur = cur->ai_next;
    8687        }
    87 
     88    } else {
     89#if ENABLE_VERBOSE_RESOLUTION_ERRORS
     90        bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc));
     91#else
     92        bb_error_msg("can't resolve '%s'", hostname);
     93#endif
    8894    }
    89     printf("\n");
    90     return 0;
    91 }
    92 
    93 /* print the results as nslookup would */
    94 static struct hostent *hostent_fprint(struct hostent *host, const char *server_host)
    95 {
    96     if (host) {
    97         printf("%s     %s\n", server_host, host->h_name);
    98         addr_list_fprint(host->h_addr_list);
    99     } else {
    100         printf("*** Unknown host\n");
    101     }
    102     return host;
    103 }
    104 
    105 /* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+
    106  * into a uint32_t
    107  */
    108 static uint32_t str_to_addr(const char *addr)
    109 {
    110     uint32_t split[4];
    111     uint32_t ip;
    112 
    113     sscanf(addr, "%d.%d.%d.%d",
    114            &split[0], &split[1], &split[2], &split[3]);
    115 
    116     /* assuming sscanf worked */
    117     ip = (split[0] << 24) |
    118         (split[1] << 16) | (split[2] << 8) | (split[3]);
    119 
    120     return htonl(ip);
    121 }
    122 
    123 /* gethostbyaddr wrapper */
    124 static struct hostent *gethostbyaddr_wrapper(const char *address)
    125 {
    126     struct in_addr addr;
    127 
    128     addr.s_addr = str_to_addr(address);
    129     return gethostbyaddr((char *) &addr, 4, AF_INET);   /* IPv4 only for now */
     95    if (ENABLE_FEATURE_CLEAN_UP)
     96        freeaddrinfo(result);
     97    return (rc != 0);
    13098}
    13199
    132100/* lookup the default nameserver and display it */
    133 static inline void server_print(void)
     101static void server_print(void)
    134102{
    135     struct sockaddr_in def = _res.nsaddr_list[0];
    136     char *ip = inet_ntoa(def.sin_addr);
     103    char *server;
    137104
    138     hostent_fprint(gethostbyaddr_wrapper(ip), "Server:");
    139     printf("\n");
     105    server = xmalloc_sockaddr2dotted_noport((struct sockaddr*)&_res.nsaddr_list[0]);
     106    /* I honestly don't know what to do if DNS server has _IPv6 address_.
     107     * Probably it is listed in
     108     * _res._u._ext_.nsaddrs[MAXNS] (of type "struct sockaddr_in6*" each)
     109     * but how to find out whether resolver uses
     110     * _res.nsaddr_list[] or _res._u._ext_.nsaddrs[], or both?
     111     * Looks like classic design from hell, BIND-grade. Hard to surpass. */
     112    print_host(server, "Server:");
     113    if (ENABLE_FEATURE_CLEAN_UP)
     114        free(server);
     115    puts("");
    140116}
    141117
    142118/* alter the global _res nameserver structure to use
    143119   an explicit dns server instead of what is in /etc/resolv.h */
    144 static inline void set_default_dns(char *server)
     120static void set_default_dns(char *server)
    145121{
    146122    struct in_addr server_in_addr;
    147123
    148     if(inet_aton(server,&server_in_addr))
    149     {
     124    if (inet_pton(AF_INET, server, &server_in_addr) > 0) {
    150125        _res.nscount = 1;
    151126        _res.nsaddr_list[0].sin_addr = server_in_addr;
     
    153128}
    154129
    155 /* naive function to check whether char *s is an ip address */
    156 static int is_ip_address(const char *s)
    157 {
    158     while (*s) {
    159         if ((isdigit(*s)) || (*s == '.')) {
    160             s++;
    161             continue;
    162         }
    163         return 0;
    164     }
    165     return 1;
    166 }
    167 
    168 /* ________________________________________________________________________ */
     130int nslookup_main(int argc, char **argv);
    169131int nslookup_main(int argc, char **argv)
    170132{
    171     struct hostent *host;
     133    /* We allow 1 or 2 arguments.
     134     * The first is the name to be looked up and the second is an
     135     * optional DNS server with which to do the lookup.
     136     * More than 3 arguments is an error to follow the pattern of the
     137     * standard nslookup */
    172138
    173     /*
    174     * initialize DNS structure _res used in printing the default
    175     * name server and in the explicit name server option feature.
    176     */
     139    if (argc < 2 || *argv[1] == '-' || argc > 3)
     140        bb_show_usage();
    177141
     142    /* initialize DNS structure _res used in printing the default
     143     * name server and in the explicit name server option feature. */
    178144    res_init();
     145    /* rfc2133 says this enables IPv6 lookups */
     146    /* (but it also says "may be enabled in /etc/resolv.conf|) */
     147    /*_res.options |= RES_USE_INET6;*/
    179148
    180     /*
    181     * We allow 1 or 2 arguments.
    182     * The first is the name to be looked up and the second is an
    183     * optional DNS server with which to do the lookup.
    184     * More than 3 arguments is an error to follow the pattern of the
    185     * standard nslookup
    186     */
    187 
    188     if (argc < 2 || *argv[1]=='-' || argc > 3)
    189         bb_show_usage();
    190     else if(argc == 3)
     149    if (argc == 3)
    191150        set_default_dns(argv[2]);
    192151
    193152    server_print();
    194     if (is_ip_address(argv[1])) {
    195         host = gethostbyaddr_wrapper(argv[1]);
    196     } else {
    197         host = xgethostbyname(argv[1]);
    198     }
    199     hostent_fprint(host, "Name:  ");
    200     if (host) {
    201         return EXIT_SUCCESS;
    202     }
    203     return EXIT_FAILURE;
     153    return print_host(argv[1], "Name:");
    204154}
    205 
    206 /* $Id: nslookup.c,v 1.33 2004/10/13 07:25:01 andersen Exp $ */
  • branches/stable/mindi-busybox/networking/ping.c

    r821 r1770  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * $Id: ping.c,v 1.56 2004/03/15 08:28:48 andersen Exp $
    43 * Mini ping implementation for busybox
    54 *
     
    87 * Adapted from the ping in netkit-base 0.10:
    98 * Copyright (c) 1989 The Regents of the University of California.
    10  * Derived from software contributed to Berkeley by Mike Muuss.
     9 * All rights reserved.
     10 *
     11 * This code is derived from software contributed to Berkeley by
     12 * Mike Muuss.
    1113 *
    1214 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    1315 */
    14 
    15 #include <sys/param.h>
    16 #include <sys/socket.h>
    17 #include <sys/file.h>
    18 #include <sys/times.h>
    19 #include <signal.h>
    20 
    21 #include <netinet/in.h>
    22 #include <netinet/ip.h>
     16/* from ping6.c:
     17 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
     18 *
     19 * This version of ping is adapted from the ping in netkit-base 0.10,
     20 * which is:
     21 *
     22 * Original copyright notice is retained at the end of this file.
     23 *
     24 * This version is an adaptation of ping.c from busybox.
     25 * The code was modified by Bart Visscher <magick@linux-fan.com>
     26 */
     27
     28#include <net/if.h>
    2329#include <netinet/ip_icmp.h>
    24 #include <arpa/inet.h>
    25 #include <netdb.h>
    26 #include <stdio.h>
    27 #include <stdlib.h>
    28 #include <errno.h>
    29 #include <unistd.h>
    30 #include <string.h>
    31 #include <stdlib.h>
    32 #include "busybox.h"
    33 
     30#include "libbb.h"
     31
     32#if ENABLE_PING6
     33#include <netinet/icmp6.h>
     34/* I see RENUMBERED constants in bits/in.h - !!?
     35 * What a fuck is going on with libc? Is it a glibc joke? */
     36#ifdef IPV6_2292HOPLIMIT
     37#undef IPV6_HOPLIMIT
     38#define IPV6_HOPLIMIT IPV6_2292HOPLIMIT
     39#endif
     40#endif
    3441
    3542enum {
     
    4047    MAX_DUP_CHK = (8 * 128),
    4148    MAXWAIT = 10,
    42     PINGINTERVAL = 1        /* second */
     49    PINGINTERVAL = 1, /* 1 second */
    4350};
    4451
    45 #define O_QUIET         (1 << 0)
     52/* common routines */
     53
     54static int in_cksum(unsigned short *buf, int sz)
     55{
     56    int nleft = sz;
     57    int sum = 0;
     58    unsigned short *w = buf;
     59    unsigned short ans = 0;
     60
     61    while (nleft > 1) {
     62        sum += *w++;
     63        nleft -= 2;
     64    }
     65
     66    if (nleft == 1) {
     67        *(unsigned char *) (&ans) = *(unsigned char *) w;
     68        sum += ans;
     69    }
     70
     71    sum = (sum >> 16) + (sum & 0xFFFF);
     72    sum += (sum >> 16);
     73    ans = ~sum;
     74    return ans;
     75}
     76
     77#if !ENABLE_FEATURE_FANCY_PING
     78
     79/* simple version */
     80
     81static char *hostname;
     82
     83static void noresp(int ign ATTRIBUTE_UNUSED)
     84{
     85    printf("No response from %s\n", hostname);
     86    exit(EXIT_FAILURE);
     87}
     88
     89static void ping4(len_and_sockaddr *lsa)
     90{
     91    struct sockaddr_in pingaddr;
     92    struct icmp *pkt;
     93    int pingsock, c;
     94    char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
     95
     96    pingsock = create_icmp_socket();
     97    pingaddr = lsa->sin;
     98
     99    pkt = (struct icmp *) packet;
     100    memset(pkt, 0, sizeof(packet));
     101    pkt->icmp_type = ICMP_ECHO;
     102    pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
     103
     104    c = xsendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN,
     105               (struct sockaddr *) &pingaddr, sizeof(pingaddr));
     106
     107    /* listen for replies */
     108    while (1) {
     109        struct sockaddr_in from;
     110        socklen_t fromlen = sizeof(from);
     111
     112        c = recvfrom(pingsock, packet, sizeof(packet), 0,
     113                (struct sockaddr *) &from, &fromlen);
     114        if (c < 0) {
     115            if (errno != EINTR)
     116                bb_perror_msg("recvfrom");
     117            continue;
     118        }
     119        if (c >= 76) {          /* ip + icmp */
     120            struct iphdr *iphdr = (struct iphdr *) packet;
     121
     122            pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */
     123            if (pkt->icmp_type == ICMP_ECHOREPLY)
     124                break;
     125        }
     126    }
     127    if (ENABLE_FEATURE_CLEAN_UP)
     128        close(pingsock);
     129}
     130
     131#if ENABLE_PING6
     132static void ping6(len_and_sockaddr *lsa)
     133{
     134    struct sockaddr_in6 pingaddr;
     135    struct icmp6_hdr *pkt;
     136    int pingsock, c;
     137    int sockopt;
     138    char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
     139
     140    pingsock = create_icmp6_socket();
     141    pingaddr = lsa->sin6;
     142
     143    pkt = (struct icmp6_hdr *) packet;
     144    memset(pkt, 0, sizeof(packet));
     145    pkt->icmp6_type = ICMP6_ECHO_REQUEST;
     146
     147    sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
     148    setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
     149
     150    c = xsendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr),
     151               (struct sockaddr *) &pingaddr, sizeof(pingaddr));
     152
     153    /* listen for replies */
     154    while (1) {
     155        struct sockaddr_in6 from;
     156        socklen_t fromlen = sizeof(from);
     157
     158        c = recvfrom(pingsock, packet, sizeof(packet), 0,
     159                (struct sockaddr *) &from, &fromlen);
     160        if (c < 0) {
     161            if (errno != EINTR)
     162                bb_perror_msg("recvfrom");
     163            continue;
     164        }
     165        if (c >= 8) {           /* icmp6_hdr */
     166            pkt = (struct icmp6_hdr *) packet;
     167            if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
     168                break;
     169        }
     170    }
     171    if (ENABLE_FEATURE_CLEAN_UP)
     172        close(pingsock);
     173}
     174#endif
     175
     176int ping_main(int argc, char **argv);
     177int ping_main(int argc, char **argv)
     178{
     179    len_and_sockaddr *lsa;
     180#if ENABLE_PING6
     181    sa_family_t af = AF_UNSPEC;
     182
     183    while ((++argv)[0] && argv[0][0] == '-') {
     184        if (argv[0][1] == '4') {
     185            af = AF_INET;
     186            continue;
     187        }
     188        if (argv[0][1] == '6') {
     189            af = AF_INET6;
     190            continue;
     191        }
     192        bb_show_usage();
     193    }
     194#else
     195    argv++;
     196#endif
     197
     198    hostname = *argv;
     199    if (!hostname)
     200        bb_show_usage();
     201
     202#if ENABLE_PING6
     203    lsa = xhost_and_af2sockaddr(hostname, 0, af);
     204#else
     205    lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET);
     206#endif
     207    /* Set timer _after_ DNS resolution */
     208    signal(SIGALRM, noresp);
     209    alarm(5); /* give the host 5000ms to respond */
     210
     211#if ENABLE_PING6
     212    if (lsa->sa.sa_family == AF_INET6)
     213        ping6(lsa);
     214    else
     215#endif
     216        ping4(lsa);
     217    printf("%s is alive!\n", hostname);
     218    return EXIT_SUCCESS;
     219}
     220
     221
     222#else /* FEATURE_FANCY_PING */
     223
     224
     225/* full(er) version */
     226
     227#define OPT_STRING ("qvc:s:I:4" USE_PING6("6"))
     228enum {
     229    OPT_QUIET = 1 << 0,
     230    OPT_VERBOSE = 1 << 1,
     231    OPT_c = 1 << 2,
     232    OPT_s = 1 << 3,
     233    OPT_I = 1 << 4,
     234    OPT_IPV4 = 1 << 5,
     235    OPT_IPV6 = (1 << 6) * ENABLE_PING6,
     236};
     237
     238
     239struct globals {
     240    int pingsock;
     241    len_and_sockaddr *source_lsa;
     242    unsigned datalen;
     243    int if_index;
     244    unsigned long ntransmitted, nreceived, nrepeats, pingcount;
     245    uint16_t myid;
     246    unsigned tmin, tmax; /* in us */
     247    unsigned long long tsum; /* in us, sum of all times */
     248    const char *hostname;
     249    const char *dotted;
     250    union {
     251        struct sockaddr sa;
     252        struct sockaddr_in sin;
     253#if ENABLE_PING6
     254        struct sockaddr_in6 sin6;
     255#endif
     256    } pingaddr;
     257    char rcvd_tbl[MAX_DUP_CHK / 8];
     258};
     259#define G (*(struct globals*)&bb_common_bufsiz1)
     260#define pingsock     (G.pingsock    )
     261#define source_lsa   (G.source_lsa  )
     262#define datalen      (G.datalen     )
     263#define if_index     (G.if_index    )
     264#define ntransmitted (G.ntransmitted)
     265#define nreceived    (G.nreceived   )
     266#define nrepeats     (G.nrepeats    )
     267#define pingcount    (G.pingcount   )
     268#define myid         (G.myid        )
     269#define tmin         (G.tmin        )
     270#define tmax         (G.tmax        )
     271#define tsum         (G.tsum        )
     272#define hostname     (G.hostname    )
     273#define dotted       (G.dotted      )
     274#define pingaddr     (G.pingaddr    )
     275#define rcvd_tbl     (G.rcvd_tbl    )
     276void BUG_ping_globals_too_big(void);
     277#define INIT_G() do { \
     278        if (sizeof(G) > COMMON_BUFSIZE) \
     279                BUG_ping_globals_too_big(); \
     280    pingsock = -1; \
     281    tmin = UINT_MAX; \
     282} while (0)
     283
    46284
    47285#define A(bit)      rcvd_tbl[(bit)>>3]  /* identify byte in array */
     
    51289#define TST(bit)    (A(bit) & B(bit))
    52290
    53 static void ping(const char *host);
    54 
    55 /* common routines */
    56 static int in_cksum(unsigned short *buf, int sz)
    57 {
    58     int nleft = sz;
    59     int sum = 0;
    60     unsigned short *w = buf;
    61     unsigned short ans = 0;
    62 
    63     while (nleft > 1) {
    64         sum += *w++;
    65         nleft -= 2;
    66     }
    67 
    68     if (nleft == 1) {
    69         *(unsigned char *) (&ans) = *(unsigned char *) w;
    70         sum += ans;
    71     }
    72 
    73     sum = (sum >> 16) + (sum & 0xFFFF);
    74     sum += (sum >> 16);
    75     ans = ~sum;
    76     return (ans);
    77 }
    78 
    79 /* simple version */
    80 #ifndef CONFIG_FEATURE_FANCY_PING
    81 static char *hostname = NULL;
    82 static void noresp(int ign)
    83 {
    84     printf("No response from %s\n", hostname);
    85     exit(EXIT_FAILURE);
    86 }
    87 
    88 static void ping(const char *host)
    89 {
    90     struct hostent *h;
    91     struct sockaddr_in pingaddr;
    92     struct icmp *pkt;
    93     int pingsock, c;
    94     char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
    95 
    96     pingsock = create_icmp_socket();
    97 
    98     memset(&pingaddr, 0, sizeof(struct sockaddr_in));
    99 
    100     pingaddr.sin_family = AF_INET;
    101     h = xgethostbyname(host);
    102     memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
    103     hostname = h->h_name;
    104 
    105     pkt = (struct icmp *) packet;
    106     memset(pkt, 0, sizeof(packet));
    107     pkt->icmp_type = ICMP_ECHO;
    108     pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
    109 
    110     c = sendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 0,
    111                (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
    112 
    113     if (c < 0) {
    114         if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);
    115         bb_perror_msg_and_die("sendto");
    116     }
    117 
    118     signal(SIGALRM, noresp);
    119     alarm(5);                   /* give the host 5000ms to respond */
    120     /* listen for replies */
    121     while (1) {
    122         struct sockaddr_in from;
    123         socklen_t fromlen = sizeof(from);
    124 
    125         if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
    126                           (struct sockaddr *) &from, &fromlen)) < 0) {
    127             if (errno == EINTR)
    128                 continue;
    129             bb_perror_msg("recvfrom");
    130             continue;
    131         }
    132         if (c >= 76) {          /* ip + icmp */
    133             struct iphdr *iphdr = (struct iphdr *) packet;
    134 
    135             pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */
    136             if (pkt->icmp_type == ICMP_ECHOREPLY)
    137                 break;
    138         }
    139     }
    140     if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);
    141     printf("%s is alive!\n", hostname);
    142     return;
    143 }
    144 
    145 int ping_main(int argc, char **argv)
    146 {
    147     argc--;
    148     argv++;
    149     if (argc < 1)
    150         bb_show_usage();
    151     ping(*argv);
    152     return EXIT_SUCCESS;
    153 }
    154 
    155 #else /* ! CONFIG_FEATURE_FANCY_PING */
    156 /* full(er) version */
    157 static struct sockaddr_in pingaddr;
    158 static int pingsock = -1;
    159 static int datalen; /* intentionally uninitialized to work around gcc bug */
    160 
    161 static long ntransmitted, nreceived, nrepeats, pingcount;
    162 static int myid, options;
    163 static unsigned long tmin = ULONG_MAX, tmax, tsum;
    164 static char rcvd_tbl[MAX_DUP_CHK / 8];
    165 
    166 #ifndef CONFIG_FEATURE_FANCY_PING6
    167 static
    168 #endif
    169     struct hostent *hostent;
    170 
    171 static void sendping(int);
    172 static void pingstats(int);
    173 static void unpack(char *, int, struct sockaddr_in *);
    174 
    175291/**************************************************************************/
    176292
    177 static void pingstats(int junk)
    178 {
    179     int status;
    180 
     293static void pingstats(int junk ATTRIBUTE_UNUSED)
     294{
    181295    signal(SIGINT, SIG_IGN);
    182296
    183     printf("\n--- %s ping statistics ---\n", hostent->h_name);
    184     printf("%ld packets transmitted, ", ntransmitted);
    185     printf("%ld packets received, ", nreceived);
     297    printf("\n--- %s ping statistics ---\n", hostname);
     298    printf("%lu packets transmitted, ", ntransmitted);
     299    printf("%lu packets received, ", nreceived);
    186300    if (nrepeats)
    187         printf("%ld duplicates, ", nrepeats);
     301        printf("%lu duplicates, ", nrepeats);
    188302    if (ntransmitted)
    189         printf("%ld%% packet loss\n",
    190                (ntransmitted - nreceived) * 100 / ntransmitted);
    191     if (nreceived)
    192         printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
    193                tmin / 10, tmin % 10,
    194                (tsum / (nreceived + nrepeats)) / 10,
    195                (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
    196     if (nreceived != 0)
    197         status = EXIT_SUCCESS;
    198     else
    199         status = EXIT_FAILURE;
    200     exit(status);
    201 }
    202 
    203 static void sendping(int junk)
    204 {
    205     struct icmp *pkt;
    206     int i;
    207     char packet[datalen + ICMP_MINLEN];
    208 
    209     pkt = (struct icmp *) packet;
     303        ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted;
     304    printf("%lu%% packet loss\n", ntransmitted);
     305    if (tmin != UINT_MAX) {
     306        unsigned tavg = tsum / (nreceived + nrepeats);
     307        printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n",
     308            tmin / 1000, tmin % 1000,
     309            tavg / 1000, tavg % 1000,
     310            tmax / 1000, tmax % 1000);
     311    }
     312    exit(nreceived == 0); /* (nreceived == 0) is true (1) -- 'failure' */
     313}
     314
     315static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt)
     316{
     317    int sz;
     318
     319    CLR((uint16_t)ntransmitted % MAX_DUP_CHK);
     320    ntransmitted++;
     321
     322    /* sizeof(pingaddr) can be larger than real sa size, but I think
     323     * it doesn't matter */
     324    sz = xsendto(pingsock, pkt, size_pkt, &pingaddr.sa, sizeof(pingaddr));
     325    if (sz != size_pkt)
     326        bb_error_msg_and_die(bb_msg_write_error);
     327
     328    signal(SIGALRM, sp);
     329    if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
     330        alarm(PINGINTERVAL);
     331    } else { /* done, wait for the last ping to come back */
     332        /* todo, don't necessarily need to wait so long... */
     333        signal(SIGALRM, pingstats);
     334        alarm(MAXWAIT);
     335    }
     336}
     337
     338static void sendping4(int junk ATTRIBUTE_UNUSED)
     339{
     340    /* +4 reserves a place for timestamp, which may end up sitting
     341     * *after* packet. Saves one if() */
     342    struct icmp *pkt = alloca(datalen + ICMP_MINLEN + 4);
    210343
    211344    pkt->icmp_type = ICMP_ECHO;
    212345    pkt->icmp_code = 0;
    213346    pkt->icmp_cksum = 0;
    214     pkt->icmp_seq = htons(ntransmitted++);
     347    pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
    215348    pkt->icmp_id = myid;
    216     CLR(ntohs(pkt->icmp_seq) % MAX_DUP_CHK);
    217 
    218     gettimeofday((struct timeval *) &pkt->icmp_dun, NULL);
    219     pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
    220 
    221     i = sendto(pingsock, packet, sizeof(packet), 0,
    222                (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));
    223 
    224     if (i < 0)
    225         bb_perror_msg_and_die("sendto");
    226     else if ((size_t)i != sizeof(packet))
    227         bb_error_msg_and_die("ping wrote %d chars; %d expected", i,
    228                (int)sizeof(packet));
    229 
    230     signal(SIGALRM, sendping);
    231     if (pingcount == 0 || ntransmitted < pingcount) {   /* schedule next in 1s */
    232         alarm(PINGINTERVAL);
    233     } else {                    /* done, wait for the last ping to come back */
    234         /* todo, don't necessarily need to wait so long... */
    235         signal(SIGALRM, pingstats);
    236         alarm(MAXWAIT);
    237     }
    238 }
    239 
    240 static char *icmp_type_name (int id)
     349
     350    /* We don't do hton, because we will read it back on the same machine */
     351    /*if (datalen >= 4)*/
     352        *(uint32_t*)&pkt->icmp_dun = monotonic_us();
     353
     354    pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN);
     355
     356    sendping_tail(sendping4, pkt, datalen + ICMP_MINLEN);
     357}
     358#if ENABLE_PING6
     359static void sendping6(int junk ATTRIBUTE_UNUSED)
     360{
     361    struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4);
     362
     363    pkt->icmp6_type = ICMP6_ECHO_REQUEST;
     364    pkt->icmp6_code = 0;
     365    pkt->icmp6_cksum = 0;
     366    pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
     367    pkt->icmp6_id = myid;
     368
     369    /*if (datalen >= 4)*/
     370        *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us();
     371
     372    sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr));
     373}
     374#endif
     375
     376static const char *icmp_type_name(int id)
    241377{
    242378    switch (id) {
    243     case ICMP_ECHOREPLY:        return "Echo Reply";
    244     case ICMP_DEST_UNREACH:     return "Destination Unreachable";
    245     case ICMP_SOURCE_QUENCH:    return "Source Quench";
    246     case ICMP_REDIRECT:         return "Redirect (change route)";
    247     case ICMP_ECHO:             return "Echo Request";
    248     case ICMP_TIME_EXCEEDED:    return "Time Exceeded";
    249     case ICMP_PARAMETERPROB:    return "Parameter Problem";
    250     case ICMP_TIMESTAMP:        return "Timestamp Request";
    251     case ICMP_TIMESTAMPREPLY:   return "Timestamp Reply";
    252     case ICMP_INFO_REQUEST:     return "Information Request";
    253     case ICMP_INFO_REPLY:       return "Information Reply";
    254     case ICMP_ADDRESS:          return "Address Mask Request";
    255     case ICMP_ADDRESSREPLY:     return "Address Mask Reply";
    256     default:                    return "unknown ICMP type";
    257     }
    258 }
    259 
    260 static void unpack(char *buf, int sz, struct sockaddr_in *from)
    261 {
    262     struct icmp *icmppkt;
    263     struct iphdr *iphdr;
    264     struct timeval tv, *tp;
    265     int hlen, dupflag;
    266     unsigned long triptime;
    267 
    268     gettimeofday(&tv, NULL);
    269 
    270     /* check IP header */
    271     iphdr = (struct iphdr *) buf;
    272     hlen = iphdr->ihl << 2;
    273     /* discard if too short */
    274     if (sz < (datalen + ICMP_MINLEN))
    275         return;
    276 
    277     sz -= hlen;
    278     icmppkt = (struct icmp *) (buf + hlen);
    279 
    280     if (icmppkt->icmp_id != myid)
    281         return;             /* not our ping */
    282 
    283     if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
    284         u_int16_t recv_seq = ntohs(icmppkt->icmp_seq);
    285         ++nreceived;
    286         tp = (struct timeval *) icmppkt->icmp_data;
    287 
    288         if ((tv.tv_usec -= tp->tv_usec) < 0) {
    289             --tv.tv_sec;
    290             tv.tv_usec += 1000000;
    291         }
    292         tv.tv_sec -= tp->tv_sec;
    293 
    294         triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
     379    case ICMP_ECHOREPLY:      return "Echo Reply";
     380    case ICMP_DEST_UNREACH:   return "Destination Unreachable";
     381    case ICMP_SOURCE_QUENCH:  return "Source Quench";
     382    case ICMP_REDIRECT:       return "Redirect (change route)";
     383    case ICMP_ECHO:           return "Echo Request";
     384    case ICMP_TIME_EXCEEDED:  return "Time Exceeded";
     385    case ICMP_PARAMETERPROB:  return "Parameter Problem";
     386    case ICMP_TIMESTAMP:      return "Timestamp Request";
     387    case ICMP_TIMESTAMPREPLY: return "Timestamp Reply";
     388    case ICMP_INFO_REQUEST:   return "Information Request";
     389    case ICMP_INFO_REPLY:     return "Information Reply";
     390    case ICMP_ADDRESS:        return "Address Mask Request";
     391    case ICMP_ADDRESSREPLY:   return "Address Mask Reply";
     392    default:                  return "unknown ICMP type";
     393    }
     394}
     395#if ENABLE_PING6
     396/* RFC3542 changed some definitions from RFC2292 for no good reason, whee!
     397 * the newer 3542 uses a MLD_ prefix where as 2292 uses ICMP6_ prefix */
     398#ifndef MLD_LISTENER_QUERY
     399# define MLD_LISTENER_QUERY ICMP6_MEMBERSHIP_QUERY
     400#endif
     401#ifndef MLD_LISTENER_REPORT
     402# define MLD_LISTENER_REPORT ICMP6_MEMBERSHIP_REPORT
     403#endif
     404#ifndef MLD_LISTENER_REDUCTION
     405# define MLD_LISTENER_REDUCTION ICMP6_MEMBERSHIP_REDUCTION
     406#endif
     407static const char *icmp6_type_name(int id)
     408{
     409    switch (id) {
     410    case ICMP6_DST_UNREACH:      return "Destination Unreachable";
     411    case ICMP6_PACKET_TOO_BIG:   return "Packet too big";
     412    case ICMP6_TIME_EXCEEDED:    return "Time Exceeded";
     413    case ICMP6_PARAM_PROB:       return "Parameter Problem";
     414    case ICMP6_ECHO_REPLY:       return "Echo Reply";
     415    case ICMP6_ECHO_REQUEST:     return "Echo Request";
     416    case MLD_LISTENER_QUERY:     return "Listener Query";
     417    case MLD_LISTENER_REPORT:    return "Listener Report";
     418    case MLD_LISTENER_REDUCTION: return "Listener Reduction";
     419    default:                     return "unknown ICMP type";
     420    }
     421}
     422#endif
     423
     424static void unpack_tail(int sz, uint32_t *tp,
     425        const char *from_str,
     426        uint16_t recv_seq, int ttl)
     427{
     428    const char *dupmsg = " (DUP!)";
     429    unsigned triptime = triptime; /* for gcc */
     430
     431    ++nreceived;
     432
     433    if (tp) {
     434        /* (int32_t) cast is for hypothetical 64-bit unsigned */
     435        /* (doesn't hurt 32-bit real-world anyway) */
     436        triptime = (int32_t) ((uint32_t)monotonic_us() - *tp);
    295437        tsum += triptime;
    296438        if (triptime < tmin)
     
    298440        if (triptime > tmax)
    299441            tmax = triptime;
    300 
    301         if (TST(recv_seq % MAX_DUP_CHK)) {
    302             ++nrepeats;
    303             --nreceived;
    304             dupflag = 1;
    305         } else {
    306             SET(recv_seq % MAX_DUP_CHK);
    307             dupflag = 0;
    308         }
    309 
    310         if (options & O_QUIET)
    311             return;
    312 
    313         printf("%d bytes from %s: icmp_seq=%u", sz,
    314                inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
    315                recv_seq);
    316         printf(" ttl=%d", iphdr->ttl);
    317         printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
    318         if (dupflag)
    319             printf(" (DUP!)");
    320         printf("\n");
    321     } else
    322         if (icmppkt->icmp_type != ICMP_ECHO)
    323             bb_error_msg("Warning: Got ICMP %d (%s)",
    324                     icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
     442    }
     443
     444    if (TST(recv_seq % MAX_DUP_CHK)) {
     445        ++nrepeats;
     446        --nreceived;
     447    } else {
     448        SET(recv_seq % MAX_DUP_CHK);
     449        dupmsg += 7;
     450    }
     451
     452    if (option_mask32 & OPT_QUIET)
     453        return;
     454
     455    printf("%d bytes from %s: seq=%u ttl=%d", sz,
     456        from_str, recv_seq, ttl);
     457    if (tp)
     458        printf(" time=%u.%03u ms", triptime / 1000, triptime % 1000);
     459    puts(dupmsg);
    325460    fflush(stdout);
    326461}
    327 
    328 static void ping(const char *host)
     462static void unpack4(char *buf, int sz, struct sockaddr_in *from)
     463{
     464    struct icmp *icmppkt;
     465    struct iphdr *iphdr;
     466    int hlen;
     467
     468    /* discard if too short */
     469    if (sz < (datalen + ICMP_MINLEN))
     470        return;
     471
     472    /* check IP header */
     473    iphdr = (struct iphdr *) buf;
     474    hlen = iphdr->ihl << 2;
     475    sz -= hlen;
     476    icmppkt = (struct icmp *) (buf + hlen);
     477    if (icmppkt->icmp_id != myid)
     478        return;             /* not our ping */
     479
     480    if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
     481        uint16_t recv_seq = ntohs(icmppkt->icmp_seq);
     482        uint32_t *tp = NULL;
     483
     484        if (sz >= ICMP_MINLEN + sizeof(uint32_t))
     485            tp = (uint32_t *) icmppkt->icmp_data;
     486        unpack_tail(sz, tp,
     487            inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
     488            recv_seq, iphdr->ttl);
     489    } else if (icmppkt->icmp_type != ICMP_ECHO) {
     490        bb_error_msg("warning: got ICMP %d (%s)",
     491                icmppkt->icmp_type,
     492                icmp_type_name(icmppkt->icmp_type));
     493    }
     494}
     495#if ENABLE_PING6
     496static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
     497{
     498    struct icmp6_hdr *icmppkt;
     499    char buf[INET6_ADDRSTRLEN];
     500
     501    /* discard if too short */
     502    if (sz < (datalen + sizeof(struct icmp6_hdr)))
     503        return;
     504
     505    icmppkt = (struct icmp6_hdr *) packet;
     506    if (icmppkt->icmp6_id != myid)
     507        return;             /* not our ping */
     508
     509    if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
     510        uint16_t recv_seq = ntohs(icmppkt->icmp6_seq);
     511        uint32_t *tp = NULL;
     512
     513        if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t))
     514            tp = (uint32_t *) &icmppkt->icmp6_data8[4];
     515        unpack_tail(sz, tp,
     516            inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr,
     517                    buf, sizeof(buf)),
     518            recv_seq, hoplimit);
     519    } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
     520        bb_error_msg("warning: got ICMP %d (%s)",
     521                icmppkt->icmp6_type,
     522                icmp6_type_name(icmppkt->icmp6_type));
     523    }
     524}
     525#endif
     526
     527static void ping4(len_and_sockaddr *lsa)
    329528{
    330529    char packet[datalen + MAXIPLEN + MAXICMPLEN];
     
    332531
    333532    pingsock = create_icmp_socket();
    334 
    335     memset(&pingaddr, 0, sizeof(struct sockaddr_in));
    336 
    337     pingaddr.sin_family = AF_INET;
    338     hostent = xgethostbyname(host);
    339     if (hostent->h_addrtype != AF_INET)
    340         bb_error_msg_and_die("unknown address type; only AF_INET is currently supported.");
    341 
    342     memcpy(&pingaddr.sin_addr, hostent->h_addr, sizeof(pingaddr.sin_addr));
     533    pingaddr.sin = lsa->sin;
     534    if (source_lsa) {
     535        if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF,
     536                &source_lsa->sa, source_lsa->len))
     537            bb_error_msg_and_die("can't set multicast source interface");
     538        xbind(pingsock, &source_lsa->sa, source_lsa->len);
     539    }
    343540
    344541    /* enable broadcast pings */
    345     sockopt = 1;
    346     setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
    347                sizeof(sockopt));
     542    setsockopt_broadcast(pingsock);
    348543
    349544    /* set recv buf for broadcast pings */
    350     sockopt = 48 * 1024;
    351     setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
    352                sizeof(sockopt));
    353 
    354     printf("PING %s (%s): %d data bytes\n",
    355                hostent->h_name,
    356            inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr),
    357            datalen);
     545    sockopt = 48 * 1024; /* explain why 48k? */
     546    setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
    358547
    359548    signal(SIGINT, pingstats);
    360549
    361550    /* start the ping's going ... */
    362     sendping(0);
     551    sendping4(0);
    363552
    364553    /* listen for replies */
     
    368557        int c;
    369558
    370         if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
    371                           (struct sockaddr *) &from, &fromlen)) < 0) {
    372             if (errno == EINTR)
    373                 continue;
    374             bb_perror_msg("recvfrom");
     559        c = recvfrom(pingsock, packet, sizeof(packet), 0,
     560                (struct sockaddr *) &from, &fromlen);
     561        if (c < 0) {
     562            if (errno != EINTR)
     563                bb_perror_msg("recvfrom");
    375564            continue;
    376565        }
    377         unpack(packet, c, &from);
     566        unpack4(packet, c, &from);
    378567        if (pingcount > 0 && nreceived >= pingcount)
    379568            break;
    380569    }
     570}
     571#if ENABLE_PING6
     572extern int BUG_bad_offsetof_icmp6_cksum(void);
     573static void ping6(len_and_sockaddr *lsa)
     574{
     575    char packet[datalen + MAXIPLEN + MAXICMPLEN];
     576    int sockopt;
     577    struct msghdr msg;
     578    struct sockaddr_in6 from;
     579    struct iovec iov;
     580    char control_buf[CMSG_SPACE(36)];
     581
     582    pingsock = create_icmp6_socket();
     583    pingaddr.sin6 = lsa->sin6;
     584    /* untested whether "-I addr" really works for IPv6: */
     585    if (source_lsa)
     586        xbind(pingsock, &source_lsa->sa, source_lsa->len);
     587
     588#ifdef ICMP6_FILTER
     589    {
     590        struct icmp6_filter filt;
     591        if (!(option_mask32 & OPT_VERBOSE)) {
     592            ICMP6_FILTER_SETBLOCKALL(&filt);
     593            ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
     594        } else {
     595            ICMP6_FILTER_SETPASSALL(&filt);
     596        }
     597        if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
     598                       sizeof(filt)) < 0)
     599            bb_error_msg_and_die("setsockopt(ICMP6_FILTER)");
     600    }
     601#endif /*ICMP6_FILTER*/
     602
     603    /* enable broadcast pings */
     604    setsockopt_broadcast(pingsock);
     605
     606    /* set recv buf for broadcast pings */
     607    sockopt = 48 * 1024; /* explain why 48k? */
     608    setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
     609
     610    sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
     611    if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2)
     612        BUG_bad_offsetof_icmp6_cksum();
     613    setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
     614
     615    /* request ttl info to be returned in ancillary data */
     616    setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1));
     617
     618    if (if_index)
     619        pingaddr.sin6.sin6_scope_id = if_index;
     620
     621    signal(SIGINT, pingstats);
     622
     623    /* start the ping's going ... */
     624    sendping6(0);
     625
     626    /* listen for replies */
     627    msg.msg_name = &from;
     628    msg.msg_namelen = sizeof(from);
     629    msg.msg_iov = &iov;
     630    msg.msg_iovlen = 1;
     631    msg.msg_control = control_buf;
     632    iov.iov_base = packet;
     633    iov.iov_len = sizeof(packet);
     634    while (1) {
     635        int c;
     636        struct cmsghdr *mp;
     637        int hoplimit = -1;
     638        msg.msg_controllen = sizeof(control_buf);
     639
     640        c = recvmsg(pingsock, &msg, 0);
     641        if (c < 0) {
     642            if (errno != EINTR)
     643                bb_perror_msg("recvfrom");
     644            continue;
     645        }
     646        for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) {
     647            if (mp->cmsg_level == SOL_IPV6
     648             && mp->cmsg_type == IPV6_HOPLIMIT
     649             /* don't check len - we trust the kernel: */
     650             /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */
     651            ) {
     652                hoplimit = *(int*)CMSG_DATA(mp);
     653            }
     654        }
     655        unpack6(packet, c, &from, hoplimit);
     656        if (pingcount > 0 && nreceived >= pingcount)
     657            break;
     658    }
     659}
     660#endif
     661
     662static void ping(len_and_sockaddr *lsa)
     663{
     664    printf("PING %s (%s)", hostname, dotted);
     665    if (source_lsa) {
     666        printf(" from %s",
     667            xmalloc_sockaddr2dotted_noport(&source_lsa->sa));
     668    }
     669    printf(": %d data bytes\n", datalen);
     670
     671#if ENABLE_PING6
     672    if (lsa->sa.sa_family == AF_INET6)
     673        ping6(lsa);
     674    else
     675#endif
     676        ping4(lsa);
     677}
     678
     679int ping_main(int argc, char **argv);
     680int ping_main(int argc, char **argv)
     681{
     682    len_and_sockaddr *lsa;
     683    char *opt_c, *opt_s, *opt_I;
     684    USE_PING6(sa_family_t af = AF_UNSPEC;)
     685
     686    INIT_G();
     687
     688    datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
     689
     690    /* exactly one argument needed, -v and -q don't mix */
     691    opt_complementary = "=1:q--v:v--q";
     692    getopt32(argv, OPT_STRING, &opt_c, &opt_s, &opt_I);
     693    if (option_mask32 & OPT_c) pingcount = xatoul(opt_c); // -c
     694    if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s
     695    if (option_mask32 & OPT_I) { // -I
     696        if_index = if_nametoindex(opt_I);
     697        if (!if_index) {
     698            /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */
     699            source_lsa = xdotted2sockaddr(opt_I, 0);
     700        }
     701    }
     702    myid = (uint16_t) getpid();
     703    hostname = argv[optind];
     704#if ENABLE_PING6
     705    if (option_mask32 & OPT_IPV4)
     706        af = AF_INET;
     707    if (option_mask32 & OPT_IPV6)
     708        af = AF_INET6;
     709    lsa = xhost_and_af2sockaddr(hostname, 0, af);
     710#else
     711    lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET);
     712#endif
     713
     714    if (source_lsa && source_lsa->sa.sa_family != lsa->sa.sa_family)
     715        /* leaking it here... */
     716        source_lsa = NULL;
     717
     718    dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa);
     719    ping(lsa);
    381720    pingstats(0);
    382 }
    383 
    384 int ping_main(int argc, char **argv)
    385 {
    386     char *thisarg;
    387 
    388     datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
    389 
    390     argc--;
    391     argv++;
    392     options = 0;
    393     /* Parse any options */
    394     while (argc >= 1 && **argv == '-') {
    395         thisarg = *argv;
    396         thisarg++;
    397         switch (*thisarg) {
    398         case 'q':
    399             options |= O_QUIET;
    400             break;
    401         case 'c':
    402             if (--argc <= 0)
    403                     bb_show_usage();
    404             argv++;
    405             pingcount = atoi(*argv);
    406             break;
    407         case 's':
    408             if (--argc <= 0)
    409                     bb_show_usage();
    410             argv++;
    411             datalen = atoi(*argv);
    412             break;
    413         default:
    414             bb_show_usage();
    415         }
    416         argc--;
    417         argv++;
    418     }
    419     if (argc < 1)
    420         bb_show_usage();
    421 
    422     myid = getpid() & 0xFFFF;
    423     ping(*argv);
    424721    return EXIT_SUCCESS;
    425722}
    426 #endif /* ! CONFIG_FEATURE_FANCY_PING */
     723#endif /* FEATURE_FANCY_PING */
     724
     725
     726#if ENABLE_PING6
     727int ping6_main(int argc, char **argv);
     728int ping6_main(int argc, char **argv)
     729{
     730    argv[0] = (char*)"-6";
     731    return ping_main(argc + 1, argv - 1);
     732}
     733#endif
     734
     735/* from ping6.c:
     736 * Copyright (c) 1989 The Regents of the University of California.
     737 * All rights reserved.
     738 *
     739 * This code is derived from software contributed to Berkeley by
     740 * Mike Muuss.
     741 *
     742 * Redistribution and use in source and binary forms, with or without
     743 * modification, are permitted provided that the following conditions
     744 * are met:
     745 * 1. Redistributions of source code must retain the above copyright
     746 *    notice, this list of conditions and the following disclaimer.
     747 * 2. Redistributions in binary form must reproduce the above copyright
     748 *    notice, this list of conditions and the following disclaimer in the
     749 *    documentation and/or other materials provided with the distribution.
     750 *
     751 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
     752 *      ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
     753 *
     754 * 4. Neither the name of the University nor the names of its contributors
     755 *    may be used to endorse or promote products derived from this software
     756 *    without specific prior written permission.
     757 *
     758 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     759 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     760 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     761 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     762 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     763 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     764 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     765 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     766 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     767 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     768 * SUCH DAMAGE.
     769 */
  • branches/stable/mindi-busybox/networking/route.c

    r821 r1770  
    1313 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    1414 *
    15  * $Id: route.c,v 1.26 2004/03/19 23:27:08 mjn3 Exp $
    1615 *
    1716 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
     
    2726 */
    2827
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>
    32 #include <errno.h>
    33 #include <assert.h>
    34 #include <unistd.h>
    35 #include <fcntl.h>
    3628#include <getopt.h>
    37 #include <sys/types.h>
    38 #include <sys/ioctl.h>
    3929#include <net/route.h>
    4030#include <net/if.h>
    41 #include "busybox.h"
     31
     32#include "libbb.h"
    4233#include "inet_common.h"
     34
    4335
    4436#ifndef RTF_UP
     
    5951#endif
    6052
    61 #if defined (SIOCADDRTOLD) || defined (RTF_IRTT)    /* route */
     53#if defined(SIOCADDRTOLD) || defined(RTF_IRTT)  /* route */
    6254#define HAVE_NEW_ADDRT 1
    6355#endif
     
    7264
    7365/* The RTACTION entries must agree with tbl_verb[] below! */
    74 #define RTACTION_ADD        1
    75 #define RTACTION_DEL        2
     66#define RTACTION_ADD 1
     67#define RTACTION_DEL 2
    7668
    7769/* For the various tbl_*[] arrays, the 1st byte is the offset to
    7870 * the next entry and the 2nd byte is return value. */
    7971
    80 #define NET_FLAG            1
    81 #define HOST_FLAG           2
     72#define NET_FLAG  1
     73#define HOST_FLAG 2
    8274
    8375/* We remap '-' to '#' to avoid problems with getopt. */
    84 static const char tbl_hash_net_host[] =
     76static const char tbl_hash_net_host[] ALIGN1 =
    8577    "\007\001#net\0"
    8678/*  "\010\002#host\0" */
     
    8880;
    8981
    90 #define KW_TAKES_ARG        020
    91 #define KW_SETS_FLAG        040
    92 
    93 #define KW_IPVx_METRIC      020
    94 #define KW_IPVx_NETMASK     021
    95 #define KW_IPVx_GATEWAY     022
    96 #define KW_IPVx_MSS         023
    97 #define KW_IPVx_WINDOW      024
    98 #define KW_IPVx_IRTT        025
    99 #define KW_IPVx_DEVICE      026
    100 
    101 #define KW_IPVx_FLAG_ONLY   040
    102 #define KW_IPVx_REJECT      040
    103 #define KW_IPVx_MOD         041
    104 #define KW_IPVx_DYN         042
    105 #define KW_IPVx_REINSTATE   043
    106 
    107 static const char tbl_ipvx[] =
     82#define KW_TAKES_ARG            020
     83#define KW_SETS_FLAG            040
     84
     85#define KW_IPVx_METRIC          020
     86#define KW_IPVx_NETMASK         021
     87#define KW_IPVx_GATEWAY         022
     88#define KW_IPVx_MSS             023
     89#define KW_IPVx_WINDOW          024
     90#define KW_IPVx_IRTT            025
     91#define KW_IPVx_DEVICE          026
     92
     93#define KW_IPVx_FLAG_ONLY       040
     94#define KW_IPVx_REJECT          040
     95#define KW_IPVx_MOD             041
     96#define KW_IPVx_DYN             042
     97#define KW_IPVx_REINSTATE       043
     98
     99static const char tbl_ipvx[] ALIGN1 =
    108100    /* 020 is the "takes an arg" bit */
    109101#if HAVE_NEW_ADDRT
     
    167159    int skfd, isnet, xflag;
    168160
    169     assert((action == RTACTION_ADD) || (action == RTACTION_DEL));
    170 
    171161    /* Grab the -net or -host options.  Remember they were transformed. */
    172162    xflag = kw_lookup(tbl_hash_net_host, &args);
     
    178168
    179169    /* Clean out the RTREQ structure. */
    180     memset((char *) &rt, 0, sizeof(struct rtentry));
     170    memset(&rt, 0, sizeof(rt));
    181171
    182172    {
     
    186176        /* recognize x.x.x.x/mask format. */
    187177        prefix = strchr(target, '/');
    188         if(prefix) {
     178        if (prefix) {
    189179            int prefix_len;
    190180
    191             prefix_len = bb_xgetularg10_bnd(prefix+1, 0, 32);
     181            prefix_len = xatoul_range(prefix+1, 0, 32);
    192182            mask_in_addr(rt) = htonl( ~ (0xffffffffUL >> prefix_len));
    193183            *prefix = '\0';
     
    197187        } else {
    198188            /* Default netmask. */
    199             netmask = bb_INET_default;
     189            netmask = bb_str_default;
    200190        }
    201191        /* Prefer hostname lookup is -host flag (xflag==1) was given. */
     
    205195            bb_error_msg_and_die("resolving %s", target);
    206196        }
    207         if(prefix) {
     197        if (prefix) {
    208198            /* do not destroy prefix for process args */
    209199            *prefix = '/';
     
    229219#if HAVE_NEW_ADDRT
    230220        if (k == KW_IPVx_METRIC) {
    231             rt.rt_metric = bb_xgetularg10(args_m1) + 1;
     221            rt.rt_metric = xatoul(args_m1) + 1;
    232222            continue;
    233223        }
     
    270260        if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */
    271261            rt.rt_flags |= RTF_MSS;
    272             rt.rt_mss = bb_xgetularg10_bnd(args_m1, 64, 32768);
     262            rt.rt_mss = xatoul_range(args_m1, 64, 32768);
    273263            continue;
    274264        }
     
    276266        if (k == KW_IPVx_WINDOW) {  /* Check valid window bounds. */
    277267            rt.rt_flags |= RTF_WINDOW;
    278             rt.rt_window = bb_xgetularg10_bnd(args_m1, 128, INT_MAX);
     268            rt.rt_window = xatoul_range(args_m1, 128, INT_MAX);
    279269            continue;
    280270        }
     
    283273        if (k == KW_IPVx_IRTT) {
    284274            rt.rt_flags |= RTF_IRTT;
    285             rt.rt_irtt = bb_xgetularg10(args_m1);
     275            rt.rt_irtt = xatoul(args_m1);
    286276            rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */
    287277#if 0                   /* FIXME: do we need to check anything of this? */
     
    308298#ifdef RTF_REJECT
    309299    if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) {
    310         rt.rt_dev = "lo";
     300        rt.rt_dev = (char*)"lo";
    311301    }
    312302#endif
     
    336326
    337327    /* Create a socket to the INET kernel. */
    338     skfd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);
    339 
    340     if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) {
    341         bb_perror_msg_and_die("SIOC[ADD|DEL]RT");
    342     }
     328    skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
     329
     330    if (action == RTACTION_ADD)
     331        xioctl(skfd, SIOCADDRT, &rt);
     332    else
     333        xioctl(skfd, SIOCDELRT, &rt);
    343334
    344335    if (ENABLE_FEATURE_CLEAN_UP) close(skfd);
    345336}
    346337
    347 #ifdef CONFIG_FEATURE_IPV6
     338#if ENABLE_FEATURE_IPV6
    348339
    349340static void INET6_setroute(int action, char **args)
     
    354345    const char *devname;
    355346
    356     assert((action == RTACTION_ADD) || (action == RTACTION_DEL));
    357 
    358     {
    359347        /* We know args isn't NULL from the check in route_main. */
    360348        const char *target = *args++;
    361349
    362         if (strcmp(target, bb_INET_default) == 0) {
     350        if (strcmp(target, bb_str_default) == 0) {
    363351            prefix_len = 0;
    364352            memset(&sa6, 0, sizeof(sa6));
     
    367355            if ((cp = strchr(target, '/'))) { /* Yes... const to non is ok. */
    368356                *cp = 0;
    369                 prefix_len = bb_xgetularg10_bnd(cp+1, 0, 128);
     357                prefix_len = xatoul_range(cp+1, 0, 128);
    370358            } else {
    371359                prefix_len = 128;
     
    375363            }
    376364        }
    377     }
    378365
    379366    /* Clean out the RTREQ structure. */
    380     memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
     367    memset(&rt, 0, sizeof(rt));
    381368
    382369    memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
     
    399386
    400387        if (k == KW_IPVx_METRIC) {
    401             rt.rtmsg_metric = bb_xgetularg10(args_m1);
     388            rt.rtmsg_metric = xatoul(args_m1);
    402389            continue;
    403390        }
     
    430417
    431418    /* Create a socket to the INET6 kernel. */
    432     skfd = bb_xsocket(AF_INET6, SOCK_DGRAM, 0);
     419    skfd = xsocket(AF_INET6, SOCK_DGRAM, 0);
    433420
    434421    rt.rtmsg_ifindex = 0;
     
    437424        struct ifreq ifr;
    438425        memset(&ifr, 0, sizeof(ifr));
    439         strcpy(ifr.ifr_name, devname);
    440 
    441         if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
    442             bb_perror_msg_and_die("SIOGIFINDEX");
    443         }
     426        strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
     427        xioctl(skfd, SIOGIFINDEX, &ifr);
    444428        rt.rtmsg_ifindex = ifr.ifr_ifindex;
    445429    }
    446430
    447431    /* Tell the kernel to accept this route. */
    448     if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) {
    449         bb_perror_msg_and_die("SIOC[ADD|DEL]RT");
    450     }
     432    if (action == RTACTION_ADD)
     433        xioctl(skfd, SIOCADDRT, &rt);
     434    else
     435        xioctl(skfd, SIOCDELRT, &rt);
    451436
    452437    if (ENABLE_FEATURE_CLEAN_UP) close(skfd);
     
    454439#endif
    455440
    456 static const unsigned int flagvals[] = { /* Must agree with flagchars[]. */
     441static const unsigned flagvals[] = { /* Must agree with flagchars[]. */
    457442    RTF_GATEWAY,
    458443    RTF_HOST,
     
    460445    RTF_DYNAMIC,
    461446    RTF_MODIFIED,
    462 #ifdef CONFIG_FEATURE_IPV6
     447#if ENABLE_FEATURE_IPV6
    463448    RTF_DEFAULT,
    464449    RTF_ADDRCONF,
     
    470455#define IPV6_MASK (RTF_GATEWAY|RTF_HOST|RTF_DEFAULT|RTF_ADDRCONF|RTF_CACHE)
    471456
    472 static const char flagchars[] =     /* Must agree with flagvals[]. */
     457/* Must agree with flagvals[]. */
     458static const char flagchars[] ALIGN1 =
    473459    "GHRDM"
    474 #ifdef CONFIG_FEATURE_IPV6
     460#if ENABLE_FEATURE_IPV6
    475461    "DAC"
    476462#endif
    477463;
    478464
    479 static
    480 #ifndef CONFIG_FEATURE_IPV6
    481 __inline
    482 #endif
    483 void set_flags(char *flagstr, int flags)
     465static void set_flags(char *flagstr, int flags)
    484466{
    485467    int i;
     
    487469    *flagstr++ = 'U';
    488470
    489     for (i=0 ; (*flagstr = flagchars[i]) != 0 ; i++) {
     471    for (i = 0; (*flagstr = flagchars[i]) != 0; i++) {
    490472        if (flags & flagvals[i]) {
    491473            ++flagstr;
     
    495477
    496478/* also used in netstat */
    497 void displayroutes(int noresolve, int netstatfmt);
    498 void displayroutes(int noresolve, int netstatfmt)
     479void bb_displayroutes(int noresolve, int netstatfmt)
    499480{
    500     char devname[64], flags[16], sdest[16], sgw[16];
    501     unsigned long int d, g, m;
     481    char devname[64], flags[16], *sdest, *sgw;
     482    unsigned long d, g, m;
    502483    int flgs, ref, use, metric, mtu, win, ir;
    503484    struct sockaddr_in s_addr;
    504485    struct in_addr mask;
    505486
    506     FILE *fp = bb_xfopen("/proc/net/route", "r");
    507 
    508     bb_printf("Kernel IP routing table\n"
    509               "Destination     Gateway         Genmask"
    510               "         Flags %s Iface\n",
    511               netstatfmt ? "  MSS Window  irtt" : "Metric Ref    Use");
     487    FILE *fp = xfopen("/proc/net/route", "r");
     488
     489    printf("Kernel IP routing table\n"
     490           "Destination     Gateway         Genmask         Flags %s Iface\n",
     491            netstatfmt ? "  MSS Window  irtt" : "Metric Ref    Use");
    512492
    513493    if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */
     
    523503                break;
    524504            }
    525         ERROR:
     505 ERROR:
    526506            bb_error_msg_and_die("fscanf");
    527507        }
     
    541521        s_addr.sin_family = AF_INET;
    542522        s_addr.sin_addr.s_addr = d;
    543         INET_rresolve(sdest, sizeof(sdest), &s_addr,
    544                       (noresolve | 0x8000), m); /* Default instead of *. */
    545 
     523        sdest = INET_rresolve(&s_addr, (noresolve | 0x8000), m); /* 'default' instead of '*' */
    546524        s_addr.sin_addr.s_addr = g;
    547         INET_rresolve(sgw, sizeof(sgw), &s_addr,
    548                       (noresolve | 0x4000), m); /* Host instead of net. */
    549 
     525        sgw = INET_rresolve(&s_addr, (noresolve | 0x4000), m); /* Host instead of net */
    550526        mask.s_addr = m;
    551         bb_printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask), flags);
     527        /* "%15.15s" truncates hostnames, do we really want that? */
     528        printf("%-15.15s %-15.15s %-16s%-6s", sdest, sgw, inet_ntoa(mask), flags);
     529        free(sdest);
     530        free(sgw);
    552531        if (netstatfmt) {
    553             bb_printf("%5d %-5d %6d %s\n", mtu, win, ir, devname);
     532            printf("%5d %-5d %6d %s\n", mtu, win, ir, devname);
    554533        } else {
    555             bb_printf("%-6d %-2d %7d %s\n", metric, ref, use, devname);
     534            printf("%-6d %-2d %7d %s\n", metric, ref, use, devname);
    556535        }
    557536    }
    558537}
    559538
    560 #ifdef CONFIG_FEATURE_IPV6
     539#if ENABLE_FEATURE_IPV6
    561540
    562541static void INET6_displayroutes(int noresolve)
    563542{
    564     char addr6[128], naddr6[128];
     543    char addr6[128], *naddr6;
    565544    /* In addr6x, we store both 40-byte ':'-delimited ipv6 addresses.
    566545     * We read the non-delimited strings into the tail of the buffer
     
    574553    struct sockaddr_in6 snaddr6;
    575554
    576     FILE *fp = bb_xfopen("/proc/net/ipv6_route", "r");
    577 
    578     bb_printf("Kernel IPv6 routing table\n%-44s%-40s"
     555    FILE *fp = xfopen("/proc/net/ipv6_route", "r");
     556
     557    printf("Kernel IPv6 routing table\n%-44s%-40s"
    579558              "Flags Metric Ref    Use Iface\n",
    580559              "Destination", "Next Hop");
     
    589568                break;
    590569            }
    591         ERROR:
     570 ERROR:
    592571            bb_error_msg_and_die("fscanf");
    593572        }
     
    602581            do {
    603582                if (!*p) {
    604                     if (i==40) { /* nul terminator for 1st address? */
     583                    if (i == 40) { /* nul terminator for 1st address? */
    605584                        addr6x[39] = 0; /* Fixup... need 0 instead of ':'. */
    606585                        ++p;    /* Skip and continue. */
     
    610589                }
    611590                addr6x[i++] = *p++;
    612                 if (!((i+1)%5)) {
     591                if (!((i+1) % 5)) {
    613592                    addr6x[i++] = ':';
    614593                }
     
    627606                      (struct sockaddr *) &snaddr6.sin6_addr);
    628607            snaddr6.sin6_family = AF_INET6;
    629             INET6_rresolve(naddr6, sizeof(naddr6),
    630                            (struct sockaddr_in6 *) &snaddr6,
    631 #if 0
    632                            (noresolve | 0x8000) /* Default instead of *. */
    633 #else
     608            naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6,
    634609                           0x0fff /* Apparently, upstream never resolves. */
    635 #endif
    636610                           );
    637611
     
    639613                snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len);
    640614                r += 40;
     615                free(naddr6);
    641616            } else {            /* 2nd pass */
    642617                /* Print the info. */
    643                 bb_printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
    644                           addr6, naddr6, flags, metric, refcnt, use, iface);
     618                printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
     619                        addr6, naddr6, flags, metric, refcnt, use, iface);
     620                free(naddr6);
    645621                break;
    646622            }
     
    651627#endif
    652628
    653 #define ROUTE_OPT_A         0x01
    654 #define ROUTE_OPT_n         0x02
    655 #define ROUTE_OPT_e         0x04
    656 #define ROUTE_OPT_INET6     0x08 /* Not an actual option. See below. */
     629#define ROUTE_OPT_A     0x01
     630#define ROUTE_OPT_n     0x02
     631#define ROUTE_OPT_e     0x04
     632#define ROUTE_OPT_INET6 0x08 /* Not an actual option. See below. */
    657633
    658634/* 1st byte is offset to next entry offset.  2nd byte is return value. */
    659 static const char tbl_verb[] =  /* 2nd byte matches RTACTION_* code */
     635/* 2nd byte matches RTACTION_* code */
     636static const char tbl_verb[] ALIGN1 =
    660637    "\006\001add\0"
    661638    "\006\002del\0"
    662639/*  "\011\002delete\0" */
    663     "\010\002delete"            /* Since last, we can save a byte. */
     640    "\010\002delete"  /* Since it's last, we can save a byte. */
    664641;
    665642
     643int route_main(int argc, char **argv);
    666644int route_main(int argc, char **argv)
    667645{
    668     unsigned long opt;
     646    unsigned opt;
    669647    int what;
    670648    char *family;
     649    char **p;
    671650
    672651    /* First, remap '-net' and '-host' to avoid getopt problems. */
    673     {
    674         char **p = argv;
    675 
    676         while (*++p) {
    677             if ((strcmp(*p, "-net") == 0) || (strcmp(*p, "-host") == 0)) {
    678                 p[0][0] = '#';
    679             }
    680         }
    681     }
    682 
    683     opt = bb_getopt_ulflags(argc, argv, "A:ne", &family);
    684 
    685     if ((opt & ROUTE_OPT_A) && strcmp(family, "inet")) {
    686 #ifdef CONFIG_FEATURE_IPV6
     652    p = argv;
     653    while (*++p) {
     654        if (strcmp(*p, "-net") == 0 || strcmp(*p, "-host") == 0) {
     655            p[0][0] = '#';
     656        }
     657    }
     658
     659    opt = getopt32(argv, "A:ne", &family);
     660
     661    if ((opt & ROUTE_OPT_A) && strcmp(family, "inet") != 0) {
     662#if ENABLE_FEATURE_IPV6
    687663        if (strcmp(family, "inet6") == 0) {
    688664            opt |= ROUTE_OPT_INET6; /* Set flag for ipv6. */
     
    697673    if (!*argv) {
    698674        int noresolve = (opt & ROUTE_OPT_n) ? 0x0fff : 0;
    699 #ifdef CONFIG_FEATURE_IPV6
     675#if ENABLE_FEATURE_IPV6
    700676        if (opt & ROUTE_OPT_INET6)
    701677            INET6_displayroutes(noresolve);
    702678        else
    703679#endif
    704             displayroutes(noresolve, opt & ROUTE_OPT_e);
    705 
    706         bb_xferror_stdout();
    707         bb_fflush_stdout_and_exit(EXIT_SUCCESS);
     680            bb_displayroutes(noresolve, opt & ROUTE_OPT_e);
     681
     682        fflush_stdout_and_exit(EXIT_SUCCESS);
    708683    }
    709684
     
    714689    }
    715690
    716 #ifdef CONFIG_FEATURE_IPV6
     691#if ENABLE_FEATURE_IPV6
    717692    if (opt & ROUTE_OPT_INET6)
    718693        INET6_setroute(what, argv);
  • branches/stable/mindi-busybox/networking/telnet.c

    r821 r1770  
    2323
    2424#include <termios.h>
    25 #include <unistd.h>
    26 #include <errno.h>
    27 #include <stdlib.h>
    28 #include <stdarg.h>
    29 #include <string.h>
    30 #include <signal.h>
    3125#include <arpa/telnet.h>
    32 #include <sys/types.h>
    33 #include <sys/socket.h>
    3426#include <netinet/in.h>
    35 #include "busybox.h"
    36 
    37 #if 0
    38 enum { DOTRACE = 1 };
    39 #endif
     27#include "libbb.h"
    4028
    4129#ifdef DOTRACE
    42 #include <arpa/inet.h> /* for inet_ntoa()... */
    4330#define TRACE(x, y) do { if (x) printf y; } while (0)
    4431#else
     
    4633#endif
    4734
    48 #define DATABUFSIZE  128
    49 #define IACBUFSIZE   128
    50 
    5135enum {
     36    DATABUFSIZE = 128,
     37    IACBUFSIZE  = 128,
     38
    5239    CHM_TRY = 0,
    5340    CHM_ON = 1,
     
    6451};
    6552
    66 #define WriteCS(fd, str) write(fd, str, sizeof str -1)
    67 
    6853typedef unsigned char byte;
    6954
    70 /* use globals to reduce size ??? */ /* test this hypothesis later */
    71 static struct Globalvars {
    72     int     netfd; /* console fd:s are 0 and 1 (and 2) */
    73     /* same buffer used both for network and console read/write */
    74     char    buf[DATABUFSIZE]; /* allocating so static size is smaller */
     55struct globals {
     56    int netfd; /* console fd:s are 0 and 1 (and 2) */
     57    short   iaclen; /* could even use byte */
    7558    byte    telstate; /* telnet negotiation state from network input */
    7659    byte    telwish;  /* DO, DONT, WILL, WONT */
     
    7962    byte    gotsig;
    8063    byte    do_termios;
     64#if ENABLE_FEATURE_TELNET_TTYPE
     65    char    *ttype;
     66#endif
     67#if ENABLE_FEATURE_TELNET_AUTOLOGIN
     68    const char *autologin;
     69#endif
     70#if ENABLE_FEATURE_AUTOWIDTH
     71    int win_width, win_height;
     72#endif
     73    /* same buffer used both for network and console read/write */
     74    char    buf[DATABUFSIZE];
    8175    /* buffer to handle telnet negotiations */
    8276    char    iacbuf[IACBUFSIZE];
    83     short   iaclen; /* could even use byte */
    8477    struct termios termios_def;
    8578    struct termios termios_raw;
    86 } G;
    87 
    88 #define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
    89 
    90 #ifdef USE_GLOBALVAR_PTR
    91 struct Globalvars * Gptr;
    92 #define G (*Gptr)
    93 #endif
    94 
    95 static inline void iacflush(void)
    96 {
    97     write(G.netfd, G.iacbuf, G.iaclen);
    98     G.iaclen = 0;
    99 }
     79};
     80#define G (*(struct globals*)&bb_common_bufsiz1)
     81void BUG_telnet_globals_too_big(void);
     82#define INIT_G() do { \
     83    if (sizeof(G) > COMMON_BUFSIZE) \
     84        BUG_telnet_globals_too_big(); \
     85    /* memset(&G, 0, sizeof G); - already is */ \
     86} while (0)
    10087
    10188/* Function prototypes */
     
    10794static int subneg(byte c);
    10895
    109 /* Some globals */
    110 static int one = 1;
    111 
    112 #ifdef CONFIG_FEATURE_TELNET_TTYPE
    113 static char *ttype;
    114 #endif
    115 
    116 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
    117 static const char *autologin;
    118 #endif
    119 
    120 #ifdef CONFIG_FEATURE_AUTOWIDTH
    121 static int win_width, win_height;
    122 #endif
     96static void iacflush(void)
     97{
     98    write(G.netfd, G.iacbuf, G.iaclen);
     99    G.iaclen = 0;
     100}
     101
     102#define write_str(fd, str) write(fd, str, sizeof(str) - 1)
    123103
    124104static void doexit(int ev)
     
    135115        rawmode();
    136116
    137     WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
     117    write_str(1, "\r\nConsole escape. Commands are:\r\n\n"
    138118            " l go to line mode\r\n"
    139119            " c go to character mode\r\n"
     
    144124        doexit(1);
    145125
    146     switch (b)
    147     {
     126    switch (b) {
    148127    case 'l':
    149         if (!G.gotsig)
    150         {
     128        if (!G.gotsig) {
    151129            do_linemode();
    152130            goto rrturn;
     
    154132        break;
    155133    case 'c':
    156         if (G.gotsig)
    157         {
     134        if (G.gotsig) {
    158135            will_charmode();
    159136            goto rrturn;
     
    169146    }
    170147
    171     WriteCS(1, "continuing...\r\n");
     148    write_str(1, "continuing...\r\n");
    172149
    173150    if (G.gotsig)
     
    178155
    179156}
     157
    180158static void handlenetoutput(int len)
    181159{
     
    190168     *  first - I cannot use programs like sz/rz
    191169     *  second - the 0x0D is sent as one character and if the next
    192      *          char is 0x0A then it's eaten by a server side.
     170     *      char is 0x0A then it's eaten by a server side.
    193171     *  third - whay doy you have to make 'many write()s'?
    194      *          I don't understand.
     172     *      I don't understand.
    195173     *  So I implemented it. It's realy useful for me. I hope that
    196174     *  others people will find it interesting to.
     
    210188        outbuf[j++] = *p;
    211189        if (*p == 0xff)
    212             outbuf[j++] = 0xff;
     190            outbuf[j++] = 0xff;
    213191        else if (*p == 0x0d)
    214             outbuf[j++] = 0x00;
    215     }
    216     if (j > 0 )
    217         write(G.netfd, outbuf, j);
    218 }
    219 
     192            outbuf[j++] = 0x00;
     193    }
     194    if (j > 0)
     195        write(G.netfd, outbuf, j);
     196}
    220197
    221198static void handlenetinput(int len)
     
    293270}
    294271
    295 
    296 /* ******************************* */
    297 
    298 static inline void putiac(int c)
     272static void putiac(int c)
    299273{
    300274    G.iacbuf[G.iaclen++] = c;
    301275}
    302 
    303276
    304277static void putiac2(byte wwdd, byte c)
     
    312285}
    313286
    314 #if 0
    315 static void putiac1(byte c)
    316 {
    317     if (G.iaclen + 2 > IACBUFSIZE)
    318         iacflush();
    319 
    320     putiac(IAC);
    321     putiac(c);
    322 }
    323 #endif
    324 
    325 #ifdef CONFIG_FEATURE_TELNET_TTYPE
     287#if ENABLE_FEATURE_TELNET_TTYPE
    326288static void putiac_subopt(byte c, char *str)
    327289{
     
    336298    putiac(0);
    337299
    338     while(*str)
     300    while (*str)
    339301        putiac(*str++);
    340302
     
    344306#endif
    345307
    346 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
     308#if ENABLE_FEATURE_TELNET_AUTOLOGIN
    347309static void putiac_subopt_autologin(void)
    348310{
    349     int len = strlen(autologin) + 6;    // (2 + 1 + 1 + strlen + 2)
    350     char *user = "USER";
     311    int len = strlen(G.autologin) + 6;  // (2 + 1 + 1 + strlen + 2)
     312    const char *user = "USER";
    351313
    352314    if (G.iaclen + len > IACBUFSIZE)
     
    359321    putiac(NEW_ENV_VAR);
    360322
    361     while(*user)
     323    while (*user)
    362324        putiac(*user++);
    363325
    364326    putiac(NEW_ENV_VALUE);
    365327
    366     while(*autologin)
    367         putiac(*autologin++);
     328    while (*G.autologin)
     329        putiac(*G.autologin++);
    368330
    369331    putiac(IAC);
     
    372334#endif
    373335
    374 #ifdef CONFIG_FEATURE_AUTOWIDTH
     336#if ENABLE_FEATURE_AUTOWIDTH
    375337static void putiac_naws(byte c, int x, int y)
    376338{
     
    392354#endif
    393355
    394 /* void putiacstring (subneg strings) */
    395 
    396 /* ******************************* */
    397 
    398 static char const escapecharis[] = "\r\nEscape character is ";
     356static char const escapecharis[] ALIGN1 = "\r\nEscape character is ";
    399357
    400358static void setConMode(void)
    401359{
    402     if (G.telflags & UF_ECHO)
    403     {
     360    if (G.telflags & UF_ECHO) {
    404361        if (G.charmode == CHM_TRY) {
    405362            G.charmode = CHM_ON;
     
    407364            rawmode();
    408365        }
    409     }
    410     else
    411     {
     366    } else {
    412367        if (G.charmode != CHM_OFF) {
    413368            G.charmode = CHM_OFF;
     
    418373}
    419374
    420 /* ******************************* */
    421 
    422375static void will_charmode(void)
    423376{
     
    442395}
    443396
    444 /* ******************************* */
    445 
    446 static inline void to_notsup(char c)
    447 {
    448     if      (G.telwish == WILL) putiac2(DONT, c);
    449     else if (G.telwish == DO)   putiac2(WONT, c);
    450 }
    451 
    452 static inline void to_echo(void)
     397static void to_notsup(char c)
     398{
     399    if (G.telwish == WILL)
     400        putiac2(DONT, c);
     401    else if (G.telwish == DO)
     402        putiac2(WONT, c);
     403}
     404
     405static void to_echo(void)
    453406{
    454407    /* if server requests ECHO, don't agree */
    455     if      (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; }
    456     else if (G.telwish == DONT) return;
    457 
    458     if (G.telflags & UF_ECHO)
    459     {
     408    if (G.telwish == DO) {
     409        putiac2(WONT, TELOPT_ECHO);
     410        return;
     411    }
     412    if (G.telwish == DONT)
     413        return;
     414
     415    if (G.telflags & UF_ECHO) {
    460416        if (G.telwish == WILL)
    461417            return;
    462     }
    463     else
    464         if (G.telwish == WONT)
    465             return;
     418    } else if (G.telwish == WONT)
     419        return;
    466420
    467421    if (G.charmode != CHM_OFF)
     
    474428
    475429    setConMode();
    476     WriteCS(1, "\r\n");  /* sudden modec */
    477 }
    478 
    479 static inline void to_sga(void)
     430    write_str(1, "\r\n");  /* sudden modec */
     431}
     432
     433static void to_sga(void)
    480434{
    481435    /* daemon always sends will/wont, client do/dont */
    482436
    483     if (G.telflags & UF_SGA)
    484     {
     437    if (G.telflags & UF_SGA) {
    485438        if (G.telwish == WILL)
    486439            return;
    487     }
    488     else
    489         if (G.telwish == WONT)
    490             return;
     440    } else if (G.telwish == WONT)
     441        return;
    491442
    492443    if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
     
    494445    else
    495446        putiac2(DONT, TELOPT_SGA);
    496 
    497     return;
    498 }
    499 
    500 #ifdef CONFIG_FEATURE_TELNET_TTYPE
    501 static inline void to_ttype(void)
     447}
     448
     449#if ENABLE_FEATURE_TELNET_TTYPE
     450static void to_ttype(void)
    502451{
    503452    /* Tell server we will (or won't) do TTYPE */
    504453
    505     if(ttype)
     454    if (G.ttype)
    506455        putiac2(WILL, TELOPT_TTYPE);
    507456    else
    508457        putiac2(WONT, TELOPT_TTYPE);
    509 
    510     return;
    511 }
    512 #endif
    513 
    514 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
    515 static inline void to_new_environ(void)
     458}
     459#endif
     460
     461#if ENABLE_FEATURE_TELNET_AUTOLOGIN
     462static void to_new_environ(void)
    516463{
    517464    /* Tell server we will (or will not) do AUTOLOGIN */
    518465
    519     if (autologin)
     466    if (G.autologin)
    520467        putiac2(WILL, TELOPT_NEW_ENVIRON);
    521468    else
    522469        putiac2(WONT, TELOPT_NEW_ENVIRON);
    523 
    524     return;
    525 }
    526 #endif
    527 
    528 #ifdef CONFIG_FEATURE_AUTOWIDTH
    529 static inline void to_naws(void)
     470}
     471#endif
     472
     473#if ENABLE_FEATURE_AUTOWIDTH
     474static void to_naws(void)
    530475{
    531476    /* Tell server we will do NAWS */
    532477    putiac2(WILL, TELOPT_NAWS);
    533     return;
    534478}
    535479#endif
     
    537481static void telopt(byte c)
    538482{
    539     switch (c)
    540     {
    541         case TELOPT_ECHO:       to_echo();  break;
    542         case TELOPT_SGA:        to_sga();   break;
    543 #ifdef CONFIG_FEATURE_TELNET_TTYPE
    544         case TELOPT_TTYPE:      to_ttype();break;
    545 #endif
    546 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
    547         case TELOPT_NEW_ENVIRON:    to_new_environ();   break;
    548 #endif
    549 #ifdef CONFIG_FEATURE_AUTOWIDTH
    550         case TELOPT_NAWS:       to_naws();
    551                                 putiac_naws(c, win_width, win_height);
    552                                 break;
    553 #endif
    554         default:                to_notsup(c);
    555                                 break;
    556     }
    557 }
    558 
    559 
    560 /* ******************************* */
     483    switch (c) {
     484    case TELOPT_ECHO:
     485        to_echo(); break;
     486    case TELOPT_SGA:
     487        to_sga(); break;
     488#if ENABLE_FEATURE_TELNET_TTYPE
     489    case TELOPT_TTYPE:
     490        to_ttype(); break;
     491#endif
     492#if ENABLE_FEATURE_TELNET_AUTOLOGIN
     493    case TELOPT_NEW_ENVIRON:
     494        to_new_environ(); break;
     495#endif
     496#if ENABLE_FEATURE_AUTOWIDTH
     497    case TELOPT_NAWS:
     498        to_naws();
     499        putiac_naws(c, G.win_width, G.win_height);
     500        break;
     501#endif
     502    default:
     503        to_notsup(c);
     504        break;
     505    }
     506}
    561507
    562508/* subnegotiation -- ignore all (except TTYPE,NAWS) */
    563 
    564509static int subneg(byte c)
    565510{
    566     switch (G.telstate)
    567     {
     511    switch (G.telstate) {
    568512    case TS_SUB1:
    569513        if (c == IAC)
    570514            G.telstate = TS_SUB2;
    571 #ifdef CONFIG_FEATURE_TELNET_TTYPE
     515#if ENABLE_FEATURE_TELNET_TTYPE
    572516        else
    573517        if (c == TELOPT_TTYPE)
    574             putiac_subopt(TELOPT_TTYPE,ttype);
    575 #endif
    576 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
     518            putiac_subopt(TELOPT_TTYPE, G.ttype);
     519#endif
     520#if ENABLE_FEATURE_TELNET_AUTOLOGIN
    577521        else
    578522        if (c == TELOPT_NEW_ENVIRON)
     
    589533}
    590534
    591 /* ******************************* */
    592 
    593535static void fgotsig(int sig)
    594536{
     
    599541static void rawmode(void)
    600542{
    601     if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw);
     543    if (G.do_termios)
     544        tcsetattr(0, TCSADRAIN, &G.termios_raw);
    602545}
    603546
    604547static void cookmode(void)
    605548{
    606     if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def);
    607 }
    608 
     549    if (G.do_termios)
     550        tcsetattr(0, TCSADRAIN, &G.termios_def);
     551}
     552
     553int telnet_main(int argc, char** argv);
    609554int telnet_main(int argc, char** argv)
    610555{
     556    char *host;
     557    int port;
    611558    int len;
    612     struct sockaddr_in s_in;
    613559#ifdef USE_POLL
    614560    struct pollfd ufds[2];
     
    618564#endif
    619565
    620 #ifdef CONFIG_FEATURE_AUTOWIDTH
    621     get_terminal_width_height(0, &win_width, &win_height);
    622 #endif
    623 
    624 #ifdef CONFIG_FEATURE_TELNET_TTYPE
    625     ttype = getenv("TERM");
    626 #endif
    627 
    628     memset(&G, 0, sizeof G);
     566    INIT_G();
     567
     568#if ENABLE_FEATURE_AUTOWIDTH
     569    get_terminal_width_height(0, &G.win_width, &G.win_height);
     570#endif
     571
     572#if ENABLE_FEATURE_TELNET_TTYPE
     573    G.ttype = getenv("TERM");
     574#endif
    629575
    630576    if (tcgetattr(0, &G.termios_def) >= 0) {
    631577        G.do_termios = 1;
    632 
    633578        G.termios_raw = G.termios_def;
    634579        cfmakeraw(&G.termios_raw);
     
    638583        bb_show_usage();
    639584
    640 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
    641     if (1 & bb_getopt_ulflags(argc, argv, "al:", &autologin))
    642         autologin = getenv("USER");
    643 
    644     if (optind < argc) {
    645         bb_lookup_host(&s_in, argv[optind++]);
    646         s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] :
    647                 "telnet", "tcp", 23);
    648         if (optind < argc)
    649             bb_show_usage();
    650     } else
     585#if ENABLE_FEATURE_TELNET_AUTOLOGIN
     586    if (1 & getopt32(argv, "al:", &G.autologin))
     587        G.autologin = getenv("USER");
     588    argv += optind;
     589#else
     590    argv++;
     591#endif
     592    if (!*argv)
    651593        bb_show_usage();
    652 #else
    653     bb_lookup_host(&s_in, argv[1]);
    654     s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23);
    655 #endif
    656 
    657     G.netfd = xconnect(&s_in);
    658 
    659     setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
     594    host = *argv++;
     595    port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23);
     596    if (*argv) /* extra params?? */
     597        bb_show_usage();
     598
     599    G.netfd = create_and_connect_stream_or_die(host, port);
     600
     601    setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
    660602
    661603    signal(SIGINT, fgotsig);
     
    671613#endif
    672614
    673     while (1)
    674     {
     615    while (1) {
    675616#ifndef USE_POLL
    676617        fd_set rfds = readfds;
     
    699640            {
    700641                len = read(0, G.buf, DATABUFSIZE);
    701 
    702642                if (len <= 0)
    703643                    doexit(0);
    704 
    705644                TRACE(0, ("Read con: %d\n", len));
    706 
    707645                handlenetoutput(len);
    708646            }
     
    715653            {
    716654                len = read(G.netfd, G.buf, DATABUFSIZE);
    717 
    718                 if (len <= 0)
    719                 {
    720                     WriteCS(1, "Connection closed by foreign host.\r\n");
     655                if (len <= 0) {
     656                    write_str(1, "Connection closed by foreign host\r\n");
    721657                    doexit(1);
    722658                }
    723659                TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
    724 
    725660                handlenetinput(len);
    726661            }
  • branches/stable/mindi-busybox/networking/telnetd.c

    r821 r1770  
    2222 */
    2323
    24 /*#define DEBUG 1 */
    25 #undef DEBUG
    26 
    27 #include <sys/socket.h>
    28 #include <sys/wait.h>
    29 #include <sys/ioctl.h>
    30 #include <string.h>
    31 #include <stdlib.h>
    32 #include <unistd.h>
    33 #include <errno.h>
    34 #include <netinet/in.h>
    35 #include <arpa/inet.h>
    36 #include <fcntl.h>
    37 #include <stdio.h>
    38 #include <signal.h>
    39 #include <termios.h>
    40 #ifdef DEBUG
     24#define DEBUG 0
     25
     26#include "libbb.h"
     27
     28#if DEBUG
    4129#define TELCMDS
    4230#define TELOPTS
    4331#endif
    4432#include <arpa/telnet.h>
    45 #include <ctype.h>
    4633#include <sys/syslog.h>
    4734
    48 #include "busybox.h"
    49 
    50 #define BUFSIZE 4000
    51 
    52 #ifdef CONFIG_FEATURE_IPV6
    53 #define SOCKET_TYPE AF_INET6
    54 typedef struct sockaddr_in6 sockaddr_type;
    55 #else
    56 #define SOCKET_TYPE AF_INET
    57 typedef struct sockaddr_in sockaddr_type;
    58 #endif
    59 
    60 
    61 #ifdef CONFIG_LOGIN
     35
     36#if ENABLE_LOGIN
    6237static const char *loginpath = "/bin/login";
    6338#else
    64 static const char *loginpath;
    65 #endif
     39static const char *loginpath = DEFAULT_SHELL;
     40#endif
     41
    6642static const char *issuefile = "/etc/issue.net";
    6743
    68 /* shell name and arguments */
    69 
    70 static const char *argv_init[] = {NULL, NULL};
    71 
    7244/* structure that describes a session */
    7345
    7446struct tsession {
    75 #ifdef CONFIG_FEATURE_TELNETD_INETD
     47    struct tsession *next;
    7648    int sockfd_read, sockfd_write, ptyfd;
    77 #else /* CONFIG_FEATURE_TELNETD_INETD */
    78     struct tsession *next;
    79     int sockfd, ptyfd;
    80 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    8149    int shell_pid;
    8250    /* two circular buffers */
     
    8654};
    8755
     56/* Two buffers are directly after tsession in malloced memory.
     57 * Make whole thing fit in 4k */
     58enum { BUFSIZE = (4*1024 - sizeof(struct tsession)) / 2 };
     59
    8860/*
    89 
    9061   This is how the buffers are used. The arrows indicate the movement
    9162   of data.
     
    10071
    10172   Each session has got two buffers.
    102 
    10373*/
    10474
     
    10979
    11080/*
    111 
    11281   Remove all IAC's from the buffer pointed to by bf (received IACs are ignored
    11382   and must be removed so as to not be interpreted by the terminal).  Make an
     
    12796
    12897   CR-LF ->'s CR mapping is also done here, for convenience
    129 
    130   */
     98 */
    13199static char *
    132 remove_iacs(struct tsession *ts, int *pnum_totty) {
     100remove_iacs(struct tsession *ts, int *pnum_totty)
     101{
    133102    unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1;
    134103    unsigned char *ptr = ptr0;
     
    148117            if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end)
    149118                ptr++;
    150         }
    151         else {
     119        } else {
    152120            /*
    153121             * TELOPT_NAWS support!
     
    169137                ws.ws_col = (ptr[3] << 8) | ptr[4];
    170138                ws.ws_row = (ptr[5] << 8) | ptr[6];
    171                 (void) ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
     139                ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
    172140                ptr += 9;
    173             }
    174             else {
     141            } else {
    175142                /* skip 3-byte IAC non-SB cmd */
    176 #ifdef DEBUG
     143#if DEBUG
    177144                fprintf(stderr, "Ignoring IAC %s,%s\n",
    178                     TELCMD(*(ptr+1)), TELOPT(*(ptr+2)));
     145                    TELCMD(ptr[1]), TELOPT(ptr[2]));
    179146#endif
    180147                ptr += 3;
     
    198165
    199166static int
    200 getpty(char *line)
     167getpty(char *line, int size)
    201168{
    202169    int p;
    203 #ifdef CONFIG_FEATURE_DEVPTS
    204     p = open("/dev/ptmx", 2);
     170#if ENABLE_FEATURE_DEVPTS
     171    p = open("/dev/ptmx", O_RDWR);
    205172    if (p > 0) {
     173        const char *name;
    206174        grantpt(p);
    207175        unlockpt(p);
    208         strcpy(line, ptsname(p));
    209         return(p);
     176        name = ptsname(p);
     177        if (!name) {
     178            bb_perror_msg("ptsname error (is /dev/pts mounted?)");
     179            return -1;
     180        }
     181        safe_strncpy(line, name, size);
     182        return p;
    210183    }
    211184#else
     
    224197        for (j = 0; j < 16; j++) {
    225198            line[9] = j < 10 ? j + '0' : j - 10 + 'a';
    226 #ifdef DEBUG
    227             fprintf(stderr, "Trying to open device: %s\n", line);
    228 #endif
    229             if ((p = open(line, O_RDWR | O_NOCTTY)) >= 0) {
     199            if (DEBUG)
     200                fprintf(stderr, "Trying to open device: %s\n", line);
     201            p = open(line, O_RDWR | O_NOCTTY);
     202            if (p >= 0) {
    230203                line[5] = 't';
    231204                return p;
     
    233206        }
    234207    }
    235 #endif /* CONFIG_FEATURE_DEVPTS */
     208#endif /* FEATURE_DEVPTS */
    236209    return -1;
    237210}
     
    241214send_iac(struct tsession *ts, unsigned char command, int option)
    242215{
    243     /* We rely on that there is space in the buffer for now.  */
     216    /* We rely on that there is space in the buffer for now. */
    244217    char *b = ts->buf2 + ts->rdidx2;
    245218    *b++ = IAC;
     
    252225
    253226static struct tsession *
    254 #ifdef CONFIG_FEATURE_TELNETD_INETD
    255 make_new_session(void)
    256 #else /* CONFIG_FEATURE_TELNETD_INETD */
    257 make_new_session(int sockfd)
    258 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    259 {
     227make_new_session(
     228        USE_FEATURE_TELNETD_STANDALONE(int sock_r, int sock_w)
     229        SKIP_FEATURE_TELNETD_STANDALONE(void)
     230) {
     231    const char *login_argv[2];
    260232    struct termios termbuf;
    261     int pty, pid;
     233    int fd, pid;
    262234    char tty_name[32];
    263235    struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
     
    266238    ts->buf2 = ts->buf1 + BUFSIZE;
    267239
    268 #ifdef CONFIG_FEATURE_TELNETD_INETD
     240    /* Got a new connection, set up a tty. */
     241    fd = getpty(tty_name, 32);
     242    if (fd < 0) {
     243        bb_error_msg("all terminals in use");
     244        return NULL;
     245    }
     246    if (fd > maxfd) maxfd = fd;
     247    ndelay_on(ts->ptyfd = fd);
     248#if ENABLE_FEATURE_TELNETD_STANDALONE
     249    if (sock_w > maxfd) maxfd = sock_w;
     250    if (sock_r > maxfd) maxfd = sock_r;
     251    ndelay_on(ts->sockfd_write = sock_w);
     252    ndelay_on(ts->sockfd_read = sock_r);
     253#else
    269254    ts->sockfd_write = 1;
    270 #else /* CONFIG_FEATURE_TELNETD_INETD */
    271     ts->sockfd = sockfd;
    272 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    273 
    274     /* Got a new connection, set up a tty and spawn a shell.  */
    275 
    276     pty = getpty(tty_name);
    277 
    278     if (pty < 0) {
    279         syslog(LOG_ERR, "All terminals in use!");
    280         return 0;
    281     }
    282 
    283     if (pty > maxfd)
    284         maxfd = pty;
    285 
    286     ts->ptyfd = pty;
    287 
     255    /* xzalloc: ts->sockfd_read = 0; */
     256    ndelay_on(0);
     257    ndelay_on(1);
     258#endif
    288259    /* Make the telnet client understand we will echo characters so it
    289260     * should not do it locally. We don't tell the client to run linemode,
    290261     * because we want to handle line editing and tab completion and other
    291      * stuff that requires char-by-char support.
    292      */
    293 
     262     * stuff that requires char-by-char support. */
    294263    send_iac(ts, DO, TELOPT_ECHO);
    295264    send_iac(ts, DO, TELOPT_NAWS);
     
    298267    send_iac(ts, WILL, TELOPT_SGA);
    299268
    300     if ((pid = fork()) < 0) {
    301         syslog(LOG_ERR, "Could not fork");
    302     }
    303     if (pid == 0) {
    304         /* In child, open the child's side of the tty.  */
    305         int i;
    306 
    307         for(i = 0; i <= maxfd; i++)
    308             close(i);
    309         /* make new process group */
    310         setsid();
    311 
    312         if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) {
    313             syslog(LOG_ERR, "Could not open tty");
    314             exit(1);
    315         }
    316         dup(0);
    317         dup(0);
    318 
    319         tcsetpgrp(0, getpid());
    320 
    321         /* The pseudo-terminal allocated to the client is configured to operate in
    322          * cooked mode, and with XTABS CRMOD enabled (see tty(4)).
    323          */
    324 
    325         tcgetattr(0, &termbuf);
    326         termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
    327         termbuf.c_oflag |= ONLCR|XTABS;
    328         termbuf.c_iflag |= ICRNL;
    329         termbuf.c_iflag &= ~IXOFF;
    330         /*termbuf.c_lflag &= ~ICANON;*/
    331         tcsetattr(0, TCSANOW, &termbuf);
    332 
    333         print_login_issue(issuefile, NULL);
    334 
    335         /* exec shell, with correct argv and env */
    336         execv(loginpath, (char *const *)argv_init);
    337 
    338         /* NOT REACHED */
    339         syslog(LOG_ERR, "execv error");
    340         exit(1);
    341     }
    342 
    343     ts->shell_pid = pid;
    344 
    345     return ts;
     269    pid = fork();
     270    if (pid < 0) {
     271        free(ts);
     272        close(fd);
     273        bb_perror_msg("fork");
     274        return NULL;
     275    }
     276    if (pid > 0) {
     277        /* parent */
     278        ts->shell_pid = pid;
     279        return ts;
     280    }
     281
     282    /* child */
     283
     284    /* make new session and process group */
     285    setsid();
     286
     287    /* open the child's side of the tty. */
     288    /* NB: setsid() disconnects from any previous ctty's. Therefore
     289     * we must open child's side of the tty AFTER setsid! */
     290    fd = xopen(tty_name, O_RDWR); /* becomes our ctty */
     291    dup2(fd, 0);
     292    dup2(fd, 1);
     293    dup2(fd, 2);
     294    while (fd > 2) close(fd--);
     295    tcsetpgrp(0, getpid()); /* switch this tty's process group to us */
     296
     297    /* The pseudo-terminal allocated to the client is configured to operate in
     298     * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */
     299    tcgetattr(0, &termbuf);
     300    termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
     301    termbuf.c_oflag |= ONLCR|XTABS;
     302    termbuf.c_iflag |= ICRNL;
     303    termbuf.c_iflag &= ~IXOFF;
     304    /*termbuf.c_lflag &= ~ICANON;*/
     305    tcsetattr(0, TCSANOW, &termbuf);
     306
     307    print_login_issue(issuefile, NULL);
     308
     309    /* exec shell / login /whatever */
     310    login_argv[0] = loginpath;
     311    login_argv[1] = NULL;
     312    execv(loginpath, (char **)login_argv);
     313    /* Hmmm... this gets sent to the client thru fd#2! Is it ok?? */
     314    bb_perror_msg_and_die("execv %s", loginpath);
    346315}
    347316
    348 #ifndef CONFIG_FEATURE_TELNETD_INETD
     317#if ENABLE_FEATURE_TELNETD_STANDALONE
     318
    349319static void
    350320free_session(struct tsession *ts)
     
    352322    struct tsession *t = sessions;
    353323
    354     /* Unlink this telnet session from the session list. */
     324    /* unlink this telnet session from the session list */
    355325    if (t == ts)
    356326        sessions = ts->next;
    357327    else {
    358         while(t->next != ts)
     328        while (t->next != ts)
    359329            t = t->next;
    360330        t->next = ts->next;
     
    362332
    363333    kill(ts->shell_pid, SIGKILL);
    364 
    365334    wait4(ts->shell_pid, NULL, 0, NULL);
    366 
    367335    close(ts->ptyfd);
    368     close(ts->sockfd);
    369 
    370     if (ts->ptyfd == maxfd || ts->sockfd == maxfd)
    371         maxfd--;
    372     if (ts->ptyfd == maxfd || ts->sockfd == maxfd)
    373         maxfd--;
    374 
     336    close(ts->sockfd_read);
     337    /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */
     338    close(ts->sockfd_write);
    375339    free(ts);
     340
     341    /* scan all sessions and find new maxfd */
     342    ts = sessions;
     343    maxfd = 0;
     344    while (ts) {
     345        if (maxfd < ts->ptyfd)
     346            maxfd = ts->ptyfd;
     347        if (maxfd < ts->sockfd_read)
     348            maxfd = ts->sockfd_read;
     349        if (maxfd < ts->sockfd_write)
     350            maxfd = ts->sockfd_write;
     351        ts = ts->next;
     352    }
    376353}
    377 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    378 
    379 int
    380 telnetd_main(int argc, char **argv)
     354
     355#else /* !FEATURE_TELNETD_STANDALONE */
     356
     357/* Never actually called */
     358void free_session(struct tsession *ts);
     359
     360#endif
     361
     362
     363int telnetd_main(int argc, char **argv);
     364int telnetd_main(int argc, char **argv)
    381365{
    382 #ifndef CONFIG_FEATURE_TELNETD_INETD
    383     sockaddr_type sa;
    384     int master_fd;
    385 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    386366    fd_set rdfdset, wrfdset;
    387     int selret;
    388 #ifndef CONFIG_FEATURE_TELNETD_INETD
    389     int on = 1;
    390     int portnbr = 23;
    391     struct in_addr bind_addr = { .s_addr = 0x0 };
    392 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    393     int c;
    394     static const char options[] =
    395 #ifdef CONFIG_FEATURE_TELNETD_INETD
    396         "f:l:";
    397 #else /* CONFIG_EATURE_TELNETD_INETD */
    398         "f:l:p:b:";
    399 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    400     int maxlen, w, r;
    401 
    402 #ifndef CONFIG_LOGIN
    403     loginpath = DEFAULT_SHELL;
    404 #endif
    405 
    406     for (;;) {
    407         c = getopt( argc, argv, options);
    408         if (c == EOF) break;
    409         switch (c) {
    410             case 'f':
    411                 issuefile = optarg;
    412                 break;
    413             case 'l':
    414                 loginpath = optarg;
    415                 break;
    416 #ifndef CONFIG_FEATURE_TELNETD_INETD
    417             case 'p':
    418                 portnbr = atoi(optarg);
    419                 break;
    420             case 'b':
    421                 if (inet_aton(optarg, &bind_addr) == 0)
    422                     bb_show_usage();
    423                 break;
    424 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    425             default:
    426                 bb_show_usage();
    427         }
    428     }
    429 
    430     if (access(loginpath, X_OK) < 0) {
    431         bb_error_msg_and_die ("'%s' unavailable.", loginpath);
    432     }
    433 
    434     argv_init[0] = loginpath;
    435 
    436     openlog(bb_applet_name, 0, LOG_USER);
    437 
    438 #ifdef CONFIG_FEATURE_TELNETD_INETD
    439     maxfd = 1;
     367    unsigned opt;
     368    int selret, maxlen, w, r;
     369    struct tsession *ts;
     370#if ENABLE_FEATURE_TELNETD_STANDALONE
     371#define IS_INETD (opt & OPT_INETD)
     372    int master_fd = -1; /* be happy, gcc */
     373    unsigned portnbr = 23;
     374    char *opt_bindaddr = NULL;
     375    char *opt_portnbr;
     376#else
     377    enum {
     378        IS_INETD = 1,
     379        master_fd = -1,
     380        portnbr = 23,
     381    };
     382#endif
     383    enum {
     384        OPT_PORT = 4 * ENABLE_FEATURE_TELNETD_STANDALONE,
     385        OPT_FOREGROUND = 0x10 * ENABLE_FEATURE_TELNETD_STANDALONE,
     386        OPT_INETD = 0x20 * ENABLE_FEATURE_TELNETD_STANDALONE,
     387    };
     388
     389    opt = getopt32(argv, "f:l:" USE_FEATURE_TELNETD_STANDALONE("p:b:Fi"),
     390            &issuefile, &loginpath
     391            USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
     392    /* Redirect log to syslog early, if needed */
     393    if (IS_INETD || !(opt & OPT_FOREGROUND)) {
     394        openlog(applet_name, 0, LOG_USER);
     395        logmode = LOGMODE_SYSLOG;
     396    }
     397    //if (opt & 1) // -f
     398    //if (opt & 2) // -l
     399    USE_FEATURE_TELNETD_STANDALONE(
     400        if (opt & OPT_PORT) // -p
     401            portnbr = xatou16(opt_portnbr);
     402        //if (opt & 8) // -b
     403        //if (opt & 0x10) // -F
     404        //if (opt & 0x20) // -i
     405    );
     406
     407    /* Used to check access(loginpath, X_OK) here. Pointless.
     408     * exec will do this for us for free later. */
     409
     410#if ENABLE_FEATURE_TELNETD_STANDALONE
     411    if (IS_INETD) {
     412        sessions = make_new_session(0, 1);
     413    } else {
     414        master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
     415        xlisten(master_fd, 1);
     416        if (!(opt & OPT_FOREGROUND))
     417            bb_daemonize(DAEMON_CHDIR_ROOT);
     418    }
     419#else
    440420    sessions = make_new_session();
    441 #else /* CONFIG_EATURE_TELNETD_INETD */
    442     sessions = 0;
    443 
    444     /* Grab a TCP socket.  */
    445 
    446     master_fd = bb_xsocket(SOCKET_TYPE, SOCK_STREAM, 0);
    447     (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    448 
    449     /* Set it to listen to specified port.  */
    450 
    451     memset((void *)&sa, 0, sizeof(sa));
    452 #ifdef CONFIG_FEATURE_IPV6
    453     sa.sin6_family = AF_INET6;
    454     sa.sin6_port = htons(portnbr);
    455     /* sa.sin6_addr = bind_addr6; */
    456 #else
    457     sa.sin_family = AF_INET;
    458     sa.sin_port = htons(portnbr);
    459     sa.sin_addr = bind_addr;
    460 #endif
    461 
    462     bb_xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa));
    463     bb_xlisten(master_fd, 1);
    464     bb_xdaemon(0, 0);
    465 
    466     maxfd = master_fd;
    467 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    468 
    469     do {
    470         struct tsession *ts;
    471 
    472         FD_ZERO(&rdfdset);
    473         FD_ZERO(&wrfdset);
    474 
    475         /* select on the master socket, all telnet sockets and their
    476          * ptys if there is room in their respective session buffers.
    477          */
    478 
    479 #ifndef CONFIG_FEATURE_TELNETD_INETD
     421#endif
     422
     423    /* We don't want to die if just one session is broken */
     424    signal(SIGPIPE, SIG_IGN);
     425
     426 again:
     427    FD_ZERO(&rdfdset);
     428    FD_ZERO(&wrfdset);
     429    if (!IS_INETD) {
    480430        FD_SET(master_fd, &rdfdset);
    481 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    482 
    483         ts = sessions;
    484 #ifndef CONFIG_FEATURE_TELNETD_INETD
    485         while (ts) {
    486 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    487             /* buf1 is used from socket to pty
    488              * buf2 is used from pty to socket
    489              */
    490             if (ts->size1 > 0) {
    491                 FD_SET(ts->ptyfd, &wrfdset);  /* can write to pty */
    492             }
    493             if (ts->size1 < BUFSIZE) {
    494 #ifdef CONFIG_FEATURE_TELNETD_INETD
    495                 FD_SET(ts->sockfd_read, &rdfdset); /* can read from socket */
    496 #else /* CONFIG_FEATURE_TELNETD_INETD */
    497                 FD_SET(ts->sockfd, &rdfdset); /* can read from socket */
    498 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    499             }
    500             if (ts->size2 > 0) {
    501 #ifdef CONFIG_FEATURE_TELNETD_INETD
    502                 FD_SET(ts->sockfd_write, &wrfdset); /* can write to socket */
    503 #else /* CONFIG_FEATURE_TELNETD_INETD */
    504                 FD_SET(ts->sockfd, &wrfdset); /* can write to socket */
    505 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    506             }
    507             if (ts->size2 < BUFSIZE) {
    508                 FD_SET(ts->ptyfd, &rdfdset);  /* can read from pty */
    509             }
    510 #ifndef CONFIG_FEATURE_TELNETD_INETD
    511             ts = ts->next;
    512         }
    513 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    514 
    515         selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0);
    516 
    517         if (!selret)
    518             break;
    519 
    520 #ifndef CONFIG_FEATURE_TELNETD_INETD
    521         /* First check for and accept new sessions.  */
    522         if (FD_ISSET(master_fd, &rdfdset)) {
    523             int fd;
    524             socklen_t salen;
    525 
    526             salen = sizeof(sa);
    527             if ((fd = accept(master_fd, (struct sockaddr *)&sa,
    528                         &salen)) < 0) {
     431        /* This is needed because free_session() does not
     432         * take into account master_fd when it finds new
     433         * maxfd among remaining fd's: */
     434        if (master_fd > maxfd)
     435            maxfd = master_fd;
     436    }
     437
     438    /* select on the master socket, all telnet sockets and their
     439     * ptys if there is room in their session buffers. */
     440    ts = sessions;
     441    while (ts) {
     442        /* buf1 is used from socket to pty
     443         * buf2 is used from pty to socket */
     444        if (ts->size1 > 0)       /* can write to pty */
     445            FD_SET(ts->ptyfd, &wrfdset);
     446        if (ts->size1 < BUFSIZE) /* can read from socket */
     447            FD_SET(ts->sockfd_read, &rdfdset);
     448        if (ts->size2 > 0)       /* can write to socket */
     449            FD_SET(ts->sockfd_write, &wrfdset);
     450        if (ts->size2 < BUFSIZE) /* can read from pty */
     451            FD_SET(ts->ptyfd, &rdfdset);
     452        ts = ts->next;
     453    }
     454
     455    selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0);
     456    if (!selret)
     457        return 0;
     458
     459#if ENABLE_FEATURE_TELNETD_STANDALONE
     460    /* First check for and accept new sessions. */
     461    if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
     462        int fd;
     463        struct tsession *new_ts;
     464
     465        fd = accept(master_fd, NULL, 0);
     466        if (fd < 0)
     467            goto again;
     468        /* Create a new session and link it into our active list */
     469        new_ts = make_new_session(fd, fd);
     470        if (new_ts) {
     471            new_ts->next = sessions;
     472            sessions = new_ts;
     473        } else {
     474            close(fd);
     475        }
     476    }
     477#endif
     478
     479    /* Then check for data tunneling. */
     480    ts = sessions;
     481    while (ts) { /* For all sessions... */
     482        struct tsession *next = ts->next; /* in case we free ts. */
     483
     484        if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) {
     485            int num_totty;
     486            char *ptr;
     487            /* Write to pty from buffer 1. */
     488            ptr = remove_iacs(ts, &num_totty);
     489            w = safe_write(ts->ptyfd, ptr, num_totty);
     490            /* needed? if (w < 0 && errno == EAGAIN) continue; */
     491            if (w < 0) {
     492                if (IS_INETD)
     493                    return 0;
     494                free_session(ts);
     495                ts = next;
    529496                continue;
    530             } else {
    531                 /* Create a new session and link it into
    532                     our active list.  */
    533                 struct tsession *new_ts = make_new_session(fd);
    534                 if (new_ts) {
    535                     new_ts->next = sessions;
    536                     sessions = new_ts;
    537                     if (fd > maxfd)
    538                         maxfd = fd;
    539                 } else {
    540                     close(fd);
    541                 }
    542             }
    543         }
    544 
    545         /* Then check for data tunneling.  */
    546 
    547         ts = sessions;
    548         while (ts) { /* For all sessions...  */
    549 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    550 #ifndef CONFIG_FEATURE_TELNETD_INETD
    551             struct tsession *next = ts->next; /* in case we free ts. */
    552 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    553 
    554             if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) {
    555                 int num_totty;
    556                 char *ptr;
    557                 /* Write to pty from buffer 1.  */
    558 
    559                 ptr = remove_iacs(ts, &num_totty);
    560 
    561                 w = write(ts->ptyfd, ptr, num_totty);
    562                 if (w < 0) {
    563 #ifdef CONFIG_FEATURE_TELNETD_INETD
    564                     exit(0);
    565 #else /* CONFIG_FEATURE_TELNETD_INETD */
    566                     free_session(ts);
    567                     ts = next;
     497            }
     498            ts->wridx1 += w;
     499            ts->size1 -= w;
     500            if (ts->wridx1 == BUFSIZE)
     501                ts->wridx1 = 0;
     502        }
     503
     504        if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) {
     505            /* Write to socket from buffer 2. */
     506            maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2);
     507            w = safe_write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen);
     508            /* needed? if (w < 0 && errno == EAGAIN) continue; */
     509            if (w < 0) {
     510                if (IS_INETD)
     511                    return 0;
     512                free_session(ts);
     513                ts = next;
     514                continue;
     515            }
     516            ts->wridx2 += w;
     517            ts->size2 -= w;
     518            if (ts->wridx2 == BUFSIZE)
     519                ts->wridx2 = 0;
     520        }
     521
     522        if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) {
     523            /* Read from socket to buffer 1. */
     524            maxlen = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
     525            r = safe_read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen);
     526            if (r < 0 && errno == EAGAIN) continue;
     527            if (r <= 0) {
     528                if (IS_INETD)
     529                    return 0;
     530                free_session(ts);
     531                ts = next;
     532                continue;
     533            }
     534            if (!ts->buf1[ts->rdidx1 + r - 1])
     535                if (!--r)
    568536                    continue;
    569 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    570                 }
    571                 ts->wridx1 += w;
    572                 ts->size1 -= w;
    573                 if (ts->wridx1 == BUFSIZE)
    574                     ts->wridx1 = 0;
    575             }
    576 
    577 #ifdef CONFIG_FEATURE_TELNETD_INETD
    578             if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) {
    579 #else /* CONFIG_FEATURE_TELNETD_INETD */
    580             if (ts->size2 && FD_ISSET(ts->sockfd, &wrfdset)) {
    581 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    582                 /* Write to socket from buffer 2.  */
    583                 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2);
    584 #ifdef CONFIG_FEATURE_TELNETD_INETD
    585                 w = write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen);
    586                 if (w < 0)
    587                     exit(0);
    588 #else /* CONFIG_FEATURE_TELNETD_INETD */
    589                 w = write(ts->sockfd, ts->buf2 + ts->wridx2, maxlen);
    590                 if (w < 0) {
    591                     free_session(ts);
    592                     ts = next;
    593                     continue;
    594                 }
    595 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    596                 ts->wridx2 += w;
    597                 ts->size2 -= w;
    598                 if (ts->wridx2 == BUFSIZE)
    599                     ts->wridx2 = 0;
    600             }
    601 
    602 #ifdef CONFIG_FEATURE_TELNETD_INETD
    603             if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) {
    604 #else /* CONFIG_FEATURE_TELNETD_INETD */
    605             if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd, &rdfdset)) {
    606 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    607                 /* Read from socket to buffer 1. */
    608                 maxlen = MIN(BUFSIZE - ts->rdidx1,
    609                         BUFSIZE - ts->size1);
    610 #ifdef CONFIG_FEATURE_TELNETD_INETD
    611                 r = read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen);
    612                 if (!r || (r < 0 && errno != EINTR))
    613                     exit(0);
    614 #else /* CONFIG_FEATURE_TELNETD_INETD */
    615                 r = read(ts->sockfd, ts->buf1 + ts->rdidx1, maxlen);
    616                 if (!r || (r < 0 && errno != EINTR)) {
    617                     free_session(ts);
    618                     ts = next;
    619                     continue;
    620                 }
    621 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    622                 if (!*(ts->buf1 + ts->rdidx1 + r - 1)) {
    623                     r--;
    624                     if (!r)
    625                         continue;
    626                 }
    627                 ts->rdidx1 += r;
    628                 ts->size1 += r;
    629                 if (ts->rdidx1 == BUFSIZE)
    630                     ts->rdidx1 = 0;
    631             }
    632 
    633             if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) {
    634                 /* Read from pty to buffer 2.  */
    635                 maxlen = MIN(BUFSIZE - ts->rdidx2,
    636                         BUFSIZE - ts->size2);
    637                 r = read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen);
    638                 if (!r || (r < 0 && errno != EINTR)) {
    639 #ifdef CONFIG_FEATURE_TELNETD_INETD
    640                     exit(0);
    641 #else /* CONFIG_FEATURE_TELNETD_INETD */
    642                     free_session(ts);
    643                     ts = next;
    644                     continue;
    645 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    646                 }
    647                 ts->rdidx2 += r;
    648                 ts->size2 += r;
    649                 if (ts->rdidx2 == BUFSIZE)
    650                     ts->rdidx2 = 0;
    651             }
    652 
    653             if (ts->size1 == 0) {
     537            ts->rdidx1 += r;
     538            ts->size1 += r;
     539            if (ts->rdidx1 == BUFSIZE)
    654540                ts->rdidx1 = 0;
    655                 ts->wridx1 = 0;
    656             }
    657             if (ts->size2 == 0) {
     541        }
     542
     543        if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) {
     544            /* Read from pty to buffer 2. */
     545            maxlen = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
     546            r = safe_read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen);
     547            if (r < 0 && errno == EAGAIN) continue;
     548            if (r <= 0) {
     549                if (IS_INETD)
     550                    return 0;
     551                free_session(ts);
     552                ts = next;
     553                continue;
     554            }
     555            ts->rdidx2 += r;
     556            ts->size2 += r;
     557            if (ts->rdidx2 == BUFSIZE)
    658558                ts->rdidx2 = 0;
    659                 ts->wridx2 = 0;
    660             }
    661 #ifndef CONFIG_FEATURE_TELNETD_INETD
    662             ts = next;
    663         }
    664 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    665 
    666     } while (1);
    667 
    668     return 0;
     559        }
     560
     561        if (ts->size1 == 0) {
     562            ts->rdidx1 = 0;
     563            ts->wridx1 = 0;
     564        }
     565        if (ts->size2 == 0) {
     566            ts->rdidx2 = 0;
     567            ts->wridx2 = 0;
     568        }
     569        ts = next;
     570    }
     571    goto again;
    669572}
  • branches/stable/mindi-busybox/networking/tftp.c

    r821 r1770  
    2020 * ------------------------------------------------------------------------- */
    2121
    22 #include <stdio.h>
    23 #include <stdlib.h>
    24 #include <string.h>
    25 #include <sys/types.h>
    26 #include <sys/socket.h>
    27 #include <sys/stat.h>
    28 #include <netdb.h>
    29 #include <netinet/in.h>
    30 #include <arpa/inet.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 
    34 #include "busybox.h"
    35 
     22#include "libbb.h"
     23
     24
     25#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
    3626
    3727#define TFTP_BLOCKSIZE_DEFAULT 512  /* according to RFC 1350, don't change */
    3828#define TFTP_TIMEOUT 5  /* seconds */
    3929#define TFTP_NUM_RETRIES 5 /* number of retries */
    40 
    41 static const char * const MODE_OCTET = "octet";
    42 #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/
    43 
    44 static const char * const OPTION_BLOCKSIZE = "blksize";
    45 #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */
    4630
    4731/* opcodes we support */
     
    5337#define TFTP_OACK  6
    5438
    55 static const char *const tftp_bb_error_msg[] = {
    56     "Undefined error",
    57     "File not found",
    58     "Access violation",
    59     "Disk full or allocation error",
    60     "Illegal TFTP operation",
    61     "Unknown transfer ID",
    62     "File already exists",
    63     "No such user"
    64 };
    65 
    66 #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET
    67 
    68 #if ENABLE_FEATURE_TFTP_PUT
    69 # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT)
     39#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
     40#define USE_GETPUT(...)
     41#define CMD_GET(cmd) 1
     42#define CMD_PUT(cmd) 0
     43#elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
     44#define USE_GETPUT(...)
     45#define CMD_GET(cmd) 0
     46#define CMD_PUT(cmd) 1
    7047#else
    71 # define tftp_cmd_put 0
    72 #endif
    73 
    74 
    75 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
     48#define USE_GETPUT(...) __VA_ARGS__
     49/* masks coming from getpot32 */
     50#define CMD_GET(cmd) ((cmd) & 1)
     51#define CMD_PUT(cmd) ((cmd) & 2)
     52#endif
     53/* NB: in the code below
     54 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
     55 */
     56
     57
     58#if ENABLE_FEATURE_TFTP_BLOCKSIZE
    7659
    7760static int tftp_blocksize_check(int blocksize, int bufsize)
     
    8366     */
    8467
    85     if ((bufsize && (blocksize > bufsize)) ||
    86         (blocksize < 8) || (blocksize > 65564)) {
     68    if ((bufsize && (blocksize > bufsize))
     69     || (blocksize < 8) || (blocksize > 65564)
     70    ) {
    8771        bb_error_msg("bad blocksize");
    8872        return 0;
     
    9276}
    9377
    94 static char *tftp_option_get(char *buf, int len, const char * const option)
     78static char *tftp_option_get(char *buf, int len, const char *option)
    9579{
    9680    int opt_val = 0;
     
    9983
    10084    while (len > 0) {
    101 
    10285        /* Make sure the options are terminated correctly */
    103 
    10486        for (k = 0; k < len; k++) {
    10587            if (buf[k] == '\0') {
    106                 break;
    107             }
    108         }
    109 
    110         if (k >= len) {
    111             break;
    112         }
    113 
     88                goto nul_found;
     89            }
     90        }
     91        return NULL;
     92 nul_found:
    11493        if (opt_val == 0) {
    11594            if (strcasecmp(buf, option) == 0) {
    11695                opt_found = 1;
    11796            }
    118         } else {
    119             if (opt_found) {
    120                 return buf;
    121             }
     97        } else if (opt_found) {
     98            return buf;
    12299        }
    123100
    124101        k++;
    125 
    126102        buf += k;
    127103        len -= k;
    128 
    129104        opt_val ^= 1;
    130105    }
     
    135110#endif
    136111
    137 static int tftp(const int cmd, const struct hostent *host,
    138            const char *remotefile, const int localfd,
    139            const unsigned short port, int tftp_bufsize)
     112static int tftp( USE_GETPUT(const int cmd,)
     113        len_and_sockaddr *peer_lsa,
     114        const char *remotefile, const int localfd,
     115        unsigned port, int tftp_bufsize)
    140116{
    141     struct sockaddr_in sa;
    142     struct sockaddr_in from;
    143117    struct timeval tv;
    144     socklen_t fromlen;
    145118    fd_set rfds;
    146119    int socketfd;
    147120    int len;
    148     int opcode = 0;
    149     int finished = 0;
     121    int send_len;
     122    USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
     123    smallint finished = 0;
     124    uint16_t opcode;
     125    uint16_t block_nr = 1;
     126    uint16_t recv_blk;
    150127    int timeout = TFTP_NUM_RETRIES;
    151     unsigned short block_nr = 1;
    152     unsigned short tmp;
    153128    char *cp;
    154129
    155     USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
     130    unsigned org_port;
     131    len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len);
    156132
    157133    /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
    158134     * size varies meaning BUFFERS_GO_ON_STACK would fail */
    159     char *buf=xmalloc(tftp_bufsize += 4);
    160 
    161     if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
    162         /* need to unlink the localfile, so don't use bb_xsocket here. */
    163         bb_perror_msg("socket");
    164         return EXIT_FAILURE;
    165     }
    166 
    167     len = sizeof(sa);
    168 
    169     memset(&sa, 0, len);
    170     bb_xbind(socketfd, (struct sockaddr *)&sa, len);
    171 
    172     sa.sin_family = host->h_addrtype;
    173     sa.sin_port = port;
    174     memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
    175            sizeof(sa.sin_addr));
     135    /* We must keep the transmit and receive buffers seperate */
     136    /* In case we rcv a garbage pkt and we need to rexmit the last pkt */
     137    char *xbuf = xmalloc(tftp_bufsize += 4);
     138    char *rbuf = xmalloc(tftp_bufsize);
     139
     140    port = org_port = htons(port);
     141
     142    socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0);
    176143
    177144    /* build opcode */
    178     if (cmd & tftp_cmd_get) {
     145    opcode = TFTP_WRQ;
     146    if (CMD_GET(cmd)) {
    179147        opcode = TFTP_RRQ;
    180148    }
    181     if (cmd & tftp_cmd_put) {
    182         opcode = TFTP_WRQ;
    183     }
     149    cp = xbuf + 2;
     150    /* add filename and mode */
     151    /* fill in packet if the filename fits into xbuf */
     152    len = strlen(remotefile) + 1;
     153    if (2 + len + sizeof("octet") >= tftp_bufsize) {
     154        bb_error_msg("remote filename is too long");
     155        goto ret;
     156    }
     157    strcpy(cp, remotefile);
     158    cp += len;
     159    /* add "mode" part of the package */
     160    strcpy(cp, "octet");
     161    cp += sizeof("octet");
     162
     163#if ENABLE_FEATURE_TFTP_BLOCKSIZE
     164    len = tftp_bufsize - 4; /* data block size */
     165    if (len != TFTP_BLOCKSIZE_DEFAULT) {
     166        /* rfc2348 says that 65464 is a max allowed value */
     167        if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
     168            bb_error_msg("remote filename is too long");
     169            goto ret;
     170        }
     171        /* add "blksize", <nul>, blocksize */
     172        strcpy(cp, "blksize");
     173        cp += sizeof("blksize");
     174        cp += snprintf(cp, 6, "%d", len) + 1;
     175        want_option_ack = 1;
     176    }
     177#endif
     178    /* First packet is built, so skip packet generation */
     179    goto send_pkt;
     180
     181    /* Using mostly goto's - continue/break will be less clear
     182     * in where we actually jump to */
    184183
    185184    while (1) {
    186 
    187         cp = buf;
    188 
    189         /* first create the opcode part */
    190         *((unsigned short *) cp) = htons(opcode);
     185        /* Build ACK or DATA */
     186        cp = xbuf + 2;
     187        *((uint16_t*)cp) = htons(block_nr);
    191188        cp += 2;
    192 
    193         /* add filename and mode */
    194         if (((cmd & tftp_cmd_get) && (opcode == TFTP_RRQ)) ||
    195             ((cmd & tftp_cmd_put) && (opcode == TFTP_WRQ)))
    196         {
    197             int too_long = 0;
    198 
    199             /* see if the filename fits into buf
    200              * and fill in packet.  */
    201             len = strlen(remotefile) + 1;
    202 
    203             if ((cp + len) >= &buf[tftp_bufsize - 1]) {
    204                 too_long = 1;
    205             } else {
    206                 safe_strncpy(cp, remotefile, len);
    207                 cp += len;
    208             }
    209 
    210             if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) {
    211                 bb_error_msg("remote filename too long");
    212                 break;
    213             }
    214 
    215             /* add "mode" part of the package */
    216             memcpy(cp, MODE_OCTET, MODE_OCTET_LEN);
    217             cp += MODE_OCTET_LEN;
    218 
    219 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
    220 
    221             len = tftp_bufsize - 4; /* data block size */
    222 
    223             if (len != TFTP_BLOCKSIZE_DEFAULT) {
    224 
    225                 if ((&buf[tftp_bufsize - 1] - cp) < 15) {
    226                     bb_error_msg("remote filename too long");
    227                     break;
     189        block_nr++;
     190        opcode = TFTP_ACK;
     191        if (CMD_PUT(cmd)) {
     192            opcode = TFTP_DATA;
     193            len = full_read(localfd, cp, tftp_bufsize - 4);
     194            if (len < 0) {
     195                bb_perror_msg(bb_msg_read_error);
     196                goto ret;
     197            }
     198            if (len != (tftp_bufsize - 4)) {
     199                finished = 1;
     200            }
     201            cp += len;
     202        }
     203 send_pkt:
     204        /* Send packet */
     205        *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */
     206        send_len = cp - xbuf;
     207        /* NB: send_len value is preserved in code below
     208         * for potential resend */
     209 send_again:
     210#if ENABLE_DEBUG_TFTP
     211        fprintf(stderr, "sending %u bytes\n", send_len);
     212        for (cp = xbuf; cp < &xbuf[send_len]; cp++)
     213            fprintf(stderr, "%02x ", (unsigned char) *cp);
     214        fprintf(stderr, "\n");
     215#endif
     216        xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len);
     217        /* Was it final ACK? then exit */
     218        if (finished && (opcode == TFTP_ACK))
     219            goto ret;
     220
     221        timeout = TFTP_NUM_RETRIES; /* re-initialize */
     222 recv_again:
     223        /* Receive packet */
     224        tv.tv_sec = TFTP_TIMEOUT;
     225        tv.tv_usec = 0;
     226        FD_ZERO(&rfds);
     227        FD_SET(socketfd, &rfds);
     228        switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
     229            unsigned from_port;
     230        case 1:
     231            from->len = peer_lsa->len;
     232            memset(&from->sa, 0, peer_lsa->len);
     233            len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
     234                        &from->sa, &from->len);
     235            if (len < 0) {
     236                bb_perror_msg("recvfrom");
     237                goto ret;
     238            }
     239            from_port = get_nport(&from->sa);
     240            if (port == org_port) {
     241                /* Our first query went to port 69
     242                 * but reply will come from different one.
     243                 * Remember and use this new port */
     244                port = from_port;
     245                set_nport(peer_lsa, from_port);
     246            }
     247            if (port != from_port)
     248                goto recv_again;
     249            goto process_pkt;
     250        case 0:
     251            timeout--;
     252            if (timeout == 0) {
     253                bb_error_msg("last timeout");
     254                goto ret;
     255            }
     256            bb_error_msg("last timeout" + 5);
     257            goto send_again; /* resend last sent pkt */
     258        default:
     259            bb_perror_msg("select");
     260            goto ret;
     261        }
     262 process_pkt:
     263        /* Process recv'ed packet */
     264        opcode = ntohs( ((uint16_t*)rbuf)[0] );
     265        recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
     266
     267#if ENABLE_DEBUG_TFTP
     268        fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
     269#endif
     270
     271        if (opcode == TFTP_ERROR) {
     272            static const char *const errcode_str[] = {
     273                "",
     274                "file not found",
     275                "access violation",
     276                "disk full",
     277                "illegal TFTP operation",
     278                "unknown transfer id",
     279                "file already exists",
     280                "no such user",
     281                "bad option"
     282            };
     283
     284            const char *msg = "";
     285
     286            if (rbuf[4] != '\0') {
     287                msg = &rbuf[4];
     288                rbuf[tftp_bufsize - 1] = '\0';
     289            } else if (recv_blk < ARRAY_SIZE(errcode_str)) {
     290                msg = errcode_str[recv_blk];
     291            }
     292            bb_error_msg("server error: (%u) %s", recv_blk, msg);
     293            goto ret;
     294        }
     295
     296#if ENABLE_FEATURE_TFTP_BLOCKSIZE
     297        if (want_option_ack) {
     298            want_option_ack = 0;
     299
     300            if (opcode == TFTP_OACK) {
     301                /* server seems to support options */
     302                char *res;
     303
     304                res = tftp_option_get(&rbuf[2], len - 2, "blksize");
     305                if (res) {
     306                    int blksize = xatoi_u(res);
     307                    if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
     308                        /* send ERROR 8 to server... */
     309                        /* htons can be impossible to use in const initializer: */
     310                        /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/
     311                        /* thus we open-code big-endian layout */
     312                        static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 };
     313                        xsendto(socketfd, error_8, 4, &peer_lsa->sa, peer_lsa->len);
     314                        bb_error_msg("server proposes bad blksize %d, exiting", blksize);
     315                        goto ret;
     316                    }
     317#if ENABLE_DEBUG_TFTP
     318                    fprintf(stderr, "using blksize %u\n",
     319                            blksize);
     320#endif
     321                    tftp_bufsize = blksize + 4;
     322                    /* Send ACK for OACK ("block" no: 0) */
     323                    block_nr = 0;
     324                    continue;
    228325                }
    229 
    230                 /* add "blksize" + number of blocks  */
    231                 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN);
    232                 cp += OPTION_BLOCKSIZE_LEN;
    233                 cp += snprintf(cp, 6, "%d", len) + 1;
    234 
    235                 want_option_ack = 1;
    236             }
    237 #endif
    238         }
    239 
    240         /* add ack and data */
    241 
    242         if (((cmd & tftp_cmd_get) && (opcode == TFTP_ACK)) ||
    243             ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA))) {
    244 
    245             *((unsigned short *) cp) = htons(block_nr);
    246 
    247             cp += 2;
    248 
    249             block_nr++;
    250 
    251             if ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA)) {
    252                 len = bb_full_read(localfd, cp, tftp_bufsize - 4);
    253 
    254                 if (len < 0) {
    255                     bb_perror_msg(bb_msg_read_error);
    256                     break;
    257                 }
    258 
    259                 if (len != (tftp_bufsize - 4)) {
    260                     finished++;
    261                 }
    262 
    263                 cp += len;
    264             }
    265         }
    266 
    267 
    268         /* send packet */
    269 
    270 
    271         timeout = TFTP_NUM_RETRIES; /* re-initialize */
    272         do {
    273 
    274             len = cp - buf;
    275 
    276 #ifdef CONFIG_DEBUG_TFTP
    277             fprintf(stderr, "sending %u bytes\n", len);
    278             for (cp = buf; cp < &buf[len]; cp++)
    279                 fprintf(stderr, "%02x ", (unsigned char) *cp);
    280             fprintf(stderr, "\n");
    281 #endif
    282             if (sendto(socketfd, buf, len, 0,
    283                        (struct sockaddr *) &sa, sizeof(sa)) < 0) {
    284                 bb_perror_msg("send");
    285                 len = -1;
    286                 break;
    287             }
    288 
    289 
    290             if (finished && (opcode == TFTP_ACK)) {
    291                 break;
    292             }
    293 
    294             /* receive packet */
    295 
    296             memset(&from, 0, sizeof(from));
    297             fromlen = sizeof(from);
    298 
    299             tv.tv_sec = TFTP_TIMEOUT;
    300             tv.tv_usec = 0;
    301 
    302             FD_ZERO(&rfds);
    303             FD_SET(socketfd, &rfds);
    304 
    305             switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
    306             case 1:
    307                 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
    308                                (struct sockaddr *) &from, &fromlen);
    309 
    310                 if (len < 0) {
    311                     bb_perror_msg("recvfrom");
    312                     break;
    313                 }
    314 
    315                 timeout = 0;
    316 
    317                 if (sa.sin_port == port) {
    318                     sa.sin_port = from.sin_port;
    319                 }
    320                 if (sa.sin_port == from.sin_port) {
    321                     break;
    322                 }
    323 
    324                 /* fall-through for bad packets! */
    325                 /* discard the packet - treat as timeout */
    326                 timeout = TFTP_NUM_RETRIES;
    327             case 0:
    328                 bb_error_msg("timeout");
    329 
    330                 timeout--;
    331                 if (timeout == 0) {
    332                     len = -1;
    333                     bb_error_msg("last timeout");
    334                 }
    335                 break;
    336             default:
    337                 bb_perror_msg("select");
    338                 len = -1;
    339             }
    340 
    341         } while (timeout && (len >= 0));
    342 
    343         if ((finished) || (len < 0)) {
    344             break;
    345         }
    346 
    347         /* process received packet */
    348 
    349         opcode = ntohs(*((unsigned short *) buf));
    350         tmp = ntohs(*((unsigned short *) &buf[2]));
    351 
    352 #ifdef CONFIG_DEBUG_TFTP
    353         fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
    354 #endif
    355 
    356         if (opcode == TFTP_ERROR) {
    357             const char *msg = NULL;
    358 
    359             if (buf[4] != '\0') {
    360                 msg = &buf[4];
    361                 buf[tftp_bufsize - 1] = '\0';
    362             } else if (tmp < (sizeof(tftp_bb_error_msg)
    363                               / sizeof(char *))) {
    364 
    365                 msg = tftp_bb_error_msg[tmp];
    366             }
    367 
    368             if (msg) {
    369                 bb_error_msg("server says: %s", msg);
    370             }
    371 
    372             break;
    373         }
    374 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
    375         if (want_option_ack) {
    376 
    377             want_option_ack = 0;
    378 
    379             if (opcode == TFTP_OACK) {
    380 
    381                 /* server seems to support options */
    382 
    383                 char *res;
    384 
    385                 res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE);
    386 
    387                 if (res) {
    388                     int blksize = atoi(res);
    389 
    390                     if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
    391 
    392                         if (cmd & tftp_cmd_put) {
    393                             opcode = TFTP_DATA;
    394                         } else {
    395                             opcode = TFTP_ACK;
    396                         }
    397 #ifdef CONFIG_DEBUG_TFTP
    398                         fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE,
    399                                 blksize);
    400 #endif
    401                         tftp_bufsize = blksize + 4;
    402                         block_nr = 0;
    403                         continue;
    404                     }
    405                 }
    406                 /* FIXME:
    407                  * we should send ERROR 8 */
    408                 bb_error_msg("bad server option");
    409                 break;
    410             }
    411 
    412             bb_error_msg("warning: blksize not supported by server"
    413                          " - reverting to 512");
    414 
     326                /* rfc2347:
     327                 * "An option not acknowledged by the server
     328                 *  must be ignored by the client and server
     329                 *  as if it were never requested." */
     330            }
     331
     332            bb_error_msg("blksize is not supported by server"
     333                        " - reverting to 512");
    415334            tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
    416335        }
    417336#endif
    418 
    419         if ((cmd & tftp_cmd_get) && (opcode == TFTP_DATA)) {
    420 
    421             if (tmp == block_nr) {
    422 
    423                 len = bb_full_write(localfd, &buf[4], len - 4);
    424 
     337        /* block_nr is already advanced to next block# we expect
     338         * to get / block# we are about to send next time */
     339
     340        if (CMD_GET(cmd) && (opcode == TFTP_DATA)) {
     341            if (recv_blk == block_nr) {
     342                len = full_write(localfd, &rbuf[4], len - 4);
    425343                if (len < 0) {
    426344                    bb_perror_msg(bb_msg_write_error);
    427                     break;
     345                    goto ret;
    428346                }
    429 
    430347                if (len != (tftp_bufsize - 4)) {
    431                     finished++;
     348                    finished = 1;
    432349                }
    433 
    434                 opcode = TFTP_ACK;
     350                continue; /* send ACK */
     351            }
     352            if (recv_blk == (block_nr - 1)) {
     353                /* Server lost our TFTP_ACK.  Resend it */
     354                block_nr = recv_blk;
    435355                continue;
    436356            }
    437             /* in case the last ack disappeared into the ether */
    438             if (tmp == (block_nr - 1)) {
    439                 --block_nr;
    440                 opcode = TFTP_ACK;
    441                 continue;
    442             } else if (tmp + 1 == block_nr) {
    443                 /* Server lost our TFTP_ACK.  Resend it */
    444                 block_nr = tmp;
    445                 opcode = TFTP_ACK;
    446                 continue;
    447             }
    448         }
    449 
    450         if ((cmd & tftp_cmd_put) && (opcode == TFTP_ACK)) {
    451 
    452             if (tmp == (unsigned short) (block_nr - 1)) {
    453                 if (finished) {
    454                     break;
    455                 }
    456 
    457                 opcode = TFTP_DATA;
    458                 continue;
    459             }
    460         }
    461     }
    462 
    463 #ifdef CONFIG_FEATURE_CLEAN_UP
    464     close(socketfd);
    465     free(buf);
    466 #endif
    467 
    468     return finished ? EXIT_SUCCESS : EXIT_FAILURE;
     357        }
     358
     359        if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) {
     360            /* did server ACK our last DATA pkt? */
     361            if (recv_blk == (uint16_t) (block_nr - 1)) {
     362                if (finished)
     363                    goto ret;
     364                continue; /* send next block */
     365            }
     366        }
     367        /* Awww... recv'd packet is not recognized! */
     368        goto recv_again;
     369        /* why recv_again? - rfc1123 says:
     370         * "The sender (i.e., the side originating the DATA packets)
     371         *  must never resend the current DATA packet on receipt
     372         *  of a duplicate ACK".
     373         * DATA pkts are resent ONLY on timeout.
     374         * Thus "goto send_again" will ba a bad mistake above.
     375         * See:
     376         * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
     377         */
     378    }
     379 ret:
     380    if (ENABLE_FEATURE_CLEAN_UP) {
     381        close(socketfd);
     382        free(xbuf);
     383        free(rbuf);
     384    }
     385    return finished == 0; /* returns 1 on failure */
    469386}
    470387
     388int tftp_main(int argc, char **argv);
    471389int tftp_main(int argc, char **argv)
    472390{
    473     struct hostent *host = NULL;
     391    len_and_sockaddr *peer_lsa;
    474392    const char *localfile = NULL;
    475393    const char *remotefile = NULL;
     394#if ENABLE_FEATURE_TFTP_BLOCKSIZE
     395    const char *sblocksize = NULL;
     396#endif
    476397    int port;
    477     int cmd = 0;
     398    USE_GETPUT(int cmd;)
    478399    int fd = -1;
    479400    int flags = 0;
     
    481402    int blocksize = TFTP_BLOCKSIZE_DEFAULT;
    482403
    483     /* figure out what to pass to getopt */
    484 
    485 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
    486     char *sblocksize = NULL;
    487 
    488 #define BS "b:"
    489 #define BS_ARG , &sblocksize
    490 #else
    491 #define BS
    492 #define BS_ARG
    493 #endif
    494 
    495 #ifdef CONFIG_FEATURE_TFTP_GET
    496 #define GET "g"
    497 #define GET_COMPL ":g"
    498 #else
    499 #define GET
    500 #define GET_COMPL
    501 #endif
    502 
    503 #ifdef CONFIG_FEATURE_TFTP_PUT
    504 #define PUT "p"
    505 #define PUT_COMPL ":p"
    506 #else
    507 #define PUT
    508 #define PUT_COMPL
    509 #endif
    510 
    511 #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT)
    512     bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g";
    513 #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT)
    514     bb_opt_complementally = GET_COMPL PUT_COMPL;
    515 #endif
    516 
    517 
    518     cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS,
    519                             &localfile, &remotefile BS_ARG);
    520 
    521     cmd &= (tftp_cmd_get | tftp_cmd_put);
    522 #ifdef CONFIG_FEATURE_TFTP_GET
    523     if (cmd == tftp_cmd_get)
     404    /* -p or -g is mandatory, and they are mutually exclusive */
     405    opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
     406            USE_GETPUT("?g--p:p--g");
     407
     408    USE_GETPUT(cmd =) getopt32(argv,
     409            USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
     410                "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
     411            &localfile, &remotefile
     412            USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize));
     413    argv += optind;
     414
     415    flags = O_RDONLY;
     416    if (CMD_GET(cmd))
    524417        flags = O_WRONLY | O_CREAT | O_TRUNC;
    525 #endif
    526 #ifdef CONFIG_FEATURE_TFTP_PUT
    527     if (cmd == tftp_cmd_put)
    528         flags = O_RDONLY;
    529 #endif
    530 
    531 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
     418
     419#if ENABLE_FEATURE_TFTP_BLOCKSIZE
    532420    if (sblocksize) {
    533         blocksize = atoi(sblocksize);
     421        blocksize = xatoi_u(sblocksize);
    534422        if (!tftp_blocksize_check(blocksize, 0)) {
    535423            return EXIT_FAILURE;
     
    538426#endif
    539427
    540     if (localfile == NULL)
     428    if (!localfile)
    541429        localfile = remotefile;
    542     if (remotefile == NULL)
     430    if (!remotefile)
    543431        remotefile = localfile;
    544     if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL))
     432    /* Error if filename or host is not known */
     433    if (!remotefile || !argv[0])
    545434        bb_show_usage();
    546435
    547     if (localfile == NULL || strcmp(localfile, "-") == 0) {
    548         fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO;
    549     } else {
    550         fd = open(localfile, flags, 0644); /* fail below */
    551     }
    552     if (fd < 0) {
    553         bb_perror_msg_and_die("local file");
    554     }
    555 
    556     host = xgethostbyname(argv[optind]);
    557     port = bb_lookup_port(argv[optind + 1], "udp", 69);
    558 
    559 #ifdef CONFIG_DEBUG_TFTP
    560     fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
    561             "localfile \"%s\".\n",
    562             inet_ntoa(*((struct in_addr *) host->h_addr)),
     436    fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
     437    if (!LONE_DASH(localfile)) {
     438        fd = xopen(localfile, flags);
     439    }
     440
     441    port = bb_lookup_port(argv[1], "udp", 69);
     442    peer_lsa = xhost2sockaddr(argv[0], port);
     443
     444#if ENABLE_DEBUG_TFTP
     445    fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n",
     446            xmalloc_sockaddr2dotted(&peer_lsa->sa),
    563447            remotefile, localfile);
    564448#endif
    565449
    566     result = tftp(cmd, host, remotefile, fd, port, blocksize);
    567 
    568     if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
    569         if (ENABLE_FEATURE_CLEAN_UP)
    570             close(fd);
    571         if (cmd == tftp_cmd_get && result != EXIT_SUCCESS)
    572             unlink(localfile);
    573     }
    574     return (result);
     450    result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize);
     451
     452    if (ENABLE_FEATURE_CLEAN_UP)
     453        close(fd);
     454    if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) {
     455        unlink(localfile);
     456    }
     457    return result;
    575458}
     459
     460#endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */
  • branches/stable/mindi-busybox/networking/traceroute.c

    r902 r1770  
    197197 */
    198198
    199 #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
     199#define TRACEROUTE_SO_DEBUG 0
     200
     201/* TODO: undefs were uncommented - ??! we have config system for that! */
     202/* probably ok to remove altogether */
     203//#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
    200204//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
    201 #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG   /* not in documentation man */
    202 #undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     205//#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    203206//#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    204 #undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     207//#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
    205208//#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
    206209
    207 #include <errno.h>
    208 #include <stdio.h>
    209 #include <stdlib.h>
    210 #include <string.h>
    211 #include <unistd.h>
    212 #include <fcntl.h>
    213 #include <netdb.h>
    214 #include <endian.h>
    215 #include <getopt.h>
    216 
    217 #include <sys/param.h>
    218 #include <sys/file.h>
    219 #include <sys/ioctl.h>
    220 #include <sys/socket.h>
    221 #include <sys/select.h>
    222 #include "inet_common.h"
    223210
    224211#include <net/if.h>
     212#include <arpa/inet.h>
    225213#include <netinet/in.h>
    226 #include <arpa/inet.h>
    227214#include <netinet/udp.h>
    228215#include <netinet/ip.h>
    229216#include <netinet/ip_icmp.h>
    230217
    231 #include "busybox.h"
     218#include "libbb.h"
     219#include "inet_common.h"
    232220
    233221
     
    236224 * Per RFC 791, September 1981.
    237225 */
    238 #define IPVERSION       4
     226#define IPVERSION 4
     227
     228#ifndef IPPROTO_ICMP
     229/* Grrrr.... */
     230#define IPPROTO_ICMP 1
     231#endif
     232#ifndef IPPROTO_IP
     233#define IPPROTO_IP 0
     234#endif
    239235
    240236/*
     
    252248 * UDP kernel structures and variables.
    253249 */
    254 struct  udpiphdr {
     250struct udpiphdr {
    255251    struct  ipovly ui_i;            /* overlaid ip structure */
    256252    struct  udphdr ui_u;            /* udp header */
     
    273269    char *name;
    274270    int n;
    275     u_int32_t *addrs;
     271    uint32_t *addrs;
    276272};
    277273
     
    280276    unsigned char seq;             /* sequence number of this packet */
    281277    unsigned char ttl;             /* ttl packet left with */
    282     struct timeval tv ATTRIBUTE_PACKED; /* time packet left */
     278// UNUSED. Retaining to have the same packet size.
     279    struct timeval tv_UNUSED ATTRIBUTE_PACKED; /* time packet left */
    283280};
    284281
    285282struct IFADDRLIST {
    286     u_int32_t addr;
     283    uint32_t addr;
    287284    char device[sizeof(struct ifreq)];
    288285};
    289286
    290 
    291 static const char route[] = "/proc/net/route";
    292 
    293 /* last inbound (icmp) packet */
    294 static unsigned char  packet[512] ATTRIBUTE_ALIGNED(32);
    295287
    296288static struct ip *outip;               /* last output (udp) packet */
     
    298290static struct outdata *outdata;        /* last output (udp) packet */
    299291
    300 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     292#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    301293static struct icmp *outicmp;           /* last output (icmp) packet */
    302 #endif
    303 
    304 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    305 /* Maximum number of gateways (include room for one noop) */
    306 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
    307 /* loose source route gateway list (including room for final destination) */
    308 static u_int32_t gwlist[NGATEWAYS + 1];
    309294#endif
    310295
     
    312297static int sndsock;                    /* send (udp/icmp) socket file descriptor */
    313298
    314 static struct sockaddr_storage whereto;        /* Who to try to reach */
    315 static struct sockaddr_storage wherefrom;      /* Who we are */
    316299static int packlen;                    /* total length of packet */
    317300static int minpacket;                  /* min ip packet size */
     
    321304static char *hostname;
    322305
    323 static u_short ident;
    324 static u_short port = 32768 + 666;     /* start udp dest port # for probe packets */
     306static uint16_t ident;
     307static uint16_t port = 32768 + 666;     /* start udp dest port # for probe packets */
    325308
    326309static int waittime = 5;               /* time to wait for response (in seconds) */
    327 static int nflag;                      /* print addresses numerically */
    328310static int doipcksum = 1;              /* calculate ip checksums by default */
    329311
    330 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     312#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    331313static int optlen;                     /* length of ip options */
    332314#else
     
    334316#endif
    335317
    336 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
    337 static int useicmp;                    /* use icmp echo instead of udp packets */
    338 #endif
    339 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
    340 static int verbose;
    341 #endif
     318
     319/* Keep in sync with getopt32 call! */
     320#define OPT_DONT_FRAGMNT (1<<0)    /* F */
     321#define OPT_USE_ICMP     (1<<1)    /* I */
     322#define OPT_TTL_FLAG     (1<<2)    /* l */
     323#define OPT_ADDR_NUM     (1<<3)    /* n */
     324#define OPT_BYPASS_ROUTE (1<<4)    /* r */
     325#define OPT_DEBUG        (1<<5)    /* d */
     326#define OPT_VERBOSE      (1<<6)    /* v */
     327#define OPT_IP_CHKSUM    (1<<7)    /* x */
     328#define OPT_TOS          (1<<8)    /* t */
     329#define OPT_DEVICE       (1<<9)    /* i */
     330#define OPT_MAX_TTL      (1<<10)   /* m */
     331#define OPT_PORT         (1<<11)   /* p */
     332#define OPT_NPROBES      (1<<12)   /* q */
     333#define OPT_SOURCE       (1<<13)   /* s */
     334#define OPT_WAITTIME     (1<<14)   /* w */
     335#define OPT_PAUSE_MS     (1<<15)   /* z */
     336#define OPT_FIRST_TTL    (1<<16)   /* f */
     337
     338#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
     339/* use icmp echo instead of udp packets */
     340#define useicmp (option_mask32 & OPT_USE_ICMP)
     341#endif
     342#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
     343#define verbose (option_mask32 & OPT_VERBOSE)
     344#endif
     345#define nflag   (option_mask32 & OPT_ADDR_NUM)
     346
     347
     348struct globals {
     349    /* last inbound (icmp) packet */
     350    unsigned char packet[512];
     351    struct sockaddr_storage whereto;        /* Who to try to reach */
     352    struct sockaddr_storage wherefrom;      /* Who we are */
     353#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
     354    /* Maximum number of gateways (include room for one noop) */
     355#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t)))
     356    /* loose source route gateway list (including room for final destination) */
     357    uint32_t gwlist[NGATEWAYS + 1];
     358#endif
     359};
     360
     361#define G (*ptr_to_globals)
     362
     363#define packet    (G.packet   )
     364#define whereto   (G.whereto  )
     365#define wherefrom (G.wherefrom)
     366#define gwlist    (G.gwlist   )
     367
    342368
    343369/*
     
    347373ifaddrlist(struct IFADDRLIST **ipaddrp)
    348374{
     375    enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) };
     376
    349377    int fd, nipaddr;
    350378#ifdef HAVE_SOCKADDR_SA_LEN
     
    355383    struct IFADDRLIST *al;
    356384    struct ifconf ifc;
    357     struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
     385    struct ifreq ifr;
     386    /* Was on stack, but 32k is a bit too much: */
     387    struct ifreq *ibuf = xmalloc(IFREQ_BUFSIZE * sizeof(ibuf[0]));
    358388    struct IFADDRLIST *st_ifaddrlist;
    359389
    360     fd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);
    361 
    362     ifc.ifc_len = sizeof(ibuf);
     390    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     391
     392    ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]);
    363393    ifc.ifc_buf = (caddr_t)ibuf;
    364394
    365     if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
    366         ifc.ifc_len < sizeof(struct ifreq)) {
     395    if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
     396     || ifc.ifc_len < sizeof(struct ifreq)
     397    ) {
    367398        if (errno == EINVAL)
    368399            bb_error_msg_and_die(
    369                 "SIOCGIFCONF: ifreq struct too small (%d bytes)",
    370                 (int)sizeof(ibuf));
    371         else
    372             bb_perror_msg_and_die("SIOCGIFCONF");
     400                "SIOCGIFCONF: ifreq struct too small (%u bytes)",
     401                (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0])));
     402        bb_perror_msg_and_die("SIOCGIFCONF");
    373403    }
    374404    ifrp = ibuf;
     
    376406
    377407    nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
    378     st_ifaddrlist = xcalloc(nipaddr, sizeof(struct IFADDRLIST));
     408    st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST));
    379409    al = st_ifaddrlist;
    380410    nipaddr = 0;
     
    416446            continue;
    417447#endif
    418         if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)
    419             bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);
     448        ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr,
     449                "SIOCGIFADDR: %s", al->device);
    420450
    421451        addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
     
    424454        ++nipaddr;
    425455    }
    426     if(nipaddr == 0)
    427         bb_error_msg_and_die ("Can't find any network interfaces");
    428     (void)close(fd);
    429 
     456    if (nipaddr == 0)
     457        bb_error_msg_and_die("can't find any network interfaces");
     458
     459    free(ibuf);
     460    close(fd);
    430461    *ipaddrp = st_ifaddrlist;
    431462    return nipaddr;
     
    434465
    435466static void
    436 setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
     467setsin(struct sockaddr_in *addr_sin, uint32_t addr)
    437468{
    438469    memset(addr_sin, 0, sizeof(*addr_sin));
     
    453484    int i, n;
    454485    FILE *f;
    455     u_int32_t mask;
    456     u_int32_t dest, tmask;
     486    uint32_t mask;
     487    uint32_t dest, tmask;
    457488    struct IFADDRLIST *al;
    458489    char buf[256], tdevice[256], device[256];
    459490
    460     f = bb_xfopen(route, "r");
     491    f = xfopen("/proc/net/route", "r");
    461492
    462493    /* Find the appropriate interface */
     
    468499        if (n == 1 && strncmp(buf, "Iface", 5) == 0)
    469500            continue;
    470         if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
    471             tdevice, &dest, &tmask)) != 3)
    472             bb_error_msg_and_die ("junk in buffer");
    473         if ((to->sin_addr.s_addr & tmask) == dest &&
    474             (tmask > mask || mask == 0)) {
     501        i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
     502                    tdevice, &dest, &tmask);
     503        if (i != 3)
     504            bb_error_msg_and_die("junk in buffer");
     505        if ((to->sin_addr.s_addr & tmask) == dest
     506         && (tmask > mask || mask == 0)
     507        ) {
    475508            mask = tmask;
    476509            strcpy(device, tdevice);
     
    480513
    481514    if (device[0] == '\0')
    482         bb_error_msg_and_die ("Can't find interface");
     515        bb_error_msg_and_die("can't find interface");
    483516
    484517    /* Get the interface address list */
     
    490523            break;
    491524    if (i <= 0)
    492         bb_error_msg_and_die("Can't find interface %s", device);
     525        bb_error_msg_and_die("can't find interface %s", device);
    493526
    494527    setsin(from, al->addr);
     
    502535*/
    503536
    504 /* String to value with optional min and max. Handles decimal and hex. */
    505537static int
    506 str2val(const char *str, const char *what, int mi, int ma)
    507 {
    508     const char *cp;
    509     int val;
    510     char *ep;
    511 
    512     if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
    513         cp = str + 2;
    514         val = (int)strtol(cp, &ep, 16);
    515     } else
    516         val = (int)strtol(str, &ep, 10);
    517     if (*ep != '\0') {
    518         bb_error_msg_and_die("\"%s\" bad value for %s \n", str, what);
    519     }
    520     if (val < mi && mi >= 0) {
    521         if (mi == 0)
    522             bb_error_msg_and_die("%s must be >= %d\n", what, mi);
    523         else
    524             bb_error_msg_and_die("%s must be > %d\n", what, mi - 1);
    525     }
    526     if (val > ma && ma >= 0)
    527         bb_error_msg_and_die("%s must be <= %d\n", what, ma);
    528     return val;
    529 }
    530 
    531 
    532 /*
    533  * Subtract 2 timeval structs:  out = out - in.
    534  * Out is assumed to be >= in.
    535  */
    536 static inline void
    537 tvsub(struct timeval *out, struct timeval *in)
    538 {
    539 
    540     if ((out->tv_usec -= in->tv_usec) < 0)   {
    541         --out->tv_sec;
    542         out->tv_usec += 1000000;
    543     }
    544     out->tv_sec -= in->tv_sec;
    545 }
    546 
    547 static int
    548 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
     538wait_for_reply(int sock, struct sockaddr_in *fromp)
    549539{
    550540    fd_set fds;
    551     struct timeval now, wait;
    552     struct timezone tz;
     541    struct timeval tvwait;
    553542    int cc = 0;
    554543    socklen_t fromlen = sizeof(*fromp);
     
    557546    FD_SET(sock, &fds);
    558547
    559     wait.tv_sec = tp->tv_sec + waittime;
    560     wait.tv_usec = tp->tv_usec;
    561     (void)gettimeofday(&now, &tz);
    562     tvsub(&wait, &now);
    563 
    564     if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
     548    tvwait.tv_sec = waittime;
     549    tvwait.tv_usec = 0;
     550
     551    if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0)
    565552        cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
    566553                (struct sockaddr *)fromp, &fromlen);
     
    572559 * Checksum routine for Internet Protocol family headers (C Version)
    573560 */
    574 static u_short
    575 in_cksum(u_short *addr, int len)
     561static uint16_t
     562in_cksum(uint16_t *addr, int len)
    576563{
    577564    int nleft = len;
    578     u_short *w = addr;
    579     u_short answer;
     565    uint16_t *w = addr;
     566    uint16_t answer;
    580567    int sum = 0;
    581568
     
    606593
    607594static void
    608 send_probe(int seq, int ttl, struct timeval *tp)
     595send_probe(int seq, int ttl)
    609596{
    610597    int cc;
     
    622609    if (doipcksum) {
    623610        outip->ip_sum =
    624             in_cksum((u_short *)outip, sizeof(*outip) + optlen);
     611            in_cksum((uint16_t *)outip, sizeof(*outip) + optlen);
    625612        if (outip->ip_sum == 0)
    626613            outip->ip_sum = 0xffff;
     
    630617    outdata->seq = seq;
    631618    outdata->ttl = ttl;
    632     memcpy(&outdata->tv, tp, sizeof(outdata->tv));
    633 
    634 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     619// UNUSED: was storing gettimeofday's result there, but never ever checked it
     620    /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
     621
     622#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    635623    if (useicmp)
    636624        outicmp->icmp_seq = htons(seq);
     
    639627        outudp->dest = htons(port + seq);
    640628
    641 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     629#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    642630    if (useicmp) {
    643631        /* Always calculate checksum for icmp packets */
    644632        outicmp->icmp_cksum = 0;
    645         outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
     633        outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
    646634            packlen - (sizeof(*outip) + optlen));
    647635        if (outicmp->icmp_cksum == 0)
     
    649637    } else
    650638#endif
    651            if (doipcksum) {
     639    if (doipcksum) {
    652640        /* Checksum (we must save and restore ip header) */
    653641        tip = *outip;
     
    661649        ui->ui_len = outudp->len;
    662650        outudp->check = 0;
    663         outudp->check = in_cksum((u_short *)ui, packlen);
     651        outudp->check = in_cksum((uint16_t *)ui, packlen);
    664652        if (outudp->check == 0)
    665653            outudp->check = 0xffff;
     
    667655    }
    668656
    669 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
     657#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    670658    /* XXX undocumented debugging hack */
    671659    if (verbose > 1) {
    672         const u_short *sp;
     660        const uint16_t *sp;
    673661        int nshorts, i;
    674662
    675         sp = (u_short *)outip;
    676         nshorts = (u_int)packlen / sizeof(u_short);
     663        sp = (uint16_t *)outip;
     664        nshorts = (unsigned)packlen / sizeof(uint16_t);
    677665        i = 0;
    678666        printf("[ %d bytes", packlen);
     
    699687#endif
    700688
    701     cc = sendto(sndsock, (char *)outip,
    702         packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto));
    703     if (cc < 0 || cc != packlen)  {
    704         if (cc < 0)
    705             bb_perror_msg_and_die("sendto");
    706         printf("%s: wrote %s %d chars, ret=%d\n",
    707             bb_applet_name, hostname, packlen, cc);
    708         (void)fflush(stdout);
    709     }
    710 }
    711 
    712 static inline double
    713 deltaT(struct timeval *t1p, struct timeval *t2p)
    714 {
    715     double dt;
    716 
    717     dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
    718          (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
    719     return dt;
    720 }
    721 
    722 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
     689    cc = xsendto(sndsock, (char *)outip,
     690        packlen, (struct sockaddr *)&whereto, sizeof(whereto));
     691    if (cc != packlen)  {
     692        bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc);
     693    }
     694}
     695
     696#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    723697/*
    724698 * Convert an ICMP "type" field to a printable string.
     
    727701pr_type(unsigned char t)
    728702{
    729     static const char * const ttab[] = {
     703    static const char *const ttab[] = {
    730704    "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
    731705    "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
     
    753727    hlen = ip->ip_hl << 2;
    754728    if (cc < hlen + ICMP_MINLEN) {
    755 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
     729#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    756730        if (verbose)
    757731            printf("packet too short (%d bytes) from %s\n", cc,
     
    777751        hip = &icp->icmp_ip;
    778752        hlen = hip->ip_hl << 2;
    779 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     753#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    780754        if (useicmp) {
    781755            struct icmp *hicmp;
     
    796770        } else
    797771#endif
    798               {
     772        {
    799773            up = (struct udphdr *)((unsigned char *)hip + hlen);
    800774            /* XXX 8 is a magic number */
     
    806780        }
    807781    }
    808 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
     782#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    809783    if (verbose) {
    810784        int i;
    811         u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
     785        uint32_t *lp = (uint32_t *)&icp->icmp_ip;
    812786
    813787        printf("\n%d bytes from %s to "
     
    815789            cc, inet_ntoa(from->sin_addr),
    816790            inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
    817         for (i = 4; i < cc ; i += sizeof(*lp))
     791        for (i = 4; i < cc; i += sizeof(*lp))
    818792            printf("%2d: x%8.8x\n", i, *lp++);
    819793    }
     
    829803 */
    830804static inline void
    831 inetname(struct sockaddr_in *from)
    832 {
    833     const char *n = NULL;
     805print_inetname(struct sockaddr_in *from)
     806{
    834807    const char *ina;
    835     char name[257];
    836 
    837     if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
    838         if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
    839             n = name;
    840     }
     808
    841809    ina = inet_ntoa(from->sin_addr);
    842810    if (nflag)
    843811        printf(" %s", ina);
    844     else
     812    else {
     813        char *n = NULL;
     814        if (from->sin_addr.s_addr != INADDR_ANY)
     815            n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
    845816        printf(" %s (%s)", (n ? n : ina), ina);
     817        free(n);
     818    }
    846819}
    847820
     
    856829    cc -= hlen;
    857830
    858     inetname(from);
    859 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
     831    print_inetname(from);
     832#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    860833    if (verbose)
    861         printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
     834        printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst));
    862835#endif
    863836}
     
    871844    struct hostinfo *hi;
    872845    char **p;
    873     u_int32_t addr, *ap;
    874 
    875     hi = xcalloc(1, sizeof(*hi));
     846    uint32_t addr, *ap;
     847
     848    hi = xzalloc(sizeof(*hi));
    876849    addr = inet_addr(host);
    877     if ((int32_t)addr != -1) {
    878         hi->name = bb_xstrdup(host);
     850    if (addr != 0xffffffff) {
     851        hi->name = xstrdup(host);
    879852        hi->n = 1;
    880         hi->addrs = xcalloc(1, sizeof(hi->addrs[0]));
     853        hi->addrs = xzalloc(sizeof(hi->addrs[0]));
    881854        hi->addrs[0] = addr;
    882855        return hi;
     
    886859    if (hp->h_addrtype != AF_INET || hp->h_length != 4)
    887860        bb_perror_msg_and_die("bad host %s", host);
    888     hi->name = bb_xstrdup(hp->h_name);
     861    hi->name = xstrdup(hp->h_name);
    889862    for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
    890863        continue;
    891864    hi->n = n;
    892     hi->addrs = xcalloc(n, sizeof(hi->addrs[0]));
     865    hi->addrs = xzalloc(n * sizeof(hi->addrs[0]));
    893866    for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
    894867        memcpy(ap, *p, sizeof(*ap));
     
    900873{
    901874    free(hi->name);
    902     hi->name = NULL;
    903     free((char *)hi->addrs);
    904     free((char *)hi);
    905 }
    906 
    907 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     875    free(hi->addrs);
     876    free(hi);
     877}
     878
     879#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    908880static void
    909 getaddr(u_int32_t *ap, const char *host)
     881getaddr(uint32_t *ap, const char *host)
    910882{
    911883    struct hostinfo *hi;
     
    917889#endif
    918890
    919 
    920 int
    921 traceroute_main(int argc, char *argv[])
     891static void
     892print_delta_ms(unsigned t1p, unsigned t2p)
     893{
     894    unsigned tt = t2p - t1p;
     895    printf("  %u.%03u ms", tt/1000, tt%1000);
     896}
     897
     898int traceroute_main(int argc, char **argv);
     899int traceroute_main(int argc, char **argv)
    922900{
    923901    int code, n;
    924     char *cp;
    925902    unsigned char *outp;
    926     u_int32_t *ap;
    927     struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
    928     struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
     903    uint32_t *ap;
     904    struct sockaddr_in *from;
     905    struct sockaddr_in *to;
    929906    struct hostinfo *hi;
    930     int on = 1;
    931     struct protoent *pe;
    932907    int ttl, probe, i;
    933908    int seq = 0;
    934909    int tos = 0;
    935     char *tos_str = NULL;
    936     char *source = NULL;
    937     unsigned long op;
    938 
    939 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     910    char *tos_str;
     911    char *source;
     912    unsigned op;
     913#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    940914    int lsrr = 0;
    941915#endif
    942     u_short off = 0;
     916    uint16_t off = 0;
    943917    struct IFADDRLIST *al;
    944     char *device = NULL;
     918    char *device;
    945919    int max_ttl = 30;
    946     char *max_ttl_str = NULL;
    947     char *port_str = NULL;
     920    char *max_ttl_str;
     921    char *port_str;
    948922    int nprobes = 3;
    949     char *nprobes_str = NULL;
    950     char *waittime_str = NULL;
    951     u_int pausemsecs = 0;
    952     char *pausemsecs_str = NULL;
     923    char *nprobes_str;
     924    char *waittime_str;
     925    unsigned pausemsecs = 0;
     926    char *pausemsecs_str;
    953927    int first_ttl = 1;
    954     char *first_ttl_str = NULL;
    955 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    956     llist_t *sourse_route_list = NULL;
    957 #endif
    958 
    959     opterr = 0;
    960 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    961     bb_opt_complementally = "x-x:g::";
     928    char *first_ttl_str;
     929#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
     930    llist_t *source_route_list = NULL;
     931#endif
     932
     933    PTR_TO_GLOBALS = xzalloc(sizeof(G));
     934    from = (struct sockaddr_in *)&wherefrom;
     935    to = (struct sockaddr_in *)&whereto;
     936
     937    //opterr = 0;
     938#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
     939    opt_complementary = "x-x:g::";
    962940#else
    963     bb_opt_complementally = "x-x";
    964 #endif
    965 
    966     op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
    967 #define USAGE_OP_DONT_FRAGMNT (1<<0)    /* F  */
    968 #define USAGE_OP_USE_ICMP     (1<<1)    /* I  */
    969 #define USAGE_OP_TTL_FLAG     (1<<2)    /* l  */
    970 #define USAGE_OP_ADDR_NUM     (1<<3)    /* n  */
    971 #define USAGE_OP_BYPASS_ROUTE (1<<4)    /* r  */
    972 #define USAGE_OP_DEBUG        (1<<5)    /* d */
    973 #define USAGE_OP_VERBOSE      (1<<6)    /* v */
    974 #define USAGE_OP_IP_CHKSUM    (1<<7)    /* x */
    975 
    976 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     941    opt_complementary = "x-x";
     942#endif
     943
     944    op = getopt32(argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
     945#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    977946                    "g:"
    978947#endif
    979     , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
    980     &source, &waittime_str, &pausemsecs_str, &first_ttl_str
    981 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    982     , &sourse_route_list
     948        , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
     949        , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
     950#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
     951        , &source_route_list
    983952#endif
    984953    );
    985954
    986     if(op & USAGE_OP_DONT_FRAGMNT)
     955    if (op & OPT_DONT_FRAGMNT)
    987956        off = IP_DF;
    988 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
    989     useicmp = op & USAGE_OP_USE_ICMP;
    990 #endif
    991     nflag = op & USAGE_OP_ADDR_NUM;
    992 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
    993     verbose = op &  USAGE_OP_VERBOSE;
    994 #endif
    995     if(op & USAGE_OP_IP_CHKSUM) {
     957    if (op & OPT_IP_CHKSUM) {
    996958        doipcksum = 0;
    997         bb_error_msg("Warning: ip checksums disabled");
    998     }
    999     if (tos_str)
    1000         tos = str2val(tos_str, "tos", 0, 255);
    1001     if(max_ttl_str)
    1002         max_ttl = str2val(max_ttl_str, "max ttl", 1, 255);
    1003     if(port_str)
    1004         port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1);
    1005     if(nprobes_str)
    1006         nprobes = str2val(nprobes_str, "nprobes", 1, -1);
    1007     if(source) {
    1008         /*
    1009          * set the ip source address of the outbound
    1010          * probe (e.g., on a multi-homed host).
    1011          */
    1012          if (getuid()) bb_error_msg_and_die("-s %s: Permission denied", source);
    1013     }
    1014     if(waittime_str)
    1015         waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60);
    1016     if(pausemsecs_str)
    1017         pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000);
    1018     if(first_ttl_str)
    1019         first_ttl = str2val(first_ttl_str, "first ttl", 1, 255);
    1020 
    1021 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
    1022     if(sourse_route_list) {
     959        bb_error_msg("warning: ip checksums disabled");
     960    }
     961    if (op & OPT_TOS)
     962        tos = xatou_range(tos_str, 0, 255);
     963    if (op & OPT_MAX_TTL)
     964        max_ttl = xatou_range(max_ttl_str, 1, 255);
     965    if (op & OPT_PORT)
     966        port = xatou16(port_str);
     967    if (op & OPT_NPROBES)
     968        nprobes = xatou_range(nprobes_str, 1, INT_MAX);
     969    if (op & OPT_SOURCE) {
     970        /*
     971         * set the ip source address of the outbound
     972         * probe (e.g., on a multi-homed host).
     973         */
     974        if (getuid())
     975            bb_error_msg_and_die("-s %s: permission denied", source);
     976    }
     977    if (op & OPT_WAITTIME)
     978        waittime = xatou_range(waittime_str, 2, 24 * 60 * 60);
     979    if (op & OPT_PAUSE_MS)
     980        pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
     981    if (op & OPT_FIRST_TTL)
     982        first_ttl = xatou_range(first_ttl_str, 1, 255);
     983
     984#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
     985    if (source_route_list) {
    1023986        llist_t *l_sr;
    1024987
    1025         for(l_sr = sourse_route_list; l_sr; ) {
     988        l_sr = source_route_list;
     989        while (l_sr) {
    1026990            if (lsrr >= NGATEWAYS)
    1027                 bb_error_msg_and_die("No more than %d gateways", NGATEWAYS);
     991                bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
    1028992            getaddr(gwlist + lsrr, l_sr->data);
    1029993            ++lsrr;
    1030994            l_sr = l_sr->link;
    1031             free(sourse_route_list);
    1032             sourse_route_list = l_sr;
     995            free(source_route_list);
     996            source_route_list = l_sr;
    1033997        }
    1034998        optlen = (lsrr + 1) * sizeof(gwlist[0]);
     
    10441008    minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
    10451009
    1046 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     1010#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    10471011    if (useicmp)
    10481012        minpacket += 8;                 /* XXX magic number */
     
    10561020
    10571021    case 2:
    1058         packlen = str2val(argv[optind + 1],
    1059             "packet length", minpacket, maxpacket);
     1022        packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket);
    10601023        /* Fall through */
    10611024
     
    10651028        setsin(to, hi->addrs[0]);
    10661029        if (hi->n > 1)
    1067             bb_error_msg(
    1068             "Warning: %s has multiple addresses; using %s",
     1030            bb_error_msg("warning: %s has multiple addresses; using %s",
    10691031                hostname, inet_ntoa(to->sin_addr));
    10701032        hostname = hi->name;
     
    10771039    }
    10781040
    1079     cp = "icmp";
    1080     if ((pe = getprotobyname(cp)) == NULL)
    1081         bb_perror_msg_and_die("unknown protocol %s", cp);
    1082 
    1083     /* Insure the socket fds won't be 0, 1 or 2 */
    1084     do n = bb_xopen(bb_dev_null, O_RDONLY); while (n < 2);
    1085     if (n > 2)
    1086         close(n);
    1087 
    1088     s = bb_xsocket(AF_INET, SOCK_RAW, pe->p_proto);
    1089 
    1090 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
    1091     if (op & USAGE_OP_DEBUG)
    1092         (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
    1093             sizeof(on));
    1094 #endif
    1095     if (op & USAGE_OP_BYPASS_ROUTE)
    1096         (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    1097             sizeof(on));
    1098 
    1099     sndsock = bb_xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    1100 
    1101 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
     1041    /* Ensure the socket fds won't be 0, 1 or 2 */
     1042    bb_sanitize_stdio();
     1043
     1044    s = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     1045
     1046#if TRACEROUTE_SO_DEBUG
     1047    if (op & OPT_DEBUG)
     1048        setsockopt(s, SOL_SOCKET, SO_DEBUG,
     1049                &const_int_1, sizeof(const_int_1));
     1050#endif
     1051    if (op & OPT_BYPASS_ROUTE)
     1052        setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
     1053                &const_int_1, sizeof(const_int_1));
     1054
     1055    sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
     1056
     1057#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    11021058#if defined(IP_OPTIONS)
    11031059    if (lsrr > 0) {
    11041060        unsigned char optlist[MAX_IPOPTLEN];
    1105 
    1106         cp = "ip";
    1107         if ((pe = getprotobyname(cp)) == NULL)
    1108             bb_perror_msg_and_die("unknown protocol");
    11091061
    11101062        /* final hop */
     
    11221074        memcpy(optlist + 4, gwlist, i);
    11231075
    1124         if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
     1076        if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
    11251077            (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
    11261078            bb_perror_msg_and_die("IP_OPTIONS");
    1127             }
     1079        }
    11281080    }
    11291081#endif /* IP_OPTIONS */
     
    11311083
    11321084#ifdef SO_SNDBUF
    1133     if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
    1134         sizeof(packlen)) < 0) {
     1085    if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
    11351086        bb_perror_msg_and_die("SO_SNDBUF");
    11361087    }
    11371088#endif
    11381089#ifdef IP_HDRINCL
    1139     if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
    1140         sizeof(on)) < 0 && errno != ENOPROTOOPT) {
     1090    if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 0
     1091     && errno != ENOPROTOOPT
     1092    ) {
    11411093        bb_perror_msg_and_die("IP_HDRINCL");
    11421094    }
    11431095#else
    11441096#ifdef IP_TOS
    1145     if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
    1146         (char *)&tos, sizeof(tos)) < 0) {
     1097    if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
    11471098        bb_perror_msg_and_die("setsockopt tos %d", tos);
    11481099    }
    11491100#endif
    11501101#endif
    1151 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
    1152     if (op & USAGE_OP_DEBUG)
    1153         (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
    1154             sizeof(on));
    1155 #endif
    1156     if (op & USAGE_OP_BYPASS_ROUTE)
    1157         (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    1158             sizeof(on));
     1102#if TRACEROUTE_SO_DEBUG
     1103    if (op & OPT_DEBUG)
     1104        setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
     1105                &const_int_1, sizeof(const_int_1));
     1106#endif
     1107    if (op & OPT_BYPASS_ROUTE)
     1108        setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
     1109                &const_int_1, sizeof(const_int_1));
    11591110
    11601111    /* Revert to non-privileged user after opening sockets */
     
    11621113    xsetuid(getuid());
    11631114
    1164     outip = (struct ip *)xcalloc(1, (unsigned)packlen);
     1115    outip = xzalloc(packlen);
    11651116
    11661117    outip->ip_v = IPVERSION;
     
    11741125    outip->ip_hl = (outp - (unsigned char *)outip) >> 2;
    11751126    ident = (getpid() & 0xffff) | 0x8000;
    1176 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
     1127#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    11771128    if (useicmp) {
    11781129        outip->ip_p = IPPROTO_ICMP;
    1179 
    11801130        outicmp = (struct icmp *)outp;
    11811131        outicmp->icmp_type = ICMP_ECHO;
    11821132        outicmp->icmp_id = htons(ident);
    1183 
    11841133        outdata = (struct outdata *)(outp + 8); /* XXX magic number */
    11851134    } else
    11861135#endif
    1187            {
     1136    {
    11881137        outip->ip_p = IPPROTO_UDP;
    1189 
    11901138        outudp = (struct udphdr *)outp;
    11911139        outudp->source = htons(ident);
    1192         outudp->len =
    1193             htons((u_short)(packlen - (sizeof(*outip) + optlen)));
     1140        outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen)));
    11941141        outdata = (struct outdata *)(outudp + 1);
    11951142    }
     
    11991146
    12001147    /* Look for a specific device */
    1201     if (device != NULL) {
     1148    if (op & OPT_DEVICE) {
    12021149        for (i = n; i > 0; --i, ++al)
    12031150            if (strcmp(device, al->device) == 0)
    1204                 break;
    1205         if (i <= 0) {
    1206             bb_error_msg_and_die("Can't find interface %s", device);
    1207         }
    1208     }
     1151                goto found_dev;
     1152        bb_error_msg_and_die("can't find interface %s", device);
     1153    }
     1154 found_dev:
    12091155
    12101156    /* Determine our source address */
    1211     if (source == NULL) {
     1157    if (!(op & OPT_SOURCE)) {
    12121158        /*
    12131159         * If a device was specified, use the interface address.
    12141160         * Otherwise, try to determine our source address.
    12151161         */
    1216         if (device != NULL)
     1162        if (op & OPT_DEVICE)
    12171163            setsin(from, al->addr);
    12181164        findsaddr(to, from);
     
    12271173         * there are more than one).
    12281174         */
    1229         if (device != NULL) {
     1175        if (op & OPT_DEVICE) {
    12301176            for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
    12311177                if (*ap == al->addr)
    1232                     break;
    1233             if (i <= 0) {
    1234                 bb_error_msg_and_die(
    1235                     "%s is not on interface %s",
    1236                     source, device);
    1237             }
     1178                    goto found_dev2;
     1179            bb_error_msg_and_die("%s is not on interface %s",
     1180                    source, device);
     1181 found_dev2:
    12381182            setsin(from, *ap);
    12391183        } else {
     
    12411185            if (hi->n > 1)
    12421186                bb_error_msg(
    1243             "Warning: %s has multiple addresses; using %s",
     1187            "warning: %s has multiple addresses; using %s",
    12441188                    source, inet_ntoa(from->sin_addr));
    12451189        }
     
    12491193    outip->ip_src = from->sin_addr;
    12501194#ifndef IP_HDRINCL
    1251     bb_xbind(sndsock, (struct sockaddr *)from, sizeof(*from));
    1252 #endif
    1253 
    1254     fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
    1255     if (source)
    1256         fprintf(stderr, " from %s", source);
    1257     fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
    1258     (void)fflush(stderr);
     1195    xbind(sndsock, (struct sockaddr *)from, sizeof(*from));
     1196#endif
     1197
     1198    printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
     1199    if (op & OPT_SOURCE)
     1200        printf(" from %s", source);
     1201    printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
     1202    fflush(stdout);
    12591203
    12601204    for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
    1261         u_int32_t lastaddr = 0;
     1205        uint32_t lastaddr = 0;
    12621206        int gotlastaddr = 0;
    12631207        int got_there = 0;
     
    12681212        for (probe = 0; probe < nprobes; ++probe) {
    12691213            int cc;
    1270             struct timeval t1, t2;
    1271             struct timezone tz;
     1214            unsigned t1;
     1215            unsigned t2;
    12721216            struct ip *ip;
    12731217
    12741218            if (sentfirst && pausemsecs > 0)
    12751219                usleep(pausemsecs * 1000);
    1276             (void)gettimeofday(&t1, &tz);
    1277             send_probe(++seq, ttl, &t1);
     1220            t1 = monotonic_us();
     1221            send_probe(++seq, ttl);
    12781222            ++sentfirst;
    1279             while ((cc = wait_for_reply(s, from, &t1)) != 0) {
    1280                 (void)gettimeofday(&t2, &tz);
     1223            while ((cc = wait_for_reply(s, from)) != 0) {
     1224                t2 = monotonic_us();
    12811225                i = packet_ok(packet, cc, from, seq);
    12821226                /* Skip short packet */
     
    12891233                    ++gotlastaddr;
    12901234                }
    1291                 printf("  %.3f ms", deltaT(&t1, &t2));
     1235                print_delta_ms(t1, t2);
    12921236                ip = (struct ip *)packet;
    1293                 if (op & USAGE_OP_TTL_FLAG)
     1237                if (op & OPT_TTL_FLAG)
    12941238                    printf(" (%d)", ip->ip_ttl);
    12951239                if (i == -2) {
  • branches/stable/mindi-busybox/networking/udhcp/Config.in

    r821 r1770  
    44#
    55
    6 menu "udhcp Server/Client"
    7 
    8 config CONFIG_APP_UDHCPD
     6config APP_UDHCPD
    97    bool "udhcp Server (udhcpd)"
    108    default n
     
    1513      See http://udhcp.busybox.net for further details.
    1614
    17 config CONFIG_APP_UDHCPC
     15config APP_DHCPRELAY
     16    bool "dhcprelay"
     17    default n
     18    depends on APP_UDHCPD
     19    help
     20      dhcprelay listens for dhcp requests on one or more interfaces
     21      and forwards these requests to a different interface or dhcp
     22      server.
     23
     24config APP_DUMPLEASES
     25    bool "Lease display utility (dumpleases)"
     26    default n
     27    depends on APP_UDHCPD
     28    help
     29      dumpleases displays the leases written out by the udhcpd server.
     30      Lease times are stored in the file by time remaining in lease, or
     31      by the absolute time that it expires in seconds from epoch.
     32
     33      See http://udhcp.busybox.net for further details.
     34
     35config FEATURE_UDHCPD_WRITE_LEASES_EARLY
     36    bool "Rewrite the lease file at every new acknowledge"
     37    default n
     38    depends on APP_UDHCPD
     39    help
     40      If selected, udhcpd will write a new file with leases every
     41      time a new lease has been accepted, thus eleminating the need
     42      to send SIGUSR1 for the initial writing, or updating. Any timed
     43      rewriting remains undisturbed
     44
     45config APP_UDHCPC
    1846    bool "udhcp Client (udhcpc)"
    1947    default n
     
    2755      See http://udhcp.busybox.net for further details.
    2856
    29 config CONFIG_APP_DUMPLEASES
    30     bool "Lease display utility (dumpleases)"
     57config FEATURE_UDHCP_DEBUG
     58    bool "Compile udhcp with noisy debugging messages"
    3159    default n
    32     depends on CONFIG_APP_UDHCPD
    33     help
    34       dumpleases displays the leases written out by the udhcpd server.
    35       Lease times are stored in the file by time remaining in lease, or
    36       by the absolute time that it expires in seconds from epoch.
    37 
    38       See http://udhcp.busybox.net for further details.
    39 
    40 config CONFIG_FEATURE_UDHCP_SYSLOG
    41     bool "  Log udhcp messages to syslog (instead of stdout)"
    42     default n
    43     depends on CONFIG_APP_UDHCPD || CONFIG_APP_UDHCPC
    44     help
    45       If selected, udhcpd will log all its messages to syslog, otherwise,
    46       it will attempt to log them to stdout.
    47 
    48       See http://udhcp.busybox.net for further details.
    49 
    50 config CONFIG_FEATURE_UDHCP_DEBUG
    51     bool "  Compile udhcp with noisy debugging messages"
    52     default n
    53     depends on CONFIG_APP_UDHCPD || CONFIG_APP_UDHCPC
     60    depends on APP_UDHCPD || APP_UDHCPC
    5461    help
    5562      If selected, udhcpd will output extra debugging output.  If using
     
    5966      See http://udhcp.busybox.net for further details.
    6067
    61 endmenu
    62 
     68config FEATURE_RFC3397
     69    bool "Support for RFC3397 domain search (experimental)"
     70    default n
     71    depends on APP_UDHCPD || APP_UDHCPC
     72    help
     73      If selected, both client and server will support passing of domain
     74      search lists via option 119, specified in RFC3397.
  • branches/stable/mindi-busybox/networking/udhcp/arpping.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * arpping.c
     
    67 */
    78
    8 #include <time.h>
    9 #include <sys/socket.h>
    109#include <netinet/if_ether.h>
    1110#include <net/if_arp.h>
    12 #include <netinet/in.h>
    13 #include <string.h>
    14 #include <unistd.h>
    15 #include <errno.h>
    1611
     12#include "common.h"
    1713#include "dhcpd.h"
    18 #include "arpping.h"
    19 #include "common.h"
    20 
    21 /* args:    yiaddr - what IP to ping
    22  *      ip - our ip
    23  *      mac - our arp address
    24  *      interface - interface to use
    25  * retn:    1 addr free
    26  *      0 addr used
    27  *      -1 error
    28  */
    29 
    30 /* FIXME: match response against chaddr */
    31 int arpping(uint32_t yiaddr, uint32_t ip, uint8_t *mac, char *interface)
    32 {
    33 
    34     int timeout = 2;
    35     int optval = 1;
    36     int s;          /* socket */
    37     int rv = 1;         /* return value */
    38     struct sockaddr addr;       /* for interface name */
    39     struct arpMsg   arp;
    40     fd_set      fdset;
    41     struct timeval  tm;
    42     time_t      prevTime;
    4314
    4415
    45     if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) {
    46 #ifdef IN_BUSYBOX
    47         LOG(LOG_ERR, bb_msg_can_not_create_raw_socket);
    48 #else
    49         LOG(LOG_ERR, "Could not open raw socket");
    50 #endif
     16struct arpMsg {
     17    /* Ethernet header */
     18    uint8_t  h_dest[6];     /* 00 destination ether addr */
     19    uint8_t  h_source[6];   /* 06 source ether addr */
     20    uint16_t h_proto;       /* 0c packet type ID field */
     21
     22    /* ARP packet */
     23    uint16_t htype;         /* 0e hardware type (must be ARPHRD_ETHER) */
     24    uint16_t ptype;         /* 10 protocol type (must be ETH_P_IP) */
     25    uint8_t  hlen;          /* 12 hardware address length (must be 6) */
     26    uint8_t  plen;          /* 13 protocol address length (must be 4) */
     27    uint16_t operation;     /* 14 ARP opcode */
     28    uint8_t  sHaddr[6];     /* 16 sender's hardware address */
     29    uint8_t  sInaddr[4];    /* 1c sender's IP address */
     30    uint8_t  tHaddr[6];     /* 20 target's hardware address */
     31    uint8_t  tInaddr[4];    /* 26 target's IP address */
     32    uint8_t  pad[18];       /* 2a pad for min. ethernet payload (60 bytes) */
     33} ATTRIBUTE_PACKED;
     34
     35
     36/* Returns 1 if no reply received */
     37
     38int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface)
     39{
     40    int timeout = 2;
     41    int s;                  /* socket */
     42    int rv = 1;             /* "no reply received" yet */
     43    struct sockaddr addr;   /* for interface name */
     44    struct arpMsg arp;
     45    fd_set fdset;
     46    struct timeval tm;
     47    unsigned prevTime;
     48
     49    s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
     50    if (s == -1) {
     51        bb_perror_msg(bb_msg_can_not_create_raw_socket);
    5152        return -1;
    5253    }
    5354
    54     if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
    55         LOG(LOG_ERR, "Could not setsocketopt on raw socket");
    56         close(s);
    57         return -1;
     55    if (setsockopt_broadcast(s) == -1) {
     56        bb_perror_msg("cannot setsocketopt on raw socket");
     57        goto ret;
    5858    }
    5959
    6060    /* send arp request */
    6161    memset(&arp, 0, sizeof(arp));
    62     memcpy(arp.h_dest, MAC_BCAST_ADDR, 6);      /* MAC DA */
    63     memcpy(arp.h_source, mac, 6);           /* MAC SA */
    64     arp.h_proto = htons(ETH_P_ARP);         /* protocol type (Ethernet) */
    65     arp.htype = htons(ARPHRD_ETHER);        /* hardware type */
    66     arp.ptype = htons(ETH_P_IP);            /* protocol type (ARP message) */
    67     arp.hlen = 6;                   /* hardware address length */
    68     arp.plen = 4;                   /* protocol address length */
    69     arp.operation = htons(ARPOP_REQUEST);       /* ARP op code */
    70     memcpy(arp.sInaddr, &ip, sizeof(ip));       /* source IP address */
    71     memcpy(arp.sHaddr, mac, 6);         /* source hardware address */
    72     memcpy(arp.tInaddr, &yiaddr, sizeof(yiaddr));   /* target IP address */
     62    memset(arp.h_dest, 0xff, 6);                    /* MAC DA */
     63    memcpy(arp.h_source, from_mac, 6);              /* MAC SA */
     64    arp.h_proto = htons(ETH_P_ARP);                 /* protocol type (Ethernet) */
     65    arp.htype = htons(ARPHRD_ETHER);                /* hardware type */
     66    arp.ptype = htons(ETH_P_IP);                    /* protocol type (ARP message) */
     67    arp.hlen = 6;                                   /* hardware address length */
     68    arp.plen = 4;                                   /* protocol address length */
     69    arp.operation = htons(ARPOP_REQUEST);           /* ARP op code */
     70    memcpy(arp.sHaddr, from_mac, 6);                /* source hardware address */
     71    memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */
     72    /* tHaddr */                                    /* target hardware address */
     73    memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */
    7374
    7475    memset(&addr, 0, sizeof(addr));
    75     strcpy(addr.sa_data, interface);
     76    safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data));
    7677    if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
    77         rv = 0;
     78        goto ret;
    7879
    79     /* wait arp reply, and check it */
    80     tm.tv_usec = 0;
    81     prevTime = uptime();
    82     while (timeout > 0) {
     80    /* wait for arp reply, and check it */
     81    do {
     82        int r;
     83        prevTime = monotonic_sec();
    8384        FD_ZERO(&fdset);
    8485        FD_SET(s, &fdset);
    8586        tm.tv_sec = timeout;
    86         if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) {
    87             DEBUG(LOG_ERR, "Error on ARPING request: %m");
    88             if (errno != EINTR) rv = 0;
    89         } else if (FD_ISSET(s, &fdset)) {
    90             if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0;
    91             if (arp.operation == htons(ARPOP_REPLY) &&
    92                 memcmp(arp.tHaddr, mac, 6) == 0 &&
    93                 *((uint32_t *) arp.sInaddr) == yiaddr) {
    94                 DEBUG(LOG_INFO, "Valid arp reply receved for this address");
     87        tm.tv_usec = 0;
     88        r = select(s + 1, &fdset, NULL, NULL, &tm);
     89        if (r < 0) {
     90            bb_perror_msg("error on ARPING request");
     91            if (errno != EINTR)
     92                break;
     93        } else if (r) {
     94            if (recv(s, &arp, sizeof(arp), 0) < 0)
     95                break;
     96            if (arp.operation == htons(ARPOP_REPLY)
     97             && memcmp(arp.tHaddr, from_mac, 6) == 0
     98             && *((uint32_t *) arp.sInaddr) == test_ip
     99            ) {
    95100                rv = 0;
    96101                break;
    97102            }
    98103        }
    99         timeout -= uptime() - prevTime;
    100         prevTime = uptime();
    101     }
     104        timeout -= monotonic_sec() - prevTime;
     105    } while (timeout > 0);
     106
     107 ret:
    102108    close(s);
    103     DEBUG(LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V");
     109    DEBUG("%srp reply received for this address", rv ? "No a" : "A");
    104110    return rv;
    105111}
  • branches/stable/mindi-busybox/networking/udhcp/clientpacket.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* clientpacket.c
    23 *
     
    89 */
    910
    10 #include <string.h>
    11 #include <sys/socket.h>
    1211#include <features.h>
    13 #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION
     12#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    1413#include <netpacket/packet.h>
    1514#include <net/ethernet.h>
     
    1918#include <linux/if_ether.h>
    2019#endif
    21 #include <stdlib.h>
    22 #include <time.h>
    23 #include <unistd.h>
    24 #include <netinet/in.h>
    25 #include <arpa/inet.h>
    26 #include <fcntl.h>
    27 
    28 
     20
     21#include "common.h"
    2922#include "dhcpd.h"
    30 #include "clientpacket.h"
     23#include "dhcpc.h"
    3124#include "options.h"
    32 #include "dhcpc.h"
    33 #include "common.h"
    3425
    3526
    3627/* Create a random xid */
    37 unsigned long random_xid(void)
    38 {
    39     static int initialized;
     28uint32_t random_xid(void)
     29{
     30    static smallint initialized;
     31
    4032    if (!initialized) {
    41         int fd;
    42         unsigned long seed;
    43 
    44         fd = open("/dev/urandom", 0);
    45         if (fd < 0 || read(fd, &seed, sizeof(seed)) < 0) {
    46             LOG(LOG_WARNING, "Could not load seed from /dev/urandom: %m");
    47             seed = time(0);
    48         }
    49         if (fd >= 0) close(fd);
    50         srand(seed);
    51         initialized++;
     33        srand(monotonic_us());
     34        initialized = 1;
    5235    }
    5336    return rand();
     
    6144    memcpy(packet->chaddr, client_config.arp, 6);
    6245    if (client_config.clientid)
    63         add_option_string(packet->options, client_config.clientid);
    64     if (client_config.hostname) add_option_string(packet->options, client_config.hostname);
    65     if (client_config.fqdn) add_option_string(packet->options, client_config.fqdn);
     46        add_option_string(packet->options, client_config.clientid);
     47    if (client_config.hostname)
     48        add_option_string(packet->options, client_config.hostname);
     49    if (client_config.fqdn)
     50        add_option_string(packet->options, client_config.fqdn);
    6651    add_option_string(packet->options, client_config.vendorclass);
    6752}
     
    8772
    8873/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
    89 int send_discover(unsigned long xid, unsigned long requested)
     74int send_discover(uint32_t xid, uint32_t requested)
    9075{
    9176    struct dhcpMessage packet;
     
    9782
    9883    add_requests(&packet);
    99     LOG(LOG_DEBUG, "Sending discover...");
     84    bb_info_msg("Sending discover...");
     85    return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
     86            SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
     87}
     88
     89
     90/* Broadcasts a DHCP request message */
     91int send_selecting(uint32_t xid, uint32_t server, uint32_t requested)
     92{
     93    struct dhcpMessage packet;
     94    struct in_addr addr;
     95
     96    init_packet(&packet, DHCPREQUEST);
     97    packet.xid = xid;
     98
     99    add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
     100    add_simple_option(packet.options, DHCP_SERVER_ID, server);
     101
     102    add_requests(&packet);
     103    addr.s_addr = requested;
     104    bb_info_msg("Sending select for %s...", inet_ntoa(addr));
    100105    return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
    101106                SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
     
    103108
    104109
    105 /* Broadcasts a DHCP request message */
    106 int send_selecting(unsigned long xid, unsigned long server, unsigned long requested)
    107 {
    108     struct dhcpMessage packet;
    109     struct in_addr addr;
    110 
    111     init_packet(&packet, DHCPREQUEST);
    112     packet.xid = xid;
    113 
    114     add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
    115     add_simple_option(packet.options, DHCP_SERVER_ID, server);
    116 
    117     add_requests(&packet);
    118     addr.s_addr = requested;
    119     LOG(LOG_DEBUG, "Sending select for %s...", inet_ntoa(addr));
    120     return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
    121                 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
    122 }
    123 
    124 
    125110/* Unicasts or broadcasts a DHCP renew message */
    126 int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr)
    127 {
    128     struct dhcpMessage packet;
    129     int ret = 0;
     111int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
     112{
     113    struct dhcpMessage packet;
    130114
    131115    init_packet(&packet, DHCPREQUEST);
     
    134118
    135119    add_requests(&packet);
    136     LOG(LOG_DEBUG, "Sending renew...");
     120    bb_info_msg("Sending renew...");
    137121    if (server)
    138         ret = udhcp_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
    139     else ret = udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
     122        return udhcp_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
     123
     124    return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
    140125                SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
    141     return ret;
    142126}
    143127
    144128
    145129/* Unicasts a DHCP release message */
    146 int send_release(unsigned long server, unsigned long ciaddr)
     130int send_release(uint32_t server, uint32_t ciaddr)
    147131{
    148132    struct dhcpMessage packet;
     
    155139    add_simple_option(packet.options, DHCP_SERVER_ID, server);
    156140
    157     LOG(LOG_DEBUG, "Sending release...");
     141    bb_info_msg("Sending release...");
    158142    return udhcp_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
    159143}
     
    171155    bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet));
    172156    if (bytes < 0) {
    173         DEBUG(LOG_INFO, "couldn't read on raw listening socket -- ignoring");
     157        DEBUG("Cannot read on raw listening socket - ignoring");
    174158        usleep(500000); /* possible down interface, looping condition */
    175159        return -1;
     
    177161
    178162    if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) {
    179         DEBUG(LOG_INFO, "message too short, ignoring");
     163        DEBUG("Message too short, ignoring");
    180164        return -2;
    181165    }
    182166
    183167    if (bytes < ntohs(packet.ip.tot_len)) {
    184         DEBUG(LOG_INFO, "Truncated packet");
     168        DEBUG("Truncated packet");
    185169        return -2;
    186170    }
     
    190174
    191175    /* Make sure its the right packet for us, and that it passes sanity checks */
    192     if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION ||
    193         packet.ip.ihl != sizeof(packet.ip) >> 2 || packet.udp.dest != htons(CLIENT_PORT) ||
    194         bytes > (int) sizeof(struct udp_dhcp_packet) ||
    195         ntohs(packet.udp.len) != (uint16_t) (bytes - sizeof(packet.ip))) {
    196         DEBUG(LOG_INFO, "unrelated/bogus packet");
     176    if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
     177     || packet.ip.ihl != sizeof(packet.ip) >> 2
     178     || packet.udp.dest != htons(CLIENT_PORT)
     179     || bytes > (int) sizeof(struct udp_dhcp_packet)
     180     || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
     181    ) {
     182        DEBUG("Unrelated/bogus packet");
    197183        return -2;
    198184    }
     
    202188    packet.ip.check = 0;
    203189    if (check != udhcp_checksum(&(packet.ip), sizeof(packet.ip))) {
    204         DEBUG(LOG_INFO, "bad IP header checksum, ignoring");
     190        DEBUG("bad IP header checksum, ignoring");
    205191        return -1;
    206192    }
     
    218204    packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */
    219205    if (check && check != udhcp_checksum(&packet, bytes)) {
    220         DEBUG(LOG_ERR, "packet with bad UDP checksum received, ignoring");
     206        bb_error_msg("packet with bad UDP checksum received, ignoring");
    221207        return -2;
    222208    }
     
    225211
    226212    if (ntohl(payload->cookie) != DHCP_MAGIC) {
    227         LOG(LOG_ERR, "received bogus message (bad magic) -- ignoring");
    228         return -2;
    229     }
    230     DEBUG(LOG_INFO, "oooooh!!! got some!");
     213        bb_error_msg("received bogus message (bad magic) - ignoring");
     214        return -2;
     215    }
     216    DEBUG("oooooh!!! got some!");
    231217    return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
    232 
    233 }
     218}
  • branches/stable/mindi-busybox/networking/udhcp/clientsocket.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * clientsocket.c -- DHCP client socket creation
     
    2122 */
    2223
    23 #include <sys/types.h>
    24 #include <sys/socket.h>
    25 #include <unistd.h>
    26 #include <netinet/in.h>
    2724#include <features.h>
    28 #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION
     25#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
    2926#include <netpacket/packet.h>
    3027#include <net/ethernet.h>
     
    3532#endif
    3633
    37 #include "clientsocket.h"
    3834#include "common.h"
    3935
     
    4440    struct sockaddr_ll sock;
    4541
    46     DEBUG(LOG_INFO, "Opening raw socket on ifindex %d", ifindex);
    47     if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
    48         DEBUG(LOG_ERR, "socket call failed: %m");
    49         return -1;
    50     }
     42    DEBUG("Opening raw socket on ifindex %d", ifindex);
     43    fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
    5144
    5245    sock.sll_family = AF_PACKET;
    5346    sock.sll_protocol = htons(ETH_P_IP);
    5447    sock.sll_ifindex = ifindex;
    55     if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
    56         DEBUG(LOG_ERR, "bind call failed: %m");
    57         close(fd);
    58         return -1;
    59     }
     48    xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
    6049
    6150    return fd;
  • branches/stable/mindi-busybox/networking/udhcp/common.c

    r821 r1770  
    11/* vi: set sw=4 ts=4: */
    22/* common.c
    3  *
    4  * Functions for debugging and logging as well as some other
    5  * simple helper functions.
    6  *
    7  * Russ Dill <Russ.Dill@asu.edu> 2001-2003
    8  * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
    93 *
    104 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    115 */
    126
    13 #include <fcntl.h>
    14 #include <unistd.h>
    15 #include <errno.h>
    16 #include <string.h>
    17 #include <stdlib.h>
    18 #include <signal.h>
    19 #include <paths.h>
    20 #include <sys/socket.h>
    21 #include <stdarg.h>
     7#include "common.h"
    228
    23 #include "common.h"
    24 #include "pidfile.h"
    25 
    26 
    27 static int daemonized;
    28 
    29 long uptime(void)
    30 {
    31     struct sysinfo info;
    32     sysinfo(&info);
    33     return info.uptime;
    34 }
    35 
    36 
    37 /*
    38  * This function makes sure our first socket calls
    39  * aren't going to fd 1 (printf badness...) and are
    40  * not later closed by daemon()
    41  */
    42 static inline void sanitize_fds(void)
    43 {
    44     int zero;
    45     if ((zero = open(bb_dev_null, O_RDWR, 0)) < 0)
    46         return;
    47     while (zero < 3)
    48         zero = dup(zero);
    49     close(zero);
    50 }
    51 
    52 
    53 void udhcp_background(const char *pidfile)
    54 {
    55 #ifdef __uClinux__
    56     LOG(LOG_ERR, "Cannot background in uclinux (yet)");
    57 #else /* __uClinux__ */
    58     int pid_fd;
    59 
    60     /* hold lock during fork. */
    61     pid_fd = pidfile_acquire(pidfile);
    62     if (daemon(0, 0) == -1) { /* bb_xdaemon? */
    63         perror("fork");
    64         exit(1);
    65     }
    66     daemonized++;
    67     pidfile_write_release(pid_fd);
    68 #endif /* __uClinux__ */
    69 }
    70 
    71 
    72 #ifdef CONFIG_FEATURE_UDHCP_SYSLOG
    73 
    74 void udhcp_logging(int level, const char *fmt, ...)
    75 {
    76     va_list p;
    77     va_list p2;
    78 
    79     va_start(p, fmt);
    80     __va_copy(p2, p);
    81     if (!daemonized) {
    82         vprintf(fmt, p);
    83         putchar('\n');
    84     }
    85     vsyslog(level, fmt, p2);
    86     va_end(p);
    87 }
    88 
    89 #else
    90 
    91 
    92 static char *syslog_level_msg[] = {
    93     [LOG_EMERG]   = "EMERGENCY!",
    94     [LOG_ALERT]   = "ALERT!",
    95     [LOG_CRIT]    = "critical!",
    96     [LOG_WARNING] = "warning",
    97     [LOG_ERR]     = "error",
    98     [LOG_INFO]    = "info",
    99     [LOG_DEBUG]   = "debug"
     9const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
     10    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    10011};
    101 
    102 
    103 void udhcp_logging(int level, const char *fmt, ...)
    104 {
    105     va_list p;
    106 
    107     va_start(p, fmt);
    108     if (!daemonized) {
    109         printf("%s, ", syslog_level_msg[level]);
    110         vprintf(fmt, p);
    111         putchar('\n');
    112     }
    113     va_end(p);
    114 }
    115 #endif
    116 
    117 
    118 void udhcp_start_log_and_pid(const char *client_server, const char *pidfile)
    119 {
    120     int pid_fd;
    121 
    122     /* Make sure our syslog fd isn't overwritten */
    123     sanitize_fds();
    124 
    125     /* do some other misc startup stuff while we are here to save bytes */
    126     pid_fd = pidfile_acquire(pidfile);
    127     pidfile_write_release(pid_fd);
    128 
    129     /* equivelent of doing a fflush after every \n */
    130     setlinebuf(stdout);
    131 
    132     if (ENABLE_FEATURE_UDHCP_SYSLOG)
    133         openlog(client_server, LOG_PID | LOG_CONS, LOG_LOCAL0);
    134 
    135     udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, BB_VER);
    136 }
  • branches/stable/mindi-busybox/networking/udhcp/common.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* common.h
    23 *
     
    1011#define _COMMON_H
    1112
    12 #include "libbb_udhcp.h"
     13#include "libbb.h"
     14
     15#define DEFAULT_SCRIPT  "/usr/share/udhcpc/default.script"
     16
     17extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
     18
     19/*** packet.h ***/
     20
     21#include <netinet/udp.h>
     22#include <netinet/ip.h>
     23
     24struct dhcpMessage {
     25    uint8_t op;
     26    uint8_t htype;
     27    uint8_t hlen;
     28    uint8_t hops;
     29    uint32_t xid;
     30    uint16_t secs;
     31    uint16_t flags;
     32    uint32_t ciaddr;
     33    uint32_t yiaddr;
     34    uint32_t siaddr;
     35    uint32_t giaddr;
     36    uint8_t chaddr[16];
     37    uint8_t sname[64];
     38    uint8_t file[128];
     39    uint32_t cookie;
     40    uint8_t options[308]; /* 312 - cookie */
     41};
     42
     43struct udp_dhcp_packet {
     44    struct iphdr ip;
     45    struct udphdr udp;
     46    struct dhcpMessage data;
     47};
     48
     49void udhcp_init_header(struct dhcpMessage *packet, char type);
     50int udhcp_get_packet(struct dhcpMessage *packet, int fd);
     51uint16_t udhcp_checksum(void *addr, int count);
     52int udhcp_raw_packet(struct dhcpMessage *payload,
     53        uint32_t source_ip, int source_port,
     54        uint32_t dest_ip, int dest_port,
     55        const uint8_t *dest_arp, int ifindex);
     56int udhcp_kernel_packet(struct dhcpMessage *payload,
     57        uint32_t source_ip, int source_port,
     58        uint32_t dest_ip, int dest_port);
    1359
    1460
    15 enum syslog_levels {
    16     LOG_EMERG = 0,
    17     LOG_ALERT,
    18     LOG_CRIT,
    19     LOG_WARNING,
    20     LOG_ERR,
    21     LOG_INFO,
    22     LOG_DEBUG
    23 };
    24 #include <syslog.h>
     61/**/
    2562
    26 long uptime(void);
     63void udhcp_run_script(struct dhcpMessage *packet, const char *name);
    2764
    28 #define LOG(level, str, args...) udhcp_logging(level, str, ## args)
     65// Still need to clean these up...
     66
     67/* from options.h */
     68#define get_option      udhcp_get_option
     69#define end_option      udhcp_end_option
     70#define add_option_string   udhcp_add_option_string
     71#define add_simple_option   udhcp_add_simple_option
     72#define option_lengths      udhcp_option_lengths
     73/* from socket.h */
     74#define listen_socket       udhcp_listen_socket
     75#define read_interface      udhcp_read_interface
     76/* from dhcpc.h */
     77#define client_config       udhcp_client_config
     78/* from dhcpd.h */
     79#define server_config       udhcp_server_config
     80
     81void udhcp_sp_setup(void);
     82int udhcp_sp_fd_set(fd_set *rfds, int extra_fd);
     83int udhcp_sp_read(fd_set *rfds);
     84int raw_socket(int ifindex);
     85int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp);
     86int listen_socket(/*uint32_t ip,*/ int port, const char *inf);
     87/* Returns 1 if no reply received */
     88int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface);
    2989
    3090#if ENABLE_FEATURE_UDHCP_DEBUG
    31 # define DEBUG(level, str, args...) LOG(level, str, ## args)
     91# define DEBUG(str, args...) bb_info_msg(str, ## args)
    3292#else
    33 # define DEBUG(level, str, args...) do {;} while(0)
     93# define DEBUG(str, args...) do {;} while (0)
    3494#endif
    3595
  • branches/stable/mindi-busybox/networking/udhcp/dhcpc.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* dhcpc.c
    23 *
     
    89 */
    910
    10 #include <sys/file.h>
    11 #include <unistd.h>
    1211#include <getopt.h>
    13 #include <stdlib.h>
    14 #include <sys/socket.h>
    15 #include <netinet/in.h>
    16 #include <arpa/inet.h>
    17 #include <signal.h>
    18 #include <time.h>
    19 #include <string.h>
    20 #include <sys/ioctl.h>
    21 #include <net/if.h>
    22 #include <errno.h>
    23 
     12#include <syslog.h>
     13
     14/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
     15#define WANT_PIDFILE 1
    2416#include "common.h"
    2517#include "dhcpd.h"
    2618#include "dhcpc.h"
    2719#include "options.h"
    28 #include "clientpacket.h"
    29 #include "clientsocket.h"
    30 #include "socket.h"
    31 #include "signalpipe.h"
    32 
    33 static int state;
    34 static unsigned long requested_ip; /* = 0 */
    35 static unsigned long server_addr;
    36 static unsigned long timeout;
     20
     21
     22/* Something is definitely wrong here. IPv4 addresses
     23 * in variables of type long?? BTW, we use inet_ntoa()
     24 * in the code. Manpage says that struct in_addr has a member of type long (!)
     25 * which holds IPv4 address, and the struct is passed by value (!!)
     26 */
     27static unsigned timeout;
     28static uint32_t requested_ip; /* = 0 */
     29static uint32_t server_addr;
    3730static int packet_num; /* = 0 */
    38 static int fd = -1;
     31static int sockfd = -1;
    3932
    4033#define LISTEN_NONE 0
    4134#define LISTEN_KERNEL 1
    4235#define LISTEN_RAW 2
    43 static int listen_mode;
    44 
    45 struct client_config_t client_config = {
    46     /* Default options. */
    47     .abort_if_no_lease = 0,
    48     .foreground = 0,
    49     .quit_after_lease = 0,
    50     .background_if_no_lease = 0,
    51     .interface = "eth0",
    52     .pidfile = NULL,
    53     .script = DEFAULT_SCRIPT,
    54     .clientid = NULL,
    55     .vendorclass = NULL,
    56     .hostname = NULL,
    57     .fqdn = NULL,
    58     .ifindex = 0,
    59     .retries = 3,
    60     .timeout = 3,
    61     .arp = "\0\0\0\0\0\0",      /* appease gcc-3.0 */
    62 };
     36static smallint listen_mode;
     37
     38static smallint state;
     39
     40struct client_config_t client_config;
     41
    6342
    6443/* just a little helper */
    6544static void change_mode(int new_mode)
    6645{
    67     DEBUG(LOG_INFO, "entering %s listen mode",
     46    DEBUG("entering %s listen mode",
    6847        new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
    69     if (fd >= 0) close(fd);
    70     fd = -1;
     48    if (sockfd >= 0) {
     49        close(sockfd);
     50        sockfd = -1;
     51    }
    7152    listen_mode = new_mode;
    7253}
     
    7657static void perform_renew(void)
    7758{
    78     LOG(LOG_INFO, "Performing a DHCP renew");
     59    bb_info_msg("Performing a DHCP renew");
    7960    switch (state) {
    8061    case BOUND:
     
    10687static void perform_release(void)
    10788{
    108     char buffer[16];
     89    char buffer[sizeof("255.255.255.255")];
    10990    struct in_addr temp_addr;
    11091
     
    11293    if (state == BOUND || state == RENEWING || state == REBINDING) {
    11394        temp_addr.s_addr = server_addr;
    114         sprintf(buffer, "%s", inet_ntoa(temp_addr));
     95        strcpy(buffer, inet_ntoa(temp_addr));
    11596        temp_addr.s_addr = requested_ip;
    116         LOG(LOG_INFO, "Unicasting a release of %s to %s",
     97        bb_info_msg("Unicasting a release of %s to %s",
    11798                inet_ntoa(temp_addr), buffer);
    11899        send_release(server_addr, requested_ip); /* unicast */
    119100        udhcp_run_script(NULL, "deconfig");
    120101    }
    121     LOG(LOG_INFO, "Entering released state");
     102    bb_info_msg("Entering released state");
    122103
    123104    change_mode(LISTEN_NONE);
    124105    state = RELEASED;
    125     timeout = 0x7fffffff;
     106    timeout = INT_MAX;
    126107}
    127108
     
    129110static void client_background(void)
    130111{
    131     udhcp_background(client_config.pidfile);
    132     client_config.foreground = 1; /* Do not fork again. */
     112#if !BB_MMU
     113    bb_error_msg("cannot background in uclinux (yet)");
     114/* ... mainly because udhcpc calls client_background()
     115 * in _the _middle _of _udhcpc _run_, not at the start!
     116 * If that will be properly disabled for NOMMU, client_background()
     117 * will work on NOMMU too */
     118#else
     119    bb_daemonize(0);
     120    logmode &= ~LOGMODE_STDIO;
     121    /* rewrite pidfile, as our pid is different now */
     122    write_pidfile(client_config.pidfile);
     123#endif
     124    /* Do not fork again. */
     125    client_config.foreground = 1;
    133126    client_config.background_if_no_lease = 0;
    134127}
    135128
    136129
    137 int udhcpc_main(int argc, char *argv[])
     130static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
     131{
     132    uint8_t *storage;
     133    int len = strlen(str);
     134    if (len > 255) len = 255;
     135    storage = xzalloc(len + extra + OPT_DATA);
     136    storage[OPT_CODE] = code;
     137    storage[OPT_LEN] = len + extra;
     138    memcpy(storage + extra + OPT_DATA, str, len);
     139    return storage;
     140}
     141
     142
     143int udhcpc_main(int argc, char **argv);
     144int udhcpc_main(int argc, char **argv)
    138145{
    139146    uint8_t *temp, *message;
    140     unsigned long t1 = 0, t2 = 0, xid = 0;
    141     unsigned long start = 0, lease;
     147    char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t;
     148    uint32_t xid = 0;
     149    uint32_t lease = 0; /* can be given as 32-bit quantity */
     150    unsigned t1 = 0, t2 = 0; /* what a wonderful names */
     151    unsigned start = 0;
     152    unsigned now;
     153    unsigned opt;
     154    int max_fd;
     155    int retval;
     156    int len;
     157    struct timeval tv;
     158    struct in_addr temp_addr;
     159    struct dhcpMessage packet;
    142160    fd_set rfds;
    143     int retval;
    144     struct timeval tv;
    145     int c, len;
    146     struct dhcpMessage packet;
    147     struct in_addr temp_addr;
    148     long now;
    149     int max_fd;
    150     int sig;
    151     int no_clientid = 0;
    152 
    153     static const struct option arg_options[] = {
    154         {"clientid",    required_argument,  0, 'c'},
    155         {"clientid-none", no_argument,      0, 'C'},
    156         {"vendorclass", required_argument,  0, 'V'},
    157         {"foreground",  no_argument,        0, 'f'},
    158         {"background",  no_argument,        0, 'b'},
    159         {"hostname",    required_argument,  0, 'H'},
    160         {"hostname",    required_argument,  0, 'h'},
    161         {"fqdn",    required_argument,  0, 'F'},
    162         {"interface",   required_argument,  0, 'i'},
    163         {"now",     no_argument,        0, 'n'},
    164         {"pidfile", required_argument,  0, 'p'},
    165         {"quit",    no_argument,        0, 'q'},
    166         {"request", required_argument,  0, 'r'},
    167         {"script",  required_argument,  0, 's'},
    168         {"timeout", required_argument,  0, 'T'},
    169         {"version", no_argument,        0, 'v'},
    170         {"retries", required_argument,  0, 't'},
    171         {0, 0, 0, 0}
     161
     162    enum {
     163        OPT_c = 1 << 0,
     164        OPT_C = 1 << 1,
     165        OPT_V = 1 << 2,
     166        OPT_f = 1 << 3,
     167        OPT_b = 1 << 4,
     168        OPT_H = 1 << 5,
     169        OPT_h = 1 << 6,
     170        OPT_F = 1 << 7,
     171        OPT_i = 1 << 8,
     172        OPT_n = 1 << 9,
     173        OPT_p = 1 << 10,
     174        OPT_q = 1 << 11,
     175        OPT_R = 1 << 12,
     176        OPT_r = 1 << 13,
     177        OPT_s = 1 << 14,
     178        OPT_T = 1 << 15,
     179        OPT_t = 1 << 16,
     180        OPT_v = 1 << 17,
     181        OPT_S = 1 << 18,
    172182    };
    173 
    174     /* get options */
    175     while (1) {
    176         int option_index = 0;
    177         c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qr:s:T:t:v", arg_options, &option_index);
    178         if (c == -1) break;
    179 
    180         switch (c) {
    181         case 'c':
    182             if (no_clientid) bb_show_usage();
    183             len = strlen(optarg) > 255 ? 255 : strlen(optarg);
    184             free(client_config.clientid);
    185             client_config.clientid = xmalloc(len + 2);
    186             client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
    187             client_config.clientid[OPT_LEN] = len;
    188             client_config.clientid[OPT_DATA] = '\0';
    189             strncpy((char*)client_config.clientid + OPT_DATA, optarg, len);
    190             break;
    191         case 'C':
    192             if (client_config.clientid) bb_show_usage();
    193             no_clientid = 1;
    194             break;
    195         case 'V':
    196             len = strlen(optarg) > 255 ? 255 : strlen(optarg);
    197             free(client_config.vendorclass);
    198             client_config.vendorclass = xmalloc(len + 2);
    199             client_config.vendorclass[OPT_CODE] = DHCP_VENDOR;
    200             client_config.vendorclass[OPT_LEN] = len;
    201             strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len);
    202             break;
    203         case 'f':
    204             client_config.foreground = 1;
    205             break;
    206         case 'b':
    207             client_config.background_if_no_lease = 1;
    208             break;
    209         case 'h':
    210         case 'H':
    211             len = strlen(optarg) > 255 ? 255 : strlen(optarg);
    212             free(client_config.hostname);
    213             client_config.hostname = xmalloc(len + 2);
    214             client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
    215             client_config.hostname[OPT_LEN] = len;
    216             strncpy((char*)client_config.hostname + 2, optarg, len);
    217             break;
    218         case 'F':
    219             len = strlen(optarg) > 255 ? 255 : strlen(optarg);
    220             free(client_config.fqdn);
    221             client_config.fqdn = xmalloc(len + 5);
    222             client_config.fqdn[OPT_CODE] = DHCP_FQDN;
    223             client_config.fqdn[OPT_LEN] = len + 3;
    224             /* Flags: 0000NEOS
    225             S: 1 => Client requests Server to update A RR in DNS as well as PTR
    226             O: 1 => Server indicates to client that DNS has been updated regardless
    227             E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
    228             N: 1 => Client requests Server to not update DNS
    229             */
    230             client_config.fqdn[OPT_LEN + 1] = 0x1;
    231             client_config.fqdn[OPT_LEN + 2] = 0;
    232             client_config.fqdn[OPT_LEN + 3] = 0;
    233             strncpy((char*)client_config.fqdn + 5, optarg, len);
    234             break;
    235         case 'i':
    236             client_config.interface =  optarg;
    237             break;
    238         case 'n':
    239             client_config.abort_if_no_lease = 1;
    240             break;
    241         case 'p':
    242             client_config.pidfile = optarg;
    243             break;
    244         case 'q':
    245             client_config.quit_after_lease = 1;
    246             break;
    247         case 'r':
    248             requested_ip = inet_addr(optarg);
    249             break;
    250         case 's':
    251             client_config.script = optarg;
    252             break;
    253         case 'T':
    254             client_config.timeout = atoi(optarg);
    255             break;
    256         case 't':
    257             client_config.retries = atoi(optarg);
    258             break;
    259         case 'v':
    260             printf("version %s\n\n", BB_VER);
    261             return 0;
    262             break;
    263         default:
    264             bb_show_usage();
    265         }
    266     }
    267 
    268     /* Start the log, sanitize fd's, and write a pid file */
    269     udhcp_start_log_and_pid("udhcpc", client_config.pidfile);
     183#if ENABLE_GETOPT_LONG
     184    static const char udhcpc_longopts[] ALIGN1 =
     185        "clientid\0"      Required_argument "c"
     186        "clientid-none\0" No_argument       "C"
     187        "vendorclass\0"   Required_argument "V"
     188        "foreground\0"    No_argument       "f"
     189        "background\0"    No_argument       "b"
     190        "hostname\0"      Required_argument "H"
     191        "hostname\0"      Required_argument "h"
     192        "fqdn\0"          Required_argument "F"
     193        "interface\0"     Required_argument "i"
     194        "now\0"           No_argument       "n"
     195        "pidfile\0"       Required_argument "p"
     196        "quit\0"          No_argument       "q"
     197        "release\0"       No_argument       "R"
     198        "request\0"       Required_argument "r"
     199        "script\0"        Required_argument "s"
     200        "timeout\0"       Required_argument "T"
     201        "version\0"       No_argument       "v"
     202        "retries\0"       Required_argument "t"
     203        "syslog\0"        No_argument       "S"
     204        ;
     205#endif
     206    /* Default options. */
     207    client_config.interface = "eth0";
     208    client_config.script = DEFAULT_SCRIPT;
     209    client_config.retries = 3;
     210    client_config.timeout = 3;
     211
     212    /* Parse command line */
     213    opt_complementary = "c--C:C--c" // mutually exclusive
     214                        ":hH:Hh"; // -h and -H are the same
     215#if ENABLE_GETOPT_LONG
     216    applet_long_options = udhcpc_longopts;
     217#endif
     218    opt = getopt32(argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:vS",
     219        &str_c, &str_V, &str_h, &str_h, &str_F,
     220        &client_config.interface, &client_config.pidfile, &str_r,
     221        &client_config.script, &str_T, &str_t
     222        );
     223
     224    if (opt & OPT_c)
     225        client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
     226    //if (opt & OPT_C)
     227    if (opt & OPT_V)
     228        client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
     229    if (opt & OPT_f)
     230        client_config.foreground = 1;
     231    if (opt & OPT_b)
     232        client_config.background_if_no_lease = 1;
     233    if (opt & OPT_h)
     234        client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
     235    if (opt & OPT_F) {
     236        client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
     237        /* Flags: 0000NEOS
     238        S: 1 => Client requests Server to update A RR in DNS as well as PTR
     239        O: 1 => Server indicates to client that DNS has been updated regardless
     240        E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
     241        N: 1 => Client requests Server to not update DNS
     242        */
     243        client_config.fqdn[OPT_DATA + 0] = 0x1;
     244        /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */
     245        /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */
     246    }
     247    // if (opt & OPT_i) client_config.interface = ...
     248    if (opt & OPT_n)
     249        client_config.abort_if_no_lease = 1;
     250    // if (opt & OPT_p) client_config.pidfile = ...
     251    if (opt & OPT_q)
     252        client_config.quit_after_lease = 1;
     253    if (opt & OPT_R)
     254        client_config.release_on_quit = 1;
     255    if (opt & OPT_r)
     256        requested_ip = inet_addr(str_r);
     257    // if (opt & OPT_s) client_config.script = ...
     258    if (opt & OPT_T)
     259        client_config.timeout = xatoi_u(str_T);
     260    if (opt & OPT_t)
     261        client_config.retries = xatoi_u(str_t);
     262    if (opt & OPT_v) {
     263        printf("version %s\n", BB_VER);
     264        return 0;
     265    }
     266
     267    if (opt & OPT_S) {
     268        openlog(applet_name, LOG_PID, LOG_LOCAL0);
     269        logmode |= LOGMODE_SYSLOG;
     270    }
    270271
    271272    if (read_interface(client_config.interface, &client_config.ifindex,
    272                NULL, client_config.arp) < 0)
     273               NULL, client_config.arp))
    273274        return 1;
    274275
     276    /* Make sure fd 0,1,2 are open */
     277    bb_sanitize_stdio();
     278    /* Equivalent of doing a fflush after every \n */
     279    setlinebuf(stdout);
     280
     281    /* Create pidfile */
     282    write_pidfile(client_config.pidfile);
     283    /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */
     284
     285    /* Goes to stdout and possibly syslog */
     286    bb_info_msg("%s (v%s) started", applet_name, BB_VER);
     287
    275288    /* if not set, and not suppressed, setup the default client ID */
    276     if (!client_config.clientid && !no_clientid) {
    277         client_config.clientid = xmalloc(6 + 3);
    278         client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
    279         client_config.clientid[OPT_LEN] = 7;
     289    if (!client_config.clientid && !(opt & OPT_C)) {
     290        client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
    280291        client_config.clientid[OPT_DATA] = 1;
    281         memcpy(client_config.clientid + 3, client_config.arp, 6);
    282     }
    283 
    284     if (!client_config.vendorclass) {
    285         client_config.vendorclass = xmalloc(sizeof("udhcp "BB_VER) + 2);
    286         client_config.vendorclass[OPT_CODE] = DHCP_VENDOR;
    287         client_config.vendorclass[OPT_LEN] = sizeof("udhcp "BB_VER) - 1;
    288         client_config.vendorclass[OPT_DATA] = 1;
    289         memcpy(&client_config.vendorclass[OPT_DATA],
    290             "udhcp "BB_VER, sizeof("udhcp "BB_VER) - 1);
    291     }
    292 
     292        memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);
     293    }
     294
     295    if (!client_config.vendorclass)
     296        client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
    293297
    294298    /* setup the signal pipe */
     
    298302    udhcp_run_script(NULL, "deconfig");
    299303    change_mode(LISTEN_RAW);
     304    tv.tv_sec = 0;
     305    goto jump_in;
    300306
    301307    for (;;) {
    302 
    303         tv.tv_sec = timeout - uptime();
     308        tv.tv_sec = timeout - monotonic_sec();
     309 jump_in:
    304310        tv.tv_usec = 0;
    305311
    306         if (listen_mode != LISTEN_NONE && fd < 0) {
     312        if (listen_mode != LISTEN_NONE && sockfd < 0) {
    307313            if (listen_mode == LISTEN_KERNEL)
    308                 fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
     314                sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
    309315            else
    310                 fd = raw_socket(client_config.ifindex);
    311             if (fd < 0) {
    312                 LOG(LOG_ERR, "FATAL: couldn't listen on socket, %m");
    313                 return 0;
    314             }
     316                sockfd = raw_socket(client_config.ifindex);
    315317        }
    316         max_fd = udhcp_sp_fd_set(&rfds, fd);
    317 
     318        max_fd = udhcp_sp_fd_set(&rfds, sockfd);
     319
     320        retval = 0; /* If we already timed out, fall through, else... */
    318321        if (tv.tv_sec > 0) {
    319             DEBUG(LOG_INFO, "Waiting on select...");
     322            DEBUG("Waiting on select...");
    320323            retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
    321         } else retval = 0; /* If we already timed out, fall through */
    322 
    323         now = uptime();
    324         if (retval == 0) {
     324        }
     325
     326        now = monotonic_sec();
     327        if (retval < 0) {
     328            /* EINTR? signal was caught, don't panic */
     329            if (errno != EINTR) {
     330                /* Else: an error occured, panic! */
     331                bb_perror_msg_and_die("select");
     332            }
     333        } else if (retval == 0) {
    325334            /* timeout dropped to zero */
    326335            switch (state) {
     
    338347                    udhcp_run_script(NULL, "leasefail");
    339348                    if (client_config.background_if_no_lease) {
    340                         LOG(LOG_INFO, "No lease, forking to background.");
     349                        bb_info_msg("No lease, forking to background");
    341350                        client_background();
    342351                    } else if (client_config.abort_if_no_lease) {
    343                         LOG(LOG_INFO, "No lease, failing.");
    344                         return 1;
     352                        bb_info_msg("No lease, failing");
     353                        retval = 1;
     354                        goto ret;
    345355                    }
    346356                    /* wait to try again */
     
    361371                } else {
    362372                    /* timed out, go back to init state */
    363                     if (state == RENEW_REQUESTED) udhcp_run_script(NULL, "deconfig");
     373                    if (state == RENEW_REQUESTED)
     374                        udhcp_run_script(NULL, "deconfig");
    364375                    state = INIT_SELECTING;
    365376                    timeout = now;
     
    372383                state = RENEWING;
    373384                change_mode(LISTEN_KERNEL);
    374                 DEBUG(LOG_INFO, "Entering renew state");
     385                DEBUG("Entering renew state");
    375386                /* fall right through */
    376387            case RENEWING:
     
    380391                    state = REBINDING;
    381392                    timeout = now + (t2 - t1);
    382                     DEBUG(LOG_INFO, "Entering rebinding state");
     393                    DEBUG("Entering rebinding state");
    383394                } else {
    384395                    /* send a request packet */
    385396                    send_renew(xid, server_addr, requested_ip); /* unicast */
    386 
    387397                    t1 = (t2 - t1) / 2 + t1;
    388                     timeout = t1 + start;
     398                    timeout = start + t1;
    389399                }
    390400                break;
     
    394404                    /* timed out, enter init state */
    395405                    state = INIT_SELECTING;
    396                     LOG(LOG_INFO, "Lease lost, entering init state");
     406                    bb_info_msg("Lease lost, entering init state");
    397407                    udhcp_run_script(NULL, "deconfig");
    398408                    timeout = now;
     
    402412                    /* send a request packet */
    403413                    send_renew(xid, 0, requested_ip); /* broadcast */
    404 
    405414                    t2 = (lease - t2) / 2 + t2;
    406                     timeout = t2 + start;
     415                    timeout = start + t2;
    407416                }
    408417                break;
    409418            case RELEASED:
    410419                /* yah, I know, *you* say it would never happen */
    411                 timeout = 0x7fffffff;
    412                 break;
    413             }
    414         } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) {
     420                timeout = INT_MAX;
     421                break;
     422            }
     423        } else if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) {
    415424            /* a packet is ready, read it */
    416425
    417426            if (listen_mode == LISTEN_KERNEL)
    418                 len = udhcp_get_packet(&packet, fd);
    419             else len = get_raw_packet(&packet, fd);
     427                len = udhcp_get_packet(&packet, sockfd);
     428            else len = get_raw_packet(&packet, sockfd);
    420429
    421430            if (len == -1 && errno != EINTR) {
    422                 DEBUG(LOG_INFO, "error on read, %m, reopening socket");
     431                DEBUG("error on read, %s, reopening socket", strerror(errno));
    423432                change_mode(listen_mode); /* just close and reopen */
    424433            }
     
    426435
    427436            if (packet.xid != xid) {
    428                 DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
    429                     (unsigned long) packet.xid, xid);
     437                DEBUG("Ignoring XID %x (our xid is %x)",
     438                    (unsigned)packet.xid, (unsigned)xid);
    430439                continue;
    431440            }
     
    433442            /* Ignore packets that aren't for us */
    434443            if (memcmp(packet.chaddr, client_config.arp, 6)) {
    435                 DEBUG(LOG_INFO, "packet does not have our chaddr -- ignoring");
     444                DEBUG("Packet does not have our chaddr - ignoring");
    436445                continue;
    437446            }
    438447
    439             if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
    440                 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
     448            message = get_option(&packet, DHCP_MESSAGE_TYPE);
     449            if (message == NULL) {
     450                bb_error_msg("cannot get option from packet - ignoring");
    441451                continue;
    442452            }
     
    446456                /* Must be a DHCPOFFER to one of our xid's */
    447457                if (*message == DHCPOFFER) {
    448                     if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
     458                    temp = get_option(&packet, DHCP_SERVER_ID);
     459                    if (temp) {
     460                        /* can be misaligned, thus memcpy */
    449461                        memcpy(&server_addr, temp, 4);
    450462                        xid = packet.xid;
     
    456468                        packet_num = 0;
    457469                    } else {
    458                         DEBUG(LOG_ERR, "No server ID in message");
     470                        bb_error_msg("no server ID in message");
    459471                    }
    460472                }
     
    465477            case REBINDING:
    466478                if (*message == DHCPACK) {
    467                     if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
    468                         LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease");
     479                    temp = get_option(&packet, DHCP_LEASE_TIME);
     480                    if (!temp) {
     481                        bb_error_msg("no lease time with ACK, using 1 hour lease");
    469482                        lease = 60 * 60;
    470483                    } else {
     484                        /* can be misaligned, thus memcpy */
    471485                        memcpy(&lease, temp, 4);
    472486                        lease = ntohl(lease);
     
    477491
    478492                    /* little fixed point for n * .875 */
    479                     t2 = (lease * 0x7) >> 3;
     493                    t2 = (lease * 7) >> 3;
    480494                    temp_addr.s_addr = packet.yiaddr;
    481                     LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",
    482                         inet_ntoa(temp_addr), lease);
     495                    bb_info_msg("Lease of %s obtained, lease time %u",
     496                        inet_ntoa(temp_addr), (unsigned)lease);
    483497                    start = now;
    484                     timeout = t1 + start;
     498                    timeout = start + t1;
    485499                    requested_ip = packet.yiaddr;
    486500                    udhcp_run_script(&packet,
     
    489503                    state = BOUND;
    490504                    change_mode(LISTEN_NONE);
    491                     if (client_config.quit_after_lease)
    492                         return 0;
     505                    if (client_config.quit_after_lease) {
     506                        if (client_config.release_on_quit)
     507                            perform_release();
     508                        goto ret0;
     509                    }
    493510                    if (!client_config.foreground)
    494511                        client_background();
     
    496513                } else if (*message == DHCPNAK) {
    497514                    /* return to init state */
    498                     LOG(LOG_INFO, "Received DHCP NAK");
     515                    bb_info_msg("Received DHCP NAK");
    499516                    udhcp_run_script(&packet, "nak");
    500517                    if (state != REQUESTING)
     
    510527            /* case BOUND, RELEASED: - ignore all packets */
    511528            }
    512         } else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) {
    513             switch (sig) {
     529        } else {
     530            int signo = udhcp_sp_read(&rfds);
     531            switch (signo) {
    514532            case SIGUSR1:
    515533                perform_renew();
     
    519537                break;
    520538            case SIGTERM:
    521                 LOG(LOG_INFO, "Received SIGTERM");
    522                 return 0;
    523             }
    524         } else if (retval == -1 && errno == EINTR) {
    525             /* a signal was caught */
    526         } else {
    527             /* An error occured */
    528             DEBUG(LOG_ERR, "Error on select");
     539                bb_info_msg("Received SIGTERM");
     540                if (client_config.release_on_quit)
     541                    perform_release();
     542                goto ret0;
     543            }
    529544        }
    530 
    531     }
    532     return 0;
     545    } /* for (;;) */
     546 ret0:
     547    retval = 0;
     548 ret:
     549    /*if (client_config.pidfile) - remove_pidfile has it's own check */
     550        remove_pidfile(client_config.pidfile);
     551    return retval;
    533552}
  • branches/stable/mindi-busybox/networking/udhcp/dhcpc.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* dhcpc.h */
    23#ifndef _DHCPC_H
    34#define _DHCPC_H
    4 
    5 /* grab define DEFAULT_SCRIPT */
    6 #include "libbb_udhcp.h"
    75
    86#define INIT_SELECTING  0
     
    1513#define RELEASED    7
    1614
    17 
    1815struct client_config_t {
    19     char foreground;        /* Do not fork */
    20     char quit_after_lease;      /* Quit after obtaining lease */
    21     char abort_if_no_lease;     /* Abort if no lease */
    22     char background_if_no_lease;    /* Fork to background if no lease */
    23     char *interface;        /* The name of the interface to use */
    24     char *pidfile;          /* Optionally store the process ID */
    25     char *script;           /* User script to run at dhcp events */
    26     uint8_t *clientid;      /* Optional client id to use */
    27     uint8_t *vendorclass;       /* Optional vendor class-id to use */
    28     uint8_t *hostname;      /* Optional hostname to use */
    29     uint8_t *fqdn;          /* Optional fully qualified domain name to use */
    30     int ifindex;            /* Index number of the interface to use */
    31     int retries;            /* Max number of request packets */       
    32     int timeout;            /* Number of seconds to try to get a lease */
    33     uint8_t arp[6];         /* Our arp address */
     16    /* TODO: combine flag fields into single "unsigned opt" */
     17    /* (can be set directly to the result of getopt32) */
     18    char foreground;                /* Do not fork */
     19    char quit_after_lease;          /* Quit after obtaining lease */
     20    char release_on_quit;           /* Perform release on quit */
     21    char abort_if_no_lease;         /* Abort if no lease */
     22    char background_if_no_lease;    /* Fork to background if no lease */
     23    const char *interface;          /* The name of the interface to use */
     24    char *pidfile;                  /* Optionally store the process ID */
     25    const char *script;             /* User script to run at dhcp events */
     26    uint8_t *clientid;              /* Optional client id to use */
     27    uint8_t *vendorclass;           /* Optional vendor class-id to use */
     28    uint8_t *hostname;              /* Optional hostname to use */
     29    uint8_t *fqdn;                  /* Optional fully qualified domain name to use */
     30    int ifindex;                    /* Index number of the interface to use */
     31    int retries;                    /* Max number of request packets */
     32    int timeout;                    /* Number of seconds to try to get a lease */
     33    uint8_t arp[6];                 /* Our arp address */
    3434};
    3535
     
    3737
    3838
     39/*** clientpacket.h ***/
     40
     41uint32_t random_xid(void);
     42int send_discover(uint32_t xid, uint32_t requested);
     43int send_selecting(uint32_t xid, uint32_t server, uint32_t requested);
     44int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
     45int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
     46int send_release(uint32_t server, uint32_t ciaddr);
     47int get_raw_packet(struct dhcpMessage *payload, int fd);
     48
     49
    3950#endif
  • branches/stable/mindi-busybox/networking/udhcp/dhcpd.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* dhcpd.c
    23 *
     
    1011 */
    1112
    12 #include <fcntl.h>
    13 #include <string.h>
    14 #include <stdlib.h>
    15 #include <sys/wait.h>
    16 #include <arpa/inet.h>
    17 #include <netdb.h>
    18 #include <netinet/in.h>
    19 #include <sys/socket.h>
    20 #include <unistd.h>
    21 #include <signal.h>
    22 #include <errno.h>
    23 #include <sys/ioctl.h>
    24 #include <time.h>
    25 
     13#include <syslog.h>
     14#include "common.h"
    2615#include "dhcpd.h"
    27 #include "arpping.h"
    28 #include "socket.h"
    2916#include "options.h"
    30 #include "files.h"
    31 #include "serverpacket.h"
    32 #include "common.h"
    33 #include "signalpipe.h"
    34 #include "static_leases.h"
    3517
    3618
     
    4022
    4123
    42 int udhcpd_main(int argc, char *argv[])
     24int udhcpd_main(int argc, char **argv);
     25int udhcpd_main(int argc, char **argv)
    4326{
    4427    fd_set rfds;
     
    4831    uint8_t *state, *server_id, *requested;
    4932    uint32_t server_id_align, requested_align, static_lease_ip;
    50     unsigned long timeout_end, num_ips;
     33    unsigned timeout_end;
     34    unsigned num_ips;
     35    unsigned opt;
    5136    struct option_set *option;
    5237    struct dhcpOfferedAddr *lease, static_lease;
    5338
    54     read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);
    55 
    56     /* Start the log, sanitize fd's, and write a pid file */
    57     udhcp_start_log_and_pid("udhcpd", server_config.pidfile);
    58 
    59     if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
     39    opt = getopt32(argv, "fS");
     40    argv += optind;
     41
     42    if (!(opt & 1)) { /* no -f */
     43        bb_daemonize_or_rexec(0, argv);
     44        logmode &= ~LOGMODE_STDIO;
     45    }
     46
     47    if (opt & 2) { /* -S */
     48        openlog(applet_name, LOG_PID, LOG_LOCAL0);
     49        logmode |= LOGMODE_SYSLOG;
     50    }
     51
     52    /* Would rather not do read_config before daemonization -
     53     * otherwise NOMMU machines will parse config twice */
     54    read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
     55
     56    /* Make sure fd 0,1,2 are open */
     57    bb_sanitize_stdio();
     58    /* Equivalent of doing a fflush after every \n */
     59    setlinebuf(stdout);
     60
     61    /* Create pidfile */
     62    write_pidfile(server_config.pidfile);
     63    /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */
     64
     65    bb_info_msg("%s (v%s) started", applet_name, BB_VER);
     66
     67    option = find_option(server_config.options, DHCP_LEASE_TIME);
     68    server_config.lease = LEASE_TIME;
     69    if (option) {
    6070        memcpy(&server_config.lease, option->data + 2, 4);
    6171        server_config.lease = ntohl(server_config.lease);
    6272    }
    63     else server_config.lease = LEASE_TIME;
    6473
    6574    /* Sanity check */
    66     num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1;
     75    num_ips = server_config.end_ip - server_config.start_ip + 1;
    6776    if (server_config.max_leases > num_ips) {
    68         LOG(LOG_ERR, "max_leases value (%lu) not sane, "
    69             "setting to %lu instead",
    70             server_config.max_leases, num_ips);
     77        bb_error_msg("max_leases=%u is too big, setting to %u",
     78            (unsigned)server_config.max_leases, num_ips);
    7179        server_config.max_leases = num_ips;
    7280    }
    7381
    74     leases = xzalloc(server_config.max_leases * sizeof(struct dhcpOfferedAddr));
     82    leases = xzalloc(server_config.max_leases * sizeof(*leases));
    7583    read_leases(server_config.lease_file);
    7684
    7785    if (read_interface(server_config.interface, &server_config.ifindex,
    78                &server_config.server, server_config.arp) < 0)
    79         return 1;
    80 
    81     if (!ENABLE_FEATURE_UDHCP_DEBUG)
    82         udhcp_background(server_config.pidfile); /* hold lock during fork. */
     86               &server_config.server, server_config.arp)) {
     87        retval = 1;
     88        goto ret;
     89    }
    8390
    8491    /* Setup the signal pipe */
    8592    udhcp_sp_setup();
    8693
    87     timeout_end = time(0) + server_config.auto_time;
    88     while(1) { /* loop until universe collapses */
    89 
    90         if (server_socket < 0)
    91             if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
    92                 LOG(LOG_ERR, "FATAL: couldn't create server socket, %m");
    93                 return 2;
    94             }
     94    timeout_end = monotonic_sec() + server_config.auto_time;
     95    while (1) { /* loop until universe collapses */
     96
     97        if (server_socket < 0) {
     98            server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
     99                    server_config.interface);
     100        }
    95101
    96102        max_sock = udhcp_sp_fd_set(&rfds, server_socket);
    97103        if (server_config.auto_time) {
    98             tv.tv_sec = timeout_end - time(0);
     104            tv.tv_sec = timeout_end - monotonic_sec();
    99105            tv.tv_usec = 0;
    100106        }
     107        retval = 0;
    101108        if (!server_config.auto_time || tv.tv_sec > 0) {
    102109            retval = select(max_sock + 1, &rfds, NULL, NULL,
    103110                    server_config.auto_time ? &tv : NULL);
    104         } else retval = 0; /* If we already timed out, fall through */
    105 
     111        }
    106112        if (retval == 0) {
    107113            write_leases();
    108             timeout_end = time(0) + server_config.auto_time;
    109             continue;
    110         } else if (retval < 0 && errno != EINTR) {
    111             DEBUG(LOG_INFO, "error on select");
     114            timeout_end = monotonic_sec() + server_config.auto_time;
     115            continue;
     116        }
     117        if (retval < 0 && errno != EINTR) {
     118            DEBUG("error on select");
    112119            continue;
    113120        }
     
    115122        switch (udhcp_sp_read(&rfds)) {
    116123        case SIGUSR1:
    117             LOG(LOG_INFO, "Received a SIGUSR1");
     124            bb_info_msg("Received a SIGUSR1");
    118125            write_leases();
    119126            /* why not just reset the timeout, eh */
    120             timeout_end = time(0) + server_config.auto_time;
     127            timeout_end = monotonic_sec() + server_config.auto_time;
    121128            continue;
    122129        case SIGTERM:
    123             LOG(LOG_INFO, "Received a SIGTERM");
    124             return 0;
     130            bb_info_msg("Received a SIGTERM");
     131            goto ret0;
    125132        case 0: break;      /* no signal */
    126133        default: continue;  /* signal or error (probably EINTR) */
    127134        }
    128135
    129         if ((bytes = udhcp_get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
     136        bytes = udhcp_get_packet(&packet, server_socket); /* this waits for a packet - idle */
     137        if (bytes < 0) {
    130138            if (bytes == -1 && errno != EINTR) {
    131                 DEBUG(LOG_INFO, "error on read, %m, reopening socket");
     139                DEBUG("error on read, %s, reopening socket", strerror(errno));
    132140                close(server_socket);
    133141                server_socket = -1;
     
    136144        }
    137145
    138         if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
    139             DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
     146        state = get_option(&packet, DHCP_MESSAGE_TYPE);
     147        if (state == NULL) {
     148            bb_error_msg("cannot get option from packet, ignoring");
    140149            continue;
    141150        }
     
    144153        static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);
    145154
    146         if(static_lease_ip)
    147         {
    148             printf("Found static lease: %x\n", static_lease_ip);
     155        if (static_lease_ip) {
     156            bb_info_msg("Found static lease: %x", static_lease_ip);
    149157
    150158            memcpy(&static_lease.chaddr, &packet.chaddr, 16);
     
    153161
    154162            lease = &static_lease;
    155 
    156         }
    157         else
    158         {
    159         lease = find_lease_by_chaddr(packet.chaddr);
     163        } else {
     164            lease = find_lease_by_chaddr(packet.chaddr);
    160165        }
    161166
    162167        switch (state[0]) {
    163168        case DHCPDISCOVER:
    164             DEBUG(LOG_INFO,"received DISCOVER");
     169            DEBUG("Received DISCOVER");
    165170
    166171            if (sendOffer(&packet) < 0) {
    167                 LOG(LOG_ERR, "send OFFER failed");
     172                bb_error_msg("send OFFER failed");
    168173            }
    169174            break;
    170175        case DHCPREQUEST:
    171             DEBUG(LOG_INFO, "received REQUEST");
     176            DEBUG("received REQUEST");
    172177
    173178            requested = get_option(&packet, DHCP_REQUESTED_IP);
     
    180185                if (server_id) {
    181186                    /* SELECTING State */
    182                     DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
    183                     if (server_id_align == server_config.server && requested &&
    184                         requested_align == lease->yiaddr) {
     187                    DEBUG("server_id = %08x", ntohl(server_id_align));
     188                    if (server_id_align == server_config.server && requested
     189                     && requested_align == lease->yiaddr
     190                    ) {
    185191                        sendACK(&packet, lease->yiaddr);
    186192                    }
     193                } else if (requested) {
     194                    /* INIT-REBOOT State */
     195                    if (lease->yiaddr == requested_align)
     196                        sendACK(&packet, lease->yiaddr);
     197                    else
     198                        sendNAK(&packet);
     199                } else if (lease->yiaddr == packet.ciaddr) {
     200                    /* RENEWING or REBINDING State */
     201                    sendACK(&packet, lease->yiaddr);
    187202                } else {
    188                     if (requested) {
    189                         /* INIT-REBOOT State */
    190                         if (lease->yiaddr == requested_align)
    191                             sendACK(&packet, lease->yiaddr);
    192                         else sendNAK(&packet);
    193                     } else {
    194                         /* RENEWING or REBINDING State */
    195                         if (lease->yiaddr == packet.ciaddr)
    196                             sendACK(&packet, lease->yiaddr);
    197                         else {
    198                             /* don't know what to do!!!! */
    199                             sendNAK(&packet);
    200                         }
    201                     }
     203                    /* don't know what to do!!!! */
     204                    sendNAK(&packet);
    202205                }
    203206
     
    208211            } else if (requested) {
    209212                /* INIT-REBOOT State */
    210                 if ((lease = find_lease_by_yiaddr(requested_align))) {
     213                lease = find_lease_by_yiaddr(requested_align);
     214                if (lease) {
    211215                    if (lease_expired(lease)) {
    212216                        /* probably best if we drop this lease */
    213217                        memset(lease->chaddr, 0, 16);
    214218                    /* make some contention for this address */
    215                     } else sendNAK(&packet);
    216                 } else if (requested_align < server_config.start ||
    217                        requested_align > server_config.end) {
    218                     sendNAK(&packet);
    219                 } /* else remain silent */
     219                    } else
     220                        sendNAK(&packet);
     221                } else {
     222                    uint32_t r = ntohl(requested_align);
     223                    if (r < server_config.start_ip
     224                         || r > server_config.end_ip
     225                    ) {
     226                        sendNAK(&packet);
     227                    }
     228                    /* else remain silent */
     229                }
    220230
    221231            } else {
    222                  /* RENEWING or REBINDING State */
     232                /* RENEWING or REBINDING State */
    223233            }
    224234            break;
    225235        case DHCPDECLINE:
    226             DEBUG(LOG_INFO,"received DECLINE");
     236            DEBUG("Received DECLINE");
    227237            if (lease) {
    228238                memset(lease->chaddr, 0, 16);
     
    231241            break;
    232242        case DHCPRELEASE:
    233             DEBUG(LOG_INFO,"received RELEASE");
    234             if (lease) lease->expires = time(0);
     243            DEBUG("Received RELEASE");
     244            if (lease)
     245                lease->expires = time(0);
    235246            break;
    236247        case DHCPINFORM:
    237             DEBUG(LOG_INFO,"received INFORM");
     248            DEBUG("Received INFORM");
    238249            send_inform(&packet);
    239250            break;
    240251        default:
    241             LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
    242         }
    243     }
    244 
    245     return 0;
     252            bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);
     253        }
     254    }
     255 ret0:
     256    retval = 0;
     257 ret:
     258    /*if (server_config.pidfile) - server_config.pidfile is never NULL */
     259        remove_pidfile(server_config.pidfile);
     260    return retval;
    246261}
    247 
  • branches/stable/mindi-busybox/networking/udhcp/dhcpd.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* dhcpd.h */
    23#ifndef _DHCPD_H
    34#define _DHCPD_H
    4 
    5 #include <netinet/ip.h>
    6 #include <netinet/udp.h>
    7 
    8 #include "libbb_udhcp.h"
    9 #include "leases.h"
    105
    116/************************************/
     
    2015#define DHCPD_CONF_FILE         "/etc/udhcpd.conf"
    2116
    22 /*****************************************************************/
    23 /* Do not modify below here unless you know what you are doing!! */
    24 /*****************************************************************/
    25 
    26 /* DHCP protocol -- see RFC 2131 */
    27 #define SERVER_PORT     67
    28 #define CLIENT_PORT     68
    29 
    30 #define DHCP_MAGIC      0x63825363
    31 
    32 /* DHCP option codes (partial list) */
    33 #define DHCP_PADDING        0x00
    34 #define DHCP_SUBNET     0x01
    35 #define DHCP_TIME_OFFSET    0x02
    36 #define DHCP_ROUTER     0x03
    37 #define DHCP_TIME_SERVER    0x04
    38 #define DHCP_NAME_SERVER    0x05
    39 #define DHCP_DNS_SERVER     0x06
    40 #define DHCP_LOG_SERVER     0x07
    41 #define DHCP_COOKIE_SERVER  0x08
    42 #define DHCP_LPR_SERVER     0x09
    43 #define DHCP_HOST_NAME      0x0c
    44 #define DHCP_BOOT_SIZE      0x0d
    45 #define DHCP_DOMAIN_NAME    0x0f
    46 #define DHCP_SWAP_SERVER    0x10
    47 #define DHCP_ROOT_PATH      0x11
    48 #define DHCP_IP_TTL     0x17
    49 #define DHCP_MTU        0x1a
    50 #define DHCP_BROADCAST      0x1c
    51 #define DHCP_NTP_SERVER     0x2a
    52 #define DHCP_WINS_SERVER    0x2c
    53 #define DHCP_REQUESTED_IP   0x32
    54 #define DHCP_LEASE_TIME     0x33
    55 #define DHCP_OPTION_OVER    0x34
    56 #define DHCP_MESSAGE_TYPE   0x35
    57 #define DHCP_SERVER_ID      0x36
    58 #define DHCP_PARAM_REQ      0x37
    59 #define DHCP_MESSAGE        0x38
    60 #define DHCP_MAX_SIZE       0x39
    61 #define DHCP_T1         0x3a
    62 #define DHCP_T2         0x3b
    63 #define DHCP_VENDOR     0x3c
    64 #define DHCP_CLIENT_ID      0x3d
    65 #define DHCP_FQDN       0x51
    66 
    67 #define DHCP_END        0xFF
    68 
    69 
    70 #define BOOTREQUEST     1
    71 #define BOOTREPLY       2
    72 
    73 #define ETH_10MB        1
    74 #define ETH_10MB_LEN        6
    75 
    76 #define DHCPDISCOVER        1
    77 #define DHCPOFFER       2
    78 #define DHCPREQUEST     3
    79 #define DHCPDECLINE     4
    80 #define DHCPACK         5
    81 #define DHCPNAK         6
    82 #define DHCPRELEASE     7
    83 #define DHCPINFORM      8
    84 
    85 #define BROADCAST_FLAG      0x8000
    86 
    87 #define OPTION_FIELD        0
    88 #define FILE_FIELD      1
    89 #define SNAME_FIELD     2
    90 
    91 /* miscellaneous defines */
    92 #define MAC_BCAST_ADDR      (uint8_t *) "\xff\xff\xff\xff\xff\xff"
    93 #define OPT_CODE 0
    94 #define OPT_LEN 1
    95 #define OPT_DATA 2
    96 
    9717struct option_set {
    9818    uint8_t *data;
     
    10121
    10222struct static_lease {
     23    struct static_lease *next;
    10324    uint8_t *mac;
    10425    uint32_t *ip;
    105     struct static_lease *next;
    10626};
    10727
    10828struct server_config_t {
    109     uint32_t server;        /* Our IP, in network order */
    110     uint32_t start;         /* Start address of leases, network order */
    111     uint32_t end;           /* End of leases, network order */
    112     struct option_set *options; /* List of DHCP options loaded from the config file */
    113     char *interface;        /* The name of the interface to use */
    114     int ifindex;            /* Index number of the interface to use */
    115     uint8_t arp[6];         /* Our arp address */
    116     unsigned long lease;        /* lease time in seconds (host order) */
    117     unsigned long max_leases;   /* maximum number of leases (including reserved address) */
    118     char remaining;         /* should the lease file be interpreted as lease time remaining, or
    119                      * as the time the lease expires */
    120     unsigned long auto_time;    /* how long should udhcpd wait before writing a config file.
    121                      * if this is zero, it will only write one on SIGUSR1 */
    122     unsigned long decline_time; /* how long an address is reserved if a client returns a
    123                      * decline message */
    124     unsigned long conflict_time;    /* how long an arp conflict offender is leased for */
    125     unsigned long offer_time;   /* how long an offered address is reserved */
    126     unsigned long min_lease;    /* minimum lease a client can request*/
     29    uint32_t server;                /* Our IP, in network order */
     30    /* start,end are in host order: we need to compare start <= ip <= end */
     31    uint32_t start_ip;              /* Start address of leases, in host order */
     32    uint32_t end_ip;                /* End of leases, in host order */
     33    struct option_set *options;     /* List of DHCP options loaded from the config file */
     34    char *interface;                /* The name of the interface to use */
     35    int ifindex;                    /* Index number of the interface to use */
     36    uint8_t arp[6];                 /* Our arp address */
     37    char remaining;                 /* should the lease file be interpreted as lease time remaining, or
     38                                     * as the time the lease expires */
     39    uint32_t lease;                 /* lease time in seconds (host order) */
     40    uint32_t max_leases;            /* maximum number of leases (including reserved address) */
     41    uint32_t auto_time;             /* how long should udhcpd wait before writing a config file.
     42                                     * if this is zero, it will only write one on SIGUSR1 */
     43    uint32_t decline_time;          /* how long an address is reserved if a client returns a
     44                                     * decline message */
     45    uint32_t conflict_time;         /* how long an arp conflict offender is leased for */
     46    uint32_t offer_time;            /* how long an offered address is reserved */
     47    uint32_t min_lease;             /* minimum lease a client can request */
    12748    char *lease_file;
    12849    char *pidfile;
    129     char *notify_file;      /* What to run whenever leases are written */
    130     uint32_t siaddr;        /* next server bootp option */
    131     char *sname;            /* bootp server name */
    132     char *boot_file;        /* bootp boot file option */
     50    char *notify_file;              /* What to run whenever leases are written */
     51    uint32_t siaddr;                /* next server bootp option */
     52    char *sname;                    /* bootp server name */
     53    char *boot_file;                /* bootp boot file option */
    13354    struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */
    13455};
     
    13859
    13960
     61/*** leases.h ***/
     62
     63struct dhcpOfferedAddr {
     64    uint8_t chaddr[16];
     65    uint32_t yiaddr;    /* network order */
     66    uint32_t expires;   /* host order */
     67};
     68
     69struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease);
     70int lease_expired(struct dhcpOfferedAddr *lease);
     71struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr);
     72struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr);
     73uint32_t find_address(int check_expired);
     74
     75
     76/*** static_leases.h ***/
     77
     78/* Config file will pass static lease info to this function which will add it
     79 * to a data structure that can be searched later */
     80int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip);
     81/* Check to see if a mac has an associated static lease */
     82uint32_t getIpByMac(struct static_lease *lease_struct, void *arg);
     83/* Check to see if an ip is reserved as a static ip */
     84uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip);
     85/* Print out static leases just to check what's going on (debug code) */
     86void printStaticLeases(struct static_lease **lease_struct);
     87
     88
     89/*** serverpacket.h ***/
     90
     91int sendOffer(struct dhcpMessage *oldpacket);
     92int sendNAK(struct dhcpMessage *oldpacket);
     93int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr);
     94int send_inform(struct dhcpMessage *oldpacket);
     95
     96
     97/*** files.h ***/
     98
     99int read_config(const char *file);
     100void write_leases(void);
     101void read_leases(const char *file);
     102struct option_set *find_option(struct option_set *opt_list, char code);
     103
     104
    140105#endif
  • branches/stable/mindi-busybox/networking/udhcp/dumpleases.c

    r821 r1770  
    33 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    44 */
    5 #include <fcntl.h>
    6 #include <string.h>
    7 #include <stdlib.h>
    8 #include <stdio.h>
    9 #include <sys/wait.h>
    10 #include <arpa/inet.h>
    11 #include <netdb.h>
    12 #include <netinet/in.h>
    13 #include <stdio.h>
    14 #include <sys/socket.h>
    15 #include <unistd.h>
    165#include <getopt.h>
    17 #include <time.h>
    186
     7#include "common.h"
    198#include "dhcpd.h"
    20 #include "leases.h"
    21 #include "libbb_udhcp.h"
    229
    23 #define REMAINING 0
    24 #define ABSOLUTE 1
    25 
    26 
    27 #ifndef IN_BUSYBOX
    28 static void ATTRIBUTE_NORETURN show_usage(void)
     10int dumpleases_main(int argc, char **argv);
     11int dumpleases_main(int argc, char **argv)
    2912{
    30     printf(
    31 "Usage: dumpleases -f <file> -[r|a]\n\n"
    32 "  -f, --file=FILENAME             Leases file to load\n"
    33 "  -r, --remaining                 Interepret lease times as time remaining\n"
    34 "  -a, --absolute                  Interepret lease times as expire time\n");
    35     exit(0);
    36 }
    37 #else
    38 #define show_usage bb_show_usage
    39 #endif
    40 
    41 
    42 #ifdef IN_BUSYBOX
    43 int dumpleases_main(int argc, char *argv[])
    44 #else
    45 int main(int argc, char *argv[])
    46 #endif
    47 {
    48     FILE *fp;
    49     int i, c, mode = REMAINING;
    50     long expires;
     13    int fd;
     14    int i;
     15    unsigned opt;
     16    time_t expires;
    5117    const char *file = LEASES_FILE;
    5218    struct dhcpOfferedAddr lease;
    5319    struct in_addr addr;
    5420
    55     static const struct option options[] = {
    56         {"absolute", 0, 0, 'a'},
    57         {"remaining", 0, 0, 'r'},
    58         {"file", 1, 0, 'f'},
    59         {0, 0, 0, 0}
     21    enum {
     22        OPT_a   = 0x1,  // -a
     23        OPT_r   = 0x2,  // -r
     24        OPT_f   = 0x4,  // -f
    6025    };
     26#if ENABLE_GETOPT_LONG
     27    static const char dumpleases_longopts[] ALIGN1 =
     28        "absolute\0"  No_argument       "a"
     29        "remaining\0" No_argument       "r"
     30        "file\0"      Required_argument "f"
     31        ;
    6132
    62     while (1) {
    63         int option_index = 0;
    64         c = getopt_long(argc, argv, "arf:", options, &option_index);
    65         if (c == -1) break;
     33    applet_long_options = dumpleases_longopts;
     34#endif
     35    opt_complementary = "=0:a--r:r--a";
     36    opt = getopt32(argv, "arf:", &file);
    6637
    67         switch (c) {
    68         case 'a': mode = ABSOLUTE; break;
    69         case 'r': mode = REMAINING; break;
    70         case 'f':
    71             file = optarg;
    72             break;
    73         default:
    74             show_usage();
    75         }
    76     }
     38    fd = xopen(file, O_RDONLY);
    7739
    78     fp = xfopen(file, "r");
    79 
    80     printf("Mac Address       IP-Address      Expires %s\n", mode == REMAINING ? "in" : "at");
     40    printf("Mac Address       IP-Address      Expires %s\n", (opt & OPT_a) ? "at" : "in");
    8141    /*     "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
    82     while (fread(&lease, sizeof(lease), 1, fp)) {
    83 
    84         for (i = 0; i < 6; i++) {
    85             printf("%02x", lease.chaddr[i]);
    86             if (i != 5) printf(":");
     42    while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
     43        printf(":%02x"+1, lease.chaddr[0]);
     44        for (i = 1; i < 6; i++) {
     45            printf(":%02x", lease.chaddr[i]);
    8746        }
    8847        addr.s_addr = lease.yiaddr;
    89         printf(" %-15s", inet_ntoa(addr));
     48        printf(" %-15s ", inet_ntoa(addr));
    9049        expires = ntohl(lease.expires);
    91         printf(" ");
    92         if (mode == REMAINING) {
    93             if (!expires) printf("expired\n");
     50        if (!(opt & OPT_a)) { /* no -a */
     51            if (!expires)
     52                puts("expired");
    9453            else {
    95                 if (expires > 60*60*24) {
    96                     printf("%ld days, ", expires / (60*60*24));
    97                     expires %= 60*60*24;
    98                 }
    99                 if (expires > 60*60) {
    100                     printf("%ld hours, ", expires / (60*60));
    101                     expires %= 60*60;
    102                 }
    103                 if (expires > 60) {
    104                     printf("%ld minutes, ", expires / 60);
    105                     expires %= 60;
    106                 }
    107                 printf("%ld seconds\n", expires);
     54                unsigned d, h, m;
     55                d = expires / (24*60*60); expires %= (24*60*60);
     56                h = expires / (60*60); expires %= (60*60);
     57                m = expires / 60; expires %= 60;
     58                if (d) printf("%u days ", d);
     59                printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
    10860            }
    109         } else printf("%s", ctime(&expires));
     61        } else /* -a */
     62            fputs(ctime(&expires), stdout);
    11063    }
    111     fclose(fp);
     64    /* close(fd); */
    11265
    11366    return 0;
  • branches/stable/mindi-busybox/networking/udhcp/files.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * files.c -- DHCP server file manipulation *
     
    45 */
    56
    6 #include <sys/socket.h>
    7 #include <arpa/inet.h>
    8 #include <string.h>
    9 #include <stdlib.h>
    10 #include <time.h>
    11 #include <ctype.h>
    12 #include <netdb.h>
    13 
    147#include <netinet/ether.h>
    15 #include "static_leases.h"
    16 
     8
     9#include "common.h"
    1710#include "dhcpd.h"
    1811#include "options.h"
    19 #include "files.h"
    20 #include "common.h"
     12
     13
     14/* on these functions, make sure your datatype matches */
     15static int read_ip(const char *line, void *arg)
     16{
     17    len_and_sockaddr *lsa;
     18
     19    lsa = host_and_af2sockaddr(line, 0, AF_INET);
     20    if (!lsa)
     21        return 0;
     22    *(uint32_t*)arg = lsa->sin.sin_addr.s_addr;
     23    free(lsa);
     24    return 1;
     25}
     26
     27static int read_mac(const char *line, void *arg)
     28{
     29    uint8_t *mac_bytes = arg;
     30    struct ether_addr *temp_ether_addr;
     31
     32    temp_ether_addr = ether_aton(line);
     33    if (temp_ether_addr == NULL)
     34        return 0;
     35    memcpy(mac_bytes, temp_ether_addr, 6);
     36    return 1;
     37}
     38
     39
     40static int read_str(const char *line, void *arg)
     41{
     42    char **dest = arg;
     43
     44    free(*dest);
     45    *dest = xstrdup(line);
     46    return 1;
     47}
     48
     49
     50static int read_u32(const char *line, void *arg)
     51{
     52    *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
     53    return errno == 0;
     54}
     55
     56
     57static int read_yn(const char *line, void *arg)
     58{
     59    char *dest = arg;
     60
     61    if (!strcasecmp("yes", line)) {
     62        *dest = 1;
     63        return 1;
     64    }
     65    if (!strcasecmp("no", line)) {
     66        *dest = 0;
     67        return 1;
     68    }
     69    return 0;
     70}
     71
     72
     73/* find option 'code' in opt_list */
     74struct option_set *find_option(struct option_set *opt_list, char code)
     75{
     76    while (opt_list && opt_list->data[OPT_CODE] < code)
     77        opt_list = opt_list->next;
     78
     79    if (opt_list && opt_list->data[OPT_CODE] == code)
     80        return opt_list;
     81    return NULL;
     82}
     83
     84
     85/* add an option to the opt_list */
     86static void attach_option(struct option_set **opt_list,
     87        const struct dhcp_option *option, char *buffer, int length)
     88{
     89    struct option_set *existing, *new, **curr;
     90
     91    existing = find_option(*opt_list, option->code);
     92    if (!existing) {
     93        DEBUG("Attaching option %s to list", option->name);
     94
     95#if ENABLE_FEATURE_RFC3397
     96        if ((option->flags & TYPE_MASK) == OPTION_STR1035)
     97            /* reuse buffer and length for RFC1035-formatted string */
     98            buffer = dname_enc(NULL, 0, buffer, &length);
     99#endif
     100
     101        /* make a new option */
     102        new = xmalloc(sizeof(*new));
     103        new->data = xmalloc(length + 2);
     104        new->data[OPT_CODE] = option->code;
     105        new->data[OPT_LEN] = length;
     106        memcpy(new->data + 2, buffer, length);
     107
     108        curr = opt_list;
     109        while (*curr && (*curr)->data[OPT_CODE] < option->code)
     110            curr = &(*curr)->next;
     111
     112        new->next = *curr;
     113        *curr = new;
     114#if ENABLE_FEATURE_RFC3397
     115        if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
     116            free(buffer);
     117#endif
     118        return;
     119    }
     120
     121    /* add it to an existing option */
     122    DEBUG("Attaching option %s to existing member of list", option->name);
     123    if (option->flags & OPTION_LIST) {
     124#if ENABLE_FEATURE_RFC3397
     125        if ((option->flags & TYPE_MASK) == OPTION_STR1035)
     126            /* reuse buffer and length for RFC1035-formatted string */
     127            buffer = dname_enc(existing->data + 2,
     128                    existing->data[OPT_LEN], buffer, &length);
     129#endif
     130        if (existing->data[OPT_LEN] + length <= 255) {
     131            existing->data = xrealloc(existing->data,
     132                    existing->data[OPT_LEN] + length + 3);
     133            if ((option->flags & TYPE_MASK) == OPTION_STRING) {
     134                /* ' ' can bring us to 256 - bad */
     135                if (existing->data[OPT_LEN] + length >= 255)
     136                    return;
     137                /* add space separator between STRING options in a list */
     138                existing->data[existing->data[OPT_LEN] + 2] = ' ';
     139                existing->data[OPT_LEN]++;
     140            }
     141            memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
     142            existing->data[OPT_LEN] += length;
     143        } /* else, ignore the data, we could put this in a second option in the future */
     144#if ENABLE_FEATURE_RFC3397
     145        if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
     146            free(buffer);
     147#endif
     148    } /* else, ignore the new data */
     149}
     150
     151
     152/* read a dhcp option and add it to opt_list */
     153static int read_opt(const char *const_line, void *arg)
     154{
     155    struct option_set **opt_list = arg;
     156    char *opt, *val, *endptr;
     157    const struct dhcp_option *option;
     158    int retval = 0, length;
     159    char buffer[8];
     160    char *line;
     161    uint16_t *result_u16 = (uint16_t *) buffer;
     162    uint32_t *result_u32 = (uint32_t *) buffer;
     163
     164    /* Cheat, the only const line we'll actually get is "" */
     165    line = (char *) const_line;
     166    opt = strtok(line, " \t=");
     167    if (!opt) return 0;
     168
     169    option = dhcp_options;
     170    while (1) {
     171        if (!option->code)
     172            return 0;
     173        if (!strcasecmp(option->name, opt))
     174            break;
     175        option++;
     176    }
     177
     178    do {
     179        val = strtok(NULL, ", \t");
     180        if (!val) break;
     181        length = option_lengths[option->flags & TYPE_MASK];
     182        retval = 0;
     183        opt = buffer; /* new meaning for variable opt */
     184        switch (option->flags & TYPE_MASK) {
     185        case OPTION_IP:
     186            retval = read_ip(val, buffer);
     187            break;
     188        case OPTION_IP_PAIR:
     189            retval = read_ip(val, buffer);
     190            val = strtok(NULL, ", \t/-");
     191            if (!val)
     192                retval = 0;
     193            if (retval)
     194                retval = read_ip(val, buffer + 4);
     195            break;
     196        case OPTION_STRING:
     197#if ENABLE_FEATURE_RFC3397
     198        case OPTION_STR1035:
     199#endif
     200            length = strlen(val);
     201            if (length > 0) {
     202                if (length > 254) length = 254;
     203                opt = val;
     204                retval = 1;
     205            }
     206            break;
     207        case OPTION_BOOLEAN:
     208            retval = read_yn(val, buffer);
     209            break;
     210        case OPTION_U8:
     211            buffer[0] = strtoul(val, &endptr, 0);
     212            retval = (endptr[0] == '\0');
     213            break;
     214        /* htonX are macros in older libc's, using temp var
     215         * in code below for safety */
     216        /* TODO: use bb_strtoX? */
     217        case OPTION_U16: {
     218            unsigned long tmp = strtoul(val, &endptr, 0);
     219            *result_u16 = htons(tmp);
     220            retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/);
     221            break;
     222        }
     223        case OPTION_S16: {
     224            long tmp = strtol(val, &endptr, 0);
     225            *result_u16 = htons(tmp);
     226            retval = (endptr[0] == '\0');
     227            break;
     228        }
     229        case OPTION_U32: {
     230            unsigned long tmp = strtoul(val, &endptr, 0);
     231            *result_u32 = htonl(tmp);
     232            retval = (endptr[0] == '\0');
     233            break;
     234        }
     235        case OPTION_S32: {
     236            long tmp = strtol(val, &endptr, 0);
     237            *result_u32 = htonl(tmp);
     238            retval = (endptr[0] == '\0');
     239            break;
     240        }
     241        default:
     242            break;
     243        }
     244        if (retval)
     245            attach_option(opt_list, option, opt, length);
     246    } while (retval && option->flags & OPTION_LIST);
     247    return retval;
     248}
     249
     250static int read_staticlease(const char *const_line, void *arg)
     251{
     252    char *line;
     253    char *mac_string;
     254    char *ip_string;
     255    uint8_t *mac_bytes;
     256    uint32_t *ip;
     257
     258    /* Allocate memory for addresses */
     259    mac_bytes = xmalloc(sizeof(unsigned char) * 8);
     260    ip = xmalloc(sizeof(uint32_t));
     261
     262    /* Read mac */
     263    line = (char *) const_line;
     264    mac_string = strtok(line, " \t");
     265    read_mac(mac_string, mac_bytes);
     266
     267    /* Read ip */
     268    ip_string = strtok(NULL, " \t");
     269    read_ip(ip_string, ip);
     270
     271    addStaticLease(arg, mac_bytes, ip);
     272
     273    if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg);
     274
     275    return 1;
     276}
     277
     278
     279struct config_keyword {
     280    const char *keyword;
     281    int (*handler)(const char *line, void *var);
     282    void *var;
     283    const char *def;
     284};
     285
     286static const struct config_keyword keywords[] = {
     287    /* keyword       handler   variable address               default */
     288    {"start",        read_ip,  &(server_config.start_ip),     "192.168.0.20"},
     289    {"end",          read_ip,  &(server_config.end_ip),       "192.168.0.254"},
     290    {"interface",    read_str, &(server_config.interface),    "eth0"},
     291    {"option",       read_opt, &(server_config.options),      ""},
     292    {"opt",          read_opt, &(server_config.options),      ""},
     293    /* Avoid "max_leases value not sane" warning by setting default
     294     * to default_end_ip - default_start_ip + 1: */
     295    {"max_leases",   read_u32, &(server_config.max_leases),   "235"},
     296    {"remaining",    read_yn,  &(server_config.remaining),    "yes"},
     297    {"auto_time",    read_u32, &(server_config.auto_time),    "7200"},
     298    {"decline_time", read_u32, &(server_config.decline_time), "3600"},
     299    {"conflict_time",read_u32, &(server_config.conflict_time),"3600"},
     300    {"offer_time",   read_u32, &(server_config.offer_time),   "60"},
     301    {"min_lease",    read_u32, &(server_config.min_lease),    "60"},
     302    {"lease_file",   read_str, &(server_config.lease_file),   LEASES_FILE},
     303    {"pidfile",      read_str, &(server_config.pidfile),      "/var/run/udhcpd.pid"},
     304    {"notify_file",  read_str, &(server_config.notify_file),  ""},
     305    {"siaddr",       read_ip,  &(server_config.siaddr),       "0.0.0.0"},
     306    {"sname",        read_str, &(server_config.sname),        ""},
     307    {"boot_file",    read_str, &(server_config.boot_file),    ""},
     308    {"static_lease", read_staticlease, &(server_config.static_leases), ""},
     309    /* ADDME: static lease */
     310};
     311
    21312
    22313/*
     
    27318#define READ_CONFIG_BUF_SIZE 80
    28319
    29 /* on these functions, make sure you datatype matches */
    30 static int read_ip(const char *line, void *arg)
    31 {
    32     struct in_addr *addr = arg;
    33     struct hostent *host;
    34     int retval = 1;
    35 
    36     if (!inet_aton(line, addr)) {
    37         if ((host = gethostbyname(line)))
    38             addr->s_addr = *((unsigned long *) host->h_addr_list[0]);
    39         else retval = 0;
    40     }
    41     return retval;
    42 }
    43 
    44 static int read_mac(const char *line, void *arg)
    45 {
    46     uint8_t *mac_bytes = arg;
    47     struct ether_addr *temp_ether_addr;
    48     int retval = 1;
    49 
    50     temp_ether_addr = ether_aton(line);
    51 
    52     if(temp_ether_addr == NULL)
    53         retval = 0;
    54     else
    55         memcpy(mac_bytes, temp_ether_addr, 6);
    56 
    57     return retval;
    58 }
    59 
    60 
    61 static int read_str(const char *line, void *arg)
    62 {
    63     char **dest = arg;
    64 
    65     free(*dest);
    66     *dest = strdup(line);
    67 
    68     return 1;
    69 }
    70 
    71 
    72 static int read_u32(const char *line, void *arg)
    73 {
    74     uint32_t *dest = arg;
    75     char *endptr;
    76     *dest = strtoul(line, &endptr, 0);
    77     return endptr[0] == '\0';
    78 }
    79 
    80 
    81 static int read_yn(const char *line, void *arg)
    82 {
    83     char *dest = arg;
    84     int retval = 1;
    85 
    86     if (!strcasecmp("yes", line))
    87         *dest = 1;
    88     else if (!strcasecmp("no", line))
    89         *dest = 0;
    90     else retval = 0;
    91 
    92     return retval;
    93 }
    94 
    95 
    96 /* find option 'code' in opt_list */
    97 struct option_set *find_option(struct option_set *opt_list, char code)
    98 {
    99     while (opt_list && opt_list->data[OPT_CODE] < code)
    100         opt_list = opt_list->next;
    101 
    102     if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;
    103     else return NULL;
    104 }
    105 
    106 
    107 /* add an option to the opt_list */
    108 static void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)
    109 {
    110     struct option_set *existing, *new, **curr;
    111 
    112     /* add it to an existing option */
    113     if ((existing = find_option(*opt_list, option->code))) {
    114         DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);
    115         if (option->flags & OPTION_LIST) {
    116             if (existing->data[OPT_LEN] + length <= 255) {
    117                 existing->data = realloc(existing->data,
    118                         existing->data[OPT_LEN] + length + 2);
    119                 memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
    120                 existing->data[OPT_LEN] += length;
    121             } /* else, ignore the data, we could put this in a second option in the future */
    122         } /* else, ignore the new data */
    123     } else {
    124         DEBUG(LOG_INFO, "Attaching option %s to list", option->name);
    125 
    126         /* make a new option */
    127         new = xmalloc(sizeof(struct option_set));
    128         new->data = xmalloc(length + 2);
    129         new->data[OPT_CODE] = option->code;
    130         new->data[OPT_LEN] = length;
    131         memcpy(new->data + 2, buffer, length);
    132 
    133         curr = opt_list;
    134         while (*curr && (*curr)->data[OPT_CODE] < option->code)
    135             curr = &(*curr)->next;
    136 
    137         new->next = *curr;
    138         *curr = new;
    139     }
    140 }
    141 
    142 
    143 /* read a dhcp option and add it to opt_list */
    144 static int read_opt(const char *const_line, void *arg)
    145 {
    146     struct option_set **opt_list = arg;
    147     char *opt, *val, *endptr;
    148     struct dhcp_option *option;
    149     int retval = 0, length;
    150     char buffer[8];
    151     char *line;
    152     uint16_t *result_u16 = (uint16_t *) buffer;
    153     uint32_t *result_u32 = (uint32_t *) buffer;
    154 
    155     /* Cheat, the only const line we'll actually get is "" */
    156     line = (char *) const_line;
    157     if (!(opt = strtok(line, " \t="))) return 0;
    158 
    159     for (option = dhcp_options; option->code; option++)
    160         if (!strcasecmp(option->name, opt))
    161             break;
    162 
    163     if (!option->code) return 0;
    164 
    165     do {
    166         if (!(val = strtok(NULL, ", \t"))) break;
    167         length = option_lengths[option->flags & TYPE_MASK];
    168         retval = 0;
    169         opt = buffer; /* new meaning for variable opt */
    170         switch (option->flags & TYPE_MASK) {
    171         case OPTION_IP:
    172             retval = read_ip(val, buffer);
    173             break;
    174         case OPTION_IP_PAIR:
    175             retval = read_ip(val, buffer);
    176             if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
    177             if (retval) retval = read_ip(val, buffer + 4);
    178             break;
    179         case OPTION_STRING:
    180             length = strlen(val);
    181             if (length > 0) {
    182                 if (length > 254) length = 254;
    183                 opt = val;
    184                 retval = 1;
    185             }
    186             break;
    187         case OPTION_BOOLEAN:
    188             retval = read_yn(val, buffer);
    189             break;
    190         case OPTION_U8:
    191             buffer[0] = strtoul(val, &endptr, 0);
    192             retval = (endptr[0] == '\0');
    193             break;
    194         case OPTION_U16:
    195             *result_u16 = htons(strtoul(val, &endptr, 0));
    196             retval = (endptr[0] == '\0');
    197             break;
    198         case OPTION_S16:
    199             *result_u16 = htons(strtol(val, &endptr, 0));
    200             retval = (endptr[0] == '\0');
    201             break;
    202         case OPTION_U32:
    203             *result_u32 = htonl(strtoul(val, &endptr, 0));
    204             retval = (endptr[0] == '\0');
    205             break;
    206         case OPTION_S32:
    207             *result_u32 = htonl(strtol(val, &endptr, 0));
    208             retval = (endptr[0] == '\0');
    209             break;
    210         default:
    211             break;
    212         }
    213         if (retval)
    214             attach_option(opt_list, option, opt, length);
    215     } while (retval && option->flags & OPTION_LIST);
    216     return retval;
    217 }
    218 
    219 static int read_staticlease(const char *const_line, void *arg)
    220 {
    221 
    222     char *line;
    223     char *mac_string;
    224     char *ip_string;
    225     uint8_t *mac_bytes;
    226     uint32_t *ip;
    227 
    228 
    229     /* Allocate memory for addresses */
    230     mac_bytes = xmalloc(sizeof(unsigned char) * 8);
    231     ip = xmalloc(sizeof(uint32_t));
    232 
    233     /* Read mac */
    234     line = (char *) const_line;
    235     mac_string = strtok(line, " \t");
    236     read_mac(mac_string, mac_bytes);
    237 
    238     /* Read ip */
    239     ip_string = strtok(NULL, " \t");
    240     read_ip(ip_string, ip);
    241 
    242     addStaticLease(arg, mac_bytes, ip);
    243 
    244     if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg);
    245 
    246     return 1;
    247 
    248 }
    249 
    250 
    251 static const struct config_keyword keywords[] = {
    252     /* keyword  handler   variable address      default */
    253     {"start",   read_ip,  &(server_config.start),   "192.168.0.20"},
    254     {"end",     read_ip,  &(server_config.end),     "192.168.0.254"},
    255     {"interface",   read_str, &(server_config.interface),   "eth0"},
    256     {"option",  read_opt, &(server_config.options), ""},
    257     {"opt",     read_opt, &(server_config.options), ""},
    258     {"max_leases",  read_u32, &(server_config.max_leases),  "254"},
    259     {"remaining",   read_yn,  &(server_config.remaining),   "yes"},
    260     {"auto_time",   read_u32, &(server_config.auto_time),   "7200"},
    261     {"decline_time",read_u32, &(server_config.decline_time),"3600"},
    262     {"conflict_time",read_u32,&(server_config.conflict_time),"3600"},
    263     {"offer_time",  read_u32, &(server_config.offer_time),  "60"},
    264     {"min_lease",   read_u32, &(server_config.min_lease),   "60"},
    265     {"lease_file",  read_str, &(server_config.lease_file),  LEASES_FILE},
    266     {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"},
    267     {"notify_file", read_str, &(server_config.notify_file), ""},
    268     {"siaddr",  read_ip,  &(server_config.siaddr),  "0.0.0.0"},
    269     {"sname",   read_str, &(server_config.sname),   ""},
    270     {"boot_file",   read_str, &(server_config.boot_file),   ""},
    271     {"static_lease",read_staticlease, &(server_config.static_leases),   ""},
    272     /*ADDME: static lease */
    273     {"",        NULL,     NULL,             ""}
    274 };
    275 
    276 
    277320int read_config(const char *file)
    278321{
     
    281324    int i, lm = 0;
    282325
    283     for (i = 0; keywords[i].keyword[0]; i++)
     326    for (i = 0; i < ARRAY_SIZE(keywords); i++)
    284327        if (keywords[i].def[0])
    285328            keywords[i].handler(keywords[i].def, keywords[i].var);
    286329
    287     if (!(in = fopen(file, "r"))) {
    288         LOG(LOG_ERR, "unable to open config file: %s", file);
     330    in = fopen_or_warn(file, "r");
     331    if (!in) {
    289332        return 0;
    290333    }
     
    292335    while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
    293336        char debug_orig[READ_CONFIG_BUF_SIZE];
     337        char *p;
    294338
    295339        lm++;
    296         if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
     340        p = strchr(buffer, '\n');
     341        if (p) *p = '\0';
    297342        if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer);
    298         if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0';
     343        p = strchr(buffer, '#');
     344        if (p) *p = '\0';
    299345
    300346        if (!(token = strtok(buffer, " \t"))) continue;
     
    302348
    303349        /* eat leading whitespace */
    304         line = line + strspn(line, " \t=");
     350        line = skip_whitespace(line);
    305351        /* eat trailing whitespace */
    306         for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--);
    307         line[i] = '\0';
    308 
    309         for (i = 0; keywords[i].keyword[0]; i++)
     352        i = strlen(line) - 1;
     353        while (i >= 0 && isspace(line[i]))
     354            line[i--] = '\0';
     355
     356        for (i = 0; i < ARRAY_SIZE(keywords); i++)
    310357            if (!strcasecmp(token, keywords[i].keyword))
    311358                if (!keywords[i].handler(line, keywords[i].var)) {
    312                     LOG(LOG_ERR, "Failure parsing line %d of %s", lm, file);
    313                     DEBUG(LOG_ERR, "unable to parse '%s'", debug_orig);
     359                    bb_error_msg("cannot parse line %d of %s", lm, file);
     360                    if (ENABLE_FEATURE_UDHCP_DEBUG)
     361                        bb_error_msg("cannot parse '%s'", debug_orig);
    314362                    /* reset back to the default value */
    315363                    keywords[i].handler(keywords[i].def, keywords[i].var);
     
    317365    }
    318366    fclose(in);
     367
     368    server_config.start_ip = ntohl(server_config.start_ip);
     369    server_config.end_ip = ntohl(server_config.end_ip);
     370
    319371    return 1;
    320372}
     
    323375void write_leases(void)
    324376{
    325     FILE *fp;
    326     unsigned int i;
    327     char buf[255];
     377    int fp;
     378    unsigned i;
    328379    time_t curr = time(0);
    329380    unsigned long tmp_time;
    330381
    331     if (!(fp = fopen(server_config.lease_file, "w"))) {
    332         LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
     382    fp = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
     383    if (fp < 0) {
    333384        return;
    334385    }
     
    346397            } /* else stick with the time we got */
    347398            leases[i].expires = htonl(leases[i].expires);
    348             fwrite(&leases[i], sizeof(struct dhcpOfferedAddr), 1, fp);
    349 
    350             /* Then restore it when done. */
     399            // FIXME: error check??
     400            full_write(fp, &leases[i], sizeof(leases[i]));
     401
     402            /* then restore it when done */
    351403            leases[i].expires = tmp_time;
    352404        }
    353405    }
    354     fclose(fp);
     406    close(fp);
    355407
    356408    if (server_config.notify_file) {
    357         sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file);
    358         system(buf);
     409        char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file);
     410        system(cmd);
     411        free(cmd);
    359412    }
    360413}
     
    363416void read_leases(const char *file)
    364417{
    365     FILE *fp;
     418    int fp;
    366419    unsigned int i = 0;
    367420    struct dhcpOfferedAddr lease;
    368421
    369     if (!(fp = fopen(file, "r"))) {
    370         LOG(LOG_ERR, "Unable to open %s for reading", file);
     422    fp = open_or_warn(file, O_RDONLY);
     423    if (fp < 0) {
    371424        return;
    372425    }
    373426
    374     while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) {
     427    while (i < server_config.max_leases
     428     && full_read(fp, &lease, sizeof(lease)) == sizeof(lease)
     429    ) {
    375430        /* ADDME: is it a static lease */
    376         if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) {
     431        uint32_t y = ntohl(lease.yiaddr);
     432        if (y >= server_config.start_ip && y <= server_config.end_ip) {
    377433            lease.expires = ntohl(lease.expires);
    378             if (!server_config.remaining) lease.expires -= time(0);
     434            if (!server_config.remaining)
     435                lease.expires -= time(0);
    379436            if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
    380                 LOG(LOG_WARNING, "Too many leases while loading %s\n", file);
     437                bb_error_msg("too many leases while loading %s", file);
    381438                break;
    382439            }
     
    384441        }
    385442    }
    386     DEBUG(LOG_INFO, "Read %d leases", i);
    387     fclose(fp);
    388 }
     443    DEBUG("Read %d leases", i);
     444    close(fp);
     445}
  • branches/stable/mindi-busybox/networking/udhcp/leases.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * leases.c -- tools to manage DHCP leases
     
    45 */
    56
    6 #include <time.h>
    7 #include <string.h>
    8 #include <sys/socket.h>
    9 #include <netinet/in.h>
    10 #include <arpa/inet.h>
    11 
     7#include "common.h"
    128#include "dhcpd.h"
    13 #include "files.h"
    14 #include "options.h"
    15 #include "leases.h"
    16 #include "arpping.h"
    17 #include "common.h"
    18 
    19 #include "static_leases.h"
    209
    2110
    22 uint8_t blank_chaddr[] = {[0 ... 15] = 0};
     11/* Find the oldest expired lease, NULL if there are no expired leases */
     12static struct dhcpOfferedAddr *oldest_expired_lease(void)
     13{
     14    struct dhcpOfferedAddr *oldest = NULL;
     15// TODO: use monotonic_sec()
     16    unsigned long oldest_lease = time(0);
     17    unsigned i;
     18
     19    for (i = 0; i < server_config.max_leases; i++)
     20        if (oldest_lease > leases[i].expires) {
     21            oldest_lease = leases[i].expires;
     22            oldest = &(leases[i]);
     23        }
     24    return oldest;
     25}
     26
    2327
    2428/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
    25 void clear_lease(uint8_t *chaddr, uint32_t yiaddr)
     29static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
    2630{
    27     unsigned int i, j;
     31    unsigned i, j;
    2832
    29     for (j = 0; j < 16 && !chaddr[j]; j++);
     33    for (j = 0; j < 16 && !chaddr[j]; j++)
     34        continue;
    3035
    3136    for (i = 0; i < server_config.max_leases; i++)
    32         if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) ||
    33             (yiaddr && leases[i].yiaddr == yiaddr)) {
    34             memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
     37        if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0)
     38         || (yiaddr && leases[i].yiaddr == yiaddr)
     39        ) {
     40            memset(&(leases[i]), 0, sizeof(leases[i]));
    3541        }
    3642}
     
    3844
    3945/* add a lease into the table, clearing out any old ones */
    40 struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
     46struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
    4147{
    4248    struct dhcpOfferedAddr *oldest;
     
    6470
    6571
    66 /* Find the oldest expired lease, NULL if there are no expired leases */
    67 struct dhcpOfferedAddr *oldest_expired_lease(void)
     72/* Find the first lease that matches chaddr, NULL if no match */
     73struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr)
    6874{
    69     struct dhcpOfferedAddr *oldest = NULL;
    70     unsigned long oldest_lease = time(0);
    71     unsigned int i;
    72 
     75    unsigned i;
    7376
    7477    for (i = 0; i < server_config.max_leases; i++)
    75         if (oldest_lease > leases[i].expires) {
    76             oldest_lease = leases[i].expires;
    77             oldest = &(leases[i]);
    78         }
    79     return oldest;
    80 
    81 }
    82 
    83 
    84 /* Find the first lease that matches chaddr, NULL if no match */
    85 struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr)
    86 {
    87     unsigned int i;
    88 
    89     for (i = 0; i < server_config.max_leases; i++)
    90         if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
     78        if (!memcmp(leases[i].chaddr, chaddr, 16))
     79            return &(leases[i]);
    9180
    9281    return NULL;
     
    9786struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr)
    9887{
    99     unsigned int i;
     88    unsigned i;
    10089
    10190    for (i = 0; i < server_config.max_leases; i++)
    102         if (leases[i].yiaddr == yiaddr) return &(leases[i]);
     91        if (leases[i].yiaddr == yiaddr)
     92            return &(leases[i]);
    10393
    10494    return NULL;
     
    10797
    10898/* check is an IP is taken, if it is, add it to the lease table */
    109 static int check_ip(uint32_t addr)
     99static int nobody_responds_to_arp(uint32_t addr)
    110100{
     101    static const uint8_t blank_chaddr[16]; /* 16 zero bytes */
     102
    111103    struct in_addr temp;
     104    int r;
    112105
    113     if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) {
    114         temp.s_addr = addr;
    115         LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
    116             inet_ntoa(temp), server_config.conflict_time);
    117         add_lease(blank_chaddr, addr, server_config.conflict_time);
    118         return 1;
    119     } else return 0;
     106    r = arpping(addr, server_config.server, server_config.arp, server_config.interface);
     107    if (r)
     108        return r;
     109
     110    temp.s_addr = addr;
     111    bb_info_msg("%s belongs to someone, reserving it for %u seconds",
     112        inet_ntoa(temp), (unsigned)server_config.conflict_time);
     113    add_lease(blank_chaddr, addr, server_config.conflict_time);
     114    return 0;
    120115}
    121116
    122117
    123 /* find an assignable address, it check_expired is true, we check all the expired leases as well.
     118/* find an assignable address, if check_expired is true, we check all the expired leases as well.
    124119 * Maybe this should try expired leases by age... */
    125120uint32_t find_address(int check_expired)
     
    128123    struct dhcpOfferedAddr *lease = NULL;
    129124
    130     addr = ntohl(server_config.start); /* addr is in host order here */
    131     for (;addr <= ntohl(server_config.end); addr++) {
    132 
     125    addr = server_config.start_ip; /* addr is in host order here */
     126    for (; addr <= server_config.end_ip; addr++) {
    133127        /* ie, 192.168.55.0 */
    134         if (!(addr & 0xFF)) continue;
    135 
     128        if (!(addr & 0xFF))
     129            continue;
    136130        /* ie, 192.168.55.255 */
    137         if ((addr & 0xFF) == 0xFF) continue;
    138 
    139         /* Only do if it isn't an assigned as a static lease */
    140         if(!reservedIp(server_config.static_leases, htonl(addr)))
    141         {
    142 
    143         /* lease is not taken */
     131        if ((addr & 0xFF) == 0xFF)
     132            continue;
     133        /* Only do if it isn't assigned as a static lease */
    144134        ret = htonl(addr);
    145         if ((!(lease = find_lease_by_yiaddr(ret)) ||
    146 
    147              /* or it expired and we are checking for expired leases */
    148              (check_expired  && lease_expired(lease))) &&
    149 
    150              /* and it isn't on the network */
    151              !check_ip(ret)) {
    152             return ret;
    153             break;
     135        if (!reservedIp(server_config.static_leases, ret)) {
     136            /* lease is not taken */
     137            lease = find_lease_by_yiaddr(ret);
     138            /* no lease or it expired and we are checking for expired leases */
     139            if ((!lease || (check_expired && lease_expired(lease)))
     140             && nobody_responds_to_arp(ret) /* it isn't used on the network */
     141            ) {
     142                return ret;
     143            }
    154144        }
    155     }
    156145    }
    157146    return 0;
  • branches/stable/mindi-busybox/networking/udhcp/options.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * options.c -- DHCP server option packet tools
     
    45 */
    56
    6 #include <stdlib.h>
    7 #include <string.h>
    8 
    97#include "common.h"
    108#include "dhcpd.h"
    119#include "options.h"
    12 #include "files.h"
    1310
    1411
    1512/* supported options are easily added here */
    16 struct dhcp_option dhcp_options[] = {
    17     /* name[10] flags                   code */
    18     {"subnet",  OPTION_IP | OPTION_REQ,         0x01},
    19     {"timezone",    OPTION_S32,             0x02},
    20     {"router",  OPTION_IP | OPTION_LIST | OPTION_REQ,   0x03},
    21     {"timesvr", OPTION_IP | OPTION_LIST,        0x04},
    22     {"namesvr", OPTION_IP | OPTION_LIST,        0x05},
    23     {"dns",     OPTION_IP | OPTION_LIST | OPTION_REQ,   0x06},
    24     {"logsvr",  OPTION_IP | OPTION_LIST,        0x07},
    25     {"cookiesvr",   OPTION_IP | OPTION_LIST,        0x08},
    26     {"lprsvr",  OPTION_IP | OPTION_LIST,        0x09},
    27     {"hostname",    OPTION_STRING | OPTION_REQ,     0x0c},
    28     {"bootsize",    OPTION_U16,             0x0d},
    29     {"domain",  OPTION_STRING | OPTION_REQ,     0x0f},
    30     {"swapsvr", OPTION_IP,              0x10},
    31     {"rootpath",    OPTION_STRING,              0x11},
    32     {"ipttl",   OPTION_U8,              0x17},
    33     {"mtu",     OPTION_U16,             0x1a},
    34     {"broadcast",   OPTION_IP | OPTION_REQ,         0x1c},
    35     {"nisdomain",   OPTION_STRING | OPTION_REQ,     0x28},
    36     {"nissrv",  OPTION_IP | OPTION_LIST | OPTION_REQ,   0x29},
    37     {"ntpsrv",  OPTION_IP | OPTION_LIST | OPTION_REQ,   0x2a},
    38     {"wins",    OPTION_IP | OPTION_LIST,        0x2c},
    39     {"requestip",   OPTION_IP,              0x32},
    40     {"lease",   OPTION_U32,             0x33},
    41     {"dhcptype",    OPTION_U8,              0x35},
    42     {"serverid",    OPTION_IP,              0x36},
    43     {"message", OPTION_STRING,              0x38},
    44     {"tftp",    OPTION_STRING,              0x42},
    45     {"bootfile",    OPTION_STRING,              0x43},
    46     {"",        0x00,               0x00}
     13const struct dhcp_option dhcp_options[] = {
     14    /* name[12]     flags                                   code */
     15    {"subnet",      OPTION_IP | OPTION_REQ,                 0x01},
     16    {"timezone",    OPTION_S32,                             0x02},
     17    {"router",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x03},
     18    {"timesvr",     OPTION_IP | OPTION_LIST,                0x04},
     19    {"namesvr",     OPTION_IP | OPTION_LIST,                0x05},
     20    {"dns",         OPTION_IP | OPTION_LIST | OPTION_REQ,   0x06},
     21    {"logsvr",      OPTION_IP | OPTION_LIST,                0x07},
     22    {"cookiesvr",   OPTION_IP | OPTION_LIST,                0x08},
     23    {"lprsvr",      OPTION_IP | OPTION_LIST,                0x09},
     24    {"hostname",    OPTION_STRING | OPTION_REQ,             0x0c},
     25    {"bootsize",    OPTION_U16,                             0x0d},
     26    {"domain",      OPTION_STRING | OPTION_LIST | OPTION_REQ, 0x0f},
     27    {"swapsvr",     OPTION_IP,                              0x10},
     28    {"rootpath",    OPTION_STRING,                          0x11},
     29    {"ipttl",       OPTION_U8,                              0x17},
     30    {"mtu",         OPTION_U16,                             0x1a},
     31    {"broadcast",   OPTION_IP | OPTION_REQ,                 0x1c},
     32    {"nisdomain",   OPTION_STRING | OPTION_REQ,             0x28},
     33    {"nissrv",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x29},
     34    {"ntpsrv",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x2a},
     35    {"wins",        OPTION_IP | OPTION_LIST,                0x2c},
     36    {"requestip",   OPTION_IP,                              0x32},
     37    {"lease",       OPTION_U32,                             0x33},
     38    {"dhcptype",    OPTION_U8,                              0x35},
     39    {"serverid",    OPTION_IP,                              0x36},
     40    {"message",     OPTION_STRING,                          0x38},
     41    {"vendorclass", OPTION_STRING,                          0x3C},
     42    {"clientid",    OPTION_STRING,                          0x3D},
     43    {"tftp",        OPTION_STRING,                          0x42},
     44    {"bootfile",    OPTION_STRING,                          0x43},
     45    {"userclass",   OPTION_STRING,                          0x4D},
     46#if ENABLE_FEATURE_RFC3397
     47    {"search",      OPTION_STR1035 | OPTION_LIST | OPTION_REQ, 0x77},
     48#endif
     49    /* MSIE's "Web Proxy Autodiscovery Protocol" support */
     50    {"wpad",        OPTION_STRING,                          0xfc},
     51    {"",            0x00,                                   0x00}
    4752};
    4853
    4954/* Lengths of the different option types */
    50 int option_lengths[] = {
    51     [OPTION_IP] =       4,
    52     [OPTION_IP_PAIR] =  8,
    53     [OPTION_BOOLEAN] =  1,
    54     [OPTION_STRING] =   1,
    55     [OPTION_U8] =       1,
    56     [OPTION_U16] =      2,
    57     [OPTION_S16] =      2,
    58     [OPTION_U32] =      4,
    59     [OPTION_S32] =      4
     55const unsigned char option_lengths[] ALIGN1 = {
     56    [OPTION_IP] =      4,
     57    [OPTION_IP_PAIR] = 8,
     58    [OPTION_BOOLEAN] = 1,
     59    [OPTION_STRING] =  1,
     60#if ENABLE_FEATURE_RFC3397
     61    [OPTION_STR1035] = 1,
     62#endif
     63    [OPTION_U8] =      1,
     64    [OPTION_U16] =     2,
     65    [OPTION_S16] =     2,
     66    [OPTION_U32] =     4,
     67    [OPTION_S32] =     4
    6068};
    6169
     
    7381    while (!done) {
    7482        if (i >= length) {
    75             LOG(LOG_WARNING, "bogus packet, option fields too long.");
     83            bb_error_msg("bogus packet, option fields too long");
    7684            return NULL;
    7785        }
    7886        if (optionptr[i + OPT_CODE] == code) {
    7987            if (i + 1 + optionptr[i + OPT_LEN] >= length) {
    80                 LOG(LOG_WARNING, "bogus packet, option fields too long.");
     88                bb_error_msg("bogus packet, option fields too long");
    8189                return NULL;
    8290            }
     
    8997        case DHCP_OPTION_OVER:
    9098            if (i + 1 + optionptr[i + OPT_LEN] >= length) {
    91                 LOG(LOG_WARNING, "bogus packet, option fields too long.");
     99                bb_error_msg("bogus packet, option fields too long");
    92100                return NULL;
    93101            }
     
    137145    /* end position + string length + option code/length + end option */
    138146    if (end + string[OPT_LEN] + 2 + 1 >= 308) {
    139         LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]);
     147        bb_error_msg("option 0x%02x did not fit into the packet",
     148                string[OPT_CODE]);
    140149        return 0;
    141150    }
    142     DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]);
     151    DEBUG("adding option 0x%02x", string[OPT_CODE]);
    143152    memcpy(optionptr + end, string, string[OPT_LEN] + 2);
    144153    optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
     
    150159int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data)
    151160{
    152     struct dhcp_option *dh;
     161    const struct dhcp_option *dh;
    153162
    154     for (dh=dhcp_options; dh->code; dh++) {
     163    for (dh = dhcp_options; dh->code; dh++) {
    155164        if (dh->code == code) {
    156165            uint8_t option[6], len;
     
    167176    }
    168177
    169     DEBUG(LOG_ERR, "Could not add option 0x%02x", code);
     178    bb_error_msg("cannot add option 0x%02x", code);
    170179    return 0;
    171180}
  • branches/stable/mindi-busybox/networking/udhcp/options.h

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* options.h */
    23#ifndef _OPTIONS_H
    34#define _OPTIONS_H
    4 
    5 #include "packet.h"
    65
    76#define TYPE_MASK   0x0F
     
    1110    OPTION_IP_PAIR,
    1211    OPTION_STRING,
     12#if ENABLE_FEATURE_RFC3397
     13    OPTION_STR1035, /* RFC1035 compressed domain name list */
     14#endif
    1315    OPTION_BOOLEAN,
    1416    OPTION_U8,
     
    2224#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */
    2325
     26/*****************************************************************/
     27/* Do not modify below here unless you know what you are doing!! */
     28/*****************************************************************/
     29
     30/* DHCP protocol -- see RFC 2131 */
     31#define SERVER_PORT     67
     32#define CLIENT_PORT     68
     33
     34#define DHCP_MAGIC      0x63825363
     35
     36/* DHCP option codes (partial list) */
     37#define DHCP_PADDING        0x00
     38#define DHCP_SUBNET     0x01
     39#define DHCP_TIME_OFFSET    0x02
     40#define DHCP_ROUTER     0x03
     41#define DHCP_TIME_SERVER    0x04
     42#define DHCP_NAME_SERVER    0x05
     43#define DHCP_DNS_SERVER     0x06
     44#define DHCP_LOG_SERVER     0x07
     45#define DHCP_COOKIE_SERVER  0x08
     46#define DHCP_LPR_SERVER     0x09
     47#define DHCP_HOST_NAME      0x0c
     48#define DHCP_BOOT_SIZE      0x0d
     49#define DHCP_DOMAIN_NAME    0x0f
     50#define DHCP_SWAP_SERVER    0x10
     51#define DHCP_ROOT_PATH      0x11
     52#define DHCP_IP_TTL     0x17
     53#define DHCP_MTU        0x1a
     54#define DHCP_BROADCAST      0x1c
     55#define DHCP_NTP_SERVER     0x2a
     56#define DHCP_WINS_SERVER    0x2c
     57#define DHCP_REQUESTED_IP   0x32
     58#define DHCP_LEASE_TIME     0x33
     59#define DHCP_OPTION_OVER    0x34
     60#define DHCP_MESSAGE_TYPE   0x35
     61#define DHCP_SERVER_ID      0x36
     62#define DHCP_PARAM_REQ      0x37
     63#define DHCP_MESSAGE        0x38
     64#define DHCP_MAX_SIZE       0x39
     65#define DHCP_T1         0x3a
     66#define DHCP_T2         0x3b
     67#define DHCP_VENDOR     0x3c
     68#define DHCP_CLIENT_ID      0x3d
     69#define DHCP_FQDN       0x51
     70
     71#define DHCP_END        0xFF
     72
     73
     74#define BOOTREQUEST     1
     75#define BOOTREPLY       2
     76
     77#define ETH_10MB        1
     78#define ETH_10MB_LEN        6
     79
     80#define DHCPDISCOVER        1
     81#define DHCPOFFER       2
     82#define DHCPREQUEST     3
     83#define DHCPDECLINE     4
     84#define DHCPACK         5
     85#define DHCPNAK         6
     86#define DHCPRELEASE     7
     87#define DHCPINFORM      8
     88
     89#define BROADCAST_FLAG      0x8000
     90
     91#define OPTION_FIELD        0
     92#define FILE_FIELD      1
     93#define SNAME_FIELD     2
     94
     95/* miscellaneous defines */
     96#define OPT_CODE 0
     97#define OPT_LEN 1
     98#define OPT_DATA 2
     99
    24100struct dhcp_option {
    25     char name[10];
     101    char name[12];
    26102    char flags;
    27103    uint8_t code;
    28104};
    29105
    30 extern struct dhcp_option dhcp_options[];
    31 extern int option_lengths[];
     106extern const struct dhcp_option dhcp_options[];
     107extern const unsigned char option_lengths[];
    32108
    33109uint8_t *get_option(struct dhcpMessage *packet, int code);
     
    35111int add_option_string(uint8_t *optionptr, uint8_t *string);
    36112int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data);
     113#if ENABLE_FEATURE_RFC3397
     114char *dname_dec(const uint8_t *cstr, int clen, const char *pre);
     115uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen);
     116#endif
    37117
    38118#endif
  • branches/stable/mindi-busybox/networking/udhcp/packet.c

    r821 r1770  
    1 #include <unistd.h>
    2 #include <string.h>
     1/* vi: set sw=4 ts=4: */
     2
    33#include <netinet/in.h>
    4 #include <sys/types.h>
    5 #include <sys/socket.h>
    6 #include <features.h>
    7 #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION
     4#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    85#include <netpacket/packet.h>
    96#include <net/ethernet.h>
     
    1310#include <linux/if_ether.h>
    1411#endif
    15 #include <errno.h>
    1612
    1713#include "common.h"
    18 #include "packet.h"
    1914#include "dhcpd.h"
    2015#include "options.h"
     
    4742int udhcp_get_packet(struct dhcpMessage *packet, int fd)
    4843{
     44#if 0
    4945    static const char broken_vendors[][8] = {
    5046        "MSFT 98",
    5147        ""
    5248    };
     49#endif
    5350    int bytes;
    54     int i;
    55     char unsigned *vendor;
    56 
    57     memset(packet, 0, sizeof(struct dhcpMessage));
    58     bytes = read(fd, packet, sizeof(struct dhcpMessage));
     51    unsigned char *vendor;
     52
     53    memset(packet, 0, sizeof(*packet));
     54    bytes = read(fd, packet, sizeof(*packet));
    5955    if (bytes < 0) {
    60         DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring");
     56        DEBUG("cannot read on listening socket, ignoring");
    6157        return -1;
    6258    }
    6359
    6460    if (ntohl(packet->cookie) != DHCP_MAGIC) {
    65         LOG(LOG_ERR, "received bogus message, ignoring");
     61        bb_error_msg("received bogus message, ignoring");
    6662        return -2;
    6763    }
    68     DEBUG(LOG_INFO, "Received a packet");
    69 
    70     if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) {
    71         for (i = 0; broken_vendors[i][0]; i++) {
    72             if (vendor[OPT_LEN - 2] == (uint8_t) strlen(broken_vendors[i]) &&
    73                 !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])) {
    74                 DEBUG(LOG_INFO, "broken client (%s), forcing broadcast",
    75                     broken_vendors[i]);
     64    DEBUG("Received a packet");
     65
     66    if (packet->op == BOOTREQUEST) {
     67        vendor = get_option(packet, DHCP_VENDOR);
     68        if (vendor) {
     69#if 0
     70            int i;
     71            for (i = 0; broken_vendors[i][0]; i++) {
     72                if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i])
     73                 && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])
     74                ) {
     75                    DEBUG("broken client (%s), forcing broadcast",
     76                        broken_vendors[i]);
     77                    packet->flags |= htons(BROADCAST_FLAG);
     78                }
     79            }
     80#else
     81            if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1)
     82             && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0
     83            ) {
     84                DEBUG("broken client (%s), forcing broadcast", "MSFT 98");
    7685                packet->flags |= htons(BROADCAST_FLAG);
    7786            }
     87#endif
    7888        }
    7989    }
     
    8898     *         beginning at location "addr".
    8999     */
    90     register int32_t sum = 0;
     100    int32_t sum = 0;
    91101    uint16_t *source = (uint16_t *) addr;
    92102
     
    114124
    115125/* Construct a ip/udp header for a packet, and specify the source and dest hardware address */
    116 int udhcp_raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
    117            uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex)
     126void BUG_sizeof_struct_udp_dhcp_packet_must_be_576(void);
     127int udhcp_raw_packet(struct dhcpMessage *payload,
     128        uint32_t source_ip, int source_port,
     129        uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, int ifindex)
    118130{
    119131    int fd;
     
    122134    struct udp_dhcp_packet packet;
    123135
    124     if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
    125         DEBUG(LOG_ERR, "socket call failed: %m");
     136    fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
     137    if (fd < 0) {
     138        bb_perror_msg("socket");
    126139        return -1;
    127140    }
     
    136149    memcpy(dest.sll_addr, dest_arp, 6);
    137150    if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
    138         DEBUG(LOG_ERR, "bind call failed: %m");
     151        bb_perror_msg("bind");
    139152        close(fd);
    140153        return -1;
     
    157170    packet.ip.check = udhcp_checksum(&(packet.ip), sizeof(packet.ip));
    158171
    159     result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
     172    if (sizeof(struct udp_dhcp_packet) != 576)
     173        BUG_sizeof_struct_udp_dhcp_packet_must_be_576();
     174
     175    result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0,
     176            (struct sockaddr *) &dest, sizeof(dest));
    160177    if (result <= 0) {
    161         DEBUG(LOG_ERR, "write on socket failed: %m");
     178        bb_perror_msg("sendto");
    162179    }
    163180    close(fd);
     
    167184
    168185/* Let the kernel do all the work for packet generation */
    169 int udhcp_kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
    170            uint32_t dest_ip, int dest_port)
    171 {
    172     int n = 1;
     186int udhcp_kernel_packet(struct dhcpMessage *payload,
     187        uint32_t source_ip, int source_port,
     188        uint32_t dest_ip, int dest_port)
     189{
    173190    int fd, result;
    174191    struct sockaddr_in client;
    175192
    176     if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    177         return -1;
    178 
    179     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) {
    180         close(fd);
    181         return -1;
    182     }
     193    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
     194    if (fd < 0)
     195        return -1;
     196
     197    setsockopt_reuseaddr(fd);
    183198
    184199    memset(&client, 0, sizeof(client));
     
    187202    client.sin_addr.s_addr = source_ip;
    188203
    189     if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) {
     204    if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
    190205        close(fd);
    191206        return -1;
  • branches/stable/mindi-busybox/networking/udhcp/script.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* script.c
    23 *
     
    89 */
    910
    10 #include <string.h>
    11 #include <unistd.h>
    12 #include <stdio.h>
    13 #include <stdlib.h>
    14 #include <sys/socket.h>
    15 #include <netinet/in.h>
    16 #include <arpa/inet.h>
    17 #include <sys/types.h>
    18 #include <sys/wait.h>
    19 
    2011#include "common.h"
     12#include "dhcpc.h"
    2113#include "options.h"
    22 #include "dhcpd.h"
    23 #include "dhcpc.h"
     14
    2415
    2516/* get a rough idea of how long an option will be (rounding up...) */
    26 static const int max_option_length[] = {
     17static const uint8_t max_option_length[] = {
    2718    [OPTION_IP] =       sizeof("255.255.255.255 "),
    2819    [OPTION_IP_PAIR] =  sizeof("255.255.255.255 ") * 2,
    2920    [OPTION_STRING] =   1,
     21#if ENABLE_FEATURE_RFC3397
     22    [OPTION_STR1035] =  1,
     23#endif
    3024    [OPTION_BOOLEAN] =  sizeof("yes "),
    3125    [OPTION_U8] =       sizeof("255 "),
     
    4438
    4539
    46 static int sprintip(char *dest, char *pre, uint8_t *ip)
     40static int sprintip(char *dest, const char *pre, const uint8_t *ip)
    4741{
    4842    return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
     
    6256
    6357
    64 /* Fill dest with the text of option 'option'. */
    65 static void fill_options(char *dest, uint8_t *option, struct dhcp_option *type_p)
    66 {
    67     int type, optlen;
     58/* Allocate and fill with the text of option 'option'. */
     59static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p)
     60{
     61    int len, type, optlen;
    6862    uint16_t val_u16;
    6963    int16_t val_s16;
    7064    uint32_t val_u32;
    7165    int32_t val_s32;
    72     int len = option[OPT_LEN - 2];
    73 
    74     dest += sprintf(dest, "%s=", type_p->name);
    75 
     66    char *dest, *ret;
     67
     68    len = option[OPT_LEN - 2];
    7669    type = type_p->flags & TYPE_MASK;
    7770    optlen = option_lengths[type];
    78     for(;;) {
     71
     72    dest = ret = xmalloc(upper_length(len, type) + strlen(type_p->name) + 2);
     73    dest += sprintf(ret, "%s=", type_p->name);
     74
     75    for (;;) {
    7976        switch (type) {
    8077        case OPTION_IP_PAIR:
    8178            dest += sprintip(dest, "", option);
    82             *(dest++) = '/';
     79            *dest++ = '/';
    8380            option += 4;
    8481            optlen = 4;
     
    111108            memcpy(dest, option, len);
    112109            dest[len] = '\0';
    113             return;  /* Short circuit this case */
     110            return ret;  /* Short circuit this case */
     111#if ENABLE_FEATURE_RFC3397
     112        case OPTION_STR1035:
     113            /* unpack option into dest; use ret for prefix (i.e., "optname=") */
     114            dest = dname_dec(option, len, ret);
     115            free(ret);
     116            return dest;
     117#endif
    114118        }
    115119        option += optlen;
     
    118122        dest += sprintf(dest, " ");
    119123    }
     124    return ret;
    120125}
    121126
     
    127132    int i, j;
    128133    char **envp;
     134    char *var;
    129135    uint8_t *temp;
    130136    struct in_addr subnet;
    131137    char over = 0;
    132138
    133     if (packet == NULL)
    134         num_options = 0;
    135     else {
    136         for (i = 0; dhcp_options[i].code; i++)
     139    if (packet) {
     140        for (i = 0; dhcp_options[i].code; i++) {
    137141            if (get_option(packet, dhcp_options[i].code)) {
    138142                num_options++;
     
    140144                    num_options++; /* for mton */
    141145            }
    142         if (packet->siaddr) num_options++;
    143         if ((temp = get_option(packet, DHCP_OPTION_OVER)))
     146        }
     147        if (packet->siaddr)
     148            num_options++;
     149        temp = get_option(packet, DHCP_OPTION_OVER);
     150        if (temp)
    144151            over = *temp;
    145         if (!(over & FILE_FIELD) && packet->file[0]) num_options++;
    146         if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
     152        if (!(over & FILE_FIELD) && packet->file[0])
     153            num_options++;
     154        if (!(over & SNAME_FIELD) && packet->sname[0])
     155            num_options++;
    147156    }
    148157
    149158    envp = xzalloc(sizeof(char *) * (num_options + 5));
    150159    j = 0;
    151     envp[j++] = bb_xasprintf("interface=%s", client_config.interface);
    152     envp[j++] = bb_xasprintf("PATH=%s",
    153         getenv("PATH") ? : "/bin:/usr/bin:/sbin:/usr/sbin");
    154     envp[j++] = bb_xasprintf("HOME=%s", getenv("HOME") ? : "/");
    155 
    156     if (packet == NULL) return envp;
     160    envp[j++] = xasprintf("interface=%s", client_config.interface);
     161    var = getenv("PATH");
     162    if (var)
     163        envp[j++] = xasprintf("PATH=%s", var);
     164    var = getenv("HOME");
     165    if (var)
     166        envp[j++] = xasprintf("HOME=%s", var);
     167
     168    if (packet == NULL)
     169        return envp;
    157170
    158171    envp[j] = xmalloc(sizeof("ip=255.255.255.255"));
    159172    sprintip(envp[j++], "ip=", (uint8_t *) &packet->yiaddr);
    160173
    161 
    162174    for (i = 0; dhcp_options[i].code; i++) {
    163         if (!(temp = get_option(packet, dhcp_options[i].code)))
     175        temp = get_option(packet, dhcp_options[i].code);
     176        if (!temp)
    164177            continue;
    165         envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2],
    166             dhcp_options[i].flags & TYPE_MASK) + strlen(dhcp_options[i].name) + 2);
    167         fill_options(envp[j++], temp, &dhcp_options[i]);
     178        envp[j++] = alloc_fill_opts(temp, &dhcp_options[i]);
    168179
    169180        /* Fill in a subnet bits option for things like /24 */
    170181        if (dhcp_options[i].code == DHCP_SUBNET) {
    171182            memcpy(&subnet, temp, 4);
    172             envp[j++] = bb_xasprintf("mask=%d", mton(&subnet));
     183            envp[j++] = xasprintf("mask=%d", mton(&subnet));
    173184        }
    174185    }
     
    180191        /* watch out for invalid packets */
    181192        packet->file[sizeof(packet->file) - 1] = '\0';
    182         envp[j++] = bb_xasprintf("boot_file=%s", packet->file);
     193        envp[j++] = xasprintf("boot_file=%s", packet->file);
    183194    }
    184195    if (!(over & SNAME_FIELD) && packet->sname[0]) {
    185196        /* watch out for invalid packets */
    186197        packet->sname[sizeof(packet->sname) - 1] = '\0';
    187         envp[j++] = bb_xasprintf("sname=%s", packet->sname);
     198        envp[j++] = xasprintf("sname=%s", packet->sname);
    188199    }
    189200    return envp;
     
    200211        return;
    201212
    202     DEBUG(LOG_INFO, "vforking and execle'ing %s", client_config.script);
     213    DEBUG("vfork'ing and execle'ing %s", client_config.script);
    203214
    204215    envp = fill_envp(packet);
     216
    205217    /* call script */
     218// can we use wait4pid(spawn(...)) here?
    206219    pid = vfork();
    207     if (pid) {
    208         waitpid(pid, NULL, 0);
    209         for (curr = envp; *curr; curr++) free(*curr);
    210         free(envp);
    211         return;
    212     } else if (pid == 0) {
     220    if (pid < 0) return;
     221    if (pid == 0) {
    213222        /* close fd's? */
    214 
    215223        /* exec script */
    216224        execle(client_config.script, client_config.script,
    217225               name, NULL, envp);
    218         LOG(LOG_ERR, "script %s failed: %m", client_config.script);
    219         exit(1);
    220     }
    221 }
     226        bb_perror_msg_and_die("script %s failed", client_config.script);
     227    }
     228    waitpid(pid, NULL, 0);
     229    for (curr = envp; *curr; curr++)
     230        free(*curr);
     231    free(envp);
     232}
  • branches/stable/mindi-busybox/networking/udhcp/serverpacket.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* serverpacket.c
    23 *
     
    2021 */
    2122
    22 #include <sys/socket.h>
    23 #include <netinet/in.h>
    24 #include <arpa/inet.h>
    25 #include <string.h>
    26 #include <time.h>
    27 
    2823#include "common.h"
    29 #include "serverpacket.h"
    3024#include "dhcpd.h"
    3125#include "options.h"
    32 #include "static_leases.h"
     26
    3327
    3428/* send a packet to giaddr using the kernel ip stack */
    3529static int send_packet_to_relay(struct dhcpMessage *payload)
    3630{
    37     DEBUG(LOG_INFO, "Forwarding packet to relay");
     31    DEBUG("Forwarding packet to relay");
    3832
    3933    return udhcp_kernel_packet(payload, server_config.server, SERVER_PORT,
     
    4539static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast)
    4640{
    47     uint8_t *chaddr;
     41    const uint8_t *chaddr;
    4842    uint32_t ciaddr;
    4943
    5044    if (force_broadcast) {
    51         DEBUG(LOG_INFO, "broadcasting packet to client (NAK)");
     45        DEBUG("broadcasting packet to client (NAK)");
    5246        ciaddr = INADDR_BROADCAST;
    5347        chaddr = MAC_BCAST_ADDR;
    5448    } else if (payload->ciaddr) {
    55         DEBUG(LOG_INFO, "unicasting packet to client ciaddr");
     49        DEBUG("unicasting packet to client ciaddr");
    5650        ciaddr = payload->ciaddr;
    5751        chaddr = payload->chaddr;
    5852    } else if (ntohs(payload->flags) & BROADCAST_FLAG) {
    59         DEBUG(LOG_INFO, "broadcasting packet to client (requested)");
     53        DEBUG("broadcasting packet to client (requested)");
    6054        ciaddr = INADDR_BROADCAST;
    6155        chaddr = MAC_BCAST_ADDR;
    6256    } else {
    63         DEBUG(LOG_INFO, "unicasting packet to client yiaddr");
     57        DEBUG("unicasting packet to client yiaddr");
    6458        ciaddr = payload->yiaddr;
    6559        chaddr = payload->chaddr;
     
    122116
    123117    /* ADDME: if static, short circuit */
    124     if(!static_lease_ip)
    125     {
    126     /* the client is in our lease/offered table */
    127     if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) {
    128         if (!lease_expired(lease))
    129             lease_time_align = lease->expires - time(0);
    130         packet.yiaddr = lease->yiaddr;
    131 
    132     /* Or the client has a requested ip */
    133     } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) &&
    134 
    135            /* Don't look here (ugly hackish thing to do) */
    136            memcpy(&req_align, req, 4) &&
    137 
    138            /* and the ip is in the lease range */
    139            ntohl(req_align) >= ntohl(server_config.start) &&
    140            ntohl(req_align) <= ntohl(server_config.end) &&
    141 
    142             !static_lease_ip &&  /* Check that its not a static lease */
    143             /* and is not already taken/offered */
    144            ((!(lease = find_lease_by_yiaddr(req_align)) ||
    145 
    146            /* or its taken, but expired */ /* ADDME: or maybe in here */
    147            lease_expired(lease)))) {
    148                 packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */
    149 
     118    if (!static_lease_ip) {
     119        /* the client is in our lease/offered table */
     120        lease = find_lease_by_chaddr(oldpacket->chaddr);
     121        if (lease) {
     122            if (!lease_expired(lease))
     123                lease_time_align = lease->expires - time(0);
     124            packet.yiaddr = lease->yiaddr;
     125        /* Or the client has a requested ip */
     126        } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP))
     127         /* Don't look here (ugly hackish thing to do) */
     128         && memcpy(&req_align, req, 4)
     129         /* and the ip is in the lease range */
     130         && ntohl(req_align) >= server_config.start_ip
     131         && ntohl(req_align) <= server_config.end_ip
     132         && !static_lease_ip /* Check that its not a static lease */
     133         /* and is not already taken/offered */
     134         && (!(lease = find_lease_by_yiaddr(req_align))
     135            /* or its taken, but expired */ /* ADDME: or maybe in here */
     136            || lease_expired(lease))
     137        ) {
     138            packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */
    150139            /* otherwise, find a free IP */
     140        } else {
     141            /* Is it a static lease? (No, because find_address skips static lease) */
     142            packet.yiaddr = find_address(0);
     143            /* try for an expired lease */
     144            if (!packet.yiaddr)
     145                packet.yiaddr = find_address(1);
     146        }
     147
     148        if (!packet.yiaddr) {
     149            bb_error_msg("no IP addresses to give - OFFER abandoned");
     150            return -1;
     151        }
     152        if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
     153            bb_error_msg("lease pool is full - OFFER abandoned");
     154            return -1;
     155        }
     156        lease_time = get_option(oldpacket, DHCP_LEASE_TIME);
     157        if (lease_time) {
     158            memcpy(&lease_time_align, lease_time, 4);
     159            lease_time_align = ntohl(lease_time_align);
     160            if (lease_time_align > server_config.lease)
     161                lease_time_align = server_config.lease;
     162        }
     163
     164        /* Make sure we aren't just using the lease time from the previous offer */
     165        if (lease_time_align < server_config.min_lease)
     166            lease_time_align = server_config.lease;
     167        /* ADDME: end of short circuit */
    151168    } else {
    152             /* Is it a static lease? (No, because find_address skips static lease) */
    153         packet.yiaddr = find_address(0);
    154 
    155         /* try for an expired lease */
    156         if (!packet.yiaddr) packet.yiaddr = find_address(1);
    157     }
    158 
    159     if(!packet.yiaddr) {
    160         LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned");
    161         return -1;
    162     }
    163 
    164     if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
    165         LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned");
    166         return -1;
    167     }
    168 
    169     if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
    170         memcpy(&lease_time_align, lease_time, 4);
    171         lease_time_align = ntohl(lease_time_align);
    172         if (lease_time_align > server_config.lease)
    173             lease_time_align = server_config.lease;
    174     }
    175 
    176     /* Make sure we aren't just using the lease time from the previous offer */
    177     if (lease_time_align < server_config.min_lease)
    178         lease_time_align = server_config.lease;
    179     }
    180     /* ADDME: end of short circuit */
    181     else
    182     {
    183169        /* It is a static lease... use it */
    184170        packet.yiaddr = static_lease_ip;
     
    197183
    198184    addr.s_addr = packet.yiaddr;
    199     LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr));
     185    bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
    200186    return send_packet(&packet, 0);
    201187}
     
    208194    init_packet(&packet, oldpacket, DHCPNAK);
    209195
    210     DEBUG(LOG_INFO, "sending NAK");
     196    DEBUG("Sending NAK");
    211197    return send_packet(&packet, 1);
    212198}
     
    224210    packet.yiaddr = yiaddr;
    225211
    226     if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
     212    lease_time = get_option(oldpacket, DHCP_LEASE_TIME);
     213    if (lease_time) {
    227214        memcpy(&lease_time_align, lease_time, 4);
    228215        lease_time_align = ntohl(lease_time_align);
     
    245232
    246233    addr.s_addr = packet.yiaddr;
    247     LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr));
     234    bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
    248235
    249236    if (send_packet(&packet, 0) < 0)
     
    251238
    252239    add_lease(packet.chaddr, packet.yiaddr, lease_time_align);
     240    if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
     241        /* rewrite the file with leases at every new acceptance */
     242        write_leases();
     243    }
    253244
    254245    return 0;
  • branches/stable/mindi-busybox/networking/udhcp/signalpipe.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/* signalpipe.c
    23 *
     
    2021 */
    2122
    22 #include <unistd.h>
    23 #include <fcntl.h>
    24 #include <signal.h>
    25 #include <sys/types.h>
    26 #include <sys/socket.h>
    27 #include <sys/select.h>
     23#include "common.h"
    2824
    29 
    30 #include "signalpipe.h"
    31 #include "common.h"
    3225
    3326static int signal_pipe[2];
     
    3528static void signal_handler(int sig)
    3629{
    37     if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0)
    38         DEBUG(LOG_ERR, "Could not send signal: %m");
     30    unsigned char ch = sig; /* use char, avoid dealing with partial writes */
     31    if (write(signal_pipe[1], &ch, 1) != 1)
     32        bb_perror_msg("cannot send signal");
    3933}
    4034
     
    4438void udhcp_sp_setup(void)
    4539{
    46     socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
     40    /* was socketpair, but it needs AF_UNIX in kernel */
     41    xpipe(signal_pipe);
    4742    fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
    4843    fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
     44    fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK);
    4945    signal(SIGUSR1, signal_handler);
    5046    signal(SIGUSR2, signal_handler);
     
    7369int udhcp_sp_read(fd_set *rfds)
    7470{
    75     int sig;
     71    unsigned char sig;
    7672
    7773    if (!FD_ISSET(signal_pipe[0], rfds))
    7874        return 0;
    7975
    80     if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
     76    if (read(signal_pipe[0], &sig, 1) != 1)
    8177        return -1;
    8278
  • branches/stable/mindi-busybox/networking/udhcp/socket.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * socket.c -- DHCP server client/server socket creation
     
    2324 */
    2425
    25 #include <sys/types.h>
    26 #include <sys/socket.h>
    27 #include <sys/ioctl.h>
    28 #include <netinet/in.h>
    29 #include <unistd.h>
    30 #include <string.h>
    31 #include <arpa/inet.h>
    3226#include <net/if.h>
    33 #include <errno.h>
    3427#include <features.h>
    35 #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION
     28#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    3629#include <netpacket/packet.h>
    3730#include <net/ethernet.h>
     
    4336
    4437#include "common.h"
    45 #include "socket.h"
    4638
    47 int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *arp)
     39
     40int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp)
    4841{
    4942    int fd;
     
    5144    struct sockaddr_in *our_ip;
    5245
    53     memset(&ifr, 0, sizeof(struct ifreq));
    54     if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
    55         ifr.ifr_addr.sa_family = AF_INET;
    56         strcpy(ifr.ifr_name, interface);
     46    memset(&ifr, 0, sizeof(ifr));
     47    fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    5748
    58         if (addr) {
    59             if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
    60                 our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
    61                 *addr = our_ip->sin_addr.s_addr;
    62                 DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
    63             } else {
    64                 LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %m");
    65                 close(fd);
    66                 return -1;
    67             }
    68         }
    69 
    70         if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
    71             DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
    72             *ifindex = ifr.ifr_ifindex;
    73         } else {
    74             LOG(LOG_ERR, "SIOCGIFINDEX failed!: %m");
     49    ifr.ifr_addr.sa_family = AF_INET;
     50    strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
     51    if (addr) {
     52        if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr,
     53            "is interface %s up and configured?", interface)
     54        ) {
    7555            close(fd);
    7656            return -1;
    7757        }
    78         if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
    79             memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
    80             DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
    81                 arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
    82         } else {
    83             LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %m");
     58        our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
     59        *addr = our_ip->sin_addr.s_addr;
     60        DEBUG("%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
     61    }
     62
     63    if (ifindex) {
     64        if (ioctl_or_warn(fd, SIOCGIFINDEX, &ifr) != 0) {
    8465            close(fd);
    8566            return -1;
    8667        }
    87     } else {
    88         LOG(LOG_ERR, "socket failed!: %m");
    89         return -1;
     68        DEBUG("adapter index %d", ifr.ifr_ifindex);
     69        *ifindex = ifr.ifr_ifindex;
    9070    }
     71
     72    if (arp) {
     73        if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) {
     74            close(fd);
     75            return -1;
     76        }
     77        memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
     78        DEBUG("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
     79            arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
     80    }
     81
    9182    close(fd);
    9283    return 0;
    9384}
    9485
     86/* 1. None of the callers expects it to ever fail */
     87/* 2. ip was always INADDR_ANY */
     88int listen_socket(/*uint32_t ip,*/ int port, const char *inf)
     89{
     90    int fd;
     91    struct ifreq interface;
     92    struct sockaddr_in addr;
    9593
    96 int listen_socket(uint32_t ip, int port, char *inf)
    97 {
    98     struct ifreq interface;
    99     int fd;
    100     struct sockaddr_in addr;
    101     int n = 1;
     94    DEBUG("Opening listen socket on *:%d %s", port, inf);
     95    fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    10296
    103     DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s", ip, port, inf);
    104     if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    105         DEBUG(LOG_ERR, "socket call failed: %m");
    106         return -1;
    107     }
     97    setsockopt_reuseaddr(fd);
     98    if (setsockopt_broadcast(fd) == -1)
     99        bb_perror_msg_and_die("SO_BROADCAST");
     100
     101    strncpy(interface.ifr_name, inf, IFNAMSIZ);
     102    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface)) == -1)
     103        bb_perror_msg_and_die("SO_BINDTODEVICE");
    108104
    109105    memset(&addr, 0, sizeof(addr));
    110106    addr.sin_family = AF_INET;
    111107    addr.sin_port = htons(port);
    112     addr.sin_addr.s_addr = ip;
    113 
    114     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) {
    115         close(fd);
    116         return -1;
    117     }
    118     if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) {
    119         close(fd);
    120         return -1;
    121     }
    122 
    123     strncpy(interface.ifr_name, inf, IFNAMSIZ);
    124     if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) {
    125         close(fd);
    126         return -1;
    127     }
    128 
    129     if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
    130         close(fd);
    131         return -1;
    132     }
     108    /* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */
     109    xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
    133110
    134111    return fd;
  • branches/stable/mindi-busybox/networking/udhcp/static_leases.c

    r821 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * static_leases.c -- Couple of functions to assist with storing and
     
    78 */
    89
     10#include "common.h"
     11#include "dhcpd.h"
    912
    10 #include <stdlib.h>
    11 #include <stdio.h>
    12 #include <string.h>
    13 
    14 #include "static_leases.h"
    15 #include "dhcpd.h"
    1613
    1714/* Takes the address of the pointer to the static_leases linked list,
     
    2017int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip)
    2118{
    22 
    2319    struct static_lease *cur;
    2420    struct static_lease *new_static_lease;
     
    3127
    3228    /* If it's the first node to be added... */
    33     if(*lease_struct == NULL)
    34     {
     29    if (*lease_struct == NULL) {
    3530        *lease_struct = new_static_lease;
    36     }
    37     else
    38     {
     31    } else {
    3932        cur = *lease_struct;
    40         while(cur->next != NULL)
    41         {
     33        while (cur->next) {
    4234            cur = cur->next;
    4335        }
     
    4739
    4840    return 1;
    49 
    5041}
    5142
     
    5950    return_ip = 0;
    6051
    61     while(cur != NULL)
    62     {
     52    while (cur) {
    6353        /* If the client has the correct mac  */
    64         if(memcmp(cur->mac, mac, 6) == 0)
    65         {
     54        if (memcmp(cur->mac, mac, 6) == 0) {
    6655            return_ip = *(cur->ip);
    6756        }
     
    7160
    7261    return return_ip;
    73 
    7462}
    7563
     
    8169    uint32_t return_val = 0;
    8270
    83     while(cur != NULL)
    84     {
     71    while (cur) {
    8572        /* If the client has the correct ip  */
    86         if(*cur->ip == ip)
     73        if (*cur->ip == ip)
    8774            return_val = 1;
    8875
     
    9178
    9279    return return_val;
    93 
    9480}
    9581
    96 #ifdef CONFIG_FEATURE_UDHCP_DEBUG
     82#if ENABLE_FEATURE_UDHCP_DEBUG
    9783/* Print out static leases just to check what's going on */
    9884/* Takes the address of the pointer to the static_leases linked list */
     
    10288    struct static_lease *cur = *arg;
    10389
    104     while(cur != NULL)
    105     {
     90    while (cur) {
    10691        /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */
    10792        printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac));
     
    11196        cur = cur->next;
    11297    }
    113 
    114 
    11598}
    11699#endif
    117 
    118 
    119 
  • branches/stable/mindi-busybox/networking/vconfig.c

    r821 r1770  
    1010/* BB_AUDIT SUSv3 N/A */
    1111
    12 #include <stdlib.h>
    13 #include <unistd.h>
    14 #include <fcntl.h>
    15 #include <sys/ioctl.h>
     12#include "libbb.h"
    1613#include <net/if.h>
    17 #include <string.h>
    18 #include <limits.h>
    19 #include "busybox.h"
    2014
    2115/* Stuff from linux/if_vlan.h, kernel version 2.4.23 */
     
    7064}
    7165
    72 static const char cmds[] = {
     66static const char cmds[] ALIGN1 = {
    7367    4, ADD_VLAN_CMD, 7,
    7468    'a', 'd', 'd', 0,
     
    7973    'n', 'a', 'm', 'e', '_',
    8074    't', 'y', 'p', 'e', 0,
    81     4, SET_VLAN_FLAG_CMD, 12,
     75    5, SET_VLAN_FLAG_CMD, 12,
    8276    's', 'e', 't', '_',
    8377    'f', 'l', 'a', 'g', 0,
     
    9286};
    9387
    94 static const char name_types[] = {
     88static const char name_types[] ALIGN1 = {
    9589    VLAN_NAME_TYPE_PLUS_VID, 16,
    9690    'V', 'L', 'A', 'N',
     
    111105};
    112106
    113 static const char conf_file_name[] = "/proc/net/vlan/config";
     107static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config";
    114108
     109int vconfig_main(int argc, char **argv);
    115110int vconfig_main(int argc, char **argv)
    116111{
     
    125120    /* Don't bother closing the filedes.  It will be closed on cleanup. */
    126121    /* Will die if 802.1q is not present */
    127     bb_xopen3(conf_file_name, O_RDONLY, 0);
     122    xopen(conf_file_name, O_RDONLY);
    128123
    129124    memset(&ifr, 0, sizeof(struct vlan_ioctl_args));
     
    140135    } else {
    141136        if (strlen(argv[1]) >= IF_NAMESIZE) {
    142             bb_error_msg_and_die("if_name >= %d chars\n", IF_NAMESIZE);
     137            bb_error_msg_and_die("if_name >= %d chars", IF_NAMESIZE);
    143138        }
    144139        strcpy(ifr.device1, argv[1]);
     
    151146         * more of a pain. */
    152147        if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */
    153             ifr.u.flag = bb_xgetularg10_bnd(p, 0, 1);
     148            ifr.u.flag = xatoul_range(p, 0, 1);
     149            /* DM: in order to set reorder header, qos must be set */
     150            ifr.vlan_qos = xatoul_range(argv[3], 0, 7);
    154151        } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */
    155             ifr.u.VID = bb_xgetularg10_bnd(p, 0, VLAN_GROUP_ARRAY_LEN-1);
     152            ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1);
    156153        } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */
    157             ifr.u.skb_priority = bb_xgetularg10_bnd(p, 0, ULONG_MAX);
    158             ifr.vlan_qos = bb_xgetularg10_bnd(argv[3], 0, 7);
     154            ifr.u.skb_priority = xatou(p);
     155            ifr.vlan_qos = xatoul_range(argv[3], 0, 7);
    159156        }
    160157    }
    161158
    162     fd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
    163     if (ioctl(fd, SIOCSIFVLAN, &ifr) < 0) {
    164         bb_perror_msg_and_die("ioctl error for %s", *argv);
    165     }
     159    fd = xsocket(AF_INET, SOCK_STREAM, 0);
     160    ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr,
     161                        "ioctl error for %s", *argv);
    166162
    167163    return 0;
    168164}
    169 
  • branches/stable/mindi-busybox/networking/wget.c

    r821 r1770  
    77 */
    88
    9 #include "busybox.h"
    10 #include <errno.h>
    11 #include <signal.h>
    12 #include <sys/ioctl.h>
    13 #include <getopt.h>
    14 
     9/* We want libc to give us xxx64 functions also */
     10/* http://www.unix.org/version2/whatsnew/lfs20mar.html */
     11//#define _LARGEFILE64_SOURCE 1
     12
     13#include <getopt.h> /* for struct option */
     14#include "libbb.h"
    1515
    1616struct host_info {
     17    // May be used if we ever will want to free() all xstrdup()s...
     18    /* char *allocated; */
    1719    char *host;
    1820    int port;
     
    2325
    2426static void parse_url(char *url, struct host_info *h);
    25 static FILE *open_socket(struct sockaddr_in *s_in);
     27static FILE *open_socket(len_and_sockaddr *lsa);
    2628static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
    27 static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
     29static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf);
    2830
    2931/* Globals (can be accessed from signal handlers */
    30 static off_t filesize;      /* content-length of the file */
    31 static int chunked;     /* chunked transfer encoding */
    32 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     32static off_t content_len;        /* Content-length of the file */
     33static off_t beg_range;          /* Range at which continue begins */
     34#if ENABLE_FEATURE_WGET_STATUSBAR
     35static off_t transferred;        /* Number of bytes transferred so far */
     36#endif
     37static bool chunked;                     /* chunked transfer encoding */
     38#if ENABLE_FEATURE_WGET_STATUSBAR
    3339static void progressmeter(int flag);
    34 static char *curfile;       /* Name of current file being transferred. */
    35 static struct timeval start;    /* Time a transfer started. */
    36 static off_t transferred;   /* Number of bytes transferred so far. */
    37 /* For progressmeter() -- number of seconds before xfer considered "stalled" */
     40static const char *curfile;             /* Name of current file being transferred */
    3841enum {
    39     STALLTIME = 5
     42    STALLTIME = 5                   /* Seconds when xfer considered "stalled" */
    4043};
    4144#else
    42 static inline void progressmeter(int flag) {}
    43 #endif
    44 
    45 static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue)
    46 {
    47     if (output != stdout && do_continue==0) {
    48         fclose(output);
    49         unlink(fname_out);
    50     }
    51 }
    52 
    53 /* Read NMEMB elements of SIZE bytes into PTR from STREAM.  Returns the
    54  * number of elements read, and a short count if an eof or non-interrupt
    55  * error is encountered.  */
    56 static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
    57 {
    58     size_t ret = 0;
     45static ALWAYS_INLINE void progressmeter(int flag) {}
     46#endif
     47
     48/* Read NMEMB bytes into PTR from STREAM.  Returns the number of bytes read,
     49 * and a short count if an eof or non-interrupt error is encountered.  */
     50static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream)
     51{
     52    size_t ret;
     53    char *p = (char*)ptr;
    5954
    6055    do {
    6156        clearerr(stream);
    62         ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
    63     } while (ret < nmemb && ferror(stream) && errno == EINTR);
    64 
    65     return ret;
    66 }
    67 
    68 /* Write NMEMB elements of SIZE bytes from PTR to STREAM.  Returns the
    69  * number of elements written, and a short count if an eof or non-interrupt
    70  * error is encountered.  */
    71 static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
    72 {
    73     size_t ret = 0;
    74 
    75     do {
    76         clearerr(stream);
    77         ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
    78     } while (ret < nmemb && ferror(stream) && errno == EINTR);
    79 
    80     return ret;
    81 }
    82 
    83 /* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM.
     57        ret = fread(p, 1, nmemb, stream);
     58        p += ret;
     59        nmemb -= ret;
     60    } while (nmemb && ferror(stream) && errno == EINTR);
     61
     62    return p - (char*)ptr;
     63}
     64
     65/* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM.
    8466 * Returns S, or NULL if an eof or non-interrupt error is encountered.  */
    8567static char *safe_fgets(char *s, int size, FILE *stream)
     
    9577}
    9678
    97 #define close_delete_and_die(s...) { \
    98     close_and_delete_outfile(output, fname_out, do_continue); \
    99     bb_error_msg_and_die(s); }
    100 
    101 
    102 #ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
    103 /*
    104  *  Base64-encode character string
    105  *  oops... isn't something similar in uuencode.c?
    106  *  XXX: It would be better to use already existing code
    107  */
    108 static char *base64enc(unsigned char *p, char *buf, int len) {
    109 
    110     char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    111             "0123456789+/";
    112     char *s = buf;
    113 
    114     while(*p) {
    115         if (s >= buf+len-4)
    116             bb_error_msg_and_die("buffer overflow");
    117         *(s++) = al[(*p >> 2) & 0x3F];
    118         *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
    119         *s = *(s+1) = '=';
    120         *(s+2) = 0;
    121         if (! *(++p)) break;
    122         *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)];
    123         if (! *(++p)) break;
    124         *(s++) = al[*(p++) & 0x3F];
    125     }
    126 
     79#if ENABLE_FEATURE_WGET_AUTHENTICATION
     80/* Base64-encode character string. buf is assumed to be char buf[512]. */
     81static char *base64enc_512(char buf[512], const char *str)
     82{
     83    unsigned len = strlen(str);
     84    if (len > 512/4*3 - 10) /* paranoia */
     85        len = 512/4*3 - 10;
     86    bb_uuencode(buf, str, len, bb_uuenc_tbl_base64);
    12787    return buf;
    12888}
    12989#endif
    13090
    131 #define WGET_OPT_CONTINUE   1
    132 #define WGET_OPT_QUIET  2
    133 #define WGET_OPT_PASSIVE    4
    134 #define WGET_OPT_OUTNAME    8
    135 #define WGET_OPT_HEADER 16
    136 #define WGET_OPT_PREFIX 32
    137 #define WGET_OPT_PROXY  64
    138 
    139 #if ENABLE_WGET_LONG_OPTIONS
    140 static const struct option wget_long_options[] = {
    141     { "continue",        0, NULL, 'c' },
    142     { "quiet",           0, NULL, 'q' },
    143     { "passive-ftp",     0, NULL, 139 },
    144     { "output-document", 1, NULL, 'O' },
    145     { "header",          1, NULL, 131 },
    146     { "directory-prefix",1, NULL, 'P' },
    147     { "proxy",           1, NULL, 'Y' },
    148     { 0,                 0, 0, 0 }
    149 };
    150 #endif
    151 
     91int wget_main(int argc, char **argv);
    15292int wget_main(int argc, char **argv)
    15393{
    154     int n, try=5, status;
    155     unsigned long opt;
     94    char buf[512];
     95    struct host_info server, target;
     96    len_and_sockaddr *lsa;
     97    int n, status;
    15698    int port;
     99    int try = 5;
     100    unsigned opt;
     101    char *str;
    157102    char *proxy = 0;
    158     char *dir_prefix=NULL;
    159     char *s, buf[512];
    160     struct stat sbuf;
    161     char extra_headers[1024];
    162     char *extra_headers_ptr = extra_headers;
    163     int extra_headers_left = sizeof(extra_headers);
    164     struct host_info server, target;
    165     struct sockaddr_in s_in;
     103    char *dir_prefix = NULL;
     104#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     105    char *extra_headers = NULL;
    166106    llist_t *headers_llist = NULL;
    167 
    168     FILE *sfp = NULL;       /* socket to web/ftp server     */
    169     FILE *dfp = NULL;       /* socket to ftp server (data)      */
    170     char *fname_out = NULL;     /* where to direct output (-O)      */
    171     int do_continue = 0;        /* continue a prev transfer (-c)    */
    172     long beg_range = 0L;        /*   range at which continue begins */
    173     int got_clen = 0;       /* got content-length: from server  */
    174     FILE *output;           /* socket to web server         */
    175     int quiet_flag = FALSE;     /* Be verry, verry quiet...     */
    176     int use_proxy = 1;      /* Use proxies if env vars are set  */
    177     char *proxy_flag = "on";    /* Use proxies if env vars are set  */
    178 
    179     /*
    180      * Crack command line.
    181      */
    182     bb_opt_complementally = "-1:\203::";
    183 #if ENABLE_WGET_LONG_OPTIONS
    184     bb_applet_long_options = wget_long_options;
    185 #endif
    186     opt = bb_getopt_ulflags(argc, argv, "cq\213O:\203:P:Y:",
    187                     &fname_out, &headers_llist,
    188                     &dir_prefix, &proxy_flag);
    189     if (opt & WGET_OPT_CONTINUE) {
    190         ++do_continue;
    191     }
    192     if (opt & WGET_OPT_QUIET) {
    193         quiet_flag = TRUE;
    194     }
     107#endif
     108
     109    FILE *sfp = NULL;               /* socket to web/ftp server         */
     110    FILE *dfp = NULL;               /* socket to ftp server (data)      */
     111    char *fname_out = NULL;         /* where to direct output (-O)      */
     112    bool got_clen = 0;              /* got content-length: from server  */
     113    int output_fd = -1;
     114    bool use_proxy = 1;             /* Use proxies if env vars are set  */
     115    const char *proxy_flag = "on";  /* Use proxies if env vars are set  */
     116    const char *user_agent = "Wget";/* "User-Agent" header field        */
     117    static const char keywords[] ALIGN1 =
     118        "content-length\0""transfer-encoding\0""chunked\0""location\0";
     119    enum {
     120        KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location
     121    };
     122    enum {
     123        WGET_OPT_CONTINUE   = 0x1,
     124        WGET_OPT_SPIDER     = 0x2,
     125        WGET_OPT_QUIET      = 0x4,
     126        WGET_OPT_OUTNAME    = 0x8,
     127        WGET_OPT_PREFIX     = 0x10,
     128        WGET_OPT_PROXY      = 0x20,
     129        WGET_OPT_USER_AGENT = 0x40,
     130        WGET_OPT_PASSIVE    = 0x80,
     131        WGET_OPT_HEADER     = 0x100,
     132    };
     133#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     134    static const char wget_longopts[] ALIGN1 =
     135        /* name, has_arg, val */
     136        "continue\0"         No_argument       "c"
     137        "spider\0"           No_argument       "s"
     138        "quiet\0"            No_argument       "q"
     139        "output-document\0"  Required_argument "O"
     140        "directory-prefix\0" Required_argument "P"
     141        "proxy\0"            Required_argument "Y"
     142        "user-agent\0"       Required_argument "U"
     143        "passive-ftp\0"      No_argument       "\xff"
     144        "header\0"           Required_argument "\xfe"
     145        ;
     146    applet_long_options = wget_longopts;
     147#endif
     148    /* server.allocated = target.allocated = NULL; */
     149    opt_complementary = "-1" USE_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
     150    opt = getopt32(argv, "csqO:P:Y:U:",
     151                &fname_out, &dir_prefix,
     152                &proxy_flag, &user_agent
     153                USE_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
     154                );
    195155    if (strcmp(proxy_flag, "off") == 0) {
    196         /* Use the proxy if necessary. */
     156        /* Use the proxy if necessary */
    197157        use_proxy = 0;
    198158    }
    199     if (opt & WGET_OPT_HEADER) {
     159#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     160    if (headers_llist) {
     161        int size = 1;
     162        char *cp;
     163        llist_t *ll = headers_llist;
     164        while (ll) {
     165            size += strlen(ll->data) + 2;
     166            ll = ll->link;
     167        }
     168        extra_headers = cp = xmalloc(size);
    200169        while (headers_llist) {
    201             int arglen = strlen(headers_llist->data);
    202             if (extra_headers_left - arglen - 2 <= 0)
    203                 bb_error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
    204             strcpy(extra_headers_ptr, headers_llist->data);
    205             extra_headers_ptr += arglen;
    206             extra_headers_left -= ( arglen + 2 );
    207             *extra_headers_ptr++ = '\r';
    208             *extra_headers_ptr++ = '\n';
    209             *(extra_headers_ptr + 1) = 0;
     170            cp += sprintf(cp, "%s\r\n", headers_llist->data);
    210171            headers_llist = headers_llist->link;
    211172        }
    212173    }
     174#endif
    213175
    214176    parse_url(argv[optind], &target);
     
    216178    server.port = target.port;
    217179
    218     /*
    219      * Use the proxy if necessary.
    220      */
     180    /* Use the proxy if necessary */
    221181    if (use_proxy) {
    222182        proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
    223183        if (proxy && *proxy) {
    224             parse_url(bb_xstrdup(proxy), &server);
     184            parse_url(proxy, &server);
    225185        } else {
    226186            use_proxy = 0;
     
    232192        // Dirty hack. Needed because bb_get_last_path_component
    233193        // will destroy trailing / by storing '\0' in last byte!
    234         if(*target.path && target.path[strlen(target.path)-1]!='/') {
    235             fname_out =
    236 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
    237                 curfile =
    238 #endif
    239                 bb_get_last_path_component(target.path);
    240         }
    241         if (fname_out==NULL || strlen(fname_out)<1) {
    242             fname_out =
    243 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
    244                 curfile =
    245 #endif
    246                 "index.html";
     194        if (!last_char_is(target.path, '/')) {
     195            fname_out = bb_get_last_path_component(target.path);
     196#if ENABLE_FEATURE_WGET_STATUSBAR
     197            curfile = fname_out;
     198#endif
     199        }
     200        if (!fname_out || !fname_out[0]) {
     201            /* bb_get_last_path_component writes
     202             * to last '/' only. We don't have one here... */
     203            fname_out = (char*)"index.html";
     204#if ENABLE_FEATURE_WGET_STATUSBAR
     205            curfile = fname_out;
     206#endif
    247207        }
    248208        if (dir_prefix != NULL)
    249209            fname_out = concat_path_file(dir_prefix, fname_out);
    250 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     210#if ENABLE_FEATURE_WGET_STATUSBAR
    251211    } else {
    252212        curfile = bb_get_last_path_component(fname_out);
    253213#endif
    254214    }
    255     if (do_continue && !fname_out)
    256         bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
    257 
    258 
    259     /*
    260      * Open the output file stream.
    261      */
    262     if (strcmp(fname_out, "-") == 0) {
    263         output = stdout;
    264         quiet_flag = TRUE;
    265     } else {
    266         output = bb_xfopen(fname_out, (do_continue ? "a" : "w"));
    267     }
    268 
    269     /*
    270      * Determine where to start transfer.
    271      */
    272     if (do_continue) {
    273         if (fstat(fileno(output), &sbuf) < 0)
    274             bb_perror_msg_and_die("fstat()");
    275         if (sbuf.st_size > 0)
    276             beg_range = sbuf.st_size;
    277         else
    278             do_continue = 0;
     215    /* Impossible?
     216    if ((opt & WGET_OPT_CONTINUE) && !fname_out)
     217        bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); */
     218
     219    /* Determine where to start transfer */
     220    if (LONE_DASH(fname_out)) {
     221        output_fd = 1;
     222        opt &= ~WGET_OPT_CONTINUE;
     223    }
     224    if (opt & WGET_OPT_CONTINUE) {
     225        output_fd = open(fname_out, O_WRONLY);
     226        if (output_fd >= 0) {
     227            beg_range = xlseek(output_fd, 0, SEEK_END);
     228        }
     229        /* File doesn't exist. We do not create file here yet.
     230           We are not sure it exists on remove side */
    279231    }
    280232
     
    282234     * sites (i.e. ftp.us.debian.org) use round-robin DNS
    283235     * and we want to connect to only one IP... */
    284     bb_lookup_host(&s_in, server.host);
    285     s_in.sin_port = server.port;
    286     if (quiet_flag==FALSE) {
    287         fprintf(stdout, "Connecting to %s[%s]:%d\n",
    288                 server.host, inet_ntoa(s_in.sin_addr), ntohs(server.port));
     236    lsa = xhost2sockaddr(server.host, server.port);
     237    if (!(opt & WGET_OPT_QUIET)) {
     238        fprintf(stderr, "Connecting to %s (%s)\n", server.host,
     239                xmalloc_sockaddr2dotted(&lsa->sa));
     240        /* We leak result of xmalloc_sockaddr2dotted */
    289241    }
    290242
     
    296248            got_clen = chunked = 0;
    297249
    298             if (! --try)
    299                 close_delete_and_die("too many redirections");
    300 
    301             /*
    302              * Open socket to http server
    303              */
     250            if (!--try)
     251                bb_error_msg_and_die("too many redirections");
     252
     253            /* Open socket to http server */
    304254            if (sfp) fclose(sfp);
    305             sfp = open_socket(&s_in);
    306 
    307             /*
    308              * Send HTTP request.
    309              */
     255            sfp = open_socket(lsa);
     256
     257            /* Send HTTP request.  */
    310258            if (use_proxy) {
    311                 const char *format = "GET %stp://%s:%d/%s HTTP/1.1\r\n";
    312 #ifdef CONFIG_FEATURE_WGET_IP6_LITERAL
    313                 if (strchr(target.host, ':'))
    314                     format = "GET %stp://[%s]:%d/%s HTTP/1.1\r\n";
    315 #endif
    316                 fprintf(sfp, format,
     259                fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n",
    317260                    target.is_ftp ? "f" : "ht", target.host,
    318                     ntohs(target.port), target.path);
     261                    target.path);
    319262            } else {
    320263                fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
    321264            }
    322265
    323             fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
    324 
    325 #ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
     266            fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",
     267                target.host, user_agent);
     268
     269#if ENABLE_FEATURE_WGET_AUTHENTICATION
    326270            if (target.user) {
    327                 fprintf(sfp, "Authorization: Basic %s\r\n",
    328                     base64enc((unsigned char*)target.user, buf, sizeof(buf)));
     271                fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
     272                    base64enc_512(buf, target.user));
    329273            }
    330274            if (use_proxy && server.user) {
    331275                fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
    332                     base64enc((unsigned char*)server.user, buf, sizeof(buf)));
     276                    base64enc_512(buf, server.user));
    333277            }
    334278#endif
    335279
    336             if (do_continue)
    337                 fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range);
    338             if(extra_headers_left < sizeof(extra_headers))
    339                 fputs(extra_headers,sfp);
    340             fprintf(sfp,"Connection: close\r\n\r\n");
     280            if (beg_range)
     281                fprintf(sfp, "Range: bytes=%"OFF_FMT"d-\r\n", beg_range);
     282#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     283            if (extra_headers)
     284                fputs(extra_headers, sfp);
     285#endif
     286            fprintf(sfp, "Connection: close\r\n\r\n");
    341287
    342288            /*
    343289            * Retrieve HTTP response line and check for "200" status code.
    344290            */
    345 read_response:
     291 read_response:
    346292            if (fgets(buf, sizeof(buf), sfp) == NULL)
    347                 close_delete_and_die("no response from server");
    348 
    349             for (s = buf ; *s != '\0' && !isspace(*s) ; ++s)
    350                 ;
    351             for ( ; isspace(*s) ; ++s)
    352                 ;
    353             switch (status = atoi(s)) {
    354                 case 0:
    355                 case 100:
    356                     while (gethdr(buf, sizeof(buf), sfp, &n) != NULL);
    357                     goto read_response;
    358                 case 200:
    359                     if (do_continue && output != stdout)
    360                         output = freopen(fname_out, "w", output);
    361                     do_continue = 0;
     293                bb_error_msg_and_die("no response from server");
     294
     295            str = buf;
     296            str = skip_non_whitespace(str);
     297            str = skip_whitespace(str);
     298            // FIXME: no error check
     299            // xatou wouldn't work: "200 OK"
     300            status = atoi(str);
     301            switch (status) {
     302            case 0:
     303            case 100:
     304                while (gethdr(buf, sizeof(buf), sfp, &n) != NULL)
     305                    /* eat all remaining headers */;
     306                goto read_response;
     307            case 200:
     308                break;
     309            case 300:   /* redirection */
     310            case 301:
     311            case 302:
     312            case 303:
     313                break;
     314            case 206:
     315                if (beg_range)
    362316                    break;
    363                 case 300:   /* redirection */
    364                 case 301:
    365                 case 302:
    366                 case 303:
    367                     break;
    368                 case 206:
    369                     if (do_continue)
    370                         break;
    371                     /*FALLTHRU*/
    372                 default:
    373                     chomp(buf);
    374                     close_delete_and_die("server returned error %d: %s", atoi(s), buf);
     317                /*FALLTHRU*/
     318            default:
     319                /* Show first line only and kill any ESC tricks */
     320                buf[strcspn(buf, "\n\r\x1b")] = '\0';
     321                bb_error_msg_and_die("server returned error: %s", buf);
    375322            }
    376323
     
    378325             * Retrieve HTTP headers.
    379326             */
    380             while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
    381                 if (strcasecmp(buf, "content-length") == 0) {
    382                     unsigned long value;
    383                     if (safe_strtoul(s, &value)) {
    384                         close_delete_and_die("content-length %s is garbage", s);
     327            while ((str = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
     328                /* gethdr did already convert the "FOO:" string to lowercase */
     329                smalluint key = index_in_strings(keywords, *&buf) + 1;
     330                if (key == KEY_content_length) {
     331                    content_len = BB_STRTOOFF(str, NULL, 10);
     332                    if (errno || content_len < 0) {
     333                        bb_error_msg_and_die("content-length %s is garbage", str);
    385334                    }
    386                     filesize = value;
    387335                    got_clen = 1;
    388336                    continue;
    389337                }
    390                 if (strcasecmp(buf, "transfer-encoding") == 0) {
    391                     if (strcasecmp(s, "chunked") == 0) {
    392                         chunked = got_clen = 1;
    393                     } else {
    394                         close_delete_and_die("server wants to do %s transfer encoding", s);
    395                     }
     338                if (key == KEY_transfer_encoding) {
     339                    if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked)
     340                        bb_error_msg_and_die("server wants to do %s transfer encoding", str);
     341                    chunked = got_clen = 1;
    396342                }
    397                 if (strcasecmp(buf, "location") == 0) {
    398                     if (s[0] == '/')
    399                         target.path = bb_xstrdup(s+1);
     343                if (key == KEY_location) {
     344                    if (str[0] == '/')
     345                        /* free(target.allocated); */
     346                        target.path = /* target.allocated = */ xstrdup(str+1);
    400347                    else {
    401                         parse_url(bb_xstrdup(s), &target);
     348                        parse_url(str, &target);
    402349                        if (use_proxy == 0) {
    403350                            server.host = target.host;
    404351                            server.port = target.port;
    405352                        }
    406                         bb_lookup_host(&s_in, server.host);
    407                         s_in.sin_port = server.port;
     353                        free(lsa);
     354                        lsa = xhost2sockaddr(server.host, server.port);
    408355                        break;
    409356                    }
    410357                }
    411358            }
    412         } while(status >= 300);
     359        } while (status >= 300);
    413360
    414361        dfp = sfp;
    415     }
    416     else
    417     {
     362
     363    } else {
     364
    418365        /*
    419366         *  FTP session
    420367         */
    421         if (! target.user)
    422             target.user = bb_xstrdup("anonymous:busybox@");
    423 
    424         sfp = open_socket(&s_in);
     368        if (!target.user)
     369            target.user = xstrdup("anonymous:busybox@");
     370
     371        sfp = open_socket(lsa);
    425372        if (ftpcmd(NULL, NULL, sfp, buf) != 220)
    426             close_delete_and_die("%s", buf+4);
     373            bb_error_msg_and_die("%s", buf+4);
    427374
    428375        /*
     
    430377         * trying to log in
    431378         */
    432         s = strchr(target.user, ':');
    433         if (s)
    434             *(s++) = '\0';
    435         switch(ftpcmd("USER ", target.user, sfp, buf)) {
    436             case 230:
     379        str = strchr(target.user, ':');
     380        if (str)
     381            *(str++) = '\0';
     382        switch (ftpcmd("USER ", target.user, sfp, buf)) {
     383        case 230:
     384            break;
     385        case 331:
     386            if (ftpcmd("PASS ", str, sfp, buf) == 230)
    437387                break;
    438             case 331:
    439                 if (ftpcmd("PASS ", s, sfp, buf) == 230)
    440                     break;
    441                 /* FALLTHRU (failed login) */
    442             default:
    443                 close_delete_and_die("ftp login: %s", buf+4);
     388            /* FALLTHRU (failed login) */
     389        default:
     390            bb_error_msg_and_die("ftp login: %s", buf+4);
    444391        }
    445392
     
    450397         */
    451398        if (ftpcmd("SIZE ", target.path, sfp, buf) == 213) {
    452             unsigned long value;
    453             if (safe_strtoul(buf+4, &value)) {
    454                 close_delete_and_die("SIZE value is garbage");
     399            content_len = BB_STRTOOFF(buf+4, NULL, 10);
     400            if (errno || content_len < 0) {
     401                bb_error_msg_and_die("SIZE value is garbage");
    455402            }
    456             filesize = value;
    457403            got_clen = 1;
    458404        }
     
    461407         * Entering passive mode
    462408         */
    463         if (ftpcmd("PASV", NULL, sfp, buf) !=  227)
    464             close_delete_and_die("PASV: %s", buf+4);
    465         s = strrchr(buf, ',');
    466         *s = 0;
    467         port = atoi(s+1);
    468         s = strrchr(buf, ',');
    469         port += atoi(s+1) * 256;
    470         s_in.sin_port = htons(port);
    471         dfp = open_socket(&s_in);
    472 
    473         if (do_continue) {
    474             sprintf(buf, "REST %ld", beg_range);
    475             if (ftpcmd(buf, NULL, sfp, buf) != 350) {
    476                 if (output != stdout)
    477                     output = freopen(fname_out, "w", output);
    478                 do_continue = 0;
    479             } else
    480                 filesize -= beg_range;
     409        if (ftpcmd("PASV", NULL, sfp, buf) != 227) {
     410 pasv_error:
     411            bb_error_msg_and_die("bad response to %s: %s", "PASV", buf);
     412        }
     413        // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
     414        // Server's IP is N1.N2.N3.N4 (we ignore it)
     415        // Server's port for data connection is P1*256+P2
     416        str = strrchr(buf, ')');
     417        if (str) str[0] = '\0';
     418        str = strrchr(buf, ',');
     419        if (!str) goto pasv_error;
     420        port = xatou_range(str+1, 0, 255);
     421        *str = '\0';
     422        str = strrchr(buf, ',');
     423        if (!str) goto pasv_error;
     424        port += xatou_range(str+1, 0, 255) * 256;
     425        set_nport(lsa, htons(port));
     426        dfp = open_socket(lsa);
     427
     428        if (beg_range) {
     429            sprintf(buf, "REST %"OFF_FMT"d", beg_range);
     430            if (ftpcmd(buf, NULL, sfp, buf) == 350)
     431                content_len -= beg_range;
    481432        }
    482433
    483434        if (ftpcmd("RETR ", target.path, sfp, buf) > 150)
    484             close_delete_and_die("RETR: %s", buf+4);
    485     }
    486 
     435            bb_error_msg_and_die("bad response to RETR: %s", buf);
     436    }
     437    if (opt & WGET_OPT_SPIDER) {
     438        if (ENABLE_FEATURE_CLEAN_UP)
     439            fclose(sfp);
     440        goto done;
     441    }
    487442
    488443    /*
     
    491446    if (chunked) {
    492447        fgets(buf, sizeof(buf), dfp);
    493         filesize = strtol(buf, (char **) NULL, 16);
    494     }
    495 
    496     if (quiet_flag==FALSE)
     448        content_len = STRTOOFF(buf, NULL, 16);
     449        /* FIXME: error check?? */
     450    }
     451
     452    /* Do it before progressmeter (want to have nice error message) */
     453    if (output_fd < 0)
     454        output_fd = xopen(fname_out,
     455            O_WRONLY|O_CREAT|O_EXCL|O_TRUNC);
     456
     457    if (!(opt & WGET_OPT_QUIET))
    497458        progressmeter(-1);
    498459
    499460    do {
    500         while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, ((chunked || got_clen) && (filesize < sizeof(buf)) ? filesize : sizeof(buf)), dfp)) > 0) {
    501             if (safe_fwrite(buf, 1, n, output) != n) {
     461        while (content_len > 0 || !got_clen) {
     462            unsigned rdsz = sizeof(buf);
     463            if (content_len < sizeof(buf) && (chunked || got_clen))
     464                rdsz = (unsigned)content_len;
     465            n = safe_fread(buf, rdsz, dfp);
     466            if (n <= 0)
     467                break;
     468            if (full_write(output_fd, buf, n) != n) {
    502469                bb_perror_msg_and_die(bb_msg_write_error);
    503470            }
    504 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     471#if ENABLE_FEATURE_WGET_STATUSBAR
    505472            transferred += n;
    506473#endif
    507474            if (got_clen) {
    508                 filesize -= n;
     475                content_len -= n;
    509476            }
    510477        }
     
    513480            safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
    514481            safe_fgets(buf, sizeof(buf), dfp);
    515             filesize = strtol(buf, (char **) NULL, 16);
    516             if (filesize==0) {
     482            content_len = STRTOOFF(buf, NULL, 16);
     483            /* FIXME: error check? */
     484            if (content_len == 0) {
    517485                chunked = 0; /* all done! */
    518486            }
     
    524492    } while (chunked);
    525493
    526     if (quiet_flag==FALSE)
     494    if (!(opt & WGET_OPT_QUIET))
    527495        progressmeter(1);
    528496
     
    533501        ftpcmd("QUIT", NULL, sfp, buf);
    534502    }
     503done:
    535504    exit(EXIT_SUCCESS);
    536505}
    537506
    538507
    539 void parse_url(char *url, struct host_info *h)
    540 {
    541     char *cp, *sp, *up, *pp;
     508static void parse_url(char *src_url, struct host_info *h)
     509{
     510    char *url, *p, *sp;
     511
     512    /* h->allocated = */ url = xstrdup(src_url);
    542513
    543514    if (strncmp(url, "http://", 7) == 0) {
     
    546517        h->is_ftp = 0;
    547518    } else if (strncmp(url, "ftp://", 6) == 0) {
    548         h->port = bb_lookup_port("ftp", "tfp", 21);
     519        h->port = bb_lookup_port("ftp", "tcp", 21);
    549520        h->host = url + 6;
    550521        h->is_ftp = 1;
     
    552523        bb_error_msg_and_die("not an http or ftp url: %s", url);
    553524
     525    // FYI:
     526    // "Real" wget 'http://busybox.net?var=a/b' sends this request:
     527    //   'GET /?var=a/b HTTP 1.0'
     528    //   and saves 'index.html?var=a%2Fb' (we save 'b')
     529    // wget 'http://busybox.net?login=john@doe':
     530    //   request: 'GET /?login=john@doe HTTP/1.0'
     531    //   saves: 'index.html?login=john@doe' (we save '?login=john@doe')
     532    // wget 'http://busybox.net#test/test':
     533    //   request: 'GET / HTTP/1.0'
     534    //   saves: 'index.html' (we save 'test')
     535    //
     536    // We also don't add unique .N suffix if file exists...
    554537    sp = strchr(h->host, '/');
    555     if (sp) {
    556         *sp++ = '\0';
     538    p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p;
     539    p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p;
     540    if (!sp) {
     541        /* must be writable because of bb_get_last_path_component() */
     542        static char nullstr[] ALIGN1 = "";
     543        h->path = nullstr;
     544    } else if (*sp == '/') {
     545        *sp = '\0';
     546        h->path = sp + 1;
     547    } else { // '#' or '?'
     548        // http://busybox.net?login=john@doe is a valid URL
     549        // memmove converts to:
     550        // http:/busybox.nett?login=john@doe...
     551        memmove(h->host-1, h->host, sp - h->host);
     552        h->host--;
     553        sp[-1] = '\0';
    557554        h->path = sp;
    558     } else
    559         h->path = bb_xstrdup("");
    560 
    561     up = strrchr(h->host, '@');
    562     if (up != NULL) {
     555    }
     556
     557    sp = strrchr(h->host, '@');
     558    h->user = NULL;
     559    if (sp != NULL) {
    563560        h->user = h->host;
    564         *up++ = '\0';
    565         h->host = up;
    566     } else
    567         h->user = NULL;
    568 
    569     pp = h->host;
    570 
    571 #ifdef CONFIG_FEATURE_WGET_IP6_LITERAL
    572     if (h->host[0] == '[') {
    573         char *ep;
    574 
    575         ep = h->host + 1;
    576         while (*ep == ':' || isxdigit (*ep))
    577             ep++;
    578         if (*ep == ']') {
    579             h->host++;
    580             *ep = '\0';
    581             pp = ep + 1;
    582         }
    583     }
    584 #endif
    585 
    586     cp = strchr(pp, ':');
    587     if (cp != NULL) {
    588         *cp++ = '\0';
    589         h->port = htons(atoi(cp));
    590     }
    591 }
    592 
    593 
    594 FILE *open_socket(struct sockaddr_in *s_in)
     561        *sp = '\0';
     562        h->host = sp + 1;
     563    }
     564
     565    sp = h->host;
     566}
     567
     568
     569static FILE *open_socket(len_and_sockaddr *lsa)
    595570{
    596571    FILE *fp;
    597572
    598     fp = fdopen(xconnect(s_in), "r+");
     573    /* glibc 2.4 seems to try seeking on it - ??! */
     574    /* hopefully it understands what ESPIPE means... */
     575    fp = fdopen(xconnect_stream(lsa), "r+");
    599576    if (fp == NULL)
    600         bb_perror_msg_and_die("fdopen()");
     577        bb_perror_msg_and_die("fdopen");
    601578
    602579    return fp;
     
    604581
    605582
    606 char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
     583static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
    607584{
    608585    char *s, *hdrval;
     
    616593
    617594    /* see if we are at the end of the headers */
    618     for (s = buf ; *s == '\r' ; ++s)
     595    for (s = buf; *s == '\r'; ++s)
    619596        ;
    620597    if (s[0] == '\n')
     
    622599
    623600    /* convert the header name to lower case */
    624     for (s = buf ; isalnum(*s) || *s == '-' ; ++s)
     601    for (s = buf; isalnum(*s) || *s == '-'; ++s)
    625602        *s = tolower(*s);
    626603
     
    630607
    631608    /* locate the start of the header value */
    632     for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
     609    for (*s++ = '\0'; *s == ' ' || *s == '\t'; ++s)
    633610        ;
    634611    hdrval = s;
     
    651628}
    652629
    653 static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
    654 {
     630static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
     631{
     632    int result;
    655633    if (s1) {
    656         if (!s2) s2="";
     634        if (!s2) s2 = "";
    657635        fprintf(fp, "%s%s\r\n", s1, s2);
    658636        fflush(fp);
     
    663641
    664642        if (fgets(buf, 510, fp) == NULL) {
    665             bb_perror_msg_and_die("fgets()");
     643            bb_perror_msg_and_die("error getting response");
    666644        }
    667645        buf_ptr = strstr(buf, "\r\n");
     
    669647            *buf_ptr = '\0';
    670648        }
    671     } while (! isdigit(buf[0]) || buf[3] != ' ');
    672 
    673     return atoi(buf);
    674 }
    675 
    676 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     649    } while (!isdigit(buf[0]) || buf[3] != ' ');
     650
     651    buf[3] = '\0';
     652    result = xatoi_u(buf);
     653    buf[3] = ' ';
     654    return result;
     655}
     656
     657#if ENABLE_FEATURE_WGET_STATUSBAR
    677658/* Stuff below is from BSD rcp util.c, as added to openshh.
    678659 * Original copyright notice is retained at the end of this file.
    679  *
    680660 */
    681 
    682 
    683661static int
    684662getttywidth(void)
    685663{
    686     int width=0;
     664    int width;
    687665    get_terminal_width_height(0, &width, NULL);
    688     return (width);
     666    return width;
    689667}
    690668
     
    698676}
    699677
    700 static void
    701 alarmtimer(int wait)
     678static void alarmtimer(int iwait)
    702679{
    703680    struct itimerval itv;
    704681
    705     itv.it_value.tv_sec = wait;
     682    itv.it_value.tv_sec = iwait;
    706683    itv.it_value.tv_usec = 0;
    707684    itv.it_interval = itv.it_value;
     
    709686}
    710687
    711 
    712688static void
    713689progressmeter(int flag)
    714690{
    715     static struct timeval lastupdate;
     691    static unsigned lastupdate_sec;
     692    static unsigned start_sec;
    716693    static off_t lastsize, totalsize;
    717694
    718     struct timeval now, td, wait;
    719695    off_t abbrevsize;
    720     int elapsed, ratio, barlength, i;
    721     char buf[256];
    722 
    723     if (flag == -1) {
    724         (void) gettimeofday(&start, (struct timezone *) 0);
    725         lastupdate = start;
     696    unsigned since_last_update, elapsed;
     697    unsigned ratio;
     698    int barlength, i;
     699
     700    if (flag == -1) { /* first call to progressmeter */
     701        start_sec = monotonic_sec();
     702        lastupdate_sec = start_sec;
    726703        lastsize = 0;
    727         totalsize = filesize; /* as filesize changes.. */
    728     }
    729 
    730     (void) gettimeofday(&now, (struct timezone *) 0);
     704        totalsize = content_len + beg_range; /* as content_len changes.. */
     705    }
     706
    731707    ratio = 100;
    732708    if (totalsize != 0 && !chunked) {
    733         ratio = (int) (100 * transferred / totalsize);
    734         ratio = MIN(ratio, 100);
     709        /* long long helps to have it working even if !LFS */
     710        ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize);
     711        if (ratio > 100) ratio = 100;
    735712    }
    736713
    737714    fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
    738715
    739     barlength = getttywidth() - 51;
    740     if (barlength > 0 && barlength < sizeof(buf)) {
     716    barlength = getttywidth() - 49;
     717    if (barlength > 0) {
     718        /* god bless gcc for variable arrays :) */
    741719        i = barlength * ratio / 100;
    742         memset(buf, '*', i);
    743         memset(buf + i, ' ', barlength - i);
    744         buf[barlength] = '\0';
    745         fprintf(stderr, "|%s|", buf);
     720        {
     721            char buf[i+1];
     722            memset(buf, '*', i);
     723            buf[i] = '\0';
     724            fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
     725        }
    746726    }
    747727    i = 0;
    748     abbrevsize = transferred;
     728    abbrevsize = transferred + beg_range;
    749729    while (abbrevsize >= 100000) {
    750730        i++;
    751731        abbrevsize >>= 10;
    752732    }
    753     /* See http://en.wikipedia.org/wiki/Tera */
    754     fprintf(stderr, "%6d %c%c ", (int)abbrevsize, " KMGTPEZY"[i], i?'B':' ');
    755 
    756     timersub(&now, &lastupdate, &wait);
     733    /* see http://en.wikipedia.org/wiki/Tera */
     734    fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]);
     735
     736// Nuts! Ain't it easier to update progress meter ONLY when we transferred++?
     737// FIXME: get rid of alarmtimer + updateprogressmeter mess
     738
     739    elapsed = monotonic_sec();
     740    since_last_update = elapsed - lastupdate_sec;
    757741    if (transferred > lastsize) {
    758         lastupdate = now;
     742        lastupdate_sec = elapsed;
    759743        lastsize = transferred;
    760         if (wait.tv_sec >= STALLTIME)
    761             timeradd(&start, &wait, &start);
    762         wait.tv_sec = 0;
    763     }
    764     timersub(&now, &start, &td);
    765     elapsed = td.tv_sec;
    766 
    767     if (wait.tv_sec >= STALLTIME) {
     744        if (since_last_update >= STALLTIME) {
     745            /* We "cut off" these seconds from elapsed time
     746             * by adjusting start time */
     747            start_sec += since_last_update;
     748        }
     749        since_last_update = 0; /* we are un-stalled now */
     750    }
     751    elapsed -= start_sec; /* now it's "elapsed since start" */
     752
     753    if (since_last_update >= STALLTIME) {
    768754        fprintf(stderr, " - stalled -");
    769     } else if (transferred <= 0 || elapsed <= 0 || transferred > totalsize || chunked) {
    770         fprintf(stderr, "--:--:-- ETA");
    771755    } else {
    772         /* totalsize / (transferred/elapsed) - elapsed: */
    773         int eta = (int) (totalsize*elapsed/transferred - elapsed);
    774         i = eta % 3600;
    775         fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
    776     }
    777 
    778     if (flag == -1) {
     756        off_t to_download = totalsize - beg_range;
     757        if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) {
     758            fprintf(stderr, "--:--:-- ETA");
     759        } else {
     760            /* to_download / (transferred/elapsed) - elapsed: */
     761            int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed);
     762            /* (long long helps to have working ETA even if !LFS) */
     763            i = eta % 3600;
     764            fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
     765        }
     766    }
     767
     768    if (flag == -1) { /* first call to progressmeter */
    779769        struct sigaction sa;
    780770        sa.sa_handler = updateprogressmeter;
     
    783773        sigaction(SIGALRM, &sa, NULL);
    784774        alarmtimer(1);
    785     } else if (flag == 1) {
     775    } else if (flag == 1) { /* last call to progressmeter */
    786776        alarmtimer(0);
    787777        transferred = 0;
     
    789779    }
    790780}
    791 #endif
     781#endif /* FEATURE_WGET_STATUSBAR */
    792782
    793783/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
     
    826816 * SUCH DAMAGE.
    827817 *
    828  *  $Id: wget.c,v 1.75 2004/10/08 08:27:40 andersen Exp $
    829818 */
  • branches/stable/mindi-busybox/networking/zcip.c

    r902 r1770  
     1/* vi: set sw=4 ts=4: */
    12/*
    23 * RFC3927 ZeroConf IPv4 Link-Local addressing
     
    2324// - link status monitoring (restart on link-up; stop on link-down)
    2425
    25 #include "busybox.h"
    26 #include <errno.h>
    27 #include <string.h>
    2826#include <syslog.h>
    2927#include <poll.h>
    30 #include <time.h>
    31 
    3228#include <sys/wait.h>
    33 
    3429#include <netinet/ether.h>
    3530#include <net/ethernet.h>
    3631#include <net/if.h>
    3732#include <net/if_arp.h>
    38 
    3933#include <linux/if_packet.h>
    4034#include <linux/sockios.h>
    4135
     36#include "libbb.h"
     37
     38/* We don't need more than 32 bits of the counter */
     39#define MONOTONIC_US() ((unsigned)monotonic_us())
    4240
    4341struct arp_packet {
     
    7270};
    7371
    74 /* Implicitly zero-initialized */
    75 static const struct in_addr null_ip;
    76 static const struct ether_addr null_addr;
    77 static int verbose;
    78 
    79 #define DBG(fmt,args...) \
     72#define VDBG(fmt,args...) \
    8073    do { } while (0)
    81 #define VDBG    DBG
    8274
    8375/**
     
    8779static void pick(struct in_addr *ip)
    8880{
    89     unsigned    tmp;
    90 
    91     /* use cheaper math than lrand48() mod N */
     81    unsigned tmp;
     82
    9283    do {
    93         tmp = (lrand48() >> 16) & IN_CLASSB_HOST;
     84        tmp = rand() & IN_CLASSB_HOST;
    9485    } while (tmp > (IN_CLASSB_HOST - 0x0200));
    9586    ip->s_addr = htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
     
    9990 * Broadcast an ARP packet.
    10091 */
    101 static int arp(int fd, struct sockaddr *saddr, int op,
     92static void arp(int fd, struct sockaddr *saddr, int op,
    10293    const struct ether_addr *source_addr, struct in_addr source_ip,
    10394    const struct ether_addr *target_addr, struct in_addr target_ip)
     
    118109    p.arp.arp_op = htons(op);
    119110    memcpy(&p.arp.arp_sha, source_addr, ETH_ALEN);
    120     memcpy(&p.arp.arp_spa, &source_ip, sizeof (p.arp.arp_spa));
     111    memcpy(&p.arp.arp_spa, &source_ip, sizeof(p.arp.arp_spa));
    121112    memcpy(&p.arp.arp_tha, target_addr, ETH_ALEN);
    122     memcpy(&p.arp.arp_tpa, &target_ip, sizeof (p.arp.arp_tpa));
     113    memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa));
    123114
    124115    // send it
    125     if (sendto(fd, &p, sizeof (p), 0, saddr, sizeof (*saddr)) < 0) {
    126         perror("sendto");
     116    xsendto(fd, &p, sizeof(p), saddr, sizeof(*saddr));
     117
     118    // Currently all callers ignore errors, that's why returns are
     119    // commented out...
     120    //return 0;
     121}
     122
     123/**
     124 * Run a script. argv[2] is already NULL.
     125 */
     126static int run(char *argv[3], const char *intf, struct in_addr *ip)
     127{
     128    int status;
     129
     130    VDBG("%s run %s %s\n", intf, argv[0], argv[1]);
     131
     132    if (ip) {
     133        char *addr = inet_ntoa(*ip);
     134        setenv("ip", addr, 1);
     135        bb_info_msg("%s %s %s", argv[1], intf, addr);
     136    }
     137
     138    status = wait4pid(spawn(argv));
     139    if (status < 0) {
     140        bb_perror_msg("%s %s", argv[1], intf);
    127141        return -errno;
    128142    }
    129     return 0;
     143    if (status != 0)
     144        bb_error_msg("script %s %s failed, exitcode=%d", argv[0], argv[1], status);
     145    return status;
    130146}
    131147
    132148/**
    133  * Run a script.
    134  */
    135 static int run(char *script, char *arg, char *intf, struct in_addr *ip)
     149 * Return milliseconds of random delay, up to "secs" seconds.
     150 */
     151static unsigned ALWAYS_INLINE ms_rdelay(unsigned secs)
    136152{
    137     int pid, status;
    138     char *why;
    139 
    140     if (script != NULL) {
    141         VDBG("%s run %s %s\n", intf, script, arg);
    142         if (ip != NULL) {
    143             char *addr = inet_ntoa(*ip);
    144             setenv("ip", addr, 1);
    145             syslog(LOG_INFO, "%s %s %s", arg, intf, addr);
    146         }
    147 
    148         pid = vfork();
    149         if (pid < 0) {          // error
    150             why = "vfork";
    151             goto bad;
    152         } else if (pid == 0) {      // child
    153             execl(script, script, arg, NULL);
    154             perror("execl");
    155             _exit(EXIT_FAILURE);
    156         }
    157 
    158         if (waitpid(pid, &status, 0) <= 0) {
    159             why = "waitpid";
    160             goto bad;
    161         }
    162         if (WEXITSTATUS(status) != 0) {
    163             bb_error_msg("script %s failed, exit=%d\n",
    164                     script, WEXITSTATUS(status));
    165             return -errno;
     153    return rand() % (secs * 1000);
     154}
     155
     156/**
     157 * main program
     158 */
     159int zcip_main(int argc, char **argv);
     160int zcip_main(int argc, char **argv)
     161{
     162    int state = PROBE;
     163    struct ether_addr eth_addr;
     164    const char *why;
     165    int fd;
     166    char *r_opt;
     167    unsigned opts;
     168
     169    /* Ugly trick, but I want these zeroed in one go */
     170    struct {
     171        const struct in_addr null_ip;
     172        const struct ether_addr null_addr;
     173        struct sockaddr saddr;
     174        struct in_addr ip;
     175        struct ifreq ifr;
     176        char *intf;
     177        char *script_av[3];
     178        int timeout_ms; /* must be signed */
     179        unsigned conflicts;
     180        unsigned nprobes;
     181        unsigned nclaims;
     182        int ready;
     183        int verbose;
     184    } L;
     185#define null_ip    (L.null_ip   )
     186#define null_addr  (L.null_addr )
     187#define saddr      (L.saddr     )
     188#define ip         (L.ip        )
     189#define ifr        (L.ifr       )
     190#define intf       (L.intf      )
     191#define script_av  (L.script_av )
     192#define timeout_ms (L.timeout_ms)
     193#define conflicts  (L.conflicts )
     194#define nprobes    (L.nprobes   )
     195#define nclaims    (L.nclaims   )
     196#define ready      (L.ready     )
     197#define verbose    (L.verbose   )
     198
     199    memset(&L, 0, sizeof(L));
     200
     201#define FOREGROUND (opts & 1)
     202#define QUIT       (opts & 2)
     203    // parse commandline: prog [options] ifname script
     204    // exactly 2 args; -v accumulates and implies -f
     205    opt_complementary = "=2:vv:vf";
     206    opts = getopt32(argv, "fqr:v", &r_opt, &verbose);
     207    if (!FOREGROUND) {
     208        /* Do it early, before all bb_xx_msg calls */
     209        openlog(applet_name, 0, LOG_DAEMON);
     210        logmode |= LOGMODE_SYSLOG;
     211    }
     212    if (opts & 4) { // -r n.n.n.n
     213        if (inet_aton(r_opt, &ip) == 0
     214         || (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR
     215        ) {
     216            bb_error_msg_and_die("invalid link address");
    166217        }
    167218    }
    168     return 0;
    169 bad:
    170     status = -errno;
    171     syslog(LOG_ERR, "%s %s, %s error: %s",
    172         arg, intf, why, strerror(errno));
    173     return status;
    174 }
    175 
    176 
    177 /**
    178  * Return milliseconds of random delay, up to "secs" seconds.
    179  */
    180 static inline unsigned ms_rdelay(unsigned secs)
    181 {
    182     return lrand48() % (secs * 1000);
    183 }
    184 
    185 /**
    186  * main program
    187  */
    188 
    189 int zcip_main(int argc, char *argv[])
    190 {
    191     char *intf = NULL;
    192     char *script = NULL;
    193     int quit = 0;
    194     int foreground = 0;
    195 
    196     char *why;
    197     struct sockaddr saddr;
    198     struct ether_addr addr;
    199     struct in_addr ip = { 0 };
    200     int fd;
    201     int ready = 0;
    202     suseconds_t timeout = 0;    // milliseconds
    203     unsigned conflicts = 0;
    204     unsigned nprobes = 0;
    205     unsigned nclaims = 0;
    206     int t;
    207     int state = PROBE;
    208 
    209     // parse commandline: prog [options] ifname script
    210     while ((t = getopt(argc, argv, "fqr:v")) != EOF) {
    211         switch (t) {
    212         case 'f':
    213             foreground = 1;
    214             continue;
    215         case 'q':
    216             quit = 1;
    217             continue;
    218         case 'r':
    219             if (inet_aton(optarg, &ip) == 0
    220                     || (ntohl(ip.s_addr) & IN_CLASSB_NET)
    221                         != LINKLOCAL_ADDR) {
    222                 bb_error_msg_and_die("invalid link address");
    223             }
    224             continue;
    225         case 'v':
    226             verbose++;
    227             foreground = 1;
    228             continue;
    229         default:
    230             bb_error_msg_and_die("bad option");
    231         }
    232     }
    233     if (optind < argc - 1) {
    234         intf = argv[optind++];
    235         setenv("interface", intf, 1);
    236         script = argv[optind++];
    237     }
    238     if (optind != argc || !intf)
    239         bb_show_usage();
    240     openlog(bb_applet_name, 0, LOG_DAEMON);
     219    // On NOMMU reexec early (or else we will rerun things twice)
     220#if !BB_MMU
     221    if (!FOREGROUND)
     222        bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
     223#endif
     224    argc -= optind;
     225    argv += optind;
     226
     227    intf = argv[0];
     228    script_av[0] = argv[1];
     229    setenv("interface", intf, 1);
    241230
    242231    // initialize the interface (modprobe, ifup, etc)
    243     if (run(script, "init", intf, NULL) < 0)
     232    script_av[1] = (char*)"init";
     233    if (run(script_av, intf, NULL))
    244234        return EXIT_FAILURE;
    245235
    246236    // initialize saddr
    247     memset(&saddr, 0, sizeof (saddr));
    248     safe_strncpy(saddr.sa_data, intf, sizeof (saddr.sa_data));
     237    //memset(&saddr, 0, sizeof(saddr));
     238    safe_strncpy(saddr.sa_data, intf, sizeof(saddr.sa_data));
    249239
    250240    // open an ARP socket
    251     if ((fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) < 0) {
    252         why = "open";
    253 fail:
    254         foreground = 1;
    255         goto bad;
    256     }
     241    fd = xsocket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
    257242    // bind to the interface's ARP socket
    258     if (bind(fd, &saddr, sizeof (saddr)) < 0) {
    259         why = "bind";
    260         goto fail;
    261     } else {
    262         struct ifreq ifr;
    263         unsigned short seed[3];
    264 
    265         // get the interface's ethernet address
    266         memset(&ifr, 0, sizeof (ifr));
    267         strncpy(ifr.ifr_name, intf, sizeof (ifr.ifr_name));
    268         if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
    269             why = "get ethernet address";
    270             goto fail;
    271         }
    272         memcpy(&addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
    273 
    274         // start with some stable ip address, either a function of
    275         // the hardware address or else the last address we used.
    276         // NOTE: the sequence of addresses we try changes only
    277         // depending on when we detect conflicts.
    278         memcpy(seed, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
    279         seed48(seed);
    280         if (ip.s_addr == 0)
    281             pick(&ip);
    282     }
     243    xbind(fd, &saddr, sizeof(saddr));
     244
     245    // get the interface's ethernet address
     246    //memset(&ifr, 0, sizeof(ifr));
     247    strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name));
     248    xioctl(fd, SIOCGIFHWADDR, &ifr);
     249    memcpy(&eth_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
     250
     251    // start with some stable ip address, either a function of
     252    // the hardware address or else the last address we used.
     253    // NOTE: the sequence of addresses we try changes only
     254    // depending on when we detect conflicts.
     255    srand(*(unsigned*)&ifr.ifr_hwaddr.sa_data);
     256    if (ip.s_addr == 0)
     257        pick(&ip);
    283258
    284259    // FIXME cases to handle:
     
    287262
    288263    // daemonize now; don't delay system startup
    289     if (!foreground) {
    290         if (daemon(0, verbose) < 0) {
    291             why = "daemon";
    292             goto bad;
    293         }
    294         syslog(LOG_INFO, "start, interface %s", intf);
     264    if (!FOREGROUND) {
     265#if BB_MMU
     266        bb_daemonize(DAEMON_CHDIR_ROOT);
     267#endif
     268        bb_info_msg("start, interface %s", intf);
    295269    }
    296270
     
    305279    while (1) {
    306280        struct pollfd fds[1];
    307         struct timeval tv1;
     281        unsigned deadline_us;
    308282        struct arp_packet p;
     283
     284        int source_ip_conflict = 0;
     285        int target_ip_conflict = 0;
    309286
    310287        fds[0].fd = fd;
     
    312289        fds[0].revents = 0;
    313290
    314         int source_ip_conflict = 0;
    315         int target_ip_conflict = 0;
    316 
    317291        // poll, being ready to adjust current timeout
    318         if (!timeout) {
    319             timeout = ms_rdelay(PROBE_WAIT);
     292        if (!timeout_ms) {
     293            timeout_ms = ms_rdelay(PROBE_WAIT);
    320294            // FIXME setsockopt(fd, SO_ATTACH_FILTER, ...) to
    321295            // make the kernel filter out all packets except
    322296            // ones we'd care about.
    323297        }
    324         // set tv1 to the point in time when we timeout
    325         gettimeofday(&tv1, NULL);
    326         tv1.tv_usec += (timeout % 1000) * 1000;
    327         while (tv1.tv_usec > 1000000) {
    328             tv1.tv_usec -= 1000000;
    329             tv1.tv_sec++;
    330         }
    331         tv1.tv_sec += timeout / 1000;
    332    
    333         VDBG("...wait %ld %s nprobes=%d, nclaims=%d\n",
    334                 timeout, intf, nprobes, nclaims);
    335         switch (poll(fds, 1, timeout)) {
     298        // set deadline_us to the point in time when we timeout
     299        deadline_us = MONOTONIC_US() + timeout_ms * 1000;
     300
     301        VDBG("...wait %d %s nprobes=%u, nclaims=%u\n",
     302                timeout_ms, intf, nprobes, nclaims);
     303        switch (poll(fds, 1, timeout_ms)) {
    336304
    337305        // timeout
     
    340308            switch (state) {
    341309            case PROBE:
    342                 // timeouts in the PROBE state means no conflicting ARP packets
     310                // timeouts in the PROBE state mean no conflicting ARP packets
    343311                // have been received, so we can progress through the states
    344312                if (nprobes < PROBE_NUM) {
    345313                    nprobes++;
    346                     VDBG("probe/%d %s@%s\n",
     314                    VDBG("probe/%u %s@%s\n",
    347315                            nprobes, intf, inet_ntoa(ip));
    348                     (void)arp(fd, &saddr, ARPOP_REQUEST,
    349                             &addr, null_ip,
     316                    arp(fd, &saddr, ARPOP_REQUEST,
     317                            &eth_addr, null_ip,
    350318                            &null_addr, ip);
    351                     timeout = PROBE_MIN * 1000;
    352                     timeout += ms_rdelay(PROBE_MAX
    353                             - PROBE_MIN);
     319                    timeout_ms = PROBE_MIN * 1000;
     320                    timeout_ms += ms_rdelay(PROBE_MAX - PROBE_MIN);
    354321                }
    355322                else {
     
    357324                    state = ANNOUNCE;
    358325                    nclaims = 0;
    359                     VDBG("announce/%d %s@%s\n",
     326                    VDBG("announce/%u %s@%s\n",
    360327                            nclaims, intf, inet_ntoa(ip));
    361                     (void)arp(fd, &saddr, ARPOP_REQUEST,
    362                             &addr, ip,
    363                             &addr, ip);
    364                     timeout = ANNOUNCE_INTERVAL * 1000;
     328                    arp(fd, &saddr, ARPOP_REQUEST,
     329                            &eth_addr, ip,
     330                            &eth_addr, ip);
     331                    timeout_ms = ANNOUNCE_INTERVAL * 1000;
    365332                }
    366333                break;
    367334            case RATE_LIMIT_PROBE:
    368                 // timeouts in the RATE_LIMIT_PROBE state means no conflicting ARP packets
     335                // timeouts in the RATE_LIMIT_PROBE state mean no conflicting ARP packets
    369336                // have been received, so we can move immediately to the announce state
    370337                state = ANNOUNCE;
    371338                nclaims = 0;
    372                 VDBG("announce/%d %s@%s\n",
     339                VDBG("announce/%u %s@%s\n",
    373340                        nclaims, intf, inet_ntoa(ip));
    374                 (void)arp(fd, &saddr, ARPOP_REQUEST,
    375                         &addr, ip,
    376                         &addr, ip);
    377                 timeout = ANNOUNCE_INTERVAL * 1000;
     341                arp(fd, &saddr, ARPOP_REQUEST,
     342                        &eth_addr, ip,
     343                        &eth_addr, ip);
     344                timeout_ms = ANNOUNCE_INTERVAL * 1000;
    378345                break;
    379346            case ANNOUNCE:
    380                 // timeouts in the ANNOUNCE state means no conflicting ARP packets
     347                // timeouts in the ANNOUNCE state mean no conflicting ARP packets
    381348                // have been received, so we can progress through the states
    382349                if (nclaims < ANNOUNCE_NUM) {
    383350                    nclaims++;
    384                     VDBG("announce/%d %s@%s\n",
     351                    VDBG("announce/%u %s@%s\n",
    385352                            nclaims, intf, inet_ntoa(ip));
    386                     (void)arp(fd, &saddr, ARPOP_REQUEST,
    387                             &addr, ip,
    388                             &addr, ip);
    389                     timeout = ANNOUNCE_INTERVAL * 1000;
     353                    arp(fd, &saddr, ARPOP_REQUEST,
     354                            &eth_addr, ip,
     355                            &eth_addr, ip);
     356                    timeout_ms = ANNOUNCE_INTERVAL * 1000;
    390357                }
    391358                else {
     
    394361                    // link is ok to use earlier
    395362                    // FIXME update filters
    396                     run(script, "config", intf, &ip);
     363                    script_av[1] = (char*)"config";
     364                    run(script_av, intf, &ip);
    397365                    ready = 1;
    398366                    conflicts = 0;
    399                     timeout = -1; // Never timeout in the monitor state.
    400 
    401                     // NOTE:  all other exit paths
     367                    timeout_ms = -1; // Never timeout in the monitor state.
     368
     369                    // NOTE: all other exit paths
    402370                    // should deconfig ...
    403                     if (quit)
     371                    if (QUIT)
    404372                        return EXIT_SUCCESS;
    405373                }
     
    408376                // We won!  No ARP replies, so just go back to monitor.
    409377                state = MONITOR;
    410                 timeout = -1;
     378                timeout_ms = -1;
    411379                conflicts = 0;
    412380                break;
     
    415383                state = PROBE;
    416384                pick(&ip);
    417                 timeout = 0;
     385                timeout_ms = 0;
    418386                nprobes = 0;
    419387                nclaims = 0;
     
    425393            // We need to adjust the timeout in case we didn't receive
    426394            // a conflicting packet.
    427             if (timeout > 0) {
    428                 struct timeval tv2;
    429 
    430                 gettimeofday(&tv2, NULL);
    431                 if (timercmp(&tv1, &tv2, <)) {
     395            if (timeout_ms > 0) {
     396                unsigned diff = deadline_us - MONOTONIC_US();
     397                if ((int)(diff) < 0) {
    432398                    // Current time is greater than the expected timeout time.
    433399                    // Should never happen.
    434400                    VDBG("missed an expected timeout\n");
    435                     timeout = 0;
     401                    timeout_ms = 0;
    436402                } else {
    437403                    VDBG("adjusting timeout\n");
    438                     timersub(&tv1, &tv2, &tv1);
    439                     timeout = 1000 * tv1.tv_sec
    440                             + tv1.tv_usec / 1000;
     404                    timeout_ms = diff / 1000;
     405                    if (!timeout_ms) timeout_ms = 1;
    441406                }
    442407            }
     
    446411                    // FIXME: links routinely go down;
    447412                    // this shouldn't necessarily exit.
    448                     bb_error_msg("%s: poll error\n", intf);
     413                    bb_error_msg("%s: poll error", intf);
    449414                    if (ready) {
    450                         run(script, "deconfig",
    451                                 intf, &ip);
     415                        script_av[1] = (char*)"deconfig";
     416                        run(script_av, intf, &ip);
    452417                    }
    453418                    return EXIT_FAILURE;
     
    457422
    458423            // read ARP packet
    459             if (recv(fd, &p, sizeof (p), 0) < 0) {
     424            if (recv(fd, &p, sizeof(p), 0) < 0) {
    460425                why = "recv";
    461426                goto bad;
     
    486451
    487452            if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
    488                 memcmp(&addr, &p.arp.arp_sha, ETH_ALEN) != 0) {
     453                memcmp(&eth_addr, &p.arp.arp_sha, ETH_ALEN) != 0) {
    489454                source_ip_conflict = 1;
    490455            }
    491456            if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
    492457                p.arp.arp_op == htons(ARPOP_REQUEST) &&
    493                 memcmp(&addr, &p.arp.arp_tha, ETH_ALEN) != 0) {
     458                memcmp(&eth_addr, &p.arp.arp_tha, ETH_ALEN) != 0) {
    494459                target_ip_conflict = 1;
    495460            }
    496461
    497             VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", 
     462            VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
    498463                state, source_ip_conflict, target_ip_conflict);
    499464            switch (state) {
     
    506471                    if (conflicts >= MAX_CONFLICTS) {
    507472                        VDBG("%s ratelimit\n", intf);
    508                         timeout = RATE_LIMIT_INTERVAL * 1000;
     473                        timeout_ms = RATE_LIMIT_INTERVAL * 1000;
    509474                        state = RATE_LIMIT_PROBE;
    510475                    }
     
    512477                    // restart the whole protocol
    513478                    pick(&ip);
    514                     timeout = 0;
     479                    timeout_ms = 0;
    515480                    nprobes = 0;
    516481                    nclaims = 0;
     
    522487                    VDBG("monitor conflict -- defending\n");
    523488                    state = DEFEND;
    524                     timeout = DEFEND_INTERVAL * 1000;
    525                     (void)arp(fd, &saddr,
     489                    timeout_ms = DEFEND_INTERVAL * 1000;
     490                    arp(fd, &saddr,
    526491                            ARPOP_REQUEST,
    527                             &addr, ip,
    528                             &addr, ip);
     492                            &eth_addr, ip,
     493                            &eth_addr, ip);
    529494                }
    530495                break;
     
    535500                    VDBG("defend conflict -- starting over\n");
    536501                    ready = 0;
    537                     run(script, "deconfig", intf, &ip);
     502                    script_av[1] = (char*)"deconfig";
     503                    run(script_av, intf, &ip);
    538504
    539505                    // restart the whole protocol
    540506                    pick(&ip);
    541                     timeout = 0;
     507                    timeout_ms = 0;
    542508                    nprobes = 0;
    543509                    nclaims = 0;
     
    549515                state = PROBE;
    550516                pick(&ip);
    551                 timeout = 0;
     517                timeout_ms = 0;
    552518                nprobes = 0;
    553519                nclaims = 0;
     
    561527        } // switch poll
    562528    }
    563 bad:
    564     if (foreground)
    565         perror(why);
    566     else
    567         syslog(LOG_ERR, "%s %s, %s error: %s",
    568             bb_applet_name, intf, why, strerror(errno));
     529 bad:
     530    bb_perror_msg("%s, %s", intf, why);
    569531    return EXIT_FAILURE;
    570532}
Note: See TracChangeset for help on using the changeset viewer.