Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (14 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
Location:
branches/2.2.9/mindi-busybox/networking
Files:
20 added
74 edited

Legend:

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

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    67menu "Networking Utilities"
    78
     9config NBDCLIENT
     10    bool "nbd-client"
     11    default y
     12    help
     13      Network block device client
     14config NC
     15    bool "nc"
     16    default y
     17    help
     18      A simple Unix utility which reads and writes data across network
     19      connections.
     20
     21config NC_SERVER
     22    bool "Netcat server options (-l)"
     23    default y
     24    depends on NC
     25    help
     26      Allow netcat to act as a server.
     27
     28config NC_EXTRA
     29    bool "Netcat extensions (-eiw and filename)"
     30    default y
     31    depends on NC
     32    help
     33      Add -e (support for executing the rest of the command line after
     34      making or receiving a successful connection), -i (delay interval for
     35      lines sent), -w (timeout for initial connection).
     36
     37config NC_110_COMPAT
     38    bool "Netcat 1.10 compatibility (+2.5k)"
     39    default n  # off specially for Rob
     40    depends on NC
     41    help
     42      This option makes nc closely follow original nc-1.10.
     43      The code is about 2.5k bigger. It enables
     44      -s ADDR, -n, -u, -v, -o FILE, -z options, but loses
     45      busybox-specific extensions: -f FILE and -ll.
     46
    847config FEATURE_IPV6
    948    bool "Enable IPv6 support"
    10     default n
     49    default y
    1150    help
    1251      Enable IPv6 support in busybox.
    1352      This adds IPv6 support in the networking applets.
     53
     54config FEATURE_UNIX_LOCAL
     55    bool "Enable Unix domain socket support (usually not needed)"
     56    default n
     57    help
     58      Enable Unix domain socket support in all busybox networking
     59      applets.  Address of the form local:/path/to/unix/socket
     60      will be recognized.
     61
     62      This extension is almost never used in real world usage.
     63      You most likely want to say N.
     64
     65config FEATURE_PREFER_IPV4_ADDRESS
     66    bool "Prefer IPv4 addresses from DNS queries"
     67    default y
     68    depends on FEATURE_IPV6
     69    help
     70      Use IPv4 address of network host if it has one.
     71
     72      If this option is off, the first returned address will be used.
     73      This may cause problems when your DNS server is IPv6-capable and
     74      is returning IPv6 host addresses too. If IPv6 address
     75      precedes IPv4 one in DNS reply, busybox network applets
     76      (e.g. wget) will use IPv6 address. On an IPv6-incapable host
     77      or network applets will fail to connect to the host
     78      using IPv6 address.
    1479
    1580config VERBOSE_RESOLUTION_ERRORS
     
    2388config ARP
    2489    bool "arp"
    25     default n
     90    default y
     91    depends on PLATFORM_LINUX
    2692    help
    2793      Manipulate the system ARP cache.
     
    2995config ARPING
    3096    bool "arping"
    31     default n
     97    default y
     98    depends on PLATFORM_LINUX
    3299    help
    33100      Ping hosts by ARP packets.
     101
     102config BRCTL
     103    bool "brctl"
     104    default y
     105    depends on PLATFORM_LINUX
     106    help
     107      Manage ethernet bridges.
     108      Supports addbr/delbr and addif/delif.
     109
     110config FEATURE_BRCTL_FANCY
     111    bool "Fancy options"
     112    default y
     113    depends on BRCTL
     114    help
     115      Add support for extended option like:
     116        setageing, setfd, sethello, setmaxage,
     117        setpathcost, setportprio, setbridgeprio,
     118        stp
     119      This adds about 600 bytes.
     120
     121config FEATURE_BRCTL_SHOW
     122    bool "Support show, showmac and showstp"
     123    default y
     124    depends on BRCTL && FEATURE_BRCTL_FANCY
     125    help
     126      Add support for option which prints the current config:
     127        showmacs, showstp, show
    34128
    35129config DNSD
    36130    bool "dnsd"
    37     default n
     131    default y
    38132    help
    39133      Small and static DNS server daemon.
     
    41135config ETHER_WAKE
    42136    bool "ether-wake"
    43     default n
     137    default y
     138    depends on PLATFORM_LINUX
    44139    help
    45140      Send a magic packet to wake up sleeping machines.
     
    47142config FAKEIDENTD
    48143    bool "fakeidentd"
    49     default n
     144    default y
    50145    select FEATURE_SYSLOG
    51146    help
     
    53148      fake value on any query.
    54149
     150config FTPD
     151    bool "ftpd"
     152    default y
     153    help
     154      simple FTP daemon. You have to run it via inetd.
     155
     156config FEATURE_FTP_WRITE
     157    bool "Enable upload commands"
     158    default y
     159    depends on FTPD
     160    help
     161      Enable all kinds of FTP upload commands (-w option)
     162
     163config FEATURE_FTPD_ACCEPT_BROKEN_LIST
     164    bool "Enable workaround for RFC-violating clients"
     165    default y
     166    depends on FTPD
     167    help
     168      Some ftp clients (among them KDE's Konqueror) issue illegal
     169      "LIST -l" requests. This option works around such problems.
     170      It might prevent you from listing files starting with "-" and
     171      it increases the code size by ~40 bytes.
     172      Most other ftp servers seem to behave similar to this.
     173
    55174config FTPGET
    56175    bool "ftpget"
    57     default n
     176    default y
    58177    help
    59178      Retrieve a remote file via FTP.
     
    61180config FTPPUT
    62181    bool "ftpput"
    63     default n
     182    default y
    64183    help
    65184      Store a remote file via FTP.
     
    67186config FEATURE_FTPGETPUT_LONG_OPTIONS
    68187    bool "Enable long options in ftpget/ftpput"
    69     default n
    70     depends on GETOPT_LONG && (FTPGET || FTPPUT)
     188    default y
     189    depends on LONG_OPTS && (FTPGET || FTPPUT)
    71190    help
    72191      Support long options for the ftpget/ftpput applet.
     
    74193config HOSTNAME
    75194    bool "hostname"
    76     default n
     195    default y
    77196    help
    78197      Show or set the system's host name.
     
    80199config HTTPD
    81200    bool "httpd"
    82     default n
     201    default y
    83202    help
    84203      Serve web pages via an HTTP server.
     204
     205config FEATURE_HTTPD_RANGES
     206    bool "Support 'Ranges:' header"
     207    default y
     208    depends on HTTPD
     209    help
     210      Makes httpd emit "Accept-Ranges: bytes" header and understand
     211      "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
     212      downloads, seeking in multimedia players etc.
    85213
    86214config FEATURE_HTTPD_USE_SENDFILE
    87215    bool "Use sendfile system call"
    88     default n
     216    default y
    89217    depends on HTTPD
    90218    help
     
    92220      instead of read/write loop.
    93221
    94 config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    95     bool "Support reloading the global config file using hup signal"
    96     default n
    97     depends on HTTPD
    98     help
    99       This option enables processing of SIGHUP to reload cached
    100       configuration settings.
    101 
    102222config FEATURE_HTTPD_SETUID
    103223    bool "Enable -u <user> option"
    104     default n
     224    default y
    105225    depends on HTTPD
    106226    help
     
    120240config FEATURE_HTTPD_AUTH_MD5
    121241    bool "Support MD5 crypted passwords for http Authentication"
    122     default n
     242    default y
    123243    depends on FEATURE_HTTPD_BASIC_AUTH
    124244    help
     
    126246      using md5 passwords.
    127247
    128 config FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    129     bool "Support loading additional MIME types at run-time"
    130     default n
    131     depends on HTTPD
    132     help
    133       This option enables support for additional MIME types at
    134       run-time to be specified in the configuration file.
    135 
    136248config FEATURE_HTTPD_CGI
    137249    bool "Support Common Gateway Interface (CGI)"
     
    143255
    144256config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    145     bool "Enable support for running scripts through an interpreter"
    146     default n
     257    bool "Support for running scripts through an interpreter"
     258    default y
    147259    depends on FEATURE_HTTPD_CGI
    148260    help
     
    154266
    155267config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
    156     bool "Support the REMOTE_PORT environment variable for CGI"
    157     default n
     268    bool "Set REMOTE_PORT environment variable for CGI"
     269    default y
    158270    depends on FEATURE_HTTPD_CGI
    159271    help
     
    162274
    163275config FEATURE_HTTPD_ENCODE_URL_STR
    164     bool "Enable the -e option for shell script CGI simplification."
     276    bool "Enable -e option (useful for CGIs written as shell scripts)"
    165277    default y
    166278    depends on HTTPD
    167279    help
    168       This option allows html encoding arbitrary
    169       strings for display of the browser. Output goes to stdout.
    170       For example, httpd -e "<Hello World>" as
     280      This option allows html encoding of arbitrary strings for display
     281      by the browser. Output goes to stdout.
     282      For example, httpd -e "<Hello World>" produces
    171283      "&#60Hello&#32World&#62".
    172284
    173285config FEATURE_HTTPD_ERROR_PAGES
    174     bool "Enable support for custom error pages"
    175     default n
     286    bool "Support for custom error pages"
     287    default y
    176288    depends on HTTPD
    177289    help
     
    184296      message.
    185297
     298config FEATURE_HTTPD_PROXY
     299    bool "Support for reverse proxy"
     300    default y
     301    depends on HTTPD
     302    help
     303      This option allows you to define URLs that will be forwarded
     304      to another HTTP server. To setup add the following line to the
     305      configuration file
     306            P:/url/:http://hostname[:port]/new/path/
     307      Then a request to /url/myfile will be forwarded to
     308      http://hostname[:port]/new/path/myfile.
     309
     310config FEATURE_HTTPD_GZIP
     311    bool "Support for GZIP content encoding"
     312    default y
     313    depends on HTTPD
     314    help
     315      Makes httpd send files using GZIP content encoding if the
     316      client supports it and a pre-compressed <file>.gz exists.
     317
    186318config IFCONFIG
    187319    bool "ifconfig"
    188     default n
     320    default y
     321    depends on PLATFORM_LINUX
    189322    help
    190323      Ifconfig is used to configure the kernel-resident network interfaces.
     
    200333config FEATURE_IFCONFIG_SLIP
    201334    bool "Enable slip-specific options \"keepalive\" and \"outfill\""
    202     default n
     335    default y
    203336    depends on IFCONFIG
    204337    help
    205       Allow "keepalive" and "outfill" support for SLIP.  If you're not
     338      Allow "keepalive" and "outfill" support for SLIP. If you're not
    206339      planning on using serial lines, leave this unchecked.
    207340
    208341config FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    209342    bool "Enable options \"mem_start\", \"io_addr\", and \"irq\""
    210     default n
     343    default y
    211344    depends on IFCONFIG
    212345    help
     
    220353    help
    221354      Set the hardware address of this interface, if the device driver
    222       supports  this  operation.  Currently, we only support the 'ether'
     355      supports  this  operation. Currently, we only support the 'ether'
    223356      class.
    224357
    225358config FEATURE_IFCONFIG_BROADCAST_PLUS
    226359    bool "Set the broadcast automatically"
    227     default n
     360    default y
    228361    depends on IFCONFIG
    229362    help
     
    231364      automatically if the value '+' is used.
    232365
     366config IFENSLAVE
     367    bool "ifenslave"
     368    default y
     369    depends on PLATFORM_LINUX
     370    help
     371      Userspace application to bind several interfaces
     372      to a logical interface (use with kernel bonding driver).
     373
     374config IFPLUGD
     375    bool "ifplugd"
     376    default y
     377    depends on PLATFORM_LINUX
     378    help
     379      Network interface plug detection daemon.
     380
    233381config IFUPDOWN
    234382    bool "ifupdown"
    235     default n
    236     help
    237       Activate or deactivate the specified interfaces.  This applet makes
     383    default y
     384    help
     385      Activate or deactivate the specified interfaces. This applet makes
    238386      use of either "ifconfig" and "route" or the "ip" command to actually
    239       configure network interfaces.  Therefore, you will probably also want
     387      configure network interfaces. Therefore, you will probably also want
    240388      to enable either IFCONFIG and ROUTE, or enable
    241       FEATURE_IFUPDOWN_IP and the various IP options.  Of
     389      FEATURE_IFUPDOWN_IP and the various IP options. Of
    242390      course you could use non-busybox versions of these programs, so
    243391      against my better judgement (since this will surely result in plenty
    244392      of support questions on the mailing list), I do not force you to
    245       enable these additional options.  It is up to you to supply either
     393      enable these additional options. It is up to you to supply either
    246394      "ifconfig", "route" and "run-parts" or the "ip" command, either
    247395      via busybox or via standalone utilities.
     
    250398    string "Absolute path to ifstate file"
    251399    default "/var/run/ifstate"
     400    depends on IFUPDOWN
    252401    help
    253402      ifupdown keeps state information in a file called ifstate.
     
    259408config FEATURE_IFUPDOWN_IP
    260409    bool "Use ip applet"
    261     default n
     410    default y
    262411    depends on IFUPDOWN
    263412    help
     
    268417    bool "Use busybox ip applet"
    269418    default y
    270     depends on FEATURE_IFUPDOWN_IP
     419    depends on FEATURE_IFUPDOWN_IP && PLATFORM_LINUX
    271420    select IP
    272421    select FEATURE_IP_ADDRESS
     
    281430config FEATURE_IFUPDOWN_IFCONFIG_BUILTIN
    282431    bool "Use busybox ifconfig and route applets"
    283     default y
     432    default n
    284433    depends on IFUPDOWN && !FEATURE_IFUPDOWN_IP
    285434    select IFCONFIG
     
    294443
    295444config FEATURE_IFUPDOWN_IPV4
    296     bool "Enable support for IPv4"
     445    bool "Support for IPv4"
    297446    default y
    298447    depends on IFUPDOWN
     
    301450
    302451config FEATURE_IFUPDOWN_IPV6
    303     bool "Enable support for IPv6"
    304     default n
     452    bool "Support for IPv6"
     453    default y
    305454    depends on IFUPDOWN && FEATURE_IPV6
    306455    help
     
    308457
    309458### 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.
     459###config FEATURE_IFUPDOWN_IPX
     460### bool "Support for IPX"
     461### default y
     462### depends on IFUPDOWN
     463### help
     464###   If this option is selected you can use busybox to work with IPX
     465###   networks.
    317466
    318467config FEATURE_IFUPDOWN_MAPPING
    319468    bool "Enable mapping support"
    320     default n
     469    default y
    321470    depends on IFUPDOWN
    322471    help
     
    325474
    326475config FEATURE_IFUPDOWN_EXTERNAL_DHCP
    327     bool "Enable support for external dhcp clients"
     476    bool "Support for external dhcp clients"
    328477    default n
    329478    depends on IFUPDOWN
     
    336485config INETD
    337486    bool "inetd"
    338     default n
     487    default y
    339488    select FEATURE_SYSLOG
    340489    help
     
    378527config FEATURE_INETD_RPC
    379528    bool "Support RPC services"
    380     default n
     529    default y
    381530    depends on INETD
    382531    select FEATURE_HAVE_RPC
     
    386535config IP
    387536    bool "ip"
    388     default n
     537    default y
     538    depends on PLATFORM_LINUX
    389539    help
    390540      The "ip" applet is a TCP/IP interface configuration and routing
    391       utility.  You generally don't need "ip" to use busybox with
     541      utility. You generally don't need "ip" to use busybox with
    392542      TCP/IP.
    393543
     
    415565config FEATURE_IP_TUNNEL
    416566    bool "ip tunnel"
    417     default n
     567    default y
    418568    depends on IP
    419569    help
     
    422572config FEATURE_IP_RULE
    423573    bool "ip rule"
    424     default n
     574    default y
    425575    depends on IP
    426576    help
     
    428578
    429579config FEATURE_IP_SHORT_FORMS
    430     bool "Support short forms of ip commands."
    431     default n
     580    bool "Support short forms of ip commands"
     581    default y
    432582    depends on IP
    433583    help
     
    442592      object commands.
    443593
     594config FEATURE_IP_RARE_PROTOCOLS
     595    bool "Support displaying rarely used link types"
     596    default n
     597    depends on IP
     598    help
     599      If you are not going to use links of type "frad", "econet",
     600      "bif" etc, you probably don't need to enable this.
     601      Ethernet, wireless, infrared, ppp/slip, ip tunnelling
     602      link types are supported without this option selected.
     603
    444604config IPADDR
    445605    bool
     
    469629config IPCALC
    470630    bool "ipcalc"
    471     default n
     631    default y
    472632    help
    473633      ipcalc takes an IP address and netmask and calculates the
     
    479639    depends on IPCALC
    480640    help
    481       Adds the options hostname, prefix and silent to the output of "ipcalc".
     641      Adds the options hostname, prefix and silent to the output of
     642      "ipcalc".
    482643
    483644config FEATURE_IPCALC_LONG_OPTIONS
    484645    bool "Enable long options"
    485     default n
    486     depends on IPCALC && GETOPT_LONG
     646    default y
     647    depends on IPCALC && LONG_OPTS
    487648    help
    488649      Support long options for the ipcalc applet.
     
    490651config NAMEIF
    491652    bool "nameif"
    492     default n
     653    default y
     654    depends on PLATFORM_LINUX
    493655    select FEATURE_SYSLOG
    494656    help
     
    497659      It is possible to use a file (default: /etc/mactab)
    498660      with list of new interface names and MACs.
    499       Maximum interface name length: IF_NAMESIZE = 16
     661      Maximum interface name length: IFNAMSIZ = 16
    500662      File fields are separated by space or tab.
    501663      File format:
     
    503665      new_interface_name    XX:XX:XX:XX:XX:XX
    504666
    505 config NC
    506     bool "nc"
    507     default n
    508     help
    509       A simple Unix utility which reads and writes data across network
    510       connections.
    511 
    512 config 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 
    519 config 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).
     667config FEATURE_NAMEIF_EXTENDED
     668    bool "Extended nameif"
     669    default y
     670    depends on NAMEIF
     671    help
     672      This extends the nameif syntax to support the bus_info and driver
     673      checks. The syntax is compatible to the normal nameif.
     674      File format:
     675        new_interface_name  driver=asix bus=usb-0000:00:08.2-3
     676        new_interface_name  bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5
     677        new_interface_name  mac=00:80:C8:38:91:B5
     678        new_interface_name  00:80:C8:38:91:B5
    527679
    528680config NETSTAT
    529681    bool "netstat"
    530     default n
     682    default y
     683    depends on PLATFORM_LINUX
    531684    help
    532685      netstat prints information about the Linux networking subsystem.
    533686
    534687config FEATURE_NETSTAT_WIDE
    535     bool "  Enable wide netstat output"
    536     default n
     688    bool "Enable wide netstat output"
     689    default y
    537690    depends on NETSTAT
    538691    help
     
    540693      (-W option).
    541694
     695config FEATURE_NETSTAT_PRG
     696    bool "Enable PID/Program name output"
     697    default y
     698    depends on NETSTAT
     699    help
     700      Add support for -p flag to print out PID and program name.
     701      +700 bytes of code.
     702
    542703config NSLOOKUP
    543704    bool "nslookup"
    544     default n
     705    default y
    545706    help
    546707      nslookup is a tool to query Internet name servers.
     708
     709config NTPD
     710    bool "ntpd"
     711    default y
     712    depends on PLATFORM_LINUX
     713    help
     714      The NTP client/server daemon.
     715
     716config FEATURE_NTPD_SERVER
     717    bool "Make ntpd usable as a NTP server"
     718    default y
     719    depends on NTPD
     720    help
     721      Make ntpd usable as a NTP server. If you disable this option
     722      ntpd will be usable only as a NTP client.
    547723
    548724config PING
    549725    bool "ping"
    550     default n
     726    default y
     727    depends on PLATFORM_LINUX
    551728    help
    552729      ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
     
    555732config PING6
    556733    bool "ping6"
    557     default n
     734    default y
    558735    depends on FEATURE_IPV6 && PING
    559736    help
    560737      This will give you a ping that can talk IPv6.
     738
     739config FEATURE_FANCY_PING
     740    bool "Enable fancy ping output"
     741    default y
     742    depends on PING
     743    help
     744      Make the output from the ping applet include statistics, and at the
     745      same time provide full support for ICMP packets.
    561746
    562747config PSCAN
    563748    bool "pscan"
    564     default n
     749    default y
    565750    help
    566751      Simple network port scanner.
    567 
    568 config FEATURE_FANCY_PING
    569     bool "Enable fancy ping output"
    570     default y
    571     depends on PING
    572     help
    573       Make the output from the ping applet include statistics, and at the
    574       same time provide full support for ICMP packets.
    575752
    576753config ROUTE
    577754    bool "route"
    578     default n
     755    default y
     756    depends on PLATFORM_LINUX
    579757    help
    580758      Route displays or manipulates the kernel's IP routing tables.
     
    582760config SLATTACH
    583761    bool "slattach"
    584     default n
    585     help
    586       slattach is a small utility to attach network interfaces to serial lines.
     762    default y
     763    depends on PLATFORM_LINUX
     764    help
     765      slattach is a small utility to attach network interfaces to serial
     766      lines.
     767
     768#config TC
     769#   bool "tc"
     770#   default y
     771#   help
     772#     show / manipulate traffic control settings
     773#
     774#config FEATURE_TC_INGRESS
     775#   def_bool n
     776#   depends on TC
     777
     778config TCPSVD
     779    bool "tcpsvd"
     780    default y
     781    help
     782      tcpsvd listens on a TCP port and runs a program for each new
     783      connection.
    587784
    588785config TELNET
    589786    bool "telnet"
    590     default n
     787    default y
    591788    help
    592789      Telnet is an interface to the TELNET protocol, but is also commonly
     
    599796    help
    600797      Setting this option will forward the TERM environment variable to the
    601       remote host you are connecting to.  This is useful to make sure that
     798      remote host you are connecting to. This is useful to make sure that
    602799      things like ANSI colors and other control sequences behave.
    603800
     
    614811config TELNETD
    615812    bool "telnetd"
    616     default n
     813    default y
    617814    select FEATURE_SYSLOG
    618815    help
    619816      A daemon for the TELNET protocol, allowing you to log onto the host
    620       running the daemon.  Please keep in mind that the TELNET protocol
    621       sends passwords in plain text.  If you can't afford the space for an
    622       SSH daemon and you trust your network, you may say 'y' here.  As a
     817      running the daemon. Please keep in mind that the TELNET protocol
     818      sends passwords in plain text. If you can't afford the space for an
     819      SSH daemon and you trust your network, you may say 'y' here. As a
    623820      more secure alternative, you should seriously consider installing the
    624821      very small Dropbear SSH daemon instead:
     
    645842          mount -t devpts devpts /dev/pts
    646843
    647       You need to be sure that Busybox has LOGIN and
    648       FEATURE_SUID enabled.  And finally, you should make
     844      You need to be sure that busybox has LOGIN and
     845      FEATURE_SUID enabled. And finally, you should make
    649846      certain that Busybox has been installed setuid root:
    650847
     
    657854config FEATURE_TELNETD_STANDALONE
    658855    bool "Support standalone telnetd (not inetd only)"
    659     default n
     856    default y
    660857    depends on TELNETD
    661858    help
    662859      Selecting this will make telnetd able to run standalone.
     860
     861config FEATURE_TELNETD_INETD_WAIT
     862    bool "Support -w SEC option (inetd wait mode)"
     863    default y
     864    depends on FEATURE_TELNETD_STANDALONE
     865    help
     866      This option allows you to run telnetd in "inet wait" mode.
     867      Example inetd.conf line (note "wait", not usual "nowait"):
     868
     869      telnet stream tcp wait root /bin/telnetd telnetd -w10
     870
     871      In this example, inetd passes _listening_ socket_ as fd 0
     872      to telnetd when connection appears.
     873      telnetd will wait for connections until all existing
     874      connections are closed, and no new connections
     875      appear during 10 seconds. Then it exits, and inetd continues
     876      to listen for new connections.
     877
     878      This option is rarely used. "tcp nowait" is much more usual
     879      way of running tcp services, including telnetd.
     880      You most probably want to say N here.
    663881
    664882config TFTP
    665883    bool "tftp"
    666     default n
    667     help
    668       This enables the Trivial File Transfer Protocol client program.  TFTP
     884    default y
     885    help
     886      This enables the Trivial File Transfer Protocol client program. TFTP
    669887      is usually used for simple, small transfers such as a root image
    670888      for a network-enabled bootloader.
    671889
     890config TFTPD
     891    bool "tftpd"
     892    default y
     893    help
     894      This enables the Trivial File Transfer Protocol server program.
     895      It expects that stdin is a datagram socket and a packet
     896      is already pending on it. It will exit after one transfer.
     897      In other words: it should be run from inetd in nowait mode,
     898      or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR"
     899
     900comment "Common options for tftp/tftpd"
     901    depends on TFTP || TFTPD
     902
    672903config FEATURE_TFTP_GET
    673     bool "Enable \"get\" command"
    674     default y
    675     depends on TFTP
    676     help
    677       Add support for the GET command within the TFTP client.  This allows
     904    bool "Enable 'tftp get' and/or tftpd upload code"
     905    default y
     906    depends on TFTP || TFTPD
     907    help
     908      Add support for the GET command within the TFTP client. This allows
    678909      a client to retrieve a file from a TFTP server.
     910      Also enable upload support in tftpd, if tftpd is selected.
     911
     912      Note: this option does _not_ make tftpd capable of download
     913      (the usual operation people need from it)!
    679914
    680915config FEATURE_TFTP_PUT
    681     bool "Enable \"put\" command"
    682     default y
    683     depends on TFTP
    684     help
    685       Add support for the PUT command within the TFTP client.  This allows
     916    bool "Enable 'tftp put' and/or tftpd download code"
     917    default y
     918    depends on TFTP || TFTPD
     919    help
     920      Add support for the PUT command within the TFTP client. This allows
    686921      a client to transfer a file to a TFTP server.
     922      Also enable download support in tftpd, if tftpd is selected.
    687923
    688924config FEATURE_TFTP_BLOCKSIZE
    689     bool "Enable \"blocksize\" command"
    690     default n
    691     depends on TFTP
    692     help
    693       Allow the client to specify the desired block size for transfers.
    694 
    695 config DEBUG_TFTP
     925    bool "Enable 'blksize' and 'tsize' protocol options"
     926    default y
     927    depends on TFTP || TFTPD
     928    help
     929      Allow tftp to specify block size, and tftpd to understand
     930      "blksize" and "tsize" options.
     931
     932config FEATURE_TFTP_PROGRESS_BAR
     933    bool "Enable tftp progress meter"
     934    default y
     935    depends on TFTP && FEATURE_TFTP_BLOCKSIZE
     936    help
     937      Show progress bar.
     938
     939config TFTP_DEBUG
    696940    bool "Enable debug"
    697941    default n
    698     depends on TFTP
    699     help
    700       Enable debug settings for tftp.  This is useful if you're running
    701       into problems with tftp as the protocol doesn't help you much when
    702       you run into problems.
     942    depends on TFTP || TFTPD
     943    help
     944      Make tftp[d] print debugging messages on stderr.
     945      This is useful if you are diagnosing a bug in tftp[d].
    703946
    704947config TRACEROUTE
    705948    bool "traceroute"
    706     default n
    707     help
    708       Utility to trace the route of IP packets
     949    default y
     950    depends on PLATFORM_LINUX
     951    help
     952      Utility to trace the route of IP packets.
     953
     954config TRACEROUTE6
     955    bool "traceroute6"
     956    default y
     957    depends on FEATURE_IPV6 && TRACEROUTE
     958    help
     959      Utility to trace the route of IPv6 packets.
    709960
    710961config FEATURE_TRACEROUTE_VERBOSE
    711962    bool "Enable verbose output"
    712     default n
     963    default y
    713964    depends on TRACEROUTE
    714965    help
    715       Add some verbosity to traceroute.  This includes amongst other things
     966      Add some verbosity to traceroute. This includes among other things
    716967      hostnames and ICMP response types.
    717968
     
    729980    depends on TRACEROUTE
    730981    help
    731       Add feature to allow for ICMP ECHO instead of UDP datagrams.
     982      Add option -I to use ICMP ECHO instead of UDP datagrams.
     983
     984config TUNCTL
     985    bool "tunctl"
     986    default y
     987    depends on PLATFORM_LINUX
     988    help
     989      tunctl creates or deletes tun devices.
     990
     991config FEATURE_TUNCTL_UG
     992    bool "Support owner:group assignment"
     993    default y
     994    depends on TUNCTL
     995    help
     996      Allow to specify owner and group of newly created interface.
     997      340 bytes of pure bloat. Say no here.
    732998
    733999source networking/udhcp/Config.in
     1000
     1001config IFUPDOWN_UDHCPC_CMD_OPTIONS
     1002    string "ifup udhcpc command line options"
     1003    default "-R -n"
     1004    depends on IFUPDOWN && UDHCPC
     1005    help
     1006      Command line options to pass to udhcpc from ifup.
     1007      Intended to alter options not available in /etc/network/interfaces.
     1008      (IE: --syslog --background etc...)
     1009
     1010config UDPSVD
     1011    bool "udpsvd"
     1012    default y
     1013    help
     1014      udpsvd listens on an UDP port and runs a program for each new
     1015      connection.
    7341016
    7351017config VCONFIG
    7361018    bool "vconfig"
    737     default n
     1019    default y
     1020    depends on PLATFORM_LINUX
    7381021    help
    7391022      Creates, removes, and configures VLAN interfaces
     
    7411024config WGET
    7421025    bool "wget"
    743     default n
     1026    default y
    7441027    help
    7451028      wget is a utility for non-interactive download of files from HTTP,
     
    7621045config FEATURE_WGET_LONG_OPTIONS
    7631046    bool "Enable long options"
    764     default n
    765     depends on WGET && GETOPT_LONG
     1047    default y
     1048    depends on WGET && LONG_OPTS
    7661049    help
    7671050      Support long options for the wget applet.
     1051
     1052config FEATURE_WGET_TIMEOUT
     1053    bool "Enable read timeout option -T SEC"
     1054    default y
     1055    depends on WGET
     1056    help
     1057      Supports network read timeout for wget, so that wget will give
     1058      up and timeout when reading network data, through the -T command
     1059      line option.  Currently only network data read timeout is
     1060      supported (i.e., timeout is not applied to the DNS nor TCP
     1061      connection initialization).  When FEATURE_WGET_LONG_OPTIONS is
     1062      also enabled, the --timeout option will work in addition to -T.
    7681063
    7691064config ZCIP
    7701065    bool "zcip"
    771     default n
     1066    default y
     1067    depends on PLATFORM_LINUX
    7721068    select FEATURE_SYSLOG
    7731069    help
  • branches/2.2.9/mindi-busybox/networking/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2, see the file LICENSE in this tarball.
     6# Licensed under GPLv2, see file LICENSE in this source tree.
    67
    78lib-y:=
     9
     10lib-$(CONFIG_NBDCLIENT) += nbd-client.o
    811lib-$(CONFIG_ARP)          += arp.o interface.o
    912lib-$(CONFIG_ARPING)       += arping.o
     13lib-$(CONFIG_BRCTL)        += brctl.o
    1014lib-$(CONFIG_DNSD)         += dnsd.o
    1115lib-$(CONFIG_ETHER_WAKE)   += ether-wake.o
    1216lib-$(CONFIG_FAKEIDENTD)   += isrv_identd.o isrv.o
     17lib-$(CONFIG_FTPD)         += ftpd.o
    1318lib-$(CONFIG_FTPGET)       += ftpgetput.o
    1419lib-$(CONFIG_FTPPUT)       += ftpgetput.o
     
    1621lib-$(CONFIG_HTTPD)        += httpd.o
    1722lib-$(CONFIG_IFCONFIG)     += ifconfig.o interface.o
     23lib-$(CONFIG_IFENSLAVE)    += ifenslave.o interface.o
     24lib-$(CONFIG_IFPLUGD)      += ifplugd.o
    1825lib-$(CONFIG_IFUPDOWN)     += ifupdown.o
    1926lib-$(CONFIG_INETD)        += inetd.o
     
    2431lib-$(CONFIG_NETSTAT)      += netstat.o
    2532lib-$(CONFIG_NSLOOKUP)     += nslookup.o
     33lib-$(CONFIG_NTPD)         += ntpd.o
    2634lib-$(CONFIG_PING)         += ping.o
    2735lib-$(CONFIG_PING6)        += ping.o
     
    2937lib-$(CONFIG_ROUTE)        += route.o
    3038lib-$(CONFIG_SLATTACH)     += slattach.o
     39lib-$(CONFIG_TC)           += tc.o
    3140lib-$(CONFIG_TELNET)       += telnet.o
    3241lib-$(CONFIG_TELNETD)      += telnetd.o
    3342lib-$(CONFIG_TFTP)         += tftp.o
     43lib-$(CONFIG_TFTPD)        += tftp.o
    3444lib-$(CONFIG_TRACEROUTE)   += traceroute.o
     45lib-$(CONFIG_TUNCTL)       += tunctl.o
    3546lib-$(CONFIG_VCONFIG)      += vconfig.o
    3647lib-$(CONFIG_WGET)         += wget.o
    3748lib-$(CONFIG_ZCIP)         += zcip.o
     49
     50lib-$(CONFIG_TCPSVD)       += tcpudp.o tcpudp_perhost.o
     51lib-$(CONFIG_UDPSVD)       += tcpudp.o tcpudp_perhost.o
  • branches/2.2.9/mindi-busybox/networking/arp.c

    r1765 r2725  
    2828#define DFLT_HW "ether"
    2929
    30 #define ARP_OPT_A (0x1)
    31 #define ARP_OPT_p (0x2)
    32 #define ARP_OPT_H (0x4)
    33 #define ARP_OPT_t (0x8)
    34 #define ARP_OPT_i (0x10)
    35 #define ARP_OPT_a (0x20)
    36 #define ARP_OPT_d (0x40)
    37 #define ARP_OPT_n (0x80)    /* do not resolve addresses     */
    38 #define ARP_OPT_D (0x100)   /* HW-address is devicename     */
    39 #define ARP_OPT_s (0x200)
    40 #define ARP_OPT_v (0x400 * DEBUG)   /* debugging output flag        */
    41 
    42 
    43 static const struct aftype *ap; /* current address family       */
    44 static const struct hwtype *hw; /* current hardware type        */
    45 static int sockfd;              /* active socket descriptor     */
    46 static smallint hw_set;         /* flag if hw-type was set (-H) */
    47 static const char *device = ""; /* current device               */
     30enum {
     31    ARP_OPT_A = (1 << 0),
     32    ARP_OPT_p = (1 << 1),
     33    ARP_OPT_H = (1 << 2),
     34    ARP_OPT_t = (1 << 3),
     35    ARP_OPT_i = (1 << 4),
     36    ARP_OPT_a = (1 << 5),
     37    ARP_OPT_d = (1 << 6),
     38    ARP_OPT_n = (1 << 7), /* do not resolve addresses */
     39    ARP_OPT_D = (1 << 8), /* HW-address is devicename */
     40    ARP_OPT_s = (1 << 9),
     41    ARP_OPT_v = (1 << 10) * DEBUG, /* debugging output flag */
     42};
     43
     44enum {
     45    sockfd = 3, /* active socket descriptor */
     46};
     47
     48struct globals {
     49    const struct aftype *ap; /* current address family */
     50    const struct hwtype *hw; /* current hardware type */
     51    const char *device;      /* current device */
     52    smallint hw_set;         /* flag if hw-type was set (-H) */
     53
     54} FIX_ALIASING;
     55#define G (*(struct globals*)&bb_common_bufsiz1)
     56#define ap         (G.ap        )
     57#define hw         (G.hw        )
     58#define device     (G.device    )
     59#define hw_set     (G.hw_set    )
     60#define INIT_G() do { \
     61    device = ""; \
     62} while (0)
     63
    4864
    4965static const char options[] ALIGN1 =
     
    201217        bb_error_msg("device '%s' has HW address %s '%s'",
    202218                     ifname, xhw->name,
    203                      xhw->print((char *) &ifr.ifr_hwaddr.sa_data));
     219                     xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data));
    204220    }
    205221}
     
    314330         char *hwa, char *mask, char *dev)
    315331{
     332    static const int arp_masks[] = {
     333        ATF_PERM, ATF_PUBL,
     334#ifdef HAVE_ATF_MAGIC
     335        ATF_MAGIC,
     336#endif
     337#ifdef HAVE_ATF_DONTPUB
     338        ATF_DONTPUB,
     339#endif
     340        ATF_USETRAILERS,
     341    };
     342    static const char arp_labels[] ALIGN1 = "PERM\0""PUP\0"
     343#ifdef HAVE_ATF_MAGIC
     344        "AUTO\0"
     345#endif
     346#ifdef HAVE_ATF_DONTPUB
     347        "DONTPUB\0"
     348#endif
     349        "TRAIL\0"
     350    ;
     351
    316352    const struct hwtype *xhw;
    317353
     
    334370        printf("netmask %s ", mask);
    335371
    336     if (arp_flags & ATF_PERM)
    337         printf("PERM ");
    338     if (arp_flags & ATF_PUBL)
    339         printf("PUP ");
    340 #ifdef HAVE_ATF_MAGIC
    341     if (arp_flags & ATF_MAGIC)
    342         printf("AUTO ");
    343 #endif
    344 #ifdef HAVE_ATF_DONTPUB
    345     if (arp_flags & ATF_DONTPUB)
    346         printf("DONTPUB ");
    347 #endif
    348     if (arp_flags & ATF_USETRAILERS)
    349         printf("TRAIL ");
    350 
    351     printf("on %s\n", dev);
     372    print_flags_separated(arp_masks, arp_labels, arp_flags, " ");
     373    printf(" on %s\n", dev);
    352374}
    353375
     
    377399        host = xstrdup(ap->sprint(&sa, 1));
    378400    }
    379     fp = xfopen("/proc/net/arp", "r");
     401    fp = xfopen_for_read("/proc/net/arp");
    380402    /* Bypass header -- read one line */
    381403    fgets(line, sizeof(line), fp);
     
    435457}
    436458
    437 int arp_main(int argc, char **argv);
    438 int arp_main(int argc, char **argv)
     459int arp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     460int arp_main(int argc UNUSED_PARAM, char **argv)
    439461{
    440     char *hw_type;
    441     char *protocol;
    442 
    443     /* Initialize variables... */
     462    const char *hw_type = "ether";
     463    const char *protocol;
     464    unsigned opts;
     465
     466    INIT_G();
     467
     468    xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sockfd);
    444469    ap = get_aftype(DFLT_AF);
    445470    if (!ap)
    446471        bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family");
    447472
    448     getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol,
     473    opts = getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol,
    449474                 &hw_type, &hw_type, &device);
    450475    argv += optind;
    451     if (option_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) {
     476    if (opts & (ARP_OPT_A | ARP_OPT_p)) {
    452477        ap = get_aftype(protocol);
    453478        if (ap == NULL)
    454479            bb_error_msg_and_die("%s: unknown %s", protocol, "address family");
    455480    }
    456     if (option_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) {
     481    if (opts & (ARP_OPT_A | ARP_OPT_p)) {
    457482        hw = get_hwtype(hw_type);
    458483        if (hw == NULL)
     
    460485        hw_set = 1;
    461486    }
    462     //if (option_mask32 & ARP_OPT_i)... -i
     487    //if (opts & ARP_OPT_i)... -i
    463488
    464489    if (ap->af != AF_INET) {
     
    477502                             hw->name, "hardware type");
    478503    }
    479     sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);
    480504
    481505    /* Now see what we have to do here... */
    482     if (option_mask32 & (ARP_OPT_d|ARP_OPT_s)) {
     506    if (opts & (ARP_OPT_d | ARP_OPT_s)) {
    483507        if (argv[0] == NULL)
    484508            bb_error_msg_and_die("need host name");
    485         if (option_mask32 & ARP_OPT_s)
     509        if (opts & ARP_OPT_s)
    486510            return arp_set(argv);
    487511        return arp_del(argv);
    488512    }
    489     //if (option_mask32 & ARP_OPT_a) - default
     513    //if (opts & ARP_OPT_a) - default
    490514    return arp_show(argv[0]);
    491515}
  • branches/2.2.9/mindi-busybox/networking/arping.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * arping.c - Ping hosts by ARP requests/replies
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    6  *
    7  * Author:  Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
     5 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
    86 * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
    97 */
     
    1816/* We don't expect to see 1000+ seconds delay, unsigned is enough */
    1917#define MONOTONIC_US() ((unsigned)monotonic_us())
    20 
    21 static struct in_addr src;
    22 static struct in_addr dst;
    23 static struct sockaddr_ll me;
    24 static struct sockaddr_ll he;
    25 static unsigned last;
    2618
    2719enum {
     
    3527};
    3628
    37 static int sock;
    38 static unsigned count = UINT_MAX;
    39 static unsigned timeout_us;
    40 static unsigned sent;
    41 static unsigned brd_sent;
    42 static unsigned received;
    43 static unsigned brd_recv;
    44 static unsigned req_recv;
     29struct globals {
     30    struct in_addr src;
     31    struct in_addr dst;
     32    struct sockaddr_ll me;
     33    struct sockaddr_ll he;
     34    int sock_fd;
     35
     36    int count; // = -1;
     37    unsigned last;
     38    unsigned timeout_us;
     39    unsigned start;
     40
     41    unsigned sent;
     42    unsigned brd_sent;
     43    unsigned received;
     44    unsigned brd_recv;
     45    unsigned req_recv;
     46} FIX_ALIASING;
     47#define G (*(struct globals*)&bb_common_bufsiz1)
     48#define src        (G.src       )
     49#define dst        (G.dst       )
     50#define me         (G.me        )
     51#define he         (G.he        )
     52#define sock_fd    (G.sock_fd   )
     53#define count      (G.count     )
     54#define last       (G.last      )
     55#define timeout_us (G.timeout_us)
     56#define start      (G.start     )
     57#define sent       (G.sent      )
     58#define brd_sent   (G.brd_sent  )
     59#define received   (G.received  )
     60#define brd_recv   (G.brd_recv  )
     61#define req_recv   (G.req_recv  )
     62#define INIT_G() do { \
     63    count = -1; \
     64} while (0)
     65
     66// If GNUisms are not available...
     67//static void *mempcpy(void *_dst, const void *_src, int n)
     68//{
     69//  memcpy(_dst, _src, n);
     70//  return (char*)_dst + n;
     71//}
    4572
    4673static int send_pack(struct in_addr *src_addr,
     
    4976{
    5077    int err;
    51     unsigned now;
    5278    unsigned char buf[256];
    5379    struct arphdr *ah = (struct arphdr *) buf;
    5480    unsigned char *p = (unsigned char *) (ah + 1);
    5581
    56     ah->ar_hrd = htons(ME->sll_hatype);
    5782    ah->ar_hrd = htons(ARPHRD_ETHER);
    5883    ah->ar_pro = htons(ETH_P_IP);
     
    6186    ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
    6287
    63     memcpy(p, &ME->sll_addr, ah->ar_hln);
    64     p += ME->sll_halen;
    65 
    66     memcpy(p, src_addr, 4);
    67     p += 4;
     88    p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
     89    p = mempcpy(p, src_addr, 4);
    6890
    6991    if (option_mask32 & ADVERT)
    70         memcpy(p, &ME->sll_addr, ah->ar_hln);
     92        p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
    7193    else
    72         memcpy(p, &HE->sll_addr, ah->ar_hln);
    73     p += ah->ar_hln;
    74 
    75     memcpy(p, dst_addr, 4);
    76     p += 4;
    77 
    78     now = MONOTONIC_US();
    79     err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
     94        p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
     95
     96    p = mempcpy(p, dst_addr, 4);
     97
     98    err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
    8099    if (err == p - buf) {
    81         last = now;
     100        last = MONOTONIC_US();
    82101        sent++;
    83102        if (!(option_mask32 & UNICASTING))
     
    87106}
    88107
    89 static void finish(void) ATTRIBUTE_NORETURN;
     108static void finish(void) NORETURN;
    90109static void finish(void)
    91110{
     
    101120        exit(!!received);
    102121    if (option_mask32 & UNSOLICITED)
    103         exit(0);
     122        exit(EXIT_SUCCESS);
    104123    exit(!received);
    105124}
     
    107126static void catcher(void)
    108127{
    109     static unsigned start;
    110 
    111128    unsigned now;
    112129
     
    115132        start = now;
    116133
    117     if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000)))
     134    if (count == 0 || (timeout_us && (now - start) > timeout_us))
    118135        finish();
    119136
    120     count--;
     137    /* count < 0 means "infinite count" */
     138    if (count > 0)
     139        count--;
    121140
    122141    if (last == 0 || (now - last) > 500000) {
     
    128147}
    129148
    130 static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
     149static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
    131150{
    132151    struct arphdr *ah = (struct arphdr *) buf;
    133152    unsigned char *p = (unsigned char *) (ah + 1);
    134153    struct in_addr src_ip, dst_ip;
     154    /* moves below assume in_addr is 4 bytes big, ensure that */
     155    struct BUG_in_addr_must_be_4 {
     156        char BUG_in_addr_must_be_4[
     157            sizeof(struct in_addr) == 4 ? 1 : -1
     158        ];
     159        char BUG_s_addr_must_be_4[
     160            sizeof(src_ip.s_addr) == 4 ? 1 : -1
     161        ];
     162    };
    135163
    136164    /* Filter out wild packets */
     
    138166     && FROM->sll_pkttype != PACKET_BROADCAST
    139167     && FROM->sll_pkttype != PACKET_MULTICAST)
    140         return 0;
    141 
    142     /* Only these types are recognised */
     168        return false;
     169
     170    /* Only these types are recognized */
    143171    if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
    144         return 0;
     172        return false;
    145173
    146174    /* ARPHRD check and this darned FDDI hack here :-( */
    147175    if (ah->ar_hrd != htons(FROM->sll_hatype)
    148176     && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
    149         return 0;
     177        return false;
    150178
    151179    /* Protocol must be IP. */
    152     if (ah->ar_pro != htons(ETH_P_IP))
    153         return 0;
    154     if (ah->ar_pln != 4)
    155         return 0;
    156     if (ah->ar_hln != me.sll_halen)
    157         return 0;
    158     if (len < sizeof(*ah) + 2 * (4 + ah->ar_hln))
    159         return 0;
    160     memcpy(&src_ip, p + ah->ar_hln, 4);
    161     memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
     180    if (ah->ar_pro != htons(ETH_P_IP)
     181     || (ah->ar_pln != 4)
     182     || (ah->ar_hln != me.sll_halen)
     183     || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
     184        return false;
     185
     186    move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
     187    move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
     188
     189    if (dst.s_addr != src_ip.s_addr)
     190        return false;
    162191    if (!(option_mask32 & DAD)) {
    163         if (src_ip.s_addr != dst.s_addr)
    164             return 0;
    165         if (src.s_addr != dst_ip.s_addr)
    166             return 0;
    167         if (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln))
    168             return 0;
     192        if ((src.s_addr != dst_ip.s_addr)
     193            || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
     194            return false;
    169195    } else {
    170196        /* DAD packet was:
     
    181207           dst_ip/dst_hw do not matter.
    182208         */
    183         if (src_ip.s_addr != dst.s_addr)
    184             return 0;
    185         if (memcmp(p, &me.sll_addr, me.sll_halen) == 0)
    186             return 0;
    187         if (src.s_addr && src.s_addr != dst_ip.s_addr)
    188             return 0;
     209        if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
     210         || (src.s_addr && src.s_addr != dst_ip.s_addr))
     211            return false;
    189212    }
    190213    if (!(option_mask32 & QUIET)) {
     
    208231
    209232        if (last) {
    210             printf(" %u.%03ums\n", last / 1000, last % 1000);
     233            unsigned diff = MONOTONIC_US() - last;
     234            printf(" %u.%03ums\n", diff / 1000, diff % 1000);
    211235        } else {
    212236            printf(" UNSOLICITED?\n");
    213237        }
    214         fflush(stdout);
     238        fflush_all();
    215239    }
    216240    received++;
     
    225249        option_mask32 |= UNICASTING;
    226250    }
    227     return 1;
     251    return true;
    228252}
    229253
    230 int arping_main(int argc, char **argv);
    231 int arping_main(int argc, char **argv)
     254int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     255int arping_main(int argc UNUSED_PARAM, char **argv)
    232256{
    233257    const char *device = "eth0";
    234     int ifindex;
    235258    char *source = NULL;
    236259    char *target;
    237260    unsigned char *packet;
    238 
    239     sock = xsocket(PF_PACKET, SOCK_DGRAM, 0);
     261    char *err_str;
     262
     263    INIT_G();
     264
     265    sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
    240266
    241267    // Drop suid root privileges
    242     xsetuid(getuid());
    243 
     268    // Need to remove SUID_NEVER from applets.h for this to work
     269    //xsetuid(getuid());
     270
     271    err_str = xasprintf("interface %s %%s", device);
    244272    {
    245273        unsigned opt;
    246         char *str_count, *str_timeout;
     274        char *str_timeout;
    247275
    248276        /* Dad also sets quit_on_reply.
    249277         * Advert also sets unsolicited.
    250278         */
    251         opt_complementary = "=1:Df:AU";
     279        opt_complementary = "=1:Df:AU:c+";
    252280        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);
     281                &count, &str_timeout, &device, &source);
    256282        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         }
     283            timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
    263284        //if (opt & 0x200) /* -s: source */
    264285        option_mask32 &= 0x3f; /* set respective flags */
     
    273294
    274295        memset(&ifr, 0, sizeof(ifr));
    275         strncpy(ifr.ifr_name, device, IFNAMSIZ - 1);
    276         ioctl_or_perror_and_die(sock, SIOCGIFINDEX, &ifr, "interface %s not found", device);
    277         ifindex = ifr.ifr_ifindex;
    278 
    279         xioctl(sock, SIOCGIFFLAGS, (char *) &ifr);
     296        strncpy_IFNAMSIZ(ifr.ifr_name, device);
     297        /* We use ifr.ifr_name in error msg so that problem
     298         * with truncated name will be visible */
     299        ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
     300        me.sll_ifindex = ifr.ifr_ifindex;
     301
     302        xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr);
    280303
    281304        if (!(ifr.ifr_flags & IFF_UP)) {
    282             bb_error_msg_and_die("interface %s is down", device);
     305            bb_error_msg_and_die(err_str, "is down");
    283306        }
    284307        if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
    285             bb_error_msg("interface %s is not ARPable", device);
     308            bb_error_msg(err_str, "is not ARPable");
    286309            return (option_mask32 & DAD ? 0 : 2);
    287310        }
    288311    }
    289312
    290     if (!inet_aton(target, &dst)) {
     313    /* if (!inet_aton(target, &dst)) - not needed */ {
    291314        len_and_sockaddr *lsa;
    292315        lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
    293         memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4);
     316        dst = lsa->u.sin.sin_addr;
    294317        if (ENABLE_FEATURE_CLEAN_UP)
    295318            free(lsa);
     
    300323    }
    301324
    302     if (!(option_mask32 & DAD) && (option_mask32 & UNSOLICITED) && src.s_addr == 0)
     325    if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0)
    303326        src = dst;
    304327
     
    307330        int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    308331
    309         if (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);
    312         }
     332        setsockopt_bindtodevice(probe_fd, device);
    313333        memset(&saddr, 0, sizeof(saddr));
    314334        saddr.sin_family = AF_INET;
    315335        if (src.s_addr) {
     336            /* Check that this is indeed our IP */
    316337            saddr.sin_addr = src;
    317338            xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
    318         } else if (!(option_mask32 & DAD)) {
     339        } else { /* !(option_mask32 & DAD) case */
     340            /* Find IP address on this iface */
    319341            socklen_t alen = sizeof(saddr);
    320342
     
    323345
    324346            if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1)
    325                 bb_perror_msg("warning: setsockopt(SO_DONTROUTE)");
     347                bb_perror_msg("setsockopt(SO_DONTROUTE)");
    326348            xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
    327             if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) {
    328                 bb_error_msg_and_die("getsockname");
    329             }
     349            getsockname(probe_fd, (struct sockaddr *) &saddr, &alen);
     350            //never happens:
     351            //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
     352            //  bb_perror_msg_and_die("getsockname");
     353            if (saddr.sin_family != AF_INET)
     354                bb_error_msg_and_die("no IP address configured");
    330355            src = saddr.sin_addr;
    331356        }
     
    334359
    335360    me.sll_family = AF_PACKET;
    336     me.sll_ifindex = ifindex;
     361    //me.sll_ifindex = ifindex; - done before
    337362    me.sll_protocol = htons(ETH_P_ARP);
    338     xbind(sock, (struct sockaddr *) &me, sizeof(me));
     363    xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
    339364
    340365    {
    341366        socklen_t alen = sizeof(me);
    342 
    343         if (getsockname(sock, (struct sockaddr *) &me, &alen) == -1) {
    344             bb_error_msg_and_die("getsockname");
    345         }
     367        getsockname(sock_fd, (struct sockaddr *) &me, &alen);
     368        //never happens:
     369        //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
     370        //  bb_perror_msg_and_die("getsockname");
    346371    }
    347372    if (me.sll_halen == 0) {
    348         bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device);
     373        bb_error_msg(err_str, "is not ARPable (no ll address)");
    349374        return (option_mask32 & DAD ? 0 : 2);
    350375    }
     
    353378
    354379    if (!(option_mask32 & QUIET)) {
    355         printf("ARPING to %s from %s via %s\n",
    356             inet_ntoa(dst), inet_ntoa(src),
    357             device ? device : "unknown");
    358     }
    359 
    360     if (!src.s_addr && !(option_mask32 & DAD)) {
    361         bb_error_msg_and_die("no src address in the non-DAD mode");
    362     }
    363 
    364     {
    365         struct sigaction sa;
    366 
    367         memset(&sa, 0, sizeof(sa));
    368         sa.sa_flags = SA_RESTART;
    369 
    370         sa.sa_handler = (void (*)(int)) finish;
    371         sigaction(SIGINT, &sa, NULL);
    372 
    373         sa.sa_handler = (void (*)(int)) catcher;
    374         sigaction(SIGALRM, &sa, NULL);
    375     }
     380        /* inet_ntoa uses static storage, can't use in same printf */
     381        printf("ARPING to %s", inet_ntoa(dst));
     382        printf(" from %s via %s\n", inet_ntoa(src), device);
     383    }
     384
     385    signal_SA_RESTART_empty_mask(SIGINT,  (void (*)(int))finish);
     386    signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
    376387
    377388    catcher();
     
    384395        int cc;
    385396
    386         cc = recvfrom(sock, packet, 4096, 0, (struct sockaddr *) &from, &alen);
     397        cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen);
    387398        if (cc < 0) {
    388399            bb_perror_msg("recvfrom");
  • branches/2.2.9/mindi-busybox/networking/dnsd.c

    r1765 r2725  
    77 * Copyright (C) 2003 Paul Sheer
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 *
    1111 * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote
     
    1818 */
    1919
     20#include "libbb.h"
    2021#include <syslog.h>
    21 #include "libbb.h"
    2222
    2323//#define DEBUG 1
     
    2525
    2626enum {
    27     MAX_HOST_LEN = 16,      // longest host name allowed is 15
    28     IP_STRING_LEN = 18,     // .xxx.xxx.xxx.xxx\0
    29 
    30 //must be strlen('.in-addr.arpa') larger than IP_STRING_LEN
    31     MAX_NAME_LEN = (IP_STRING_LEN + 13),
    32 
    33 /* Cannot get bigger packets than 512 per RFC1035
    34    In practice this can be set considerably smaller:
    35    Length of response packet is  header (12B) + 2*type(4B) + 2*class(4B) +
    36    ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) +
    37    2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte
    38 */
    39     MAX_PACK_LEN = 512 + 1,
    40 
    41     DEFAULT_TTL = 30,       // increase this when not testing?
    42 
     27    /* can tweak this */
     28    DEFAULT_TTL = 120,
     29
     30    /* cannot get bigger packets than 512 per RFC1035. */
     31    MAX_PACK_LEN = 512,
     32    IP_STRING_LEN = sizeof(".xxx.xxx.xxx.xxx"),
     33    MAX_NAME_LEN = IP_STRING_LEN - 1 + sizeof(".in-addr.arpa"),
    4334    REQ_A = 1,
    44     REQ_PTR = 12
     35    REQ_PTR = 12,
    4536};
    4637
    47 struct dns_repl {       // resource record, add 0 or 1 to accepted dns_msg in resp
    48     uint16_t rlen;
    49     uint8_t *r;     // resource
    50     uint16_t flags;
    51 };
    52 
    53 struct dns_head {       // the message from client and first part of response mag
     38/* the message from client and first part of response msg */
     39struct dns_head {
    5440    uint16_t id;
    5541    uint16_t flags;
    56     uint16_t nquer;     // accepts 0
    57     uint16_t nansw;     // 1 in response
    58     uint16_t nauth;     // 0
    59     uint16_t nadd;      // 0
     42    uint16_t nquer;
     43    uint16_t nansw;
     44    uint16_t nauth;
     45    uint16_t nadd;
    6046};
    61 struct dns_prop {
    62     uint16_t type;
    63     uint16_t class;
     47/* Structure used to access type and class fields.
     48 * They are totally unaligned, but gcc 4.3.4 thinks that pointer of type uint16_t*
     49 * is 16-bit aligned and replaces 16-bit memcpy (in move_from_unaligned16 macro)
     50 * with aligned halfword access on arm920t!
     51 * Oh well. Slapping PACKED everywhere seems to help: */
     52struct type_and_class {
     53    uint16_t type PACKED;
     54    uint16_t class PACKED;
     55} PACKED;
     56/* element of known name, ip address and reversed ip address */
     57struct dns_entry {
     58    struct dns_entry *next;
     59    uint32_t ip;
     60    char rip[IP_STRING_LEN]; /* length decimal reversed IP */
     61    char name[1];
    6462};
    65 struct dns_entry {      // element of known name, ip address and reversed ip address
    66     struct dns_entry *next;
    67     char ip[IP_STRING_LEN];     // dotted decimal IP
    68     char rip[IP_STRING_LEN];    // length decimal reversed IP
    69     char name[MAX_HOST_LEN];
    70 };
    71 
    72 static struct dns_entry *dnsentry;
    73 static uint32_t ttl = DEFAULT_TTL;
    74 
    75 static 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 
    82 /*
    83  * Convert host name from C-string to dns length/string.
    84  */
    85 static void convname(char *a, uint8_t *q)
    86 {
    87     int i = (q[0] == '.') ? 0 : 1;
    88     for (; i < MAX_HOST_LEN-1 && *q; i++, q++)
    89         a[i] = tolower(*q);
    90     a[0] = i - 1;
    91     a[i] = 0;
    92 }
     63
     64#define OPT_verbose (option_mask32 & 1)
     65#define OPT_silent  (option_mask32 & 2)
     66
    9367
    9468/*
    9569 * Insert length of substrings instead of dots
    9670 */
    97 static void undot(uint8_t * rip)
     71static void undot(char *rip)
    9872{
    99     int i = 0, s = 0;
     73    int i = 0;
     74    int s = 0;
     75
    10076    while (rip[i])
    10177        i++;
     
    10480            rip[i] = s;
    10581            s = 0;
    106         } else s++;
    107     }
    108 }
    109 
    110 /*
    111  * Read one line of hostname/IP from file
    112  * Returns 0 for each valid entry read, -1 at EOF
    113  * Assumes all host names are lower case only
    114  * Hostnames with more than one label are not handled correctly.
    115  * Presently the dot is copied into name without
    116  * converting to a length/string substring for that label.
    117  */
    118 static int getfileentry(FILE * fp, struct dns_entry *s)
    119 {
    120     unsigned int a,b,c,d;
    121     char *line, *r, *name;
    122 
    123  restart:
    124     line = r = xmalloc_fgets(fp);
    125     if (!r)
    126         return -1;
    127     while (*r == ' ' || *r == '\t') {
    128         r++;
    129         if (!*r || *r == '#' || *r == '\n') {
    130             free(line);
    131             goto restart; /* skipping empty/blank and commented lines  */
     82        } else {
     83            s++;
    13284        }
    13385    }
    134     name = r;
    135     while (*r != ' ' && *r != '\t')
    136         r++;
    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);
    145     undot((uint8_t*)s->rip);
    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;
    15386}
    15487
     
    15689 * Read hostname/IP records from file
    15790 */
    158 static void dnsentryinit(void)
     91static struct dns_entry *parse_conf_file(const char *fileconf)
    15992{
    160     FILE *fp;
    161     struct dns_entry *m, *prev;
    162 
    163     prev = dnsentry = NULL;
    164     fp = xfopen(fileconf, "r");
    165 
    166     while (1) {
    167         m = xzalloc(sizeof(*m));
     93    char *token[2];
     94    parser_t *parser;
     95    struct dns_entry *m, *conf_data;
     96    struct dns_entry **nextp;
     97
     98    conf_data = NULL;
     99    nextp = &conf_data;
     100
     101    parser = config_open(fileconf);
     102    while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
     103        struct in_addr ip;
     104        uint32_t v32;
     105
     106        if (inet_aton(token[1], &ip) == 0) {
     107            bb_error_msg("error at line %u, skipping", parser->lineno);
     108            continue;
     109        }
     110
     111        if (OPT_verbose)
     112            bb_error_msg("name:%s, ip:%s", token[0], token[1]);
     113
     114        /* sizeof(*m) includes 1 byte for m->name[0] */
     115        m = xzalloc(sizeof(*m) + strlen(token[0]) + 1);
    168116        /*m->next = NULL;*/
    169         if (getfileentry(fp, m))
    170             break;
    171 
    172         if (prev == NULL)
    173             dnsentry = m;
    174         else
    175             prev->next = m;
    176         prev = m;
    177     }
    178     fclose(fp);
     117        *nextp = m;
     118        nextp = &m->next;
     119
     120        m->name[0] = '.';
     121        strcpy(m->name + 1, token[0]);
     122        undot(m->name);
     123        m->ip = ip.s_addr; /* in network order */
     124        v32 = ntohl(m->ip);
     125        /* inverted order */
     126        sprintf(m->rip, ".%u.%u.%u.%u",
     127            (uint8_t)(v32),
     128            (uint8_t)(v32 >> 8),
     129            (uint8_t)(v32 >> 16),
     130            (v32 >> 24)
     131        );
     132        undot(m->rip);
     133    }
     134    config_close(parser);
     135    return conf_data;
    179136}
    180137
    181138/*
    182  * Look query up in dns records and return answer if found
    183  * qs is the query string, first byte the string length
    184  */
    185 static int table_lookup(uint16_t type, uint8_t * as, uint8_t * qs)
     139 * Look query up in dns records and return answer if found.
     140 */
     141static char *table_lookup(struct dns_entry *d,
     142        uint16_t type,
     143        char* query_string)
    186144{
    187     int i;
    188     struct dns_entry *d = dnsentry;
    189 
    190     do {
     145    while (d) {
     146        unsigned len = d->name[0];
     147        /* d->name[len] is the last (non NUL) char */
    191148#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));
     149        char *p, *q;
     150        q = query_string + 1;
     151        p = d->name + 1;
     152        fprintf(stderr, "%d/%d p:%s q:%s %d\n",
     153            (int)strlen(p), len,
     154            p, q, (int)strlen(q)
     155        );
    198156#endif
    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])
    202                     break;
    203             if (i > (int)(d->name[0])) {
    204                 strcpy((char *)as, d->ip);
     157        if (type == htons(REQ_A)) {
     158            /* search by host name */
     159            if (len != 1 || d->name[1] != '*') {
     160/* we are lax, hope no name component is ever >64 so that length
     161 * (which will be represented as 'A','B'...) matches a lowercase letter.
     162 * Actually, I think false matches are hard to construct.
     163 * Example.
     164 * [31] len is represented as '1', [65] as 'A', [65+32] as 'a'.
     165 * [65]   <65 same chars>[31]<31 same chars>NUL
     166 * [65+32]<65 same chars>1   <31 same chars>NUL
     167 * This example seems to be the minimal case when false match occurs.
     168 */
     169                if (strcasecmp(d->name, query_string) != 0)
     170                    goto next;
     171            }
     172            return (char *)&d->ip;
    205173#if DEBUG
    206                 fprintf(stderr, " OK as:%s\n", as);
     174            fprintf(stderr, "Found IP:%x\n", (int)d->ip);
    207175#endif
    208                 return 0;
    209             }
    210         } else if (type == REQ_PTR) { /* search by IP-address */
    211             if (!strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) {
    212                 strcpy((char *)as, d->name);
    213                 return 0;
    214             }
     176            return 0;
    215177        }
     178        /* search by IP-address */
     179        if ((len != 1 || d->name[1] != '*')
     180        /* we assume (do not check) that query_string
     181         * ends in ".in-addr.arpa" */
     182         && strncmp(d->rip, query_string, strlen(d->rip)) == 0
     183        ) {
     184#if DEBUG
     185            fprintf(stderr, "Found name:%s\n", d->name);
     186#endif
     187            return d->name;
     188        }
     189 next:
    216190        d = d->next;
    217     } while (d);
    218     return -1;
     191    }
     192
     193    return NULL;
    219194}
    220 
    221195
    222196/*
    223197 * Decode message and generate answer
    224198 */
    225 static int process_packet(uint8_t * buf)
     199/* RFC 1035
     200...
     201Whenever an octet represents a numeric quantity, the left most bit
     202in the diagram is the high order or most significant bit.
     203That is, the bit labeled 0 is the most significant bit.
     204...
     205
     2064.1.1. Header section format
     207      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
     208    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     209    |                      ID                       |
     210    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     211    |QR|   OPCODE  |AA|TC|RD|RA| 0  0  0|   RCODE   |
     212    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     213    |                    QDCOUNT                    |
     214    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     215    |                    ANCOUNT                    |
     216    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     217    |                    NSCOUNT                    |
     218    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     219    |                    ARCOUNT                    |
     220    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     221ID      16 bit random identifier assigned by querying peer.
     222        Used to match query/response.
     223QR      message is a query (0), or a response (1).
     224OPCODE  0   standard query (QUERY)
     225        1   inverse query (IQUERY)
     226        2   server status request (STATUS)
     227AA      Authoritative Answer - this bit is valid in responses.
     228        Responding name server is an authority for the domain name
     229        in question section. Answer section may have multiple owner names
     230        because of aliases.  The AA bit corresponds to the name which matches
     231        the query name, or the first owner name in the answer section.
     232TC      TrunCation - this message was truncated.
     233RD      Recursion Desired - this bit may be set in a query and
     234        is copied into the response.  If RD is set, it directs
     235        the name server to pursue the query recursively.
     236        Recursive query support is optional.
     237RA      Recursion Available - this be is set or cleared in a
     238        response, and denotes whether recursive query support is
     239        available in the name server.
     240RCODE   Response code.
     241        0   No error condition
     242        1   Format error
     243        2   Server failure - server was unable to process the query
     244            due to a problem with the name server.
     245        3   Name Error - meaningful only for responses from
     246            an authoritative name server. The referenced domain name
     247            does not exist.
     248        4   Not Implemented.
     249        5   Refused.
     250QDCOUNT number of entries in the question section.
     251ANCOUNT number of records in the answer section.
     252NSCOUNT number of records in the authority records section.
     253ARCOUNT number of records in the additional records section.
     254
     2554.1.2. Question section format
     256
     257The section contains QDCOUNT (usually 1) entries, each of this format:
     258      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
     259    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     260    /                     QNAME                     /
     261    /                                               /
     262    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     263    |                     QTYPE                     |
     264    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     265    |                     QCLASS                    |
     266    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     267QNAME   a domain name represented as a sequence of labels, where
     268        each label consists of a length octet followed by that
     269        number of octets. The domain name terminates with the
     270        zero length octet for the null label of the root. Note
     271        that this field may be an odd number of octets; no
     272        padding is used.
     273QTYPE   a two octet type of the query.
     274          1 a host address [REQ_A const]
     275          2 an authoritative name server
     276          3 a mail destination (Obsolete - use MX)
     277          4 a mail forwarder (Obsolete - use MX)
     278          5 the canonical name for an alias
     279          6 marks the start of a zone of authority
     280          7 a mailbox domain name (EXPERIMENTAL)
     281          8 a mail group member (EXPERIMENTAL)
     282          9 a mail rename domain name (EXPERIMENTAL)
     283         10 a null RR (EXPERIMENTAL)
     284         11 a well known service description
     285         12 a domain name pointer [REQ_PTR const]
     286         13 host information
     287         14 mailbox or mail list information
     288         15 mail exchange
     289         16 text strings
     290       0x1c IPv6?
     291        252 a request for a transfer of an entire zone
     292        253 a request for mailbox-related records (MB, MG or MR)
     293        254 a request for mail agent RRs (Obsolete - see MX)
     294        255 a request for all records
     295QCLASS  a two octet code that specifies the class of the query.
     296          1 the Internet
     297        (others are historic only)
     298        255 any class
     299
     3004.1.3. Resource Record format
     301
     302The answer, authority, and additional sections all share the same format:
     303a variable number of resource records, where the number of records
     304is specified in the corresponding count field in the header.
     305Each resource record has this format:
     306      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
     307    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     308    /                                               /
     309    /                      NAME                     /
     310    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     311    |                      TYPE                     |
     312    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     313    |                     CLASS                     |
     314    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     315    |                      TTL                      |
     316    |                                               |
     317    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     318    |                   RDLENGTH                    |
     319    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
     320    /                     RDATA                     /
     321    /                                               /
     322    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     323NAME    a domain name to which this resource record pertains.
     324TYPE    two octets containing one of the RR type codes.  This
     325        field specifies the meaning of the data in the RDATA field.
     326CLASS   two octets which specify the class of the data in the RDATA field.
     327TTL     a 32 bit unsigned integer that specifies the time interval
     328        (in seconds) that the record may be cached.
     329RDLENGTH a 16 bit integer, length in octets of the RDATA field.
     330RDATA   a variable length string of octets that describes the resource.
     331        The format of this information varies according to the TYPE
     332        and CLASS of the resource record.
     333        If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
     334
     3354.1.4. Message compression
     336
     337In order to reduce the size of messages, domain names coan be compressed.
     338An entire domain name or a list of labels at the end of a domain name
     339is replaced with a pointer to a prior occurance of the same name.
     340
     341The pointer takes the form of a two octet sequence:
     342    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     343    | 1  1|                OFFSET                   |
     344    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     345The first two bits are ones.  This allows a pointer to be distinguished
     346from a label, since the label must begin with two zero bits because
     347labels are restricted to 63 octets or less.  The OFFSET field specifies
     348an offset from the start of the message (i.e., the first octet
     349of the ID field in the domain header).
     350A zero offset specifies the first byte of the ID field, etc.
     351Domain name in a message can be represented as either:
     352   - a sequence of labels ending in a zero octet
     353   - a pointer
     354   - a sequence of labels ending with a pointer
     355 */
     356static int process_packet(struct dns_entry *conf_data,
     357        uint32_t conf_ttl,
     358        uint8_t *buf)
    226359{
    227360    struct dns_head *head;
    228     struct dns_prop *qprop;
    229     struct dns_repl outr;
    230     void *next, *from, *answb;
    231 
    232     uint8_t answstr[MAX_NAME_LEN + 1];
    233     int lookup_result, type, len, packet_len;
    234     uint16_t flags;
    235 
    236     answstr[0] = '\0';
     361    struct type_and_class *unaligned_type_class;
     362    const char *err_msg;
     363    char *query_string;
     364    char *answstr;
     365    uint8_t *answb;
     366    uint16_t outr_rlen;
     367    uint16_t outr_flags;
     368    uint16_t type;
     369    uint16_t class;
     370    int query_len;
    237371
    238372    head = (struct dns_head *)buf;
    239373    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     }
    248 
    249     from = (void *)&head[1];    //  start of query string
    250     next = answb = from + strlen((char *)from) + 1 + sizeof(struct dns_prop);   // where to append answer block
    251 
    252     outr.rlen = 0;          // may change later
    253     outr.r = NULL;
    254     outr.flags = 0;
    255 
    256     qprop = (struct dns_prop *)(answb - 4);
    257     type = ntohs(qprop->type);
    258 
    259     // only let REQ_A and REQ_PTR pass
    260     if (!(type == REQ_A || type == REQ_PTR)) {
    261         goto empty_packet;  /* we can't handle the query type */
    262     }
    263 
    264     if (ntohs(qprop->class) != 1 /* class INET */ ) {
    265         outr.flags = 4; /* not supported */
     374        bb_error_msg("packet has 0 queries, ignored");
     375        return 0; /* don't reply */
     376    }
     377    if (head->flags & htons(0x8000)) { /* QR bit */
     378        bb_error_msg("response packet, ignored");
     379        return 0; /* don't reply */
     380    }
     381    /* QR = 1 "response", RCODE = 4 "Not Implemented" */
     382    outr_flags = htons(0x8000 | 4);
     383    err_msg = NULL;
     384
     385    /* start of query string */
     386    query_string = (void *)(head + 1);
     387    /* caller guarantees strlen is <= MAX_PACK_LEN */
     388    query_len = strlen(query_string) + 1;
     389    /* may be unaligned! */
     390    unaligned_type_class = (void *)(query_string + query_len);
     391    query_len += sizeof(*unaligned_type_class);
     392    /* where to append answer block */
     393    answb = (void *)(unaligned_type_class + 1);
     394
     395    /* OPCODE != 0 "standard query"? */
     396    if ((head->flags & htons(0x7800)) != 0) {
     397        err_msg = "opcode != 0";
    266398        goto empty_packet;
    267399    }
    268     /* we only support standard queries */
    269 
    270     if ((ntohs(head->flags) & 0x7800) != 0)
     400    move_from_unaligned16(class, &unaligned_type_class->class);
     401    if (class != htons(1)) { /* not class INET? */
     402        err_msg = "class != 1";
    271403        goto empty_packet;
    272 
    273     // We have a standard query
    274     bb_info_msg("%s", (char *)from);
    275     lookup_result = table_lookup(type, answstr, (uint8_t*)from);
    276     if (lookup_result != 0) {
    277         outr.flags = 3 | 0x0400;    //name do not exist and auth
     404    }
     405    move_from_unaligned16(type, &unaligned_type_class->type);
     406    if (type != htons(REQ_A) && type != htons(REQ_PTR)) {
     407        /* we can't handle this query type */
     408//TODO: happens all the time with REQ_AAAA (0x1c) requests - implement those?
     409        err_msg = "type is !REQ_A and !REQ_PTR";
    278410        goto empty_packet;
    279411    }
    280     if (type == REQ_A) {    // return an address
    281         struct in_addr a;
    282         if (!inet_aton((char*)answstr, &a)) {//dotted dec to long conv
    283             outr.flags = 1; /* Frmt err */
    284             goto empty_packet;
     412
     413    /* look up the name */
     414    answstr = table_lookup(conf_data, type, query_string);
     415#if DEBUG
     416    /* Shows lengths instead of dots, unusable for !DEBUG */
     417    bb_error_msg("'%s'->'%s'", query_string, answstr);
     418#endif
     419    outr_rlen = 4;
     420    if (answstr && type == htons(REQ_PTR)) {
     421        /* returning a host name */
     422        outr_rlen = strlen(answstr) + 1;
     423    }
     424    if (!answstr
     425     || (unsigned)(answb - buf) + query_len + 4 + 2 + outr_rlen > MAX_PACK_LEN
     426    ) {
     427        /* QR = 1 "response"
     428         * AA = 1 "Authoritative Answer"
     429         * RCODE = 3 "Name Error" */
     430        err_msg = "name is not found";
     431        outr_flags = htons(0x8000 | 0x0400 | 3);
     432        goto empty_packet;
     433    }
     434
     435    /* Append answer Resource Record */
     436    memcpy(answb, query_string, query_len); /* name, type, class */
     437    answb += query_len;
     438    move_to_unaligned32((uint32_t *)answb, htonl(conf_ttl));
     439    answb += 4;
     440    move_to_unaligned16((uint16_t *)answb, htons(outr_rlen));
     441    answb += 2;
     442    memcpy(answb, answstr, outr_rlen);
     443    answb += outr_rlen;
     444
     445    /* QR = 1 "response",
     446     * AA = 1 "Authoritative Answer",
     447     * TODO: need to set RA bit 0x80? One user says nslookup complains
     448     * "Got recursion not available from SERVER, trying next server"
     449     * "** server can't find HOSTNAME"
     450     * RCODE = 0 "success"
     451     */
     452    if (OPT_verbose)
     453        bb_error_msg("returning positive reply");
     454    outr_flags = htons(0x8000 | 0x0400 | 0);
     455    /* we have one answer */
     456    head->nansw = htons(1);
     457
     458 empty_packet:
     459    if ((outr_flags & htons(0xf)) != 0) { /* not a positive response */
     460        if (OPT_verbose) {
     461            bb_error_msg("%s, %s",
     462                err_msg,
     463                OPT_silent ? "dropping query" : "sending error reply"
     464            );
    285465        }
    286         memcpy(answstr, &a.s_addr, 4);  // save before a disappears
    287         outr.rlen = 4;          // uint32_t IP
    288     } else
    289         outr.rlen = strlen((char *)answstr) + 1;    // a host name
    290     outr.r = answstr;           // 32 bit ip or a host name
    291     outr.flags |= 0x0400;           /* authority-bit */
    292     // we have an answer
    293     head->nansw = htons(1);
    294 
    295     // copy query block to answer block
    296     len = answb - from;
    297     memcpy(answb, from, len);
    298     next += len;
    299 
    300     // and append answer rr
    301     *(uint32_t *) next = htonl(ttl);
    302     next += 4;
    303     *(uint16_t *) next = htons(outr.rlen);
    304     next += 2;
    305     memcpy(next, (void *)answstr, outr.rlen);
    306     next += outr.rlen;
    307 
    308  empty_packet:
    309 
    310     flags = ntohs(head->flags);
    311     // clear rcode and RA, set responsebit and our new flags
    312     flags |= (outr.flags & 0xff80) | 0x8000;
    313     head->flags = htons(flags);
    314     head->nauth = head->nadd = htons(0);
    315     head->nquer = htons(1);
    316 
    317     packet_len = (uint8_t *)next - buf;
    318     return packet_len;
     466        if (OPT_silent)
     467            return 0;
     468    }
     469    head->flags |= outr_flags;
     470    head->nauth = head->nadd = 0;
     471    head->nquer = htons(1); // why???
     472
     473    return answb - buf;
    319474}
    320475
    321 /*
    322  * Exit on signal
    323  */
    324 static void interrupt(int x)
    325 {
    326     /* unlink("/var/run/dnsd.lock"); */
    327     bb_error_msg("interrupt, exiting\n");
    328     exit(2);
    329 }
    330 
    331 int dnsd_main(int argc, char **argv);
    332 int dnsd_main(int argc, char **argv)
     476int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     477int dnsd_main(int argc UNUSED_PARAM, char **argv)
    333478{
    334479    const char *listen_interface = "0.0.0.0";
     480    const char *fileconf = "/etc/dnsd.conf";
     481    struct dns_entry *conf_data;
     482    uint32_t conf_ttl = DEFAULT_TTL;
    335483    char *sttl, *sport;
    336     len_and_sockaddr *lsa;
    337     int udps;
     484    len_and_sockaddr *lsa, *from, *to;
     485    unsigned lsa_size;
     486    int udps, opts;
    338487    uint16_t port = 53;
    339     uint8_t buf[MAX_PACK_LEN];
    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
     488    /* Ensure buf is 32bit aligned (we need 16bit, but 32bit can't hurt) */
     489    uint8_t buf[MAX_PACK_LEN + 1] ALIGN4;
     490
     491    opts = getopt32(argv, "vsi:c:t:p:d", &listen_interface, &fileconf, &sttl, &sport);
     492    //if (opts & (1 << 0)) // -v
     493    //if (opts & (1 << 1)) // -s
     494    //if (opts & (1 << 2)) // -i
     495    //if (opts & (1 << 3)) // -c
     496    if (opts & (1 << 4)) // -t
     497        conf_ttl = xatou_range(sttl, 1, 0xffffffff);
     498    if (opts & (1 << 5)) // -p
    347499        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) {
     500    if (opts & (1 << 6)) { // -d
    356501        bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
    357502        openlog(applet_name, LOG_PID, LOG_DAEMON);
     
    359504    }
    360505
    361     dnsentryinit();
    362 
    363     signal(SIGINT, interrupt);
    364     /* why? signal(SIGPIPE, SIG_IGN); */
    365     signal(SIGHUP, SIG_IGN);
    366 #ifdef SIGTSTP
    367     signal(SIGTSTP, SIG_IGN);
    368 #endif
    369 #ifdef SIGURG
    370     signal(SIGURG, SIG_IGN);
    371 #endif
     506    conf_data = parse_conf_file(fileconf);
    372507
    373508    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));
     509    udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
     510    xbind(udps, &lsa->u.sa, lsa->len);
     511    socket_want_pktinfo(udps); /* needed for recv_from_to to work */
     512    lsa_size = LSA_LEN_SIZE + lsa->len;
     513    from = xzalloc(lsa_size);
     514    to = xzalloc(lsa_size);
     515
     516    {
     517        char *p = xmalloc_sockaddr2dotted(&lsa->u.sa);
     518        bb_error_msg("accepting UDP packets on %s", p);
     519        free(p);
     520    }
    379521
    380522    while (1) {
    381523        int r;
    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");
     524        /* Try to get *DEST* address (to which of our addresses
     525         * this query was directed), and reply from the same address.
     526         * Or else we can exhibit usual UDP ugliness:
     527         * [ip1.multihomed.ip2] <=  query to ip1  <= peer
     528         * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */
     529        memcpy(to, lsa, lsa_size);
     530        r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len);
     531        if (r < 12 || r > MAX_PACK_LEN) {
     532            bb_error_msg("packet size %d, ignored", r);
    393533            continue;
    394534        }
    395         r = process_packet(buf);
     535        if (OPT_verbose)
     536            bb_error_msg("got UDP packet");
     537        buf[r] = '\0'; /* paranoia */
     538        r = process_packet(conf_data, conf_ttl, buf);
    396539        if (r <= 0)
    397540            continue;
    398         sendto(udps, buf, r, 0, &lsa->sa, fromlen);
     541        send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len);
    399542    }
    400543    return 0;
  • branches/2.2.9/mindi-busybox/networking/ether-wake.c

    r1765 r2725  
    33 * ether-wake.c - Send a magic packet to wake up sleeping machines.
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    66 *
    77 * Author:      Donald Becker, http://www.scyld.com/"; http://www.scyld.com/wakeonlan.html
     
    9393    for (i = 0; i < pktsize; ++i) {
    9494        printf("%2.2x ", outpack[i]);
    95         if (i % 20 == 19) puts("");
     95        if (i % 20 == 19) bb_putchar('\n');
    9696    }
    9797    printf("\n\n");
     
    112112    struct ether_addr *eap;
    113113
    114     eap = ether_aton(hostid);
     114    eap = ether_aton_r(hostid, eaddr);
    115115    if (eap) {
    116         *eaddr = *eap;
    117         bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr));
    118 #if !defined(__UCLIBC__)
     116        bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eap));
     117#if !defined(__UCLIBC_MAJOR__) \
     118 || __UCLIBC_MAJOR__ > 0 \
     119 || __UCLIBC_MINOR__ > 9 \
     120 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ >= 30)
    119121    } else if (ether_hostton(hostid, eaddr) == 0) {
    120122        bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));
    121123#endif
    122     } else
     124    } else {
    123125        bb_show_usage();
     126    }
    124127}
    125128
     
    165168                          &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
    166169    if (byte_cnt < 4) {
    167         bb_error_msg("cannot read Wake-On-LAN pass");
     170        bb_error_msg("can't read Wake-On-LAN pass");
    168171        return 0;
    169172    }
     
    179182}
    180183
    181 int ether_wake_main(int argc, char **argv);
    182 int ether_wake_main(int argc, char **argv)
     184int ether_wake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     185int ether_wake_main(int argc UNUSED_PARAM, char **argv)
    183186{
    184187    const char *ifname = "eth0";
     
    187190    unsigned char wol_passwd[6];
    188191    int wol_passwd_sz = 0;
    189     int s;                      /* Raw socket */
     192    int s;  /* Raw socket */
    190193    int pktsize;
    191194    unsigned char outpack[1000];
    192195
    193196    struct ether_addr eaddr;
    194     struct whereto_t whereto;   /* who to wake up */
     197    struct whereto_t whereto;  /* who to wake up */
    195198
    196199    /* handle misc user options */
     
    220223        struct ifreq if_hwaddr;
    221224
    222         strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name));
     225        strncpy_IFNAMSIZ(if_hwaddr.ifr_name, ifname);
    223226        ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname);
    224227
     
    256259    {
    257260        struct ifreq ifr;
    258         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     261        strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    259262        xioctl(s, SIOCGIFINDEX, &ifr);
    260263        memset(&whereto, 0, sizeof(whereto));
  • branches/2.2.9/mindi-busybox/networking/ftpgetput.c

    r1765 r2725  
    66 *
    77 * Copyright (C) 2002 Jeff Angielski, The PTR Group <jeff@theptrgroup.com>
    8  * Copyright (C) 2002 Glenn McGrath <bug1@iinet.net.au>
     8 * Copyright (C) 2002 Glenn McGrath
    99 *
    1010 * Based on wget.c by Chip Rosenthal Covad Communications
    1111 * <chip@laserlink.net>
    1212 *
    13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1414 */
    1515
    16 #include <getopt.h>
    1716#include "libbb.h"
    1817
    19 typedef struct ftp_host_info_s {
     18struct globals {
    2019    const char *user;
    2120    const char *password;
    2221    struct len_and_sockaddr *lsa;
    23 } ftp_host_info_t;
    24 
    25 static smallint verbose_flag;
    26 static smallint do_continue;
    27 
    28 static void ftp_die(const char *msg, const char *remote) ATTRIBUTE_NORETURN;
    29 static void ftp_die(const char *msg, const char *remote)
    30 {
     22    FILE *control_stream;
     23    int verbose_flag;
     24    int do_continue;
     25    char buf[1]; /* actually [BUFSZ] */
     26} FIX_ALIASING;
     27#define G (*(struct globals*)&bb_common_bufsiz1)
     28enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) };
     29struct BUG_G_too_big {
     30    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     31};
     32#define user           (G.user          )
     33#define password       (G.password      )
     34#define lsa            (G.lsa           )
     35#define control_stream (G.control_stream)
     36#define verbose_flag   (G.verbose_flag  )
     37#define do_continue    (G.do_continue   )
     38#define buf            (G.buf           )
     39#define INIT_G() do { } while (0)
     40
     41
     42static void ftp_die(const char *msg) NORETURN;
     43static void ftp_die(const char *msg)
     44{
     45    char *cp = buf; /* buf holds peer's response */
     46
    3147    /* 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 
    39 
    40 static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
     48    while (*cp >= ' ' && *cp < '\x7f')
     49        cp++;
     50    *cp = '\0';
     51    bb_error_msg_and_die("unexpected server response%s%s: %s",
     52            (msg ? " to " : ""), (msg ? msg : ""), buf);
     53}
     54
     55static int ftpcmd(const char *s1, const char *s2)
    4156{
    4257    unsigned n;
     58
    4359    if (verbose_flag) {
    4460        bb_error_msg("cmd %s %s", s1, s2);
     
    4662
    4763    if (s1) {
    48         if (s2) {
    49             fprintf(stream, "%s %s\r\n", s1, s2);
    50         } else {
    51             fprintf(stream, "%s\r\n", s1);
    52         }
    53     }
     64        fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
     65                        s1, s2);
     66        fflush(control_stream);
     67    }
     68
    5469    do {
    55         char *buf_ptr;
    56 
    57         if (fgets(buf, 510, stream) == NULL) {
    58             bb_perror_msg_and_die("fgets");
    59         }
    60         buf_ptr = strstr(buf, "\r\n");
    61         if (buf_ptr) {
    62             *buf_ptr = '\0';
     70        strcpy(buf, "EOF");
     71        if (fgets(buf, BUFSZ - 2, control_stream) == NULL) {
     72            ftp_die(NULL);
    6373        }
    6474    } while (!isdigit(buf[0]) || buf[3] != ' ');
     
    7080}
    7181
    72 static int xconnect_ftpdata(ftp_host_info_t *server, char *buf)
     82static void ftp_login(void)
     83{
     84    /* Connect to the command socket */
     85    control_stream = fdopen(xconnect_stream(lsa), "r+");
     86    if (control_stream == NULL) {
     87        /* fdopen failed - extremely unlikely */
     88        bb_perror_nomsg_and_die();
     89    }
     90
     91    if (ftpcmd(NULL, NULL) != 220) {
     92        ftp_die(NULL);
     93    }
     94
     95    /*  Login to the server */
     96    switch (ftpcmd("USER", user)) {
     97    case 230:
     98        break;
     99    case 331:
     100        if (ftpcmd("PASS", password) != 230) {
     101            ftp_die("PASS");
     102        }
     103        break;
     104    default:
     105        ftp_die("USER");
     106    }
     107
     108    ftpcmd("TYPE I", NULL);
     109}
     110
     111static int xconnect_ftpdata(void)
    73112{
    74113    char *buf_ptr;
    75     unsigned short port_num;
     114    unsigned port_num;
     115
     116/*
     117TODO: PASV command will not work for IPv6. RFC2428 describes
     118IPv6-capable "extended PASV" - EPSV.
     119
     120"EPSV [protocol]" asks server to bind to and listen on a data port
     121in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
     122If not specified, defaults to "same as used for control connection".
     123If server understood you, it should answer "229 <some text>(|||port|)"
     124where "|" are literal pipe chars and "port" is ASCII decimal port#.
     125
     126There is also an IPv6-capable replacement for PORT (EPRT),
     127but we don't need that.
     128
     129NB: PASV may still work for some servers even over IPv6.
     130For example, vsftp happily answers
     131"227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
     132
     133TODO2: need to stop ignoring IP address in PASV response.
     134*/
     135
     136    if (ftpcmd("PASV", NULL) != 227) {
     137        ftp_die("PASV");
     138    }
    76139
    77140    /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]
     
    89152    port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
    90153
    91     set_nport(server->lsa, htons(port_num));
    92     return xconnect_stream(server->lsa);
    93 }
    94 
    95 static FILE *ftp_login(ftp_host_info_t *server)
    96 {
    97     FILE *control_stream;
    98     char buf[512];
    99 
    100     /* Connect to the command socket */
    101     control_stream = fdopen(xconnect_stream(server->lsa), "r+");
    102     if (control_stream == NULL) {
    103         /* fdopen failed - extremely unlikely */
    104         bb_perror_nomsg_and_die();
    105     }
    106 
    107     if (ftpcmd(NULL, NULL, control_stream, buf) != 220) {
    108         ftp_die(NULL, buf);
    109     }
    110 
    111     /*  Login to the server */
    112     switch (ftpcmd("USER", server->user, control_stream, buf)) {
    113     case 230:
    114         break;
    115     case 331:
    116         if (ftpcmd("PASS", server->password, control_stream, buf) != 230) {
    117             ftp_die("PASS", buf);
    118         }
    119         break;
    120     default:
    121         ftp_die("USER", buf);
    122     }
    123 
    124     ftpcmd("TYPE I", NULL, control_stream, buf);
    125 
    126     return control_stream;
     154    set_nport(lsa, htons(port_num));
     155    return xconnect_stream(lsa);
     156}
     157
     158static int pump_data_and_QUIT(int from, int to)
     159{
     160    /* copy the file */
     161    if (bb_copyfd_eof(from, to) == -1) {
     162        /* error msg is already printed by bb_copyfd_eof */
     163        return EXIT_FAILURE;
     164    }
     165
     166    /* close data connection */
     167    close(from); /* don't know which one is that, so we close both */
     168    close(to);
     169
     170    /* does server confirm that transfer is finished? */
     171    if (ftpcmd(NULL, NULL) != 226) {
     172        ftp_die(NULL);
     173    }
     174    ftpcmd("QUIT", NULL);
     175
     176    return EXIT_SUCCESS;
    127177}
    128178
    129179#if !ENABLE_FTPGET
    130 int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
    131         const char *local_path, char *server_path);
     180int ftp_receive(const char *local_path, char *server_path);
    132181#else
    133182static
    134 int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
    135         const char *local_path, char *server_path)
    136 {
    137     char buf[512];
    138 /* I think 'filesize' usage here is bogus. Let's see... */
    139     //off_t filesize = -1;
    140 #define filesize ((off_t)-1)
     183int ftp_receive(const char *local_path, char *server_path)
     184{
    141185    int fd_data;
    142186    int fd_local = -1;
    143187    off_t beg_range = 0;
    144188
    145     /* Connect to the data socket */
    146     if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
    147         ftp_die("PASV", buf);
    148     }
    149     fd_data = xconnect_ftpdata(server, buf);
    150 
    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);
    155     } else {
     189    /* connect to the data socket */
     190    fd_data = xconnect_ftpdata();
     191
     192    if (ftpcmd("SIZE", server_path) != 213) {
    156193        do_continue = 0;
    157194    }
     
    164201    if (do_continue) {
    165202        struct stat sbuf;
    166         if (lstat(local_path, &sbuf) < 0) {
    167             bb_perror_msg_and_die("lstat");
     203        /* lstat would be wrong here! */
     204        if (stat(local_path, &sbuf) < 0) {
     205            bb_perror_msg_and_die("stat");
    168206        }
    169207        if (sbuf.st_size > 0) {
     
    175213
    176214    if (do_continue) {
    177         sprintf(buf, "REST %"OFF_FMT"d", beg_range);
    178         if (ftpcmd(buf, NULL, control_stream, buf) != 350) {
     215        sprintf(buf, "REST %"OFF_FMT"u", beg_range);
     216        if (ftpcmd(buf, NULL) != 350) {
    179217            do_continue = 0;
    180         } else {
    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);
    188     }
    189 
    190     /* only make a local file if we know that one exists on the remote server */
     218        }
     219    }
     220
     221    if (ftpcmd("RETR", server_path) > 150) {
     222        ftp_die("RETR");
     223    }
     224
     225    /* create local file _after_ we know that remote file exists */
    191226    if (fd_local == -1) {
    192         if (do_continue) {
    193             fd_local = xopen(local_path, O_APPEND | O_WRONLY);
    194         } else {
    195             fd_local = xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY);
    196         }
    197     }
    198 
    199     /* Copy the file */
    200     if (filesize != -1) {
    201         if (bb_copyfd_size(fd_data, fd_local, filesize) == -1)
    202             return EXIT_FAILURE;
    203     } else {
    204         if (bb_copyfd_eof(fd_data, fd_local) == -1)
    205             return EXIT_FAILURE;
    206     }
    207 
    208     /* close it all down */
    209     close(fd_data);
    210     if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
    211         ftp_die(NULL, buf);
    212     }
    213     ftpcmd("QUIT", NULL, control_stream, buf);
    214 
    215     return EXIT_SUCCESS;
     227        fd_local = xopen(local_path,
     228            do_continue ? (O_APPEND | O_WRONLY)
     229                        : (O_CREAT | O_TRUNC | O_WRONLY)
     230        );
     231    }
     232
     233    return pump_data_and_QUIT(fd_data, fd_local);
    216234}
    217235#endif
    218236
    219237#if !ENABLE_FTPPUT
    220 int ftp_send(ftp_host_info_t *server, FILE *control_stream,
    221         const char *server_path, char *local_path);
     238int ftp_send(const char *server_path, char *local_path);
    222239#else
    223240static
    224 int ftp_send(ftp_host_info_t *server, FILE *control_stream,
    225         const char *server_path, char *local_path)
    226 {
    227     struct stat sbuf;
    228     char buf[512];
     241int ftp_send(const char *server_path, char *local_path)
     242{
    229243    int fd_data;
    230244    int fd_local;
    231245    int response;
    232246
    233     /*  Connect to the data socket */
    234     if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
    235         ftp_die("PASV", buf);
    236     }
    237     fd_data = xconnect_ftpdata(server, buf);
     247    /* connect to the data socket */
     248    fd_data = xconnect_ftpdata();
    238249
    239250    /* get the local file */
    240251    fd_local = STDIN_FILENO;
    241     if (NOT_LONE_DASH(local_path)) {
     252    if (NOT_LONE_DASH(local_path))
    242253        fd_local = xopen(local_path, O_RDONLY);
    243         fstat(fd_local, &sbuf);
    244 
    245         sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size);
    246         response = ftpcmd(buf, NULL, control_stream, buf);
    247         switch (response) {
    248         case 200:
    249         case 202:
    250             break;
    251         default:
    252             close(fd_local);
    253             ftp_die("ALLO", buf);
    254             break;
    255         }
    256     }
    257     response = ftpcmd("STOR", server_path, control_stream, buf);
     254
     255    response = ftpcmd("STOR", server_path);
    258256    switch (response) {
    259257    case 125:
     
    261259        break;
    262260    default:
    263         close(fd_local);
    264         ftp_die("STOR", buf);
    265     }
    266 
    267     /* transfer the file  */
    268     if (bb_copyfd_eof(fd_local, fd_data) == -1) {
    269         exit(EXIT_FAILURE);
    270     }
    271 
    272     /* close it all down */
    273     close(fd_data);
    274     if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
    275         ftp_die("close", buf);
    276     }
    277     ftpcmd("QUIT", NULL, control_stream, buf);
    278 
    279     return EXIT_SUCCESS;
    280 }
    281 #endif
    282 
    283 #define FTPGETPUT_OPT_CONTINUE  1
    284 #define FTPGETPUT_OPT_VERBOSE   2
    285 #define FTPGETPUT_OPT_USER  4
    286 #define FTPGETPUT_OPT_PASSWORD  8
    287 #define FTPGETPUT_OPT_PORT  16
     261        ftp_die("STOR");
     262    }
     263
     264    return pump_data_and_QUIT(fd_local, fd_data);
     265}
     266#endif
    288267
    289268#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
     
    297276#endif
    298277
    299 int ftpgetput_main(int argc, char **argv);
    300 int ftpgetput_main(int argc, char **argv)
    301 {
    302     /* content-length of the file */
     278int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     279int ftpgetput_main(int argc UNUSED_PARAM, char **argv)
     280{
    303281    unsigned opt;
    304282    const char *port = "ftp";
    305283    /* socket to ftp server */
    306     FILE *control_stream;
    307     /* continue previous transfer (-c) */
    308     ftp_host_info_t *server;
    309284
    310285#if ENABLE_FTPPUT && !ENABLE_FTPGET
     
    313288# define ftp_action ftp_receive
    314289#else
    315     int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = ftp_send;
     290    int (*ftp_action)(const char *, char *) = ftp_send;
     291
    316292    /* Check to see if the command is ftpget or ftput */
    317293    if (applet_name[3] == 'g') {
     
    320296#endif
    321297
     298    INIT_G();
    322299    /* Set default values */
    323     server = xmalloc(sizeof(*server));
    324     server->user = "anonymous";
    325     server->password = "busybox@";
     300    user = "anonymous";
     301    password = "busybox@";
    326302
    327303    /*
     
    331307    applet_long_options = ftpgetput_longopts;
    332308#endif
    333     opt_complementary = "=3"; /* must have 3 params */
    334     opt = getopt32(argv, "cvu:p:P:", &server->user, &server->password, &port);
     309    opt_complementary = "-2:vv:cc"; /* must have 2 to 3 params; -v and -c count */
     310    opt = getopt32(argv, "cvu:p:P:", &user, &password, &port,
     311                    &verbose_flag, &do_continue);
    335312    argv += optind;
    336 
    337     /* Process the non-option command line arguments */
    338     if (opt & FTPGETPUT_OPT_CONTINUE) {
    339         do_continue = 1;
    340     }
    341     if (opt & FTPGETPUT_OPT_VERBOSE) {
    342         verbose_flag = 1;
    343     }
    344313
    345314    /* We want to do exactly _one_ DNS lookup, since some
    346315     * sites (i.e. ftp.us.debian.org) use round-robin DNS
    347316     * and we want to connect to only one IP... */
    348     server->lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
     317    lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
    349318    if (verbose_flag) {
    350319        printf("Connecting to %s (%s)\n", argv[0],
    351             xmalloc_sockaddr2dotted(&server->lsa->sa));
    352     }
    353 
    354     /*  Connect/Setup/Configure the FTP session */
    355     control_stream = ftp_login(server);
    356 
    357     return ftp_action(server, control_stream, argv[1], argv[2]);
    358 }
     320            xmalloc_sockaddr2dotted(&lsa->u.sa));
     321    }
     322
     323    ftp_login();
     324    return ftp_action(argv[1], argv[2] ? argv[2] : argv[1]);
     325}
  • branches/2.2.9/mindi-busybox/networking/hostname.c

    r1765 r2725  
    55 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
    66 *
    7  * adjusted by Erik Andersen <andersen@codepoet.org> to remove
     7 * Adjusted by Erik Andersen <andersen@codepoet.org> to remove
    88 * use of long options and GNU getopt.  Improved the usage info.
    99 *
    10  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    11  *
    12  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1311 */
    14 
    1512#include "libbb.h"
    1613
    1714static void do_sethostname(char *s, int isfile)
    1815{
    19     FILE *f;
    20 
    21     if (!s)
    22         return;
    23     if (!isfile) {
    24         if (sethostname(s, strlen(s)) < 0) {
    25             if (errno == EPERM)
    26                 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
    27             else
    28                 bb_perror_msg_and_die("sethostname");
    29         }
    30     } else {
    31         f = xfopen(s, "r");
    32 #define strbuf bb_common_bufsiz1
    33         while (fgets(strbuf, sizeof(strbuf), f) != NULL) {
    34             if (strbuf[0] == '#') {
    35                 continue;
    36             }
    37             chomp(strbuf);
    38             do_sethostname(strbuf, 0);
     16//  if (!s)
     17//      return;
     18    if (isfile) {
     19        parser_t *parser = config_open2(s, xfopen_for_read);
     20        while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
     21            do_sethostname(s, 0);
    3922        }
    4023        if (ENABLE_FEATURE_CLEAN_UP)
    41             fclose(f);
     24            config_close(parser);
     25    } else if (sethostname(s, strlen(s))) {
     26//      if (errno == EPERM)
     27//          bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
     28        bb_perror_msg_and_die("sethostname");
    4229    }
    4330}
    4431
    45 int hostname_main(int argc, char **argv);
    46 int hostname_main(int argc, char **argv)
     32/* Manpage circa 2009:
     33 *
     34 * hostname [-v] [-a] [--alias] [-d] [--domain] [-f] [--fqdn] [--long]
     35 *      [-i] [--ip-address] [-s] [--short] [-y] [--yp] [--nis]
     36 *
     37 * hostname [-v] [-F filename] [--file filename] / [hostname]
     38 *
     39 * domainname [-v] [-F filename] [--file filename]  / [name]
     40 *  { bbox: not supported }
     41 *
     42 * nodename [-v] [-F filename] [--file filename] / [name]
     43 *  { bbox: not supported }
     44 *
     45 * dnsdomainname [-v]
     46 *  { bbox: supported: Linux kernel build needs this }
     47 * nisdomainname [-v]
     48 *  { bbox: not supported }
     49 * ypdomainname [-v]
     50 *  { bbox: not supported }
     51 *
     52 * -a, --alias
     53 *  Display the alias name of the host (if used).
     54 *  { bbox: not supported }
     55 * -d, --domain
     56 *  Display the name of the DNS domain. Don't use the command
     57 *  domainname to get the DNS domain name because it will show the
     58 *  NIS domain name and not the DNS domain name. Use dnsdomainname
     59 *  instead.
     60 * -f, --fqdn, --long
     61 *  Display the FQDN (Fully Qualified Domain Name). A FQDN consists
     62 *  of a short host name and the DNS domain name. Unless you are
     63 *  using bind or NIS for host lookups you can change the FQDN and
     64 *  the DNS domain name (which is part of the FQDN) in the
     65 *  /etc/hosts file.
     66 * -i, --ip-address
     67 *  Display the IP address(es) of the host.
     68 * -s, --short
     69 *  Display the short host name. This is the host name cut at the
     70 *  first dot.
     71 * -v, --verbose
     72 *  Be verbose and tell what's going on.
     73 *  { bbox: supported but ignored }
     74 * -y, --yp, --nis
     75 *  Display the NIS domain name. If a parameter is given (or --file
     76 *  name ) then root can also set a new NIS domain.
     77 *  { bbox: not supported }
     78 * -F, --file filename
     79 *  Read the host name from the specified file. Comments (lines
     80 *  starting with a `#') are ignored.
     81 */
     82int hostname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     83int hostname_main(int argc UNUSED_PARAM, char **argv)
    4784{
    4885    enum {
     
    5592    };
    5693
    57     char buf[256];
     94    unsigned opts;
     95    char *buf;
    5896    char *hostname_str;
    5997
    60     if (argc < 1)
    61         bb_show_usage();
     98#if ENABLE_LONG_OPTS
     99    applet_long_options =
     100        "domain\0"     No_argument "d"
     101        "fqdn\0"       No_argument "f"
     102    //Enable if seen in active use in some distro:
     103    //  "long\0"       No_argument "f"
     104    //  "ip-address\0" No_argument "i"
     105    //  "short\0"      No_argument "s"
     106    //  "verbose\0"    No_argument "v"
     107        "file\0"       No_argument "F"
     108        ;
    62109
    63     getopt32(argv, "dfisF:", &hostname_str);
     110#endif
     111    /* dnsdomainname from net-tools 1.60, hostname 1.100 (2001-04-14),
     112     * supports hostname's options too (not just -v as manpage says) */
     113    opts = getopt32(argv, "dfisF:v", &hostname_str);
     114    argv += optind;
     115    buf = safe_gethostname();
     116    if (applet_name[0] == 'd') /* dnsdomainname? */
     117        opts = OPT_d;
    64118
    65     /* Output in desired format */
    66     if (option_mask32 & OPT_dfis) {
     119    if (opts & OPT_dfis) {
     120        /* Cases when we need full hostname (or its part) */
    67121        struct hostent *hp;
    68122        char *p;
    69         gethostname(buf, sizeof(buf));
     123
    70124        hp = xgethostbyname(buf);
    71         p = strchr(hp->h_name, '.');
    72         if (option_mask32 & OPT_f) {
     125        p = strchrnul(hp->h_name, '.');
     126        if (opts & OPT_f) {
    73127            puts(hp->h_name);
    74         } else if (option_mask32 & OPT_s) {
    75             if (p != NULL) {
    76                 *p = '\0';
     128        } else if (opts & OPT_s) {
     129            *p = '\0';
     130            puts(hp->h_name);
     131        } else if (opts & OPT_d) {
     132            if (*p)
     133                puts(p + 1);
     134        } else /*if (opts & OPT_i)*/ {
     135            if (hp->h_length == sizeof(struct in_addr)) {
     136                struct in_addr **h_addr_list = (struct in_addr **)hp->h_addr_list;
     137                while (*h_addr_list) {
     138                    printf("%s ", inet_ntoa(**h_addr_list));
     139                    h_addr_list++;
     140                }
     141                bb_putchar('\n');
    77142            }
    78             puts(hp->h_name);
    79         } else if (option_mask32 & OPT_d) {
    80             if (p)
    81                 puts(p + 1);
    82         } else if (option_mask32 & OPT_i) {
    83             while (hp->h_addr_list[0]) {
    84                 printf("%s ", inet_ntoa(*(struct in_addr *) (*hp->h_addr_list++)));
    85             }
    86             puts("");
    87143        }
    88     }
    89     /* Set the hostname */
    90     else if (option_mask32 & OPT_F) {
     144    } else if (opts & OPT_F) {
     145        /* Set the hostname */
    91146        do_sethostname(hostname_str, 1);
    92     } else if (optind < argc) {
    93         do_sethostname(argv[optind], 0);
    94     }
    95     /* Or if all else fails,
    96      * just print the current hostname */
    97     else {
    98         gethostname(buf, sizeof(buf));
     147    } else if (argv[0]) {
     148        /* Set the hostname */
     149        do_sethostname(argv[0], 0);
     150    } else {
     151        /* Just print the current hostname */
    99152        puts(buf);
    100153    }
    101     return 0;
     154
     155    if (ENABLE_FEATURE_CLEAN_UP)
     156        free(buf);
     157    return EXIT_SUCCESS;
    102158}
  • branches/2.2.9/mindi-busybox/networking/httpd.c

    r1772 r2725  
    66 * Copyright (C) 2003-2006 Vladimir Oleynik <dzo@simtreas.ru>
    77 *
    8  * simplify patch stolen from libbb without using strdup
    9  *
    10  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    119 *
    1210 *****************************************************************************
    1311 *
    1412 * Typical usage:
    15  *   for non root user
    16  * httpd -p 8080 -h $HOME/public_html
    17  *   or for daemon start from rc script with uid=0:
    18  * httpd -u www
    19  * This is equivalent if www user have uid=80 to
    20  * httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication"
    21  *
    22  *
    23  * When a url starts by "/cgi-bin/" it is assumed to be a cgi script.  The
    24  * server changes directory to the location of the script and executes it
     13 * For non root user:
     14 *      httpd -p 8080 -h $HOME/public_html
     15 * For daemon start from rc script with uid=0:
     16 *      httpd -u www
     17 * which is equivalent to (assuming user www has uid 80):
     18 *      httpd -p 80 -u 80 -h $PWD -c /etc/httpd.conf -r "Web Server Authentication"
     19 *
     20 * When an url starts with "/cgi-bin/" it is assumed to be a cgi script.
     21 * The server changes directory to the location of the script and executes it
    2522 * after setting QUERY_STRING and other environment variables.
    2623 *
     
    2825 * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html
    2926 *
    30  * The server can also be invoked as a url arg decoder and html text encoder
     27 * The applet can also be invoked as an url arg decoder and html text encoder
    3128 * as follows:
    32  *  foo=`httpd -d $foo`           # decode "Hello%20World" as "Hello World"
    33  *  bar=`httpd -e "<Hello World>"`  # encode as "&#60Hello&#32World&#62"
     29 *      foo=`httpd -d $foo`             # decode "Hello%20World" as "Hello World"
     30 *      bar=`httpd -e "<Hello World>"`  # encode as "&#60Hello&#32World&#62"
    3431 * Note that url encoding for arguments is not the same as html encoding for
    35  * presentation.  -d decodes a url-encoded argument while -e encodes in html
     32 * presentation.  -d decodes an url-encoded argument while -e encodes in html
    3633 * for page display.
    3734 *
    3835 * httpd.conf has the following format:
    3936 *
     37 * H:/serverroot     # define the server root. It will override -h
    4038 * A:172.20.         # Allow address from 172.20.0.0/16
    4139 * A:10.0.0.0/25     # Allow any address from 10.0.0.0-10.0.0.127
     
    4442 * D:*               # Deny from other IP connections
    4543 * E404:/path/e404.html # /path/e404.html is the 404 (not found) error page
     44 * I:index.html      # Show index.html when a directory is requested
     45 *
     46 * P:/url:[http://]hostname[:port]/new/path
     47 *                   # When /urlXXXXXX is requested, reverse proxy
     48 *                   # it to http://hostname[:port]/new/pathXXXXXX
     49 *
    4650 * /cgi-bin:foo:bar  # Require user foo, pwd bar on urls starting with /cgi-bin/
    4751 * /adm:admin:setup  # Require user admin, pwd setup on urls starting with /adm/
    4852 * /adm:toor:PaSsWd  # or user toor, pwd PaSsWd on urls starting with /adm/
    4953 * .au:audio/basic   # additional mime type for audio.au files
    50  * *.php:/path/php   # running cgi.php scripts through an interpreter
    51  *
    52  * A/D may be as a/d or allow/deny - first char case insensitive
    53  * Deny IP rules take precedence over allow rules.
    54  *
    55  *
    56  * The Deny/Allow IP logic:
    57  *
    58  *  - Default is to allow all.  No addresses are denied unless
    59  *         denied with a D: rule.
    60  *  - Order of Deny/Allow rules is significant
     54 * *.php:/path/php   # run xxx.php through an interpreter
     55 *
     56 * A/D may be as a/d or allow/deny - only first char matters.
     57 * Deny/Allow IP logic:
     58 *  - Default is to allow all (Allow all (A:*) is a no-op).
    6159 *  - Deny rules take precedence over allow rules.
    62  *  - If a deny all rule (D:*) is used it acts as a catch-all for unmatched
    63  *       addresses.
    64  *  - Specification of Allow all (A:*) is a no-op
     60 *  - "Deny all" rule (D:*) is applied last.
    6561 *
    6662 * Example:
     
    9692 *
    9793 */
     94 /* TODO: use TCP_CORK, parse_config() */
    9895
    9996#include "libbb.h"
    10097#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
    101 #include <sys/sendfile.h>
    102 #endif
    103 
    104 //#define DEBUG 1
    105 #define DEBUG 0
    106 
     98# include <sys/sendfile.h>
     99#endif
    107100/* amount of buffering in a pipe */
    108101#ifndef PIPE_BUF
     
    110103#endif
    111104
    112 #define IOBUF_SIZE 8192    /* IO buffer */
     105#define DEBUG 0
     106
     107#define IOBUF_SIZE 8192
     108#if PIPE_BUF >= IOBUF_SIZE
     109# error "PIPE_BUF >= IOBUF_SIZE"
     110#endif
    113111
    114112#define HEADER_READ_TIMEOUT 60
    115113
    116 static const char default_path_httpd_conf[] ALIGN1 = "/etc";
    117 static const char httpd_conf[] ALIGN1 = "httpd.conf";
     114static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc";
     115static const char HTTPD_CONF[] ALIGN1 = "httpd.conf";
    118116static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n";
     117static const char index_html[] ALIGN1 = "index.html";
    119118
    120119typedef struct has_next_ptr {
     
    137136} Htaccess_IP;
    138137
     138/* Must have "next" as a first member */
     139typedef struct Htaccess_Proxy {
     140    struct Htaccess_Proxy *next;
     141    char *url_from;
     142    char *host_port;
     143    char *url_to;
     144} Htaccess_Proxy;
     145
    139146enum {
    140147    HTTP_OK = 200,
     148    HTTP_PARTIAL_CONTENT = 206,
    141149    HTTP_MOVED_TEMPORARILY = 302,
    142150    HTTP_BAD_REQUEST = 400,       /* malformed syntax */
     
    160168    HTTP_BAD_GATEWAY = 502,
    161169    HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */
    162     HTTP_RESPONSE_SETSIZE = 0xffffffff
    163170#endif
    164171};
     
    166173static const uint16_t http_response_type[] ALIGN2 = {
    167174    HTTP_OK,
     175#if ENABLE_FEATURE_HTTPD_RANGES
     176    HTTP_PARTIAL_CONTENT,
     177#endif
    168178    HTTP_MOVED_TEMPORARILY,
    169179    HTTP_REQUEST_TIMEOUT,
    170180    HTTP_NOT_IMPLEMENTED,
    171 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 
     181#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    172182    HTTP_UNAUTHORIZED,
    173183#endif
     
    193203} http_response[ARRAY_SIZE(http_response_type)] = {
    194204    { "OK", NULL },
    195     { "Found", "Directories must end with a slash" }, /* ?? */
     205#if ENABLE_FEATURE_HTTPD_RANGES
     206    { "Partial Content", NULL },
     207#endif
     208    { "Found", NULL },
    196209    { "Request Timeout", "No request appeared within 60 seconds" },
    197210    { "Not Implemented", "The requested method is not recognized" },
     
    219232    smallint flg_deny_all;
    220233
    221     unsigned rmt_ip;    /* used for IP-based allow/deny rules */
     234    unsigned rmt_ip;        /* used for IP-based allow/deny rules */
    222235    time_t last_mod;
    223     off_t ContentLength;    /* -1 - unknown */
    224236    char *rmt_ip_str;       /* for $REMOTE_ADDR and $REMOTE_PORT */
    225237    const char *bind_addr_or_port;
    226238
    227239    const char *g_query;
    228     const char *configFile;
     240    const char *opt_c_configFile;
    229241    const char *home_httpd;
     242    const char *index_page;
    230243
    231244    const char *found_mime_type;
     
    233246    Htaccess_IP *ip_a_d;    /* config allow/deny lines */
    234247
    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;)
     248    IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
     249    IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
     250    IF_FEATURE_HTTPD_CGI(char *referer;)
     251    IF_FEATURE_HTTPD_CGI(char *user_agent;)
     252    IF_FEATURE_HTTPD_CGI(char *host;)
     253    IF_FEATURE_HTTPD_CGI(char *http_accept;)
     254    IF_FEATURE_HTTPD_CGI(char *http_accept_language;)
     255
     256    off_t file_size;        /* -1 - unknown */
     257#if ENABLE_FEATURE_HTTPD_RANGES
     258    off_t range_start;
     259    off_t range_end;
     260    off_t range_len;
     261#endif
    239262
    240263#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    241264    Htaccess *g_auth;       /* config user:password lines */
    242265#endif
    243 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    244266    Htaccess *mime_a;       /* config mime types */
    245 #endif
    246267#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    247268    Htaccess *script_i;     /* config script interpreters */
    248269#endif
    249     char *iobuf;            /* [IOBUF_SIZE] */
     270    char *iobuf;            /* [IOBUF_SIZE] */
    250271#define hdr_buf bb_common_bufsiz1
    251272    char *hdr_ptr;
     
    253274#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
    254275    const char *http_error_page[ARRAY_SIZE(http_response_type)];
     276#endif
     277#if ENABLE_FEATURE_HTTPD_PROXY
     278    Htaccess_Proxy *proxy;
     279#endif
     280#if ENABLE_FEATURE_HTTPD_GZIP
     281    /* client can handle gzip / we are going to send gzip */
     282    smallint content_gzip;
    255283#endif
    256284};
     
    261289#define bind_addr_or_port (G.bind_addr_or_port)
    262290#define g_query           (G.g_query          )
    263 #define configFile        (G.configFile      )
     291#define opt_c_configFile  (G.opt_c_configFile )
    264292#define home_httpd        (G.home_httpd       )
     293#define index_page        (G.index_page       )
    265294#define found_mime_type   (G.found_mime_type  )
    266295#define found_moved_temporarily (G.found_moved_temporarily)
    267 #define ContentLength     (G.ContentLength    )
    268296#define last_mod          (G.last_mod         )
    269297#define ip_a_d            (G.ip_a_d           )
     
    272300#define referer           (G.referer          )
    273301#define user_agent        (G.user_agent       )
     302#define host              (G.host             )
     303#define http_accept       (G.http_accept      )
     304#define http_accept_language (G.http_accept_language)
     305#define file_size         (G.file_size        )
     306#if ENABLE_FEATURE_HTTPD_RANGES
     307#define range_start       (G.range_start      )
     308#define range_end         (G.range_end        )
     309#define range_len         (G.range_len        )
     310#else
     311enum {
     312    range_start = 0,
     313    range_end = MAXINT(off_t) - 1,
     314    range_len = MAXINT(off_t),
     315};
     316#endif
    274317#define rmt_ip_str        (G.rmt_ip_str       )
    275318#define g_auth            (G.g_auth           )
     
    280323#define hdr_cnt           (G.hdr_cnt          )
    281324#define http_error_page   (G.http_error_page  )
     325#define proxy             (G.proxy            )
     326#if ENABLE_FEATURE_HTTPD_GZIP
     327# define content_gzip     (G.content_gzip     )
     328#else
     329# define content_gzip     0
     330#endif
    282331#define INIT_G() do { \
    283     PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
    284     USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
     332    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     333    IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
    285334    bind_addr_or_port = "80"; \
    286     ContentLength = -1; \
     335    index_page = index_html; \
     336    file_size = -1; \
    287337} while (0)
    288338
     
    291341
    292342/* Prototypes */
    293 static void send_file_and_exit(const char *url, int headers) ATTRIBUTE_NORETURN;
     343enum {
     344    SEND_HEADERS     = (1 << 0),
     345    SEND_BODY        = (1 << 1),
     346    SEND_HEADERS_AND_BODY = SEND_HEADERS + SEND_BODY,
     347};
     348static void send_file_and_exit(const char *url, int what) NORETURN;
    294349
    295350static void free_llist(has_next_ptr **pptr)
     
    304359}
    305360
    306 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \
    307  || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \
    308  || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    309361static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr)
    310362{
    311363    free_llist((has_next_ptr**)pptr);
    312364}
    313 #endif
    314365
    315366static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
     
    406457 * Parse configuration file into in-memory linked list.
    407458 *
    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  *
    415459 * Any previous IP rules are discarded.
    416460 * If the flag argument is not SUBDIR_PARSE then all /path and mime rules
     
    422466 * flag   Type of the parse request.
    423467 */
    424 /* flag */
    425 #define FIRST_PARSE          0
    426 #define SUBDIR_PARSE         1
    427 #define SIGNALED_PARSE       2
    428 #define FIND_FROM_HTTPD_ROOT 3
     468/* flag param: */
     469enum {
     470    FIRST_PARSE    = 0, /* path will be "/etc" */
     471    SIGNALED_PARSE = 1, /* path will be "/etc" */
     472    SUBDIR_PARSE   = 2, /* path will be derived from URL */
     473};
    429474static void parse_conf(const char *path, int flag)
    430475{
     476    /* internally used extra flag state */
     477    enum { TRY_CURDIR_PARSE = 3 };
     478
    431479    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;
     480    const char *filename;
    441481    char buf[160];
    442     char *p0 = NULL;
    443     char *c, *p;
    444     Htaccess_IP *pip;
    445482
    446483    /* discard old rules */
    447484    free_Htaccess_IP_list(&ip_a_d);
    448485    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
    452486    /* retain previous auth and mime config only for subdir parse */
    453487    if (flag != SUBDIR_PARSE) {
     488        free_Htaccess_list(&mime_a);
    454489#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    455490        free_Htaccess_list(&g_auth);
    456491#endif
    457 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
    458         free_Htaccess_list(&mime_a);
    459 #endif
    460492#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    461493        free_Htaccess_list(&script_i);
    462494#endif
    463495    }
    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) {
     496
     497    filename = opt_c_configFile;
     498    if (flag == SUBDIR_PARSE || filename == NULL) {
     499        filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2);
     500        sprintf((char *)filename, "%s/%s", path, HTTPD_CONF);
     501    }
     502
     503    while ((f = fopen_for_read(filename)) == NULL) {
     504        if (flag >= SUBDIR_PARSE) { /* SUBDIR or TRY_CURDIR */
    473505            /* config file not found, no changes to config */
    474506            return;
    475507        }
    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;
     508        if (flag == FIRST_PARSE) {
     509            /* -c CONFFILE given, but CONFFILE doesn't exist? */
     510            if (opt_c_configFile)
     511                bb_simple_perror_msg_and_die(opt_c_configFile);
     512            /* else: no -c, thus we looked at /etc/httpd.conf,
     513             * and it's not there. try ./httpd.conf: */
     514        }
     515        flag = TRY_CURDIR_PARSE;
     516        filename = HTTPD_CONF;
    480517    }
    481518
    482519#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')
     520    /* in "/file:user:pass" lines, we prepend path in subdirs */
     521    if (flag != SUBDIR_PARSE)
     522        path = "";
     523#endif
     524    /* The lines can be:
     525     *
     526     * I:default_index_file
     527     * H:http_home
     528     * [AD]:IP[/mask]   # allow/deny, * for wildcard
     529     * Ennn:error.html  # error page for status nnn
     530     * P:/url:[http://]hostname[:port]/new/path # reverse proxy
     531     * .ext:mime/type   # mime type
     532     * *.php:/path/php  # run xxx.php through an interpreter
     533     * /file:user:pass  # username and password
     534     */
     535    while (fgets(buf, sizeof(buf), f) != NULL) {
     536        unsigned strlen_buf;
     537        unsigned char ch;
     538        char *after_colon;
     539
     540        { /* remove all whitespace, and # comments */
     541            char *p, *p0;
     542
     543            p0 = buf;
     544            /* skip non-whitespace beginning. Often the whole line
     545             * is non-whitespace. We want this case to work fast,
     546             * without needless copying, therefore we don't merge
     547             * this operation into next while loop. */
     548            while ((ch = *p0) != '\0' && ch != '\n' && ch != '#'
     549             && ch != ' ' && ch != '\t'
     550            ) {
     551                p0++;
     552            }
     553            p = p0;
     554            /* if we enter this loop, we have some whitespace.
     555             * discard it */
     556            while (ch != '\0' && ch != '\n' && ch != '#') {
     557                if (ch != ' ' && ch != '\t') {
     558                    *p++ = ch;
     559                }
     560                ch = *++p0;
     561            }
     562            *p = '\0';
     563            strlen_buf = p - buf;
     564            if (strlen_buf == 0)
     565                continue; /* empty line */
     566        }
     567
     568        after_colon = strchr(buf, ':');
     569        /* strange line? */
     570        if (after_colon == NULL || *++after_colon == '\0')
     571            goto config_error;
     572
     573        ch = (buf[0] & ~0x20); /* toupper if it's a letter */
     574
     575        if (ch == 'I') {
     576            if (index_page != index_html)
     577                free((char*)index_page);
     578            index_page = xstrdup(after_colon);
    499579            continue;
    500         p0 = buf;
    501         if (*p0 == 'd')
    502             *p0 = 'D';
    503         if (*c == '*') {
    504             if (*p0 == 'D') {
    505                 /* memorize deny all */
    506                 flg_deny_all = 1;
    507             }
    508             /* skip default other "word:*" config lines */
     580        }
     581
     582        /* do not allow jumping around using H in subdir's configs */
     583        if (flag == FIRST_PARSE && ch == 'H') {
     584            home_httpd = xstrdup(after_colon);
     585            xchdir(home_httpd);
    509586            continue;
    510587        }
    511588
    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;
     589        if (ch == 'A' || ch == 'D') {
     590            Htaccess_IP *pip;
     591
     592            if (*after_colon == '*') {
     593                if (ch == 'D') {
     594                    /* memorize "deny all" */
     595                    flg_deny_all = 1;
    522596                }
    523                 pip->allow_deny = *p0;
    524                 if (*p0 == 'D') {
    525                     /* Deny:from_IP move top */
    526                     pip->next = ip_a_d;
     597                /* skip assumed "A:*", it is a default anyway */
     598                continue;
     599            }
     600            /* store "allow/deny IP/mask" line */
     601            pip = xzalloc(sizeof(*pip));
     602            if (scan_ip_mask(after_colon, &pip->ip, &pip->mask)) {
     603                /* IP{/mask} syntax error detected, protect all */
     604                ch = 'D';
     605                pip->mask = 0;
     606            }
     607            pip->allow_deny = ch;
     608            if (ch == 'D') {
     609                /* Deny:from_IP - prepend */
     610                pip->next = ip_a_d;
     611                ip_a_d = pip;
     612            } else {
     613                /* A:from_IP - append (thus all D's precedes A's) */
     614                Htaccess_IP *prev_IP = ip_a_d;
     615                if (prev_IP == NULL) {
    527616                    ip_a_d = pip;
    528617                } 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                     }
     618                    while (prev_IP->next)
     619                        prev_IP = prev_IP->next;
     620                    prev_IP->next = pip;
    539621                }
    540622            }
     
    543625
    544626#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++; */
     627        if (flag == FIRST_PARSE && ch == 'E') {
     628            unsigned i;
     629            int status = atoi(buf + 1); /* error status code */
     630
    551631            if (status < HTTP_CONTINUE) {
    552                 bb_error_msg("config error '%s' in '%s'", buf, cf);
    553                 continue;
    554             }
    555 
     632                goto config_error;
     633            }
    556634            /* then error page; find matching status */
    557635            for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
    558636                if (http_response_type[i] == status) {
    559                     http_error_page[i] = concat_path_file((*c == '/') ? NULL : home_httpd, c);
     637                    /* We chdir to home_httpd, thus no need to
     638                     * concat_path_file(home_httpd, after_colon)
     639                     * here */
     640                    http_error_page[i] = xstrdup(after_colon);
    560641                    break;
    561642                }
     
    565646#endif
    566647
    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 */
     648#if ENABLE_FEATURE_HTTPD_PROXY
     649        if (flag == FIRST_PARSE && ch == 'P') {
     650            /* P:/url:[http://]hostname[:port]/new/path */
     651            char *url_from, *host_port, *url_to;
     652            Htaccess_Proxy *proxy_entry;
     653
     654            url_from = after_colon;
     655            host_port = strchr(after_colon, ':');
     656            if (host_port == NULL) {
     657                goto config_error;
     658            }
     659            *host_port++ = '\0';
     660            if (strncmp(host_port, "http://", 7) == 0)
     661                host_port += 7;
     662            if (*host_port == '\0') {
     663                goto config_error;
     664            }
     665            url_to = strchr(host_port, '/');
     666            if (url_to == NULL) {
     667                goto config_error;
     668            }
     669            *url_to = '\0';
     670            proxy_entry = xzalloc(sizeof(*proxy_entry));
     671            proxy_entry->url_from = xstrdup(url_from);
     672            proxy_entry->host_port = xstrdup(host_port);
     673            *url_to = '/';
     674            proxy_entry->url_to = xstrdup(url_to);
     675            proxy_entry->next = proxy;
     676            proxy = proxy_entry;
     677            continue;
     678        }
     679#endif
     680        /* the rest of directives are non-alphabetic,
     681         * must avoid using "toupper'ed" ch */
     682        ch = buf[0];
     683
     684        if (ch == '.' /* ".ext:mime/type" */
     685#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
     686         || (ch == '*' && buf[1] == '.') /* "*.php:/path/php" */
     687#endif
     688        ) {
     689            char *p;
     690            Htaccess *cur;
     691
     692            cur = xzalloc(sizeof(*cur) /* includes space for NUL */ + strlen_buf);
     693            strcpy(cur->before_colon, buf);
     694            p = cur->before_colon + (after_colon - buf);
     695            p[-1] = '\0';
     696            cur->after_colon = p;
     697            if (ch == '.') {
     698                /* .mime line: prepend to mime_a list */
    618699                cur->next = mime_a;
    619700                mime_a = cur;
    620                 continue;
    621             }
    622 #endif
     701            }
    623702#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    624             if (*cf == '*' && cf[1] == '.') {
    625                 /* config script interpreter line move top for overwrite previous */
     703            else {
     704                /* script interpreter line: prepend to script_i list */
    626705                cur->next = script_i;
    627706                script_i = cur;
    628                 continue;
    629             }
    630 #endif
     707            }
     708#endif
     709            continue;
     710        }
     711
    631712#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                         }
     713        if (ch == '/') { /* "/file:user:pass" */
     714            char *p;
     715            Htaccess *cur;
     716            unsigned file_len;
     717
     718            /* note: path is "" unless we are in SUBDIR parse,
     719             * otherwise it does NOT start with "/" */
     720            cur = xzalloc(sizeof(*cur) /* includes space for NUL */
     721                + 1 + strlen(path)
     722                + strlen_buf
     723                );
     724            /* form "/path/file" */
     725            sprintf(cur->before_colon, "/%s%.*s",
     726                path,
     727                (int) (after_colon - buf - 1), /* includes "/", but not ":" */
     728                buf);
     729            /* canonicalize it */
     730            p = bb_simplify_abs_path_inplace(cur->before_colon);
     731            file_len = p - cur->before_colon;
     732            /* add "user:pass" after NUL */
     733            strcpy(++p, after_colon);
     734            cur->after_colon = p;
     735
     736            /* insert cur into g_auth */
     737            /* g_auth is sorted by decreased filename length */
     738            {
     739                Htaccess *auth, **authp;
     740
     741                authp = &g_auth;
     742                while ((auth = *authp) != NULL) {
     743                    if (file_len >= strlen(auth->before_colon)) {
     744                        /* insert cur before auth */
     745                        cur->next = auth;
    652746                        break;
    653747                    }
    654                     if (prev_hti != hti)
    655                         prev_hti = prev_hti->next;
     748                    authp = &auth->next;
    656749                }
    657                 if (!hti) {       /* not inserted, add to bottom */
    658                     prev->next = cur;
    659                     prev = cur;
    660                 }
    661             }
    662 #endif
    663         }
    664 #endif
    665      }
     750                *authp = cur;
     751            }
     752            continue;
     753        }
     754#endif /* BASIC_AUTH */
     755
     756        /* the line is not recognized */
     757 config_error:
     758        bb_error_msg("config error '%s' in '%s'", buf, filename);
     759     } /* while (fgets) */
     760
    666761     fclose(f);
    667762}
     
    685780    char ch;
    686781
    687     while ((ch = *string++)) {
     782    while ((ch = *string++) != '\0') {
    688783        /* very simple check for what to encode */
    689784        if (isalnum(ch))
     
    695790    return out;
    696791}
    697 #endif          /* FEATURE_HTTPD_ENCODE_URL_STR */
     792#endif
    698793
    699794/*
    700795 * Given a URL encoded string, convert it to plain ascii.
    701796 * 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
     797 * Thus, callers should xstrdup() the argument if they do not want the
    703798 * argument modified.  The return is the original pointer, allowing this
    704799 * function to be easily used as arguments to other functions.
     
    722817        return v + 10;
    723818    return ~0;
    724 }
    725819/* For testing:
    726820void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
     
    728822t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
    729823*/
     824}
    730825static char *decodeString(char *orig, int option_d)
    731826{
     
    821916static int openServer(void)
    822917{
    823     int n = bb_strtou(bind_addr_or_port, NULL, 10);
     918    unsigned n = bb_strtou(bind_addr_or_port, NULL, 10);
    824919    if (!errno && n && n <= 0xffff)
    825920        n = create_and_bind_stream_or_die(NULL, n);
     
    833928 * Log the connection closure and exit.
    834929 */
    835 static void log_and_exit(void) ATTRIBUTE_NORETURN;
     930static void log_and_exit(void) NORETURN;
    836931static void log_and_exit(void)
    837932{
     
    839934     * or be confused by us just exiting without SHUT_WR. Oh well. */
    840935    shutdown(1, SHUT_WR);
     936    /* Why??
     937    (this also messes up stdin when user runs httpd -i from terminal)
    841938    ndelay_on(0);
    842     while (read(0, iobuf, IOBUF_SIZE) > 0)
     939    while (read(STDIN_FILENO, iobuf, IOBUF_SIZE) > 0)
    843940        continue;
     941    */
    844942
    845943    if (verbose > 2)
     
    863961    const char *mime_type;
    864962#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
    865     const char *error_page = 0;
     963    const char *error_page = NULL;
    866964#endif
    867965    unsigned i;
    868     time_t timer = time(0);
     966    time_t timer = time(NULL);
    869967    char tmp_str[80];
    870968    int len;
     
    9091007
    9101008#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
    911     if (error_page && !access(error_page, R_OK)) {
     1009    if (error_page && access(error_page, R_OK) == 0) {
    9121010        strcat(iobuf, "\r\n");
    9131011        len += 2;
     
    9151013        if (DEBUG)
    9161014            fprintf(stderr, "headers: '%s'\n", iobuf);
    917         full_write(1, iobuf, len);
     1015        full_write(STDOUT_FILENO, iobuf, len);
    9181016        if (DEBUG)
    9191017            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 */
     1018        return send_file_and_exit(error_page, SEND_BODY);
     1019    }
     1020#endif
     1021
     1022    if (file_size != -1) {    /* file */
    9251023        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     }
     1024#if ENABLE_FEATURE_HTTPD_RANGES
     1025        if (responseNum == HTTP_PARTIAL_CONTENT) {
     1026            len += sprintf(iobuf + len, "Content-Range: bytes %"OFF_FMT"u-%"OFF_FMT"u/%"OFF_FMT"u\r\n",
     1027                    range_start,
     1028                    range_end,
     1029                    file_size);
     1030            file_size = range_end - range_start + 1;
     1031        }
     1032#endif
     1033        len += sprintf(iobuf + len,
     1034#if ENABLE_FEATURE_HTTPD_RANGES
     1035            "Accept-Ranges: bytes\r\n"
     1036#endif
     1037            "Last-Modified: %s\r\n%s %"OFF_FMT"u\r\n",
     1038                tmp_str,
     1039                content_gzip ? "Transfer-length:" : "Content-length:",
     1040                file_size
     1041        );
     1042    }
     1043
     1044    if (content_gzip)
     1045        len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n");
     1046
    9291047    iobuf[len++] = '\r';
    9301048    iobuf[len++] = '\n';
     
    9381056    if (DEBUG)
    9391057        fprintf(stderr, "headers: '%s'\n", iobuf);
    940     if (full_write(1, iobuf, len) != len) {
     1058    if (full_write(STDOUT_FILENO, iobuf, len) != len) {
    9411059        if (verbose > 1)
    9421060            bb_perror_msg("error");
     
    9451063}
    9461064
    947 static void send_headers_and_exit(int responseNum) ATTRIBUTE_NORETURN;
     1065static void send_headers_and_exit(int responseNum) NORETURN;
    9481066static void send_headers_and_exit(int responseNum)
    9491067{
     
    9641082    char c;
    9651083
     1084    alarm(HEADER_READ_TIMEOUT);
    9661085    while (1) {
    9671086        if (hdr_cnt <= 0) {
    968             hdr_cnt = safe_read(0, hdr_buf, sizeof(hdr_buf));
     1087            hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf));
    9691088            if (hdr_cnt <= 0)
    9701089                break;
     
    9781097        if (c == '\n') {
    9791098            iobuf[count] = '\0';
    980             return count;
     1099            break;
    9811100        }
    9821101        if (count < (IOBUF_SIZE - 1))      /* check overflow */
     
    9861105}
    9871106
     1107#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
     1108
     1109/* gcc 4.2.1 fares better with NOINLINE */
     1110static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post_len) NORETURN;
     1111static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post_len)
     1112{
     1113    enum { FROM_CGI = 1, TO_CGI = 2 }; /* indexes in pfd[] */
     1114    struct pollfd pfd[3];
     1115    int out_cnt; /* we buffer a bit of initial CGI output */
     1116    int count;
     1117
     1118    /* iobuf is used for CGI -> network data,
     1119     * hdr_buf is for network -> CGI data (POSTDATA) */
     1120
     1121    /* If CGI dies, we still want to correctly finish reading its output
     1122     * and send it to the peer. So please no SIGPIPEs! */
     1123    signal(SIGPIPE, SIG_IGN);
     1124
     1125    // We inconsistently handle a case when more POSTDATA from network
     1126    // is coming than we expected. We may give *some part* of that
     1127    // extra data to CGI.
     1128
     1129    //if (hdr_cnt > post_len) {
     1130    //  /* We got more POSTDATA from network than we expected */
     1131    //  hdr_cnt = post_len;
     1132    //}
     1133    post_len -= hdr_cnt;
     1134    /* post_len - number of POST bytes not yet read from network */
     1135
     1136    /* NB: breaking out of this loop jumps to log_and_exit() */
     1137    out_cnt = 0;
     1138    while (1) {
     1139        memset(pfd, 0, sizeof(pfd));
     1140
     1141        pfd[FROM_CGI].fd = fromCgi_rd;
     1142        pfd[FROM_CGI].events = POLLIN;
     1143
     1144        if (toCgi_wr) {
     1145            pfd[TO_CGI].fd = toCgi_wr;
     1146            if (hdr_cnt > 0) {
     1147                pfd[TO_CGI].events = POLLOUT;
     1148            } else if (post_len > 0) {
     1149                pfd[0].events = POLLIN;
     1150            } else {
     1151                /* post_len <= 0 && hdr_cnt <= 0:
     1152                 * no more POST data to CGI,
     1153                 * let CGI see EOF on CGI's stdin */
     1154                if (toCgi_wr != fromCgi_rd)
     1155                    close(toCgi_wr);
     1156                toCgi_wr = 0;
     1157            }
     1158        }
     1159
     1160        /* Now wait on the set of sockets */
     1161        count = safe_poll(pfd, toCgi_wr ? TO_CGI+1 : FROM_CGI+1, -1);
     1162        if (count <= 0) {
     1163#if 0
     1164            if (safe_waitpid(pid, &status, WNOHANG) <= 0) {
     1165                /* Weird. CGI didn't exit and no fd's
     1166                 * are ready, yet poll returned?! */
     1167                continue;
     1168            }
     1169            if (DEBUG && WIFEXITED(status))
     1170                bb_error_msg("CGI exited, status=%d", WEXITSTATUS(status));
     1171            if (DEBUG && WIFSIGNALED(status))
     1172                bb_error_msg("CGI killed, signal=%d", WTERMSIG(status));
     1173#endif
     1174            break;
     1175        }
     1176
     1177        if (pfd[TO_CGI].revents) {
     1178            /* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */
     1179            /* Have data from peer and can write to CGI */
     1180            count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt);
     1181            /* Doesn't happen, we dont use nonblocking IO here
     1182             *if (count < 0 && errno == EAGAIN) {
     1183             *  ...
     1184             *} else */
     1185            if (count > 0) {
     1186                hdr_ptr += count;
     1187                hdr_cnt -= count;
     1188            } else {
     1189                /* EOF/broken pipe to CGI, stop piping POST data */
     1190                hdr_cnt = post_len = 0;
     1191            }
     1192        }
     1193
     1194        if (pfd[0].revents) {
     1195            /* post_len > 0 && hdr_cnt == 0 here */
     1196            /* We expect data, prev data portion is eaten by CGI
     1197             * and there *is* data to read from the peer
     1198             * (POSTDATA) */
     1199            //count = post_len > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : post_len;
     1200            //count = safe_read(STDIN_FILENO, hdr_buf, count);
     1201            count = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf));
     1202            if (count > 0) {
     1203                hdr_cnt = count;
     1204                hdr_ptr = hdr_buf;
     1205                post_len -= count;
     1206            } else {
     1207                /* no more POST data can be read */
     1208                post_len = 0;
     1209            }
     1210        }
     1211
     1212        if (pfd[FROM_CGI].revents) {
     1213            /* There is something to read from CGI */
     1214            char *rbuf = iobuf;
     1215
     1216            /* Are we still buffering CGI output? */
     1217            if (out_cnt >= 0) {
     1218                /* HTTP_200[] has single "\r\n" at the end.
     1219                 * According to http://hoohoo.ncsa.uiuc.edu/cgi/out.html,
     1220                 * CGI scripts MUST send their own header terminated by
     1221                 * empty line, then data. That's why we have only one
     1222                 * <cr><lf> pair here. We will output "200 OK" line
     1223                 * if needed, but CGI still has to provide blank line
     1224                 * between header and body */
     1225
     1226                /* Must use safe_read, not full_read, because
     1227                 * CGI may output a few first bytes and then wait
     1228                 * for POSTDATA without closing stdout.
     1229                 * With full_read we may wait here forever. */
     1230                count = safe_read(fromCgi_rd, rbuf + out_cnt, PIPE_BUF - 8);
     1231                if (count <= 0) {
     1232                    /* eof (or error) and there was no "HTTP",
     1233                     * so write it, then write received data */
     1234                    if (out_cnt) {
     1235                        full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1);
     1236                        full_write(STDOUT_FILENO, rbuf, out_cnt);
     1237                    }
     1238                    break; /* CGI stdout is closed, exiting */
     1239                }
     1240                out_cnt += count;
     1241                count = 0;
     1242                /* "Status" header format is: "Status: 302 Redirected\r\n" */
     1243                if (out_cnt >= 8 && memcmp(rbuf, "Status: ", 8) == 0) {
     1244                    /* send "HTTP/1.0 " */
     1245                    if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9)
     1246                        break;
     1247                    rbuf += 8; /* skip "Status: " */
     1248                    count = out_cnt - 8;
     1249                    out_cnt = -1; /* buffering off */
     1250                } else if (out_cnt >= 4) {
     1251                    /* Did CGI add "HTTP"? */
     1252                    if (memcmp(rbuf, HTTP_200, 4) != 0) {
     1253                        /* there is no "HTTP", do it ourself */
     1254                        if (full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
     1255                            break;
     1256                    }
     1257                    /* Commented out:
     1258                    if (!strstr(rbuf, "ontent-")) {
     1259                        full_write(s, "Content-type: text/plain\r\n\r\n", 28);
     1260                    }
     1261                     * Counter-example of valid CGI without Content-type:
     1262                     * echo -en "HTTP/1.0 302 Found\r\n"
     1263                     * echo -en "Location: http://www.busybox.net\r\n"
     1264                     * echo -en "\r\n"
     1265                     */
     1266                    count = out_cnt;
     1267                    out_cnt = -1; /* buffering off */
     1268                }
     1269            } else {
     1270                count = safe_read(fromCgi_rd, rbuf, PIPE_BUF);
     1271                if (count <= 0)
     1272                    break;  /* eof (or error) */
     1273            }
     1274            if (full_write(STDOUT_FILENO, rbuf, count) != count)
     1275                break;
     1276            if (DEBUG)
     1277                fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
     1278        } /* if (pfd[FROM_CGI].revents) */
     1279    } /* while (1) */
     1280    log_and_exit();
     1281}
     1282#endif
     1283
    9881284#if ENABLE_FEATURE_HTTPD_CGI
     1285
    9891286static void setenv1(const char *name, const char *value)
    9901287{
     
    9961293 *
    9971294 * 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
     1295 * for stdin/stdout.  If a POST is being done the script is fed the POST
    9991296 * data in addition to setting the QUERY_STRING variable (for GETs or POSTs).
    10001297 *
    10011298 * Parameters:
    10021299 * const char *url              The requested URL (with leading /).
    1003  * int bodyLen                  Length of the post body.
     1300 * int post_len                 Length of the POST body.
    10041301 * const char *cookie           For set HTTP_COOKIE.
    10051302 * const char *content_type     For set CONTENT_TYPE.
     
    10081305        const char *url,
    10091306        const char *request,
    1010         int bodyLen,
     1307        int post_len,
    10111308        const char *cookie,
    1012         const char *content_type) ATTRIBUTE_NORETURN;
     1309        const char *content_type) NORETURN;
    10131310static void send_cgi_and_exit(
    10141311        const char *url,
    10151312        const char *request,
    1016         int bodyLen,
     1313        int post_len,
    10171314        const char *cookie,
    10181315        const char *content_type)
    10191316{
    1020     struct { int rd; int wr; } fromCgi;  /* CGI -> httpd pipe */
    1021     struct { int rd; int wr; } toCgi;    /* httpd -> CGI pipe */
    1022     char *fullpath;
     1317    struct fd_pair fromCgi;  /* CGI -> httpd pipe */
     1318    struct fd_pair toCgi;    /* httpd -> CGI pipe */
    10231319    char *script;
    1024     char *purl;
    1025     int buf_count;
    1026     int status;
    1027     int pid = 0;
     1320    int pid;
     1321
     1322    /* Make a copy. NB: caller guarantees:
     1323     * url[0] == '/', url[1] != '/' */
     1324    url = xstrdup(url);
    10281325
    10291326    /*
    10301327     * We are mucking with environment _first_ and then vfork/exec,
    1031      * this allows us to use vfork safely. Parent don't care about
     1328     * this allows us to use vfork safely. Parent doesn't care about
    10321329     * these environment changes anyway.
    10331330     */
    10341331
    1035     /*
    1036      * Find PATH_INFO.
    1037      */
    1038     purl = xstrdup(url);
    1039     script = purl;
     1332    /* Check for [dirs/]script.cgi/PATH_INFO */
     1333    script = (char*)url;
    10401334    while ((script = strchr(script + 1, '/')) != NULL) {
    1041         /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */
    1042         struct stat sb;
    1043 
    10441335        *script = '\0';
    1045         if (!is_directory(purl + 1, 1, &sb)) {
     1336        if (!is_directory(url + 1, 1, NULL)) {
    10461337            /* not directory, found script.cgi/PATH_INFO */
    10471338            *script = '/';
    10481339            break;
    10491340        }
    1050         *script = '/';          /* is directory, find next '/' */
    1051     }
    1052     setenv1("PATH_INFO", script);   /* set /PATH_INFO or "" */
     1341        *script = '/'; /* is directory, find next '/' */
     1342    }
     1343    setenv1("PATH_INFO", script);   /* set to /PATH_INFO or "" */
    10531344    setenv1("REQUEST_METHOD", request);
    10541345    if (g_query) {
    1055         putenv(xasprintf("%s=%s?%s", "REQUEST_URI", purl, g_query));
     1346        putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query));
    10561347    } else {
    1057         setenv1("REQUEST_URI", purl);
     1348        setenv1("REQUEST_URI", url);
    10581349    }
    10591350    if (script != NULL)
    10601351        *script = '\0';         /* cut off /PATH_INFO */
    10611352
    1062     /* SCRIPT_FILENAME required by PHP in CGI mode */
    1063     fullpath = concat_path_file(home_httpd, purl);
    1064     setenv1("SCRIPT_FILENAME", fullpath);
     1353    /* SCRIPT_FILENAME is required by PHP in CGI mode */
     1354    if (home_httpd[0] == '/') {
     1355        char *fullpath = concat_path_file(home_httpd, url);
     1356        setenv1("SCRIPT_FILENAME", fullpath);
     1357    }
    10651358    /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
    1066     setenv1("SCRIPT_NAME", purl);
     1359    setenv1("SCRIPT_NAME", url);
    10671360    /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
    10681361     * QUERY_STRING: The information which follows the ? in the URL
     
    10961389    }
    10971390    setenv1("HTTP_USER_AGENT", user_agent);
    1098     if (bodyLen)
    1099         putenv(xasprintf("CONTENT_LENGTH=%d", bodyLen));
     1391    if (http_accept)
     1392        setenv1("HTTP_ACCEPT", http_accept);
     1393    if (http_accept_language)
     1394        setenv1("HTTP_ACCEPT_LANGUAGE", http_accept_language);
     1395    if (post_len)
     1396        putenv(xasprintf("CONTENT_LENGTH=%d", post_len));
    11001397    if (cookie)
    11011398        setenv1("HTTP_COOKIE", cookie);
     
    11101407    if (referer)
    11111408        setenv1("HTTP_REFERER", referer);
    1112 
    1113     xpipe(&fromCgi.rd);
    1114     xpipe(&toCgi.rd);
     1409    setenv1("HTTP_HOST", host); /* set to "" if NULL */
     1410    /* setenv1("SERVER_NAME", safe_gethostname()); - don't do this,
     1411     * just run "env SERVER_NAME=xyz httpd ..." instead */
     1412
     1413    xpiped_pair(fromCgi);
     1414    xpiped_pair(toCgi);
    11151415
    11161416    pid = vfork();
     
    11221422    if (!pid) {
    11231423        /* Child process */
     1424        char *argv[3];
     1425
    11241426        xfunc_error_retval = 242;
    11251427
     1428        /* NB: close _first_, then move fds! */
     1429        close(toCgi.wr);
     1430        close(fromCgi.rd);
    11261431        xmove_fd(toCgi.rd, 0);  /* replace stdin with the pipe */
    11271432        xmove_fd(fromCgi.wr, 1);  /* replace stdout with the pipe */
    1128         close(fromCgi.rd);
    1129         close(toCgi.wr);
    11301433        /* User seeing stderr output can be a security problem.
    11311434         * If CGI really wants that, it can always do dup itself. */
    11321435        /* dup2(1, 2); */
    11331436
    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];
     1437        /* Chdiring to script's dir */
     1438        script = strrchr(url, '/');
     1439        if (script != url) { /* paranoia */
     1440            *script = '\0';
     1441            if (chdir(url + 1) != 0) {
     1442                bb_perror_msg("chdir(%s)", url + 1);
     1443                goto error_execing_cgi;
     1444            }
     1445            // not needed: *script = '/';
     1446        }
     1447        script++;
     1448
     1449        /* set argv[0] to name without path */
     1450        argv[0] = script;
     1451        argv[1] = NULL;
     1452
    11421453#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    1143             char *interpr = NULL;
    1144             char *suffix = strrchr(purl, '.');
     1454        {
     1455            char *suffix = strrchr(script, '.');
    11451456
    11461457            if (suffix) {
     
    11481459                for (cur = script_i; cur; cur = cur->next) {
    11491460                    if (strcmp(cur->before_colon + 1, suffix) == 0) {
    1150                         interpr = cur->after_colon;
     1461                        /* found interpreter name */
     1462                        argv[0] = cur->after_colon;
     1463                        argv[1] = script;
     1464                        argv[2] = NULL;
    11511465                        break;
    11521466                    }
    11531467                }
    11541468            }
    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         }
     1469        }
     1470#endif
     1471        /* restore default signal dispositions for CGI process */
     1472        bb_signals(0
     1473            | (1 << SIGCHLD)
     1474            | (1 << SIGPIPE)
     1475            | (1 << SIGHUP)
     1476            , SIG_DFL);
     1477
     1478        /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
     1479         * without any dir components and will only match a file
     1480         * in the current directory */
     1481        execv(argv[0], argv);
     1482        if (verbose)
     1483            bb_perror_msg("can't execute '%s'", argv[0]);
    11671484 error_execing_cgi:
    11681485        /* send to stdout
     
    11731490    /* Parent process */
    11741491
    1175     /* First, restore variables possibly changed by child */
     1492    /* Restore variables possibly changed by child */
    11761493    xfunc_error_retval = 0;
    11771494
    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;
     1495    /* Pump data */
    11821496    close(fromCgi.wr);
    11831497    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     /* Accound for POSTDATA already in hdr_buf */
    1190     bodyLen -= hdr_cnt;
    1191 
    1192     /* This loop still looks messy. What is an exit criteria?
    1193      * "CGI's output closed"? Or "CGI has exited"?
    1194      * What to do if CGI has closed both input and output, but
    1195      * didn't exit? etc... */
    1196 
    1197     /* NB: breaking out of this loop jumps to log_and_exit() */
    1198     while (1) {
    1199         fd_set readSet;
    1200         fd_set writeSet;
    1201         int nfound;
    1202         int count;
    1203 
    1204         FD_ZERO(&readSet);
    1205         FD_ZERO(&writeSet);
    1206         FD_SET(fromCgi.rd, &readSet);
    1207         if (bodyLen > 0 || hdr_cnt > 0) {
    1208             FD_SET(toCgi.wr, &writeSet);
    1209             nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd;
    1210             if (hdr_cnt <= 0)
    1211                 FD_SET(0, &readSet);
    1212             /* Now wait on the set of sockets! */
    1213             nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
    1214         } else {
    1215             if (!bodyLen) {
    1216                 close(toCgi.wr); /* no more POST data to CGI */
    1217                 bodyLen = -1;
    1218             }
    1219             nfound = select(fromCgi.rd + 1, &readSet, NULL, NULL, NULL);
    1220         }
    1221 
    1222         if (nfound <= 0) {
    1223             if (waitpid(pid, &status, WNOHANG) <= 0) {
    1224                 /* Weird. CGI didn't exit and no fd's
    1225                  * are ready, yet select returned?! */
    1226                 continue;
    1227             }
    1228             close(fromCgi.rd);
    1229             if (DEBUG && WIFEXITED(status))
    1230                 bb_error_msg("CGI exited, status=%d", WEXITSTATUS(status));
    1231             if (DEBUG && WIFSIGNALED(status))
    1232                 bb_error_msg("CGI killed, signal=%d", WTERMSIG(status));
    1233             break;
    1234         }
    1235 
    1236         if (hdr_cnt > 0 && FD_ISSET(toCgi.wr, &writeSet)) {
    1237             /* Have data from peer and can write to CGI */
    1238             count = safe_write(toCgi.wr, hdr_ptr, hdr_cnt);
    1239             /* Doesn't happen, we dont use nonblocking IO here
    1240              *if (count < 0 && errno == EAGAIN) {
    1241              *  ...
    1242              *} else */
    1243             if (count > 0) {
    1244                 hdr_ptr += count;
    1245                 hdr_cnt -= count;
    1246             } else {
    1247                 hdr_cnt = bodyLen = 0; /* EOF/broken pipe to CGI */
    1248             }
    1249         } else if (bodyLen > 0 && hdr_cnt == 0
    1250          && FD_ISSET(0, &readSet)
    1251         ) {
    1252             /* We expect data, prev data portion is eaten by CGI
    1253              * and there *is* data to read from the peer
    1254              * (POSTDATA?) */
    1255             count = bodyLen > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : bodyLen;
    1256             count = safe_read(0, hdr_buf, count);
    1257             if (count > 0) {
    1258                 hdr_cnt = count;
    1259                 hdr_ptr = hdr_buf;
    1260                 bodyLen -= count;
    1261             } else {
    1262                 bodyLen = 0; /* closed */
    1263             }
    1264         }
    1265 
    1266 #define PIPESIZE PIPE_BUF
    1267 #if PIPESIZE >= IOBUF_SIZE
    1268 # error "PIPESIZE >= IOBUF_SIZE"
    1269 #endif
    1270         if (FD_ISSET(fromCgi.rd, &readSet)) {
    1271             /* There is something to read from CGI */
    1272             char *rbuf = iobuf;
    1273 
    1274             /* Are we still buffering CGI output? */
    1275             if (buf_count >= 0) {
    1276                 /* HTTP_200[] has single "\r\n" at the end.
    1277                  * According to http://hoohoo.ncsa.uiuc.edu/cgi/out.html,
    1278                  * CGI scripts MUST send their own header terminated by
    1279                  * empty line, then data. That's why we have only one
    1280                  * <cr><lf> pair here. We will output "200 OK" line
    1281                  * if needed, but CGI still has to provide blank line
    1282                  * between header and body */
    1283 
    1284                 /* Must use safe_read, not full_read, because
    1285                  * CGI may output a few first bytes and then wait
    1286                  * for POSTDATA without closing stdout.
    1287                  * With full_read we may wait here forever. */
    1288                 count = safe_read(fromCgi.rd, rbuf + buf_count, PIPESIZE - 8);
    1289                 if (count <= 0) {
    1290                     /* eof (or error) and there was no "HTTP",
    1291                      * so write it, then write received data */
    1292                     if (buf_count) {
    1293                         full_write(1, HTTP_200, sizeof(HTTP_200)-1);
    1294                         full_write(1, rbuf, buf_count);
    1295                     }
    1296                     break; /* CGI stdout is closed, exiting */
    1297                 }
    1298                 buf_count += count;
    1299                 count = 0;
    1300                 /* "Status" header format is: "Status: 302 Redirected\r\n" */
    1301                 if (buf_count >= 8 && memcmp(rbuf, "Status: ", 8) == 0) {
    1302                     /* send "HTTP/1.0 " */
    1303                     if (full_write(1, HTTP_200, 9) != 9)
    1304                         break;
    1305                     rbuf += 8; /* skip "Status: " */
    1306                     count = buf_count - 8;
    1307                     buf_count = -1; /* buffering off */
    1308                 } else if (buf_count >= 4) {
    1309                     /* Did CGI add "HTTP"? */
    1310                     if (memcmp(rbuf, HTTP_200, 4) != 0) {
    1311                         /* there is no "HTTP", do it ourself */
    1312                         if (full_write(1, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
    1313                             break;
    1314                     }
    1315                     /* Commented out:
    1316                     if (!strstr(rbuf, "ontent-")) {
    1317                         full_write(s, "Content-type: text/plain\r\n\r\n", 28);
    1318                     }
    1319                      * Counter-example of valid CGI without Content-type:
    1320                      * echo -en "HTTP/1.0 302 Found\r\n"
    1321                      * echo -en "Location: http://www.busybox.net\r\n"
    1322                      * echo -en "\r\n"
    1323                      */
    1324                     count = buf_count;
    1325                     buf_count = -1; /* buffering off */
    1326                 }
    1327             } else {
    1328                 count = safe_read(fromCgi.rd, rbuf, PIPESIZE);
    1329                 if (count <= 0)
    1330                     break;  /* eof (or error) */
    1331             }
    1332             if (full_write(1, rbuf, count) != count)
    1333                 break;
    1334             if (DEBUG)
    1335                 fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf);
    1336         } /* if (FD_ISSET(fromCgi.rd)) */
    1337     } /* while (1) */
    1338     log_and_exit();
    1339 }
     1498    cgi_io_loop_and_exit(fromCgi.rd, toCgi.wr, post_len);
     1499}
     1500
    13401501#endif          /* FEATURE_HTTPD_CGI */
    13411502
    13421503/*
    13431504 * Send a file response to a HTTP request, and exit
    1344  * 
     1505 *
    13451506 * Parameters:
    1346  * const char *url    The requested URL (with leading /).
    1347  * headers            Don't send headers before if FALSE.
     1507 * const char *url  The requested URL (with leading /).
     1508 * what             What to send (headers/body/both).
    13481509 */
    1349 static void send_file_and_exit(const char *url, int headers)
    1350 {
    1351     static const char *const suffixTable[] = {
    1352     /* Warning: shorter equivalent suffix in one line must be first */
    1353         ".htm.html", "text/html",
    1354         ".jpg.jpeg", "image/jpeg",
    1355         ".gif",      "image/gif",
    1356         ".png",      "image/png",
    1357         ".txt.h.c.cc.cpp", "text/plain",
    1358         ".css",      "text/css",
    1359         ".wav",      "audio/wav",
    1360         ".avi",      "video/x-msvideo",
    1361         ".qt.mov",   "video/quicktime",
    1362         ".mpe.mpeg", "video/mpeg",
    1363         ".mid.midi", "audio/midi",
    1364         ".mp3",      "audio/mpeg",
    1365 #if 0                        /* unpopular */
    1366         ".au",       "audio/basic",
    1367         ".pac",      "application/x-ns-proxy-autoconfig",
    1368         ".vrml.wrl", "model/vrml",
    1369 #endif
    1370         NULL
    1371     };
    1372 
     1510static NOINLINE void send_file_and_exit(const char *url, int what)
     1511{
    13731512    char *suffix;
    1374     int f;
    1375     const char *const *table;
    1376     const char *try_suffix;
     1513    int fd;
    13771514    ssize_t count;
    1378 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
    1379     off_t offset = 0;
    1380 #endif
    1381 
     1515
     1516    if (content_gzip) {
     1517        /* does <url>.gz exist? Then use it instead */
     1518        char *gzurl = xasprintf("%s.gz", url);
     1519        fd = open(gzurl, O_RDONLY);
     1520        free(gzurl);
     1521        if (fd != -1) {
     1522            struct stat sb;
     1523            fstat(fd, &sb);
     1524            file_size = sb.st_size;
     1525            last_mod = sb.st_mtime;
     1526        } else {
     1527            IF_FEATURE_HTTPD_GZIP(content_gzip = 0;)
     1528            fd = open(url, O_RDONLY);
     1529        }
     1530    } else {
     1531        fd = open(url, O_RDONLY);
     1532    }
     1533    if (fd < 0) {
     1534        if (DEBUG)
     1535            bb_perror_msg("can't open '%s'", url);
     1536        /* Error pages are sent by using send_file_and_exit(SEND_BODY).
     1537         * IOW: it is unsafe to call send_headers_and_exit
     1538         * if what is SEND_BODY! Can recurse! */
     1539        if (what != SEND_BODY)
     1540            send_headers_and_exit(HTTP_NOT_FOUND);
     1541        log_and_exit();
     1542    }
     1543    /* If you want to know about EPIPE below
     1544     * (happens if you abort downloads from local httpd): */
     1545    signal(SIGPIPE, SIG_IGN);
     1546
     1547    /* If not found, default is "application/octet-stream" */
     1548    found_mime_type = "application/octet-stream";
    13821549    suffix = strrchr(url, '.');
    1383 
    1384     /* If not found, set default as "application/octet-stream";  */
    1385     found_mime_type = "application/octet-stream";
    13861550    if (suffix) {
    1387 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     1551        static const char suffixTable[] ALIGN1 =
     1552            /* Shorter suffix must be first:
     1553             * ".html.htm" will fail for ".htm"
     1554             */
     1555            ".txt.h.c.cc.cpp\0" "text/plain\0"
     1556            /* .htm line must be after .h line */
     1557            ".htm.html\0" "text/html\0"
     1558            ".jpg.jpeg\0" "image/jpeg\0"
     1559            ".gif\0"      "image/gif\0"
     1560            ".png\0"      "image/png\0"
     1561            /* .css line must be after .c line */
     1562            ".css\0"      "text/css\0"
     1563            ".wav\0"      "audio/wav\0"
     1564            ".avi\0"      "video/x-msvideo\0"
     1565            ".qt.mov\0"   "video/quicktime\0"
     1566            ".mpe.mpeg\0" "video/mpeg\0"
     1567            ".mid.midi\0" "audio/midi\0"
     1568            ".mp3\0"      "audio/mpeg\0"
     1569#if 0  /* unpopular */
     1570            ".au\0"       "audio/basic\0"
     1571            ".pac\0"      "application/x-ns-proxy-autoconfig\0"
     1572            ".vrml.wrl\0" "model/vrml\0"
     1573#endif
     1574            /* compiler adds another "\0" here */
     1575        ;
    13881576        Htaccess *cur;
    1389 #endif
    1390         for (table = suffixTable; *table; table += 2) {
    1391             try_suffix = strstr(table[0], suffix);
    1392             if (try_suffix) {
    1393                 try_suffix += strlen(suffix);
    1394                 if (*try_suffix == '\0' || *try_suffix == '.') {
    1395                     found_mime_type = table[1];
    1396                     break;
    1397                 }
    1398             }
    1399         }
    1400 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
     1577
     1578        /* Examine built-in table */
     1579        const char *table = suffixTable;
     1580        const char *table_next;
     1581        for (; *table; table = table_next) {
     1582            const char *try_suffix;
     1583            const char *mime_type;
     1584            mime_type  = table + strlen(table) + 1;
     1585            table_next = mime_type + strlen(mime_type) + 1;
     1586            try_suffix = strstr(table, suffix);
     1587            if (!try_suffix)
     1588                continue;
     1589            try_suffix += strlen(suffix);
     1590            if (*try_suffix == '\0' || *try_suffix == '.') {
     1591                found_mime_type = mime_type;
     1592                break;
     1593            }
     1594            /* Example: strstr(table, ".av") != NULL, but it
     1595             * does not match ".avi" after all and we end up here.
     1596             * The table is arranged so that in this case we know
     1597             * that it can't match anything in the following lines,
     1598             * and we stop the search: */
     1599            break;
     1600        }
     1601        /* ...then user's table */
    14011602        for (cur = mime_a; cur; cur = cur->next) {
    14021603            if (strcmp(cur->before_colon, suffix) == 0) {
     
    14051606            }
    14061607        }
    1407 #endif
    14081608    }
    14091609
     
    14121612            url, found_mime_type);
    14131613
    1414     f = open(url, O_RDONLY);
    1415     if (f < 0) {
    1416         if (DEBUG)
    1417             bb_perror_msg("cannot open '%s'", url);
    1418         if (headers)
    1419             send_headers_and_exit(HTTP_NOT_FOUND);
    1420     }
    1421 
    1422     if (headers)
     1614#if ENABLE_FEATURE_HTTPD_RANGES
     1615    if (what == SEND_BODY /* err pages and ranges don't mix */
     1616     || content_gzip /* we are sending compressed page: can't do ranges */  ///why?
     1617    ) {
     1618        range_start = 0;
     1619    }
     1620    range_len = MAXINT(off_t);
     1621    if (range_start) {
     1622        if (!range_end) {
     1623            range_end = file_size - 1;
     1624        }
     1625        if (range_end < range_start
     1626         || lseek(fd, range_start, SEEK_SET) != range_start
     1627        ) {
     1628            lseek(fd, 0, SEEK_SET);
     1629            range_start = 0;
     1630        } else {
     1631            range_len = range_end - range_start + 1;
     1632            send_headers(HTTP_PARTIAL_CONTENT);
     1633            what = SEND_BODY;
     1634        }
     1635    }
     1636#endif
     1637    if (what & SEND_HEADERS)
    14231638        send_headers(HTTP_OK);
    1424 
    1425     /* If you want to know about EPIPE below
    1426      * (happens if you abort downloads from local httpd): */
    1427     signal(SIGPIPE, SIG_IGN);
    1428 
    14291639#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
    1430     do {
    1431         /* byte count (3rd arg) is rounded down to 64k */
    1432         count = sendfile(1, f, &offset, MAXINT(ssize_t) - 0xffff);
    1433         if (count < 0) {
    1434             if (offset == 0)
    1435                 goto fallback;
    1436             goto fin;
    1437         }
    1438     } while (count > 0);
    1439     log_and_exit();
    1440 
    1441  fallback:
    1442 #endif
    1443     while ((count = safe_read(f, iobuf, IOBUF_SIZE)) > 0) {
    1444         ssize_t n = count;
    1445         count = full_write(1, iobuf, count);
     1640    {
     1641        off_t offset = range_start;
     1642        while (1) {
     1643            /* sz is rounded down to 64k */
     1644            ssize_t sz = MAXINT(ssize_t) - 0xffff;
     1645            IF_FEATURE_HTTPD_RANGES(if (sz > range_len) sz = range_len;)
     1646            count = sendfile(STDOUT_FILENO, fd, &offset, sz);
     1647            if (count < 0) {
     1648                if (offset == range_start)
     1649                    break; /* fall back to read/write loop */
     1650                goto fin;
     1651            }
     1652            IF_FEATURE_HTTPD_RANGES(range_len -= sz;)
     1653            if (count == 0 || range_len == 0)
     1654                log_and_exit();
     1655        }
     1656    }
     1657#endif
     1658    while ((count = safe_read(fd, iobuf, IOBUF_SIZE)) > 0) {
     1659        ssize_t n;
     1660        IF_FEATURE_HTTPD_RANGES(if (count > range_len) count = range_len;)
     1661        n = full_write(STDOUT_FILENO, iobuf, count);
    14461662        if (count != n)
    14471663            break;
    1448     }
    1449 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
    1450  fin:
    1451 #endif
    1452     if (count < 0 && verbose > 1)
    1453         bb_perror_msg("error");
     1664        IF_FEATURE_HTTPD_RANGES(range_len -= count;)
     1665        if (range_len == 0)
     1666            break;
     1667    }
     1668    if (count < 0) {
     1669 IF_FEATURE_HTTPD_USE_SENDFILE(fin:)
     1670        if (verbose > 1)
     1671            bb_perror_msg("error");
     1672    }
    14541673    log_and_exit();
    14551674}
     
    14591678    Htaccess_IP *cur;
    14601679
    1461     /* This could stand some work */
    14621680    for (cur = ip_a_d; cur; cur = cur->next) {
    14631681#if DEBUG
     
    14761694#endif
    14771695        if ((rmt_ip & cur->mask) == cur->ip)
    1478             return cur->allow_deny == 'A';   /* Allow/Deny */
    1479     }
    1480 
    1481     /* if unconfigured, return 1 - access from all */
    1482     return !flg_deny_all;
     1696            return (cur->allow_deny == 'A'); /* A -> 1 */
     1697    }
     1698
     1699    return !flg_deny_all; /* depends on whether we saw "D:*" */
    14831700}
    14841701
    14851702#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    14861703/*
    1487  * Check the permission file for access password protected.
    1488  *
    1489  * If config file isn't present, everything is allowed.
    1490  * Entries are of the form you can see example from header source
    1491  *
    1492  * path      The file path.
    1493  * request   User information to validate.
    1494  *
    1495  * Returns 1 if request is OK.
     1704 * Config file entries are of the form "/<path>:<user>:<passwd>".
     1705 * If config file has no prefix match for path, access is allowed.
     1706 *
     1707 * path                 The file path
     1708 * user_and_passwd      "user:passwd" to validate
     1709 *
     1710 * Returns 1 if user_and_passwd is OK.
    14961711 */
    1497 static int checkPerm(const char *path, const char *request)
     1712static int check_user_passwd(const char *path, const char *user_and_passwd)
    14981713{
    14991714    Htaccess *cur;
    1500     const char *p;
    1501     const char *p0;
    1502 
    15031715    const char *prev = NULL;
    15041716
    1505     /* This could stand some work */
    15061717    for (cur = g_auth; cur; cur = cur->next) {
    1507         size_t l;
    1508 
    1509         p0 = cur->before_colon;
    1510         if (prev != NULL && strcmp(prev, p0) != 0)
    1511             continue;       /* find next identical */
    1512         p = cur->after_colon;
     1718        const char *dir_prefix;
     1719        size_t len;
     1720
     1721        dir_prefix = cur->before_colon;
     1722
     1723        /* WHY? */
     1724        /* If already saw a match, don't accept other different matches */
     1725        if (prev && strcmp(prev, dir_prefix) != 0)
     1726            continue;
     1727
    15131728        if (DEBUG)
    1514             fprintf(stderr, "checkPerm: '%s' ? '%s'\n", p0, request);
    1515 
    1516         l = strlen(p0);
    1517         if (strncmp(p0, path, l) == 0
    1518          && (l == 1 || path[l] == '/' || path[l] == '\0')
     1729            fprintf(stderr, "checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd);
     1730
     1731        /* If it's not a prefix match, continue searching */
     1732        len = strlen(dir_prefix);
     1733        if (len != 1 /* dir_prefix "/" matches all, don't need to check */
     1734         && (strncmp(dir_prefix, path, len) != 0
     1735            || (path[len] != '/' && path[len] != '\0'))
    15191736        ) {
    1520             char *u;
    1521             /* path match found.  Check request */
    1522             /* for check next /path:user:password */
    1523             prev = p0;
    1524             u = strchr(request, ':');
    1525             if (u == NULL) {
    1526                 /* bad request, ':' required */
    1527                 break;
    1528             }
    1529 
    1530             if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
    1531                 char *cipher;
    1532                 char *pp;
    1533 
    1534                 if (strncmp(p, request, u - request) != 0) {
    1535                     /* user doesn't match */
     1737            continue;
     1738        }
     1739
     1740        /* Path match found */
     1741        prev = dir_prefix;
     1742
     1743        if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
     1744            char *md5_passwd;
     1745
     1746            md5_passwd = strchr(cur->after_colon, ':');
     1747            if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
     1748             && md5_passwd[3] == '$' && md5_passwd[4]
     1749            ) {
     1750                char *encrypted;
     1751                int r, user_len_p1;
     1752
     1753                md5_passwd++;
     1754                user_len_p1 = md5_passwd - cur->after_colon;
     1755                /* comparing "user:" */
     1756                if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
    15361757                    continue;
    15371758                }
    1538                 pp = strchr(p, ':');
    1539                 if (pp && pp[1] == '$' && pp[2] == '1'
    1540                  && pp[3] == '$' && pp[4]
    1541                 ) {
    1542                     pp++;
    1543                     cipher = pw_encrypt(u+1, pp);
    1544                     if (strcmp(cipher, pp) == 0)
    1545                         goto set_remoteuser_var;  /* Ok */
    1546                     /* unauthorized */
    1547                     continue;
    1548                 }
    1549             }
    1550 
    1551             if (strcmp(p, request) == 0) {
     1759
     1760                encrypted = pw_encrypt(
     1761                    user_and_passwd + user_len_p1 /* cleartext pwd from user */,
     1762                    md5_passwd /*salt */, 1 /* cleanup */);
     1763                r = strcmp(encrypted, md5_passwd);
     1764                free(encrypted);
     1765                if (r == 0)
     1766                    goto set_remoteuser_var; /* Ok */
     1767                continue;
     1768            }
     1769        }
     1770
     1771        /* Comparing plaintext "user:pass" in one go */
     1772        if (strcmp(cur->after_colon, user_and_passwd) == 0) {
    15521773 set_remoteuser_var:
    1553                 remoteuser = strdup(request);
    1554                 if (remoteuser)
    1555                     remoteuser[u - request] = '\0';
    1556                 return 1;   /* Ok */
    1557             }
    1558             /* unauthorized */
     1774            remoteuser = xstrndup(user_and_passwd,
     1775                    strchrnul(user_and_passwd, ':') - user_and_passwd);
     1776            return 1; /* Ok */
    15591777        }
    15601778    } /* for */
    15611779
    1562     return prev == NULL;
     1780    /* 0(bad) if prev is set: matches were found but passwd was wrong */
     1781    return (prev == NULL);
    15631782}
    15641783#endif  /* FEATURE_HTTPD_BASIC_AUTH */
     1784
     1785#if ENABLE_FEATURE_HTTPD_PROXY
     1786static Htaccess_Proxy *find_proxy_entry(const char *url)
     1787{
     1788    Htaccess_Proxy *p;
     1789    for (p = proxy; p; p = p->next) {
     1790        if (strncmp(url, p->url_from, strlen(p->url_from)) == 0)
     1791            return p;
     1792    }
     1793    return NULL;
     1794}
     1795#endif
    15651796
    15661797/*
    15671798 * Handle timeouts
    15681799 */
    1569 static void exit_on_signal(int sig) ATTRIBUTE_NORETURN;
    1570 static void exit_on_signal(int sig)
     1800static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
     1801static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM)
    15711802{
    15721803    send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
     
    15761807 * Handle an incoming http request and exit.
    15771808 */
    1578 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN;
     1809static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) NORETURN;
    15791810static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
    15801811{
    15811812    static const char request_GET[] ALIGN1 = "GET";
    1582 
    15831813    struct stat sb;
    15841814    char *urlcopy;
    15851815    char *urlp;
    15861816    char *tptr;
    1587     int http_major_version;
    1588     int ip_allowed;
    15891817#if ENABLE_FEATURE_HTTPD_CGI
     1818    static const char request_HEAD[] ALIGN1 = "HEAD";
    15901819    const char *prequest;
     1820    char *cookie = NULL;
     1821    char *content_type = NULL;
    15911822    unsigned long length = 0;
    1592     char *cookie = 0;
    1593     char *content_type = 0;
    1594 #endif
    1595     struct sigaction sa;
     1823#elif ENABLE_FEATURE_HTTPD_PROXY
     1824#define prequest request_GET
     1825    unsigned long length = 0;
     1826#endif
    15961827#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    1597     int credentials = -1;  /* if not required this is Ok */
     1828    smallint authorized = -1;
     1829#endif
     1830    smallint ip_allowed;
     1831    char http_major_version;
     1832#if ENABLE_FEATURE_HTTPD_PROXY
     1833    char http_minor_version;
     1834    char *header_buf = header_buf; /* for gcc */
     1835    char *header_ptr = header_ptr;
     1836    Htaccess_Proxy *proxy_entry;
    15981837#endif
    15991838
     
    16031842
    16041843    rmt_ip = 0;
    1605     if (fromAddr->sa.sa_family == AF_INET) {
    1606         rmt_ip = ntohl(fromAddr->sin.sin_addr.s_addr);
     1844    if (fromAddr->u.sa.sa_family == AF_INET) {
     1845        rmt_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
    16071846    }
    16081847#if ENABLE_FEATURE_IPV6
    1609     if (fromAddr->sa.sa_family == AF_INET6
    1610      && fromAddr->sin6.sin6_addr.s6_addr32[0] == 0
    1611      && fromAddr->sin6.sin6_addr.s6_addr32[1] == 0
    1612      && ntohl(fromAddr->sin6.sin6_addr.s6_addr32[2]) == 0xffff)
    1613         rmt_ip = ntohl(fromAddr->sin6.sin6_addr.s6_addr32[3]);
     1848    if (fromAddr->u.sa.sa_family == AF_INET6
     1849     && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
     1850     && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
     1851     && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
     1852        rmt_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
    16141853#endif
    16151854    if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
    1616         rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->sa);
     1855        /* NB: can be NULL (user runs httpd -i by hand?) */
     1856        rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->u.sa);
    16171857    }
    16181858    if (verbose) {
    16191859        /* this trick makes -v logging much simpler */
    1620         applet_name = rmt_ip_str;
     1860        if (rmt_ip_str)
     1861            applet_name = rmt_ip_str;
    16211862        if (verbose > 2)
    16221863            bb_error_msg("connected");
    16231864    }
    16241865
    1625     /* Install timeout handler */
    1626     memset(&sa, 0, sizeof(sa));
    1627     sa.sa_handler = exit_on_signal;
    1628     /* sigemptyset(&sa.sa_mask); - memset should be enough */
    1629     /*sa.sa_flags = 0; - no SA_RESTART */
    1630     sigaction(SIGALRM, &sa, NULL);
    1631     alarm(HEADER_READ_TIMEOUT);
     1866    /* Install timeout handler. get_line() needs it. */
     1867    signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
    16321868
    16331869    if (!get_line()) /* EOF or error or empty line */
     
    16421878    prequest = request_GET;
    16431879    if (strcasecmp(iobuf, prequest) != 0) {
    1644         prequest = "POST";
    1645         if (strcasecmp(iobuf, prequest) != 0)
    1646             send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
     1880        prequest = request_HEAD;
     1881        if (strcasecmp(iobuf, prequest) != 0) {
     1882            prequest = "POST";
     1883            if (strcasecmp(iobuf, prequest) != 0)
     1884                send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
     1885        }
    16471886    }
    16481887#else
     
    16551894
    16561895    /* Find end of URL and parse HTTP version, if any */
    1657     http_major_version = -1;
     1896    http_major_version = '0';
     1897    IF_FEATURE_HTTPD_PROXY(http_minor_version = '0';)
    16581898    tptr = strchrnul(urlp, ' ');
    16591899    /* Is it " HTTP/"? */
    1660     if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0)
    1661         http_major_version = (tptr[6] - '0');
     1900    if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0) {
     1901        http_major_version = tptr[6];
     1902        IF_FEATURE_HTTPD_PROXY(http_minor_version = tptr[8];)
     1903    }
    16621904    *tptr = '\0';
    16631905
    16641906    /* Copy URL from after "GET "/"POST " to stack-allocated char[] */
    1665     urlcopy = alloca((tptr - urlp) + sizeof("/index.html"));
     1907    urlcopy = alloca((tptr - urlp) + 2 + strlen(index_page));
    16661908    /*if (urlcopy == NULL)
    16671909     *  send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/
     
    16701912
    16711913    /* Extract url args if present */
     1914    g_query = NULL;
    16721915    tptr = strchr(urlcopy, '?');
    1673     g_query = NULL;
    16741916    if (tptr) {
    16751917        *tptr++ = '\0';
     
    16881930    /* Canonicalize path */
    16891931    /* Algorithm stolen from libbb bb_simplify_path(),
    1690      * but don't strdup and reducing trailing slash and protect out root */
     1932     * but don't strdup, retain trailing slash, protect root */
    16911933    urlp = tptr = urlcopy;
    16921934    do {
     
    16971939            }
    16981940            if (*tptr == '.') {
    1699                 /* skip extra '.' */
     1941                /* skip extra "/./" */
    17001942                if (tptr[1] == '/' || !tptr[1]) {
    17011943                    continue;
    17021944                }
    1703                 /* '..': be careful */
     1945                /* "..": be careful */
    17041946                if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) {
    17051947                    ++tptr;
     
    17131955        *++urlp = *tptr;
    17141956    } while (*++tptr);
    1715     *++urlp = '\0';       /* so keep last character */
    1716     tptr = urlp;          /* end ptr */
     1957    *++urlp = '\0';       /* terminate after last character */
    17171958
    17181959    /* If URL is a directory, add '/' */
    1719     if (tptr[-1] != '/') {
    1720         if (is_directory(urlcopy + 1, 1, &sb)) {
     1960    if (urlp[-1] != '/') {
     1961        if (is_directory(urlcopy + 1, 1, NULL)) {
    17211962            found_moved_temporarily = urlcopy;
    17221963        }
     
    17321973        /* have path1/path2 */
    17331974        *tptr = '\0';
    1734         if (is_directory(urlcopy + 1, 1, &sb)) {
    1735             /* may be having subdir config */
     1975        if (is_directory(urlcopy + 1, 1, NULL)) {
     1976            /* may have subdir config */
    17361977            parse_conf(urlcopy + 1, SUBDIR_PARSE);
    17371978            ip_allowed = checkPermIP();
     
    17391980        *tptr = '/';
    17401981    }
    1741     if (http_major_version >= 0) {
     1982
     1983#if ENABLE_FEATURE_HTTPD_PROXY
     1984    proxy_entry = find_proxy_entry(urlcopy);
     1985    if (proxy_entry)
     1986        header_buf = header_ptr = xmalloc(IOBUF_SIZE);
     1987#endif
     1988
     1989    if (http_major_version >= '0') {
    17421990        /* Request was with "... HTTP/nXXX", and n >= 0 */
    17431991
    1744         /* Read until blank line for HTTP version specified, else parse immediate */
     1992        /* Read until blank line */
    17451993        while (1) {
    1746             alarm(HEADER_READ_TIMEOUT);
    17471994            if (!get_line())
    17481995                break; /* EOF or error or empty line */
     
    17501997                bb_error_msg("header: '%s'", iobuf);
    17511998
    1752 #if ENABLE_FEATURE_HTTPD_CGI
    1753             /* try and do our best to parse more lines */
     1999#if ENABLE_FEATURE_HTTPD_PROXY
     2000            /* We need 2 more bytes for yet another "\r\n" -
     2001             * see near fdprintf(proxy_fd...) further below */
     2002            if (proxy_entry && (header_ptr - header_buf) < IOBUF_SIZE - 2) {
     2003                int len = strlen(iobuf);
     2004                if (len > IOBUF_SIZE - (header_ptr - header_buf) - 4)
     2005                    len = IOBUF_SIZE - (header_ptr - header_buf) - 4;
     2006                memcpy(header_ptr, iobuf, len);
     2007                header_ptr += len;
     2008                header_ptr[0] = '\r';
     2009                header_ptr[1] = '\n';
     2010                header_ptr += 2;
     2011            }
     2012#endif
     2013
     2014#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
     2015            /* Try and do our best to parse more lines */
    17542016            if ((STRNCASECMP(iobuf, "Content-length:") == 0)) {
    17552017                /* extra read only for POST */
    1756                 if (prequest != request_GET) {
    1757                     tptr = iobuf + sizeof("Content-length:") - 1;
     2018                if (prequest != request_GET
     2019# if ENABLE_FEATURE_HTTPD_CGI
     2020                 && prequest != request_HEAD
     2021# endif
     2022                ) {
     2023                    tptr = skip_whitespace(iobuf + sizeof("Content-length:") - 1);
    17582024                    if (!tptr[0])
    17592025                        send_headers_and_exit(HTTP_BAD_REQUEST);
    1760                     errno = 0;
    17612026                    /* not using strtoul: it ignores leading minus! */
    1762                     length = strtol(tptr, &tptr, 10);
     2027                    length = bb_strtou(tptr, NULL, 10);
    17632028                    /* length is "ulong", but we need to pass it to int later */
    1764                     /* so we check for negative or too large values in one go: */
    1765                     /* (long -> ulong conv caused negatives to be seen as > INT_MAX) */
    1766                     if (tptr[0] || errno || length > INT_MAX)
     2029                    if (errno || length > INT_MAX)
    17672030                        send_headers_and_exit(HTTP_BAD_REQUEST);
    17682031                }
    1769             } else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
    1770                 cookie = strdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
     2032            }
     2033#endif
     2034#if ENABLE_FEATURE_HTTPD_CGI
     2035            else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
     2036                cookie = xstrdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
    17712037            } else if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
    1772                 content_type = strdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
     2038                content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
    17732039            } else if (STRNCASECMP(iobuf, "Referer:") == 0) {
    1774                 referer = strdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
     2040                referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
    17752041            } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) {
    1776                 user_agent = strdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
     2042                user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
     2043            } else if (STRNCASECMP(iobuf, "Host:") == 0) {
     2044                host = xstrdup(skip_whitespace(iobuf + sizeof("Host:")-1));
     2045            } else if (STRNCASECMP(iobuf, "Accept:") == 0) {
     2046                http_accept = xstrdup(skip_whitespace(iobuf + sizeof("Accept:")-1));
     2047            } else if (STRNCASECMP(iobuf, "Accept-Language:") == 0) {
     2048                http_accept_language = xstrdup(skip_whitespace(iobuf + sizeof("Accept-Language:")-1));
    17772049            }
    17782050#endif
     
    17802052            if (STRNCASECMP(iobuf, "Authorization:") == 0) {
    17812053                /* We only allow Basic credentials.
    1782                  * It shows up as "Authorization: Basic <userid:password>" where
    1783                  * the userid:password is base64 encoded.
     2054                 * It shows up as "Authorization: Basic <user>:<passwd>" where
     2055                 * "<user>:<passwd>" is base64 encoded.
    17842056                 */
    17852057                tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1);
     
    17892061                /* decodeBase64() skips whitespace itself */
    17902062                decodeBase64(tptr);
    1791                 credentials = checkPerm(urlcopy, tptr);
    1792             }
    1793 #endif          /* FEATURE_HTTPD_BASIC_AUTH */
     2063                authorized = check_user_passwd(urlcopy, tptr);
     2064            }
     2065#endif
     2066#if ENABLE_FEATURE_HTTPD_RANGES
     2067            if (STRNCASECMP(iobuf, "Range:") == 0) {
     2068                /* We know only bytes=NNN-[MMM] */
     2069                char *s = skip_whitespace(iobuf + sizeof("Range:")-1);
     2070                if (strncmp(s, "bytes=", 6) == 0) {
     2071                    s += sizeof("bytes=")-1;
     2072                    range_start = BB_STRTOOFF(s, &s, 10);
     2073                    if (s[0] != '-' || range_start < 0) {
     2074                        range_start = 0;
     2075                    } else if (s[1]) {
     2076                        range_end = BB_STRTOOFF(s+1, NULL, 10);
     2077                        if (errno || range_end < range_start)
     2078                            range_start = 0;
     2079                    }
     2080                }
     2081            }
     2082#endif
     2083#if ENABLE_FEATURE_HTTPD_GZIP
     2084            if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) {
     2085                /* Note: we do not support "gzip;q=0"
     2086                 * method of _disabling_ gzip
     2087                 * delivery. No one uses that, though */
     2088                const char *s = strstr(iobuf, "gzip");
     2089                if (s) {
     2090                    // want more thorough checks?
     2091                    //if (s[-1] == ' '
     2092                    // || s[-1] == ','
     2093                    // || s[-1] == ':'
     2094                    //) {
     2095                        content_gzip = 1;
     2096                    //}
     2097                }
     2098            }
     2099#endif
    17942100        } /* while extra header reading */
    17952101    }
    17962102
    1797     /* We read headers, disable peer timeout */
     2103    /* We are done reading headers, disable peer timeout */
    17982104    alarm(0);
    17992105
    1800     if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || ip_allowed == 0) {
    1801         /* protect listing [/path]/httpd_conf or IP deny */
     2106    if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0 || !ip_allowed) {
     2107        /* protect listing [/path]/httpd.conf or IP deny */
    18022108        send_headers_and_exit(HTTP_FORBIDDEN);
    18032109    }
    18042110
    18052111#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    1806     if (credentials <= 0 && checkPerm(urlcopy, ":") == 0) {
     2112    /* Case: no "Authorization:" was seen, but page does require passwd.
     2113     * Check that with dummy user:pass */
     2114    if (authorized < 0)
     2115        authorized = check_user_passwd(urlcopy, ":");
     2116    if (!authorized)
    18072117        send_headers_and_exit(HTTP_UNAUTHORIZED);
    1808     }
    18092118#endif
    18102119
     
    18122121        send_headers_and_exit(HTTP_MOVED_TEMPORARILY);
    18132122    }
     2123
     2124#if ENABLE_FEATURE_HTTPD_PROXY
     2125    if (proxy_entry != NULL) {
     2126        int proxy_fd;
     2127        len_and_sockaddr *lsa;
     2128
     2129        proxy_fd = socket(AF_INET, SOCK_STREAM, 0);
     2130        if (proxy_fd < 0)
     2131            send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
     2132        lsa = host2sockaddr(proxy_entry->host_port, 80);
     2133        if (lsa == NULL)
     2134            send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
     2135        if (connect(proxy_fd, &lsa->u.sa, lsa->len) < 0)
     2136            send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);
     2137        fdprintf(proxy_fd, "%s %s%s%s%s HTTP/%c.%c\r\n",
     2138                prequest, /* GET or POST */
     2139                proxy_entry->url_to, /* url part 1 */
     2140                urlcopy + strlen(proxy_entry->url_from), /* url part 2 */
     2141                (g_query ? "?" : ""), /* "?" (maybe) */
     2142                (g_query ? g_query : ""), /* query string (maybe) */
     2143                http_major_version, http_minor_version);
     2144        header_ptr[0] = '\r';
     2145        header_ptr[1] = '\n';
     2146        header_ptr += 2;
     2147        write(proxy_fd, header_buf, header_ptr - header_buf);
     2148        free(header_buf); /* on the order of 8k, free it */
     2149        cgi_io_loop_and_exit(proxy_fd, proxy_fd, length);
     2150    }
     2151#endif
    18142152
    18152153    tptr = urlcopy + 1;      /* skip first '/' */
     
    18232161        send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);
    18242162    }
     2163#endif
     2164
     2165    if (urlp[-1] == '/')
     2166        strcpy(urlp, index_page);
     2167    if (stat(tptr, &sb) == 0) {
    18252168#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
    1826     {
    18272169        char *suffix = strrchr(tptr, '.');
    18282170        if (suffix) {
     
    18342176            }
    18352177        }
    1836     }
    1837 #endif
    1838     if (prequest != request_GET) {
    1839         send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
    1840     }
    1841 #endif  /* FEATURE_HTTPD_CGI */
    1842 
    1843     if (urlp[-1] == '/')
    1844         strcpy(urlp, "index.html");
    1845     if (stat(tptr, &sb) == 0) {
    1846         /* It's a dir URL and there is index.html */
    1847         ContentLength = sb.st_size;
     2178#endif
     2179        file_size = sb.st_size;
    18482180        last_mod = sb.st_mtime;
    18492181    }
     
    18582190        }
    18592191    }
    1860 #endif
    1861     /* else {
    1862      *  fall through to send_file, it errors out if open fails
    1863      * }
    1864      */
    1865 
    1866     send_file_and_exit(tptr, TRUE);
     2192    /* else fall through to send_file, it errors out if open fails: */
     2193
     2194    if (prequest != request_GET && prequest != request_HEAD) {
     2195        /* POST for files does not make sense */
     2196        send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
     2197    }
     2198    send_file_and_exit(tptr,
     2199        (prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS)
     2200    );
     2201#else
     2202    send_file_and_exit(tptr, SEND_HEADERS_AND_BODY);
     2203#endif
    18672204}
    18682205
     
    18742211 */
    18752212#if BB_MMU
    1876 static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN;
     2213static void mini_httpd(int server_socket) NORETURN;
    18772214static void mini_httpd(int server_socket)
    18782215{
     
    18852222        int n;
    18862223        len_and_sockaddr fromAddr;
    1887        
     2224
    18882225        /* Wait for connections... */
    18892226        fromAddr.len = LSA_SIZEOF_SA;
    1890         n = accept(server_socket, &fromAddr.sa, &fromAddr.len);
    1891 
     2227        n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
    18922228        if (n < 0)
    18932229            continue;
     2230
    18942231        /* set the KEEPALIVE option to cull dead connections */
    18952232        setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     
    18972234        if (fork() == 0) {
    18982235            /* child */
    1899 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    19002236            /* Do not reload config on HUP */
    19012237            signal(SIGHUP, SIG_IGN);
    1902 #endif
    19032238            close(server_socket);
    19042239            xmove_fd(n, 0);
     
    19132248}
    19142249#else
    1915 static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN;
     2250static void mini_httpd_nommu(int server_socket, int argc, char **argv) NORETURN;
    19162251static void mini_httpd_nommu(int server_socket, int argc, char **argv)
    19172252{
     
    19302265        int n;
    19312266        len_and_sockaddr fromAddr;
    1932        
     2267
    19332268        /* Wait for connections... */
    19342269        fromAddr.len = LSA_SIZEOF_SA;
    1935         n = accept(server_socket, &fromAddr.sa, &fromAddr.len);
    1936 
     2270        n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
    19372271        if (n < 0)
    19382272            continue;
     2273
    19392274        /* set the KEEPALIVE option to cull dead connections */
    19402275        setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     
    19422277        if (vfork() == 0) {
    19432278            /* child */
    1944 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    19452279            /* Do not reload config on HUP */
    19462280            signal(SIGHUP, SIG_IGN);
    1947 #endif
    19482281            close(server_socket);
    19492282            xmove_fd(n, 0);
     
    19642297 * Never returns.
    19652298 */
    1966 static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN;
     2299static void mini_httpd_inetd(void) NORETURN;
    19672300static void mini_httpd_inetd(void)
    19682301{
    19692302    len_and_sockaddr fromAddr;
    19702303
     2304    memset(&fromAddr, 0, sizeof(fromAddr));
    19712305    fromAddr.len = LSA_SIZEOF_SA;
    1972     getpeername(0, &fromAddr.sa, &fromAddr.len);
     2306    /* NB: can fail if user runs it by hand and types in http cmds */
     2307    getpeername(0, &fromAddr.u.sa, &fromAddr.len);
    19732308    handle_incoming_and_exit(&fromAddr);
    19742309}
    19752310
    1976 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
    1977 static void sighup_handler(int sig)
    1978 {
    1979     struct sigaction sa;
    1980 
    1981     parse_conf(default_path_httpd_conf, sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE);
    1982 
    1983     memset(&sa, 0, sizeof(sa));
    1984     sa.sa_handler = sighup_handler;
    1985     /*sigemptyset(&sa.sa_mask); - memset should be enough */
    1986     sa.sa_flags = SA_RESTART;
    1987     sigaction(SIGHUP, &sa, NULL);
    1988 }
    1989 #endif
     2311static void sighup_handler(int sig UNUSED_PARAM)
     2312{
     2313    parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE);
     2314}
    19902315
    19912316enum {
     
    19932318    d_opt_decode_url,
    19942319    h_opt_home_httpd,
    1995     USE_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,)
    1996     USE_FEATURE_HTTPD_BASIC_AUTH(    r_opt_realm     ,)
    1997     USE_FEATURE_HTTPD_AUTH_MD5(      m_opt_md5       ,)
    1998     USE_FEATURE_HTTPD_SETUID(        u_opt_setuid    ,)
     2320    IF_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,)
     2321    IF_FEATURE_HTTPD_BASIC_AUTH(    r_opt_realm     ,)
     2322    IF_FEATURE_HTTPD_AUTH_MD5(      m_opt_md5       ,)
     2323    IF_FEATURE_HTTPD_SETUID(        u_opt_setuid    ,)
    19992324    p_opt_port      ,
    20002325    p_opt_inetd     ,
     
    20042329    OPT_DECODE_URL  = 1 << d_opt_decode_url,
    20052330    OPT_HOME_HTTPD  = 1 << h_opt_home_httpd,
    2006     OPT_ENCODE_URL  = USE_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0,
    2007     OPT_REALM       = USE_FEATURE_HTTPD_BASIC_AUTH(    (1 << r_opt_realm     )) + 0,
    2008     OPT_MD5         = USE_FEATURE_HTTPD_AUTH_MD5(      (1 << m_opt_md5       )) + 0,
    2009     OPT_SETUID      = USE_FEATURE_HTTPD_SETUID(        (1 << u_opt_setuid    )) + 0,
     2331    OPT_ENCODE_URL  = IF_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0,
     2332    OPT_REALM       = IF_FEATURE_HTTPD_BASIC_AUTH(    (1 << r_opt_realm     )) + 0,
     2333    OPT_MD5         = IF_FEATURE_HTTPD_AUTH_MD5(      (1 << m_opt_md5       )) + 0,
     2334    OPT_SETUID      = IF_FEATURE_HTTPD_SETUID(        (1 << u_opt_setuid    )) + 0,
    20102335    OPT_PORT        = 1 << p_opt_port,
    20112336    OPT_INETD       = 1 << p_opt_inetd,
     
    20152340
    20162341
    2017 int httpd_main(int argc, char **argv);
    2018 int httpd_main(int argc, char **argv)
     2342int httpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     2343int httpd_main(int argc UNUSED_PARAM, char **argv)
    20192344{
    20202345    int server_socket = server_socket; /* for gcc */
    20212346    unsigned opt;
    20222347    char *url_for_decode;
    2023     USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
    2024     USE_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
    2025     USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
    2026     USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
     2348    IF_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
     2349    IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
     2350    IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
     2351    IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
    20272352
    20282353    INIT_G();
     
    20372362    opt_complementary = "vv:if";
    20382363    /* We do not "absolutize" path given by -h (home) opt.
    2039      * If user gives relative path in -h, $SCRIPT_FILENAME can end up
    2040      * relative too. */
     2364     * If user gives relative path in -h,
     2365     * $SCRIPT_FILENAME will not be set. */
    20412366    opt = getopt32(argv, "c:d:h:"
    2042             USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
    2043             USE_FEATURE_HTTPD_BASIC_AUTH("r:")
    2044             USE_FEATURE_HTTPD_AUTH_MD5("m:")
    2045             USE_FEATURE_HTTPD_SETUID("u:")
     2367            IF_FEATURE_HTTPD_ENCODE_URL_STR("e:")
     2368            IF_FEATURE_HTTPD_BASIC_AUTH("r:")
     2369            IF_FEATURE_HTTPD_AUTH_MD5("m:")
     2370            IF_FEATURE_HTTPD_SETUID("u:")
    20462371            "p:ifv",
    2047             &configFile, &url_for_decode, &home_httpd
    2048             USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
    2049             USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
    2050             USE_FEATURE_HTTPD_AUTH_MD5(, &pass)
    2051             USE_FEATURE_HTTPD_SETUID(, &s_ugid)
     2372            &opt_c_configFile, &url_for_decode, &home_httpd
     2373            IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
     2374            IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
     2375            IF_FEATURE_HTTPD_AUTH_MD5(, &pass)
     2376            IF_FEATURE_HTTPD_SETUID(, &s_ugid)
    20522377            , &bind_addr_or_port
    20532378            , &verbose
     
    20652390#if ENABLE_FEATURE_HTTPD_AUTH_MD5
    20662391    if (opt & OPT_MD5) {
    2067         puts(pw_encrypt(pass, "$1$"));
     2392        char salt[sizeof("$1$XXXXXXXX")];
     2393        salt[0] = '$';
     2394        salt[1] = '1';
     2395        salt[2] = '$';
     2396        crypt_make_salt(salt + 3, 4, 0);
     2397        puts(pw_encrypt(pass, salt, 1));
    20682398        return 0;
    20692399    }
     
    20712401#if ENABLE_FEATURE_HTTPD_SETUID
    20722402    if (opt & OPT_SETUID) {
    2073         if (!get_uidgid(&ugid, s_ugid, 1))
    2074             bb_error_msg_and_die("unrecognized user[:group] "
    2075                         "name '%s'", s_ugid);
     2403        xget_uidgid(&ugid, s_ugid);
    20762404    }
    20772405#endif
     
    21002428    }
    21012429
    2102 #if ENABLE_FEATURE_HTTPD_CGI
     2430#if 0
     2431    /* User can do it himself: 'env - PATH="$PATH" httpd'
     2432     * We don't do it because we don't want to screw users
     2433     * which want to do
     2434     * 'env - VAR1=val1 VAR2=val2 httpd'
     2435     * and have VAR1 and VAR2 values visible in their CGIs.
     2436     * Besides, it is also smaller. */
    21032437    {
    21042438        char *p = getenv("PATH");
    2105         /* env strings themself are not freed, no need to strdup(p): */
     2439        /* env strings themself are not freed, no need to xstrdup(p): */
    21062440        clearenv();
    21072441        if (p)
     
    21122446#endif
    21132447
    2114 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
     2448    parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE);
    21152449    if (!(opt & OPT_INETD))
    2116         sighup_handler(0);
    2117     else /* do not install HUP handler in inetd mode */
    2118 #endif
    2119         parse_conf(default_path_httpd_conf, FIRST_PARSE);
     2450        signal(SIGHUP, sighup_handler);
    21202451
    21212452    xfunc_error_retval = 0;
  • branches/2.2.9/mindi-busybox/networking/httpd_indexcgi.c

    r1765 r2725  
    22 * Copyright (c) 2007 Denys Vlasenko <vda.linux@googlemail.com>
    33 *
    4  * Licensed under GPLv2, see file LICENSE in this tarball for details.
     4 * Licensed under GPLv2, see file LICENSE in this source tree.
    55 */
    66
     
    2929/* Currently malloc machinery is the biggest part of libc we pull in. */
    3030/* We have only one realloc and one strdup, any idea how to do without? */
    31 /* Size (i386, approximate):
     31
     32/* Size (i386, static uclibc, approximate):
    3233 *   text    data     bss     dec     hex filename
    3334 *  13036      44    3052   16132    3f04 index.cgi
     
    126127    if (buffer + (BUFFER_SIZE-HEADROOM) - dst >= size)
    127128        return;
    128     write(1, buffer, dst - buffer);
     129    write(STDOUT_FILENO, buffer, dst - buffer);
    129130    dst = buffer;
    130131}
     
    149150        *dst = c;
    150151        if ((c - '0') > 9 /* not a digit */
    151          && ((c|0x20) - 'a') > 26 /* not A-Z or a-z */
     152         && ((c|0x20) - 'a') > ('z' - 'a') /* not A-Z or a-z */
    152153         && !strchr("._-+@", c)
    153154        ) {
     
    211212}
    212213
    213 int main(void)
     214int main(int argc, char *argv[])
    214215{
    215216    dir_list_t *dir_list;
     
    226227    if (!QUERY_STRING
    227228     || QUERY_STRING[0] != '/'
     229     || strstr(QUERY_STRING, "//")
    228230     || strstr(QUERY_STRING, "/../")
    229231     || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0
     
    290292    cdir = dir_list;
    291293    while (dir_list_count--) {
    292         struct tm *tm;
     294        struct tm *ptm;
    293295
    294296        if (S_ISDIR(cdir->dl_mode)) {
     
    314316            fmt_ull(cdir->dl_size);
    315317        fmt_str("<td class=dt>");
    316         tm = gmtime(&cdir->dl_mtime);
    317         fmt_04u(1900 + tm->tm_year); *dst++ = '-';
    318         fmt_02u(tm->tm_mon + 1); *dst++ = '-';
    319         fmt_02u(tm->tm_mday); *dst++ = ' ';
    320         fmt_02u(tm->tm_hour); *dst++ = ':';
    321         fmt_02u(tm->tm_min); *dst++ = ':';
    322         fmt_02u(tm->tm_sec);
     318        ptm = gmtime(&cdir->dl_mtime);
     319        fmt_04u(1900 + ptm->tm_year); *dst++ = '-';
     320        fmt_02u(ptm->tm_mon + 1); *dst++ = '-';
     321        fmt_02u(ptm->tm_mday); *dst++ = ' ';
     322        fmt_02u(ptm->tm_hour); *dst++ = ':';
     323        fmt_02u(ptm->tm_min); *dst++ = ':';
     324        fmt_02u(ptm->tm_sec);
    323325        *dst++ = '\n';
    324326
  • branches/2.2.9/mindi-busybox/networking/ifconfig.c

    r1765 r2725  
    1111 *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
    1212 *
    13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1414 */
    1515
     
    3737#include <netinet/if_ether.h>
    3838#endif
     39#include "libbb.h"
    3940#include "inet_common.h"
    40 #include "libbb.h"
    4141
    4242#if ENABLE_FEATURE_IFCONFIG_SLIP
     
    165165struct arg1opt {
    166166    const char *name;
    167     int selector;
     167    unsigned short selector;
    168168    unsigned short ifr_offset;
    169169};
     
    184184
    185185static const struct arg1opt Arg1Opt[] = {
    186     {"SIOCSIFMETRIC",  SIOCSIFMETRIC,  ifreq_offsetof(ifr_metric)},
    187     {"SIOCSIFMTU",     SIOCSIFMTU,     ifreq_offsetof(ifr_mtu)},
    188     {"SIOCSIFTXQLEN",  SIOCSIFTXQLEN,  ifreq_offsetof(ifr_qlen)},
    189     {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
    190     {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
    191     {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
    192 #if ENABLE_FEATURE_IFCONFIG_HW
    193     {"SIOCSIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr)},
    194 #endif
    195     {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
     186    { "SIFMETRIC",  SIOCSIFMETRIC,  ifreq_offsetof(ifr_metric) },
     187    { "SIFMTU",     SIOCSIFMTU,     ifreq_offsetof(ifr_mtu) },
     188    { "SIFTXQLEN",  SIOCSIFTXQLEN,  ifreq_offsetof(ifr_qlen) },
     189    { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) },
     190    { "SIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask) },
     191    { "SIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr) },
     192#if ENABLE_FEATURE_IFCONFIG_HW
     193    { "SIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr) },
     194#endif
     195    { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) },
    196196#ifdef SIOCSKEEPALIVE
    197     {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
     197    { "SKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data) },
    198198#endif
    199199#ifdef SIOCSOUTFILL
    200     {"SIOCSOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data)},
     200    { "SOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data) },
    201201#endif
    202202#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    203     {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start)},
    204     {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr)},
    205     {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq)},
     203    { "SIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start) },
     204    { "SIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr) },
     205    { "SIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq) },
    206206#endif
    207207    /* Last entry if for unmatched (possibly hostname) arg. */
    208208#if ENABLE_FEATURE_IPV6
    209     {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
    210     {"SIOCDIFADDR",    SIOCDIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
    211 #endif
    212     {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)},
     209    { "SIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */
     210    { "DIFADDR",    SIOCDIFADDR,    ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */
     211#endif
     212    { "SIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr) },
    213213};
    214214
    215215static const struct options OptArray[] = {
    216     {"metric",      N_ARG,         ARG_METRIC,      0},
    217     {"mtu",         N_ARG,         ARG_MTU,         0},
    218     {"txqueuelen",  N_ARG,         ARG_TXQUEUELEN,  0},
    219     {"dstaddr",     N_ARG,         ARG_DSTADDR,     0},
    220     {"netmask",     N_ARG,         ARG_NETMASK,     0},
    221     {"broadcast",   N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST},
    222 #if ENABLE_FEATURE_IFCONFIG_HW
    223     {"hw",          N_ARG, ARG_HW,                  0},
    224 #endif
    225     {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
     216    { "metric",      N_ARG,         ARG_METRIC,      0 },
     217    { "mtu",         N_ARG,         ARG_MTU,         0 },
     218    { "txqueuelen",  N_ARG,         ARG_TXQUEUELEN,  0 },
     219    { "dstaddr",     N_ARG,         ARG_DSTADDR,     0 },
     220    { "netmask",     N_ARG,         ARG_NETMASK,     0 },
     221    { "broadcast",   N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST },
     222#if ENABLE_FEATURE_IFCONFIG_HW
     223    { "hw",          N_ARG,         ARG_HW,          0 },
     224#endif
     225    { "pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT },
    226226#ifdef SIOCSKEEPALIVE
    227     {"keepalive",   N_ARG,         ARG_KEEPALIVE,   0},
     227    { "keepalive",   N_ARG,         ARG_KEEPALIVE,   0 },
    228228#endif
    229229#ifdef SIOCSOUTFILL
    230     {"outfill",     N_ARG,         ARG_OUTFILL,     0},
     230    { "outfill",     N_ARG,         ARG_OUTFILL,     0 },
    231231#endif
    232232#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
    233     {"mem_start",   N_ARG,         ARG_MEM_START,   0},
    234     {"io_addr",     N_ARG,         ARG_IO_ADDR,     0},
    235     {"irq",         N_ARG,         ARG_IRQ,         0},
     233    { "mem_start",   N_ARG,         ARG_MEM_START,   0 },
     234    { "io_addr",     N_ARG,         ARG_IO_ADDR,     0 },
     235    { "irq",         N_ARG,         ARG_IRQ,         0 },
    236236#endif
    237237#if ENABLE_FEATURE_IPV6
    238     {"add",         N_ARG,         ARG_ADD_DEL,     0},
    239     {"del",         N_ARG,         ARG_ADD_DEL,     0},
    240 #endif
    241     {"arp",         N_CLR | M_SET, 0,               IFF_NOARP},
    242     {"trailers",    N_CLR | M_SET, 0,               IFF_NOTRAILERS},
    243     {"promisc",     N_SET | M_CLR, 0,               IFF_PROMISC},
    244     {"multicast",   N_SET | M_CLR, 0,               IFF_MULTICAST},
    245     {"allmulti",    N_SET | M_CLR, 0,               IFF_ALLMULTI},
    246     {"dynamic",     N_SET | M_CLR, 0,               IFF_DYNAMIC},
    247     {"up",          N_SET,         0,               (IFF_UP | IFF_RUNNING)},
    248     {"down",        N_CLR,         0,               IFF_UP},
    249     {NULL,          0,             ARG_HOSTNAME,    (IFF_UP | IFF_RUNNING)}
     238    { "add",         N_ARG,         ARG_ADD_DEL,     0 },
     239    { "del",         N_ARG,         ARG_ADD_DEL,     0 },
     240#endif
     241    { "arp",         N_CLR | M_SET, 0,               IFF_NOARP },
     242    { "trailers",    N_CLR | M_SET, 0,               IFF_NOTRAILERS },
     243    { "promisc",     N_SET | M_CLR, 0,               IFF_PROMISC },
     244    { "multicast",   N_SET | M_CLR, 0,               IFF_MULTICAST },
     245    { "allmulti",    N_SET | M_CLR, 0,               IFF_ALLMULTI },
     246    { "dynamic",     N_SET | M_CLR, 0,               IFF_DYNAMIC },
     247    { "up",          N_SET,         0,               (IFF_UP | IFF_RUNNING) },
     248    { "down",        N_CLR,         0,               IFF_UP },
     249    { NULL,          0,             ARG_HOSTNAME,    (IFF_UP | IFF_RUNNING) }
    250250};
    251251
     
    253253 * A couple of prototypes.
    254254 */
    255 
    256255#if ENABLE_FEATURE_IFCONFIG_HW
    257256static int in_ether(const char *bufp, struct sockaddr *sap);
     
    261260 * Our main function.
    262261 */
    263 
    264 int ifconfig_main(int argc, char **argv);
    265 int ifconfig_main(int argc, char **argv)
     262int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     263int ifconfig_main(int argc UNUSED_PARAM, char **argv)
    266264{
    267265    struct ifreq ifr;
     
    294292    /* skip argv[0] */
    295293    ++argv;
    296     --argc;
    297294
    298295#if ENABLE_FEATURE_IFCONFIG_STATUS
    299     if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) {
     296    if (argv[0] && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) {
    300297        interface_opt_a = 1;
    301         --argc;
    302298        ++argv;
    303299    }
    304300#endif
    305301
    306     if (argc <= 1) {
     302    if (!argv[0] || !argv[1]) { /* one or no args */
    307303#if ENABLE_FEATURE_IFCONFIG_STATUS
    308         return display_interfaces(argc ? *argv : NULL);
     304        return display_interfaces(argv[0] /* can be NULL */);
    309305#else
    310306        bb_error_msg_and_die("no support for status display");
     
    316312
    317313    /* get interface name */
    318     safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
     314    strncpy_IFNAMSIZ(ifr.ifr_name, *argv);
    319315
    320316    /* Process the remaining arguments. */
     
    375371                        sai.sin_family = AF_INET;
    376372                        sai.sin_port = 0;
    377                         if (!strcmp(host, bb_str_default)) {
     373                        if (strcmp(host, "default") == 0) {
    378374                            /* Default is special, meaning 0.0.0.0. */
    379375                            sai.sin_addr.s_addr = INADDR_ANY;
     
    393389                            lsa = xhost2sockaddr(host, 0);
    394390#if ENABLE_FEATURE_IPV6
    395                             if (lsa->sa.sa_family == AF_INET6) {
     391                            if (lsa->u.sa.sa_family == AF_INET6) {
    396392                                int sockfd6;
    397393                                struct in6_ifreq ifr6;
    398394
    399395                                memcpy((char *) &ifr6.ifr6_addr,
    400                                         (char *) &(lsa->sin6.sin6_addr),
     396                                        (char *) &(lsa->u.sin6.sin6_addr),
    401397                                        sizeof(struct in6_addr));
    402398
     
    406402                                ifr6.ifr6_ifindex = ifr.ifr_ifindex;
    407403                                ifr6.ifr6_prefixlen = prefix_len;
    408                                 ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "%s", a1op->name);
     404                                ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "SIOC%s", a1op->name);
    409405                                if (ENABLE_FEATURE_CLEAN_UP)
    410406                                    free(lsa);
     
    412408                            }
    413409#endif
    414                             sai.sin_addr = lsa->sin.sin_addr;
     410                            sai.sin_addr = lsa->u.sin.sin_addr;
    415411                            if (ENABLE_FEATURE_CLEAN_UP)
    416412                                free(lsa);
     
    426422                    } else {    /* A_CAST_HOST_COPY_IN_ETHER */
    427423                        /* This is the "hw" arg case. */
    428                         if (strcmp("ether", *argv) || !*++argv)
     424                        smalluint hw_class= index_in_substrings("ether\0"
     425                                IF_FEATURE_HWIB("infiniband\0"), *argv) + 1;
     426                        if (!hw_class || !*++argv)
    429427                            bb_show_usage();
    430428                        /*safe_strncpy(host, *argv, sizeof(host));*/
    431429                        host = *argv;
    432                         if (in_ether(host, &sa))
     430                        if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa))
    433431                            bb_error_msg_and_die("invalid hw-addr %s", host);
    434432                        p = (char *) &sa;
     
    458456                }
    459457
    460                 ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "%s", a1op->name);
     458                ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "SIOC%s", a1op->name);
    461459#ifdef QUESTIONABLE_ALIAS_CASE
    462460                if (mask & A_COLON_CHK) {
     
    507505
    508506    sap->sa_family = ARPHRD_ETHER;
    509     ptr = sap->sa_data;
     507    ptr = (char *) sap->sa_data;
    510508
    511509    i = 0;
  • branches/2.2.9/mindi-busybox/networking/ifupdown.c

    r1765 r2725  
    22/*
    33 *  ifupdown for busybox
    4  *  Copyright (c) 2002 Glenn McGrath <bug1@iinet.net.au>
     4 *  Copyright (c) 2002 Glenn McGrath
    55 *  Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>
    66 *
     
    1515 *  configuration.
    1616 *
    17  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     17 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1818 */
    1919
     20#include "libbb.h"
     21/* After libbb.h, since it needs sys/types.h on some systems */
    2022#include <sys/utsname.h>
    2123#include <fnmatch.h>
    22 #include <getopt.h>
    23 
    24 #include "libbb.h"
    2524
    2625#define MAX_OPT_DEPTH 10
     
    3332#endif
    3433
     34#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
     35
    3536#define debug_noise(args...) /*fprintf(stderr, args)*/
    3637
     
    4243struct method_t {
    4344    const char *name;
    44     int (*up)(struct interface_defn_t *ifd, execfn *e);
    45     int (*down)(struct interface_defn_t *ifd, execfn *e);
     45    int (*up)(struct interface_defn_t *ifd, execfn *e) FAST_FUNC;
     46    int (*down)(struct interface_defn_t *ifd, execfn *e) FAST_FUNC;
    4647};
    4748
     
    8788};
    8889
    89 #define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:"
     90
     91#define OPTION_STR "anvf" IF_FEATURE_IFUPDOWN_MAPPING("m") "i:"
    9092enum {
    91     OPT_do_all = 0x1,
    92     OPT_no_act = 0x2,
    93     OPT_verbose = 0x4,
    94     OPT_force = 0x8,
     93    OPT_do_all      = 0x1,
     94    OPT_no_act      = 0x2,
     95    OPT_verbose     = 0x4,
     96    OPT_force       = 0x8,
    9597    OPT_no_mappings = 0x10,
    9698};
    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)
     99#define DO_ALL      (option_mask32 & OPT_do_all)
     100#define NO_ACT      (option_mask32 & OPT_no_act)
     101#define VERBOSE     (option_mask32 & OPT_verbose)
     102#define FORCE       (option_mask32 & OPT_force)
    101103#define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
    102104
    103 static char **my_environ;
    104 
    105 static const char *startup_PATH;
     105
     106struct globals {
     107    char **my_environ;
     108    const char *startup_PATH;
     109} FIX_ALIASING;
     110#define G (*(struct globals*)&bb_common_bufsiz1)
     111#define INIT_G() do { } while (0)
     112
    106113
    107114#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
     
    126133
    127134    if (i == 0)
    128         return -r[llen];
     135        return - (unsigned char)r[llen];
    129136    return i;
    130137}
     
    135142
    136143    if (strncmpz(id, "iface", idlen) == 0) {
    137         char *result;
    138         static char label_buf[20];
    139         safe_strncpy(label_buf, ifd->iface, sizeof(label_buf));
    140         result = strchr(label_buf, ':');
    141         if (result) {
    142             *result = '\0';
    143         }
    144         return label_buf;
     144        // ubuntu's ifup doesn't do this:
     145        //static char *label_buf;
     146        //char *result;
     147        //free(label_buf);
     148        //label_buf = xstrdup(ifd->iface);
     149        // Remove virtual iface suffix
     150        //result = strchrnul(label_buf, ':');
     151        //*result = '\0';
     152        //return label_buf;
     153
     154        return ifd->iface;
    145155    }
    146156    if (strncmpz(id, "label", idlen) == 0) {
     
    155165}
    156166
    157 #if ENABLE_FEATURE_IFUPDOWN_IP
     167# if ENABLE_FEATURE_IFUPDOWN_IP
    158168static int count_netmask_bits(const char *dotted_quad)
    159169{
     
    186196    return result;
    187197}
    188 #endif
     198# endif
    189199
    190200static char *parse(const char *command, struct interface_defn_t *ifd)
     
    249259
    250260                if (varvalue) {
     261# if ENABLE_FEATURE_IFUPDOWN_IP
     262                    /* "hwaddress <class> <address>":
     263                     * unlike ifconfig, ip doesnt want <class>
     264                     * (usually "ether" keyword). Skip it. */
     265                    if (strncmp(command, "hwaddress", 9) == 0) {
     266                        varvalue = skip_whitespace(skip_non_whitespace(varvalue));
     267                    }
     268# endif
    251269                    addstr(&result, varvalue, strlen(varvalue));
    252270                } else {
    253 #if ENABLE_FEATURE_IFUPDOWN_IP
     271# if ENABLE_FEATURE_IFUPDOWN_IP
    254272                    /* Sigh...  Add a special case for 'ip' to convert from
    255273                     * dotted quad to bit count style netmasks.  */
     
    267285                        }
    268286                    }
    269 #endif
     287# endif
    270288                    okay[opt_depth - 1] = 0;
    271289                }
     
    312330    return 1;
    313331}
    314 #endif
     332
     333#endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */
     334
    315335
    316336#if ENABLE_FEATURE_IFUPDOWN_IPV6
    317 static int loopback_up6(struct interface_defn_t *ifd, execfn *exec)
    318 {
    319 #if ENABLE_FEATURE_IFUPDOWN_IP
     337
     338static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec)
     339{
     340# if ENABLE_FEATURE_IFUPDOWN_IP
    320341    int result;
    321342    result = execute("ip addr add ::1 dev %iface%", ifd, exec);
    322343    result += execute("ip link set %iface% up", ifd, exec);
    323344    return ((result == 2) ? 2 : 0);
    324 #else
     345# else
    325346    return execute("ifconfig %iface% add ::1", ifd, exec);
    326 #endif
    327 }
    328 
    329 static int loopback_down6(struct interface_defn_t *ifd, execfn *exec)
    330 {
    331 #if ENABLE_FEATURE_IFUPDOWN_IP
     347# endif
     348}
     349
     350static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec)
     351{
     352# if ENABLE_FEATURE_IFUPDOWN_IP
    332353    return execute("ip link set %iface% down", ifd, exec);
    333 #else
     354# else
    334355    return execute("ifconfig %iface% del ::1", ifd, exec);
    335 #endif
    336 }
    337 
    338 static int static_up6(struct interface_defn_t *ifd, execfn *exec)
     356# endif
     357}
     358
     359static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
     360{
     361    return 1;
     362}
     363
     364static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
    339365{
    340366    int result;
    341 #if ENABLE_FEATURE_IFUPDOWN_IP
     367# if ENABLE_FEATURE_IFUPDOWN_IP
    342368    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);
     369    result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
    344370    /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
    345371    result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
    346 #else
     372# else
    347373    result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
    348374    result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
    349375    result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);
    350 #endif
     376# endif
    351377    return ((result == 3) ? 3 : 0);
    352378}
    353379
    354 static int static_down6(struct interface_defn_t *ifd, execfn *exec)
    355 {
    356 #if ENABLE_FEATURE_IFUPDOWN_IP
     380static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec)
     381{
     382# if ENABLE_FEATURE_IFUPDOWN_IP
    357383    return execute("ip link set %iface% down", ifd, exec);
    358 #else
     384# else
    359385    return execute("ifconfig %iface% down", ifd, exec);
    360 #endif
    361 }
    362 
    363 #if ENABLE_FEATURE_IFUPDOWN_IP
    364 static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
     386# endif
     387}
     388
     389# if ENABLE_FEATURE_IFUPDOWN_IP
     390static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
    365391{
    366392    int result;
     
    373399}
    374400
    375 static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
     401static int FAST_FUNC v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
    376402{
    377403    return execute("ip tunnel del %iface%", ifd, exec);
    378404}
    379 #endif
     405# endif
    380406
    381407static const struct method_t methods6[] = {
    382 #if ENABLE_FEATURE_IFUPDOWN_IP
    383     { "v4tunnel", v4tunnel_up, v4tunnel_down, },
    384 #endif
    385     { "static", static_up6, static_down6, },
    386     { "loopback", loopback_up6, loopback_down6, },
     408# if ENABLE_FEATURE_IFUPDOWN_IP
     409    { "v4tunnel" , v4tunnel_up     , v4tunnel_down   , },
     410# endif
     411    { "static"   , static_up6      , static_down6    , },
     412    { "manual"   , manual_up_down6 , manual_up_down6 , },
     413    { "loopback" , loopback_up6    , loopback_down6  , },
    387414};
    388415
     
    392419    methods6
    393420};
     421
    394422#endif /* FEATURE_IFUPDOWN_IPV6 */
    395423
     424
    396425#if ENABLE_FEATURE_IFUPDOWN_IPV4
    397 static int loopback_up(struct interface_defn_t *ifd, execfn *exec)
    398 {
    399 #if ENABLE_FEATURE_IFUPDOWN_IP
     426
     427static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec)
     428{
     429# if ENABLE_FEATURE_IFUPDOWN_IP
    400430    int result;
    401431    result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
    402432    result += execute("ip link set %iface% up", ifd, exec);
    403433    return ((result == 2) ? 2 : 0);
    404 #else
     434# else
    405435    return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
    406 #endif
    407 }
    408 
    409 static int loopback_down(struct interface_defn_t *ifd, execfn *exec)
    410 {
    411 #if ENABLE_FEATURE_IFUPDOWN_IP
     436# endif
     437}
     438
     439static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec)
     440{
     441# if ENABLE_FEATURE_IFUPDOWN_IP
    412442    int result;
    413443    result = execute("ip addr flush dev %iface%", ifd, exec);
    414444    result += execute("ip link set %iface% down", ifd, exec);
    415445    return ((result == 2) ? 2 : 0);
    416 #else
     446# else
    417447    return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
    418 #endif
    419 }
    420 
    421 static int static_up(struct interface_defn_t *ifd, execfn *exec)
     448# endif
     449}
     450
     451static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
    422452{
    423453    int result;
    424 #if ENABLE_FEATURE_IFUPDOWN_IP
     454# if ENABLE_FEATURE_IFUPDOWN_IP
    425455    result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
    426456            "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
    427     result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
     457    result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
    428458    result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
    429459    return ((result == 3) ? 3 : 0);
    430 #else
     460# else
    431461    /* ifconfig said to set iface up before it processes hw %hwaddress%,
    432462     * which then of course fails. Thus we run two separate ifconfig */
     
    438468    result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
    439469    return ((result == 3) ? 3 : 0);
    440 #endif
    441 }
    442 
    443 static int static_down(struct interface_defn_t *ifd, execfn *exec)
     470# endif
     471}
     472
     473static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec)
    444474{
    445475    int result;
    446 #if ENABLE_FEATURE_IFUPDOWN_IP
     476# if ENABLE_FEATURE_IFUPDOWN_IP
    447477    result = execute("ip addr flush dev %iface%", ifd, exec);
    448478    result += execute("ip link set %iface% down", ifd, exec);
    449 #else
    450     result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec);
     479# else
     480    /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */
     481    /* Bringing the interface down deletes the routes in itself.
     482       Otherwise this fails if we reference 'gateway' when using this from dhcp_down */
     483    result = 1;
    451484    result += execute("ifconfig %iface% down", ifd, exec);
    452 #endif
     485# endif
    453486    return ((result == 2) ? 2 : 0);
    454487}
    455488
    456 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
    457 struct dhcp_client_t
    458 {
     489# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     490struct dhcp_client_t {
    459491    const char *name;
    460492    const char *startcmd;
     
    464496static const struct dhcp_client_t ext_dhcp_clients[] = {
    465497    { "dhcpcd",
    466         "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",
     498        "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %client%]][[ -l %leasetime%]] %iface%",
    467499        "dhcpcd -k %iface%",
    468500    },
     
    476508    },
    477509    { "udhcpc",
    478         "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
     510        "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %client%]]"
     511                "[[ -s %script%]][[ %udhcpc_opts%]]",
    479512        "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
    480513    },
    481514};
    482 #endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
    483 
    484 static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
    485 {
    486 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
    487     int i;
    488 #if ENABLE_FEATURE_IFUPDOWN_IP
     515# endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
     516
     517# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     518static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
     519{
     520    unsigned i;
     521#  if ENABLE_FEATURE_IFUPDOWN_IP
    489522    /* ip doesn't up iface when it configures it (unlike ifconfig) */
    490     if (!execute("ip link set %iface% up", ifd, exec))
     523    if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
    491524        return 0;
    492 #endif
     525#  else
     526    /* needed if we have hwaddress on dhcp iface */
     527    if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
     528        return 0;
     529#  endif
    493530    for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
    494531        if (exists_execable(ext_dhcp_clients[i].name))
     
    497534    bb_error_msg("no dhcp clients found");
    498535    return 0;
    499 #elif ENABLE_APP_UDHCPC
    500 #if ENABLE_FEATURE_IFUPDOWN_IP
     536}
     537# elif ENABLE_UDHCPC
     538static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
     539{
     540#  if ENABLE_FEATURE_IFUPDOWN_IP
    501541    /* ip doesn't up iface when it configures it (unlike ifconfig) */
    502     if (!execute("ip link set %iface% up", ifd, exec))
     542    if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
    503543        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%]]",
     544#  else
     545    /* needed if we have hwaddress on dhcp iface */
     546    if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
     547        return 0;
     548#  endif
     549    return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid "
     550            "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]",
    507551            ifd, exec);
    508 #else
     552}
     553# else
     554static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM,
     555        execfn *exec UNUSED_PARAM)
     556{
    509557    return 0; /* no dhcp support */
    510 #endif
    511 }
    512 
    513 static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
    514 {
    515 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
    516     int i;
     558}
     559# endif
     560
     561# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     562static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
     563{
     564    int result = 0;
     565    unsigned i;
     566
    517567    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
     568        if (exists_execable(ext_dhcp_clients[i].name)) {
     569            result = execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
     570            if (result)
     571                break;
     572        }
     573    }
     574
     575    if (!result)
     576        bb_error_msg("warning: no dhcp clients found and stopped");
     577
     578    /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
     579       and it may come back up because udhcpc is still shutting down */
     580    usleep(100000);
     581    result += static_down(ifd, exec);
     582    return ((result == 3) ? 3 : 0);
     583}
     584# elif ENABLE_UDHCPC
     585static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
     586{
     587    int result;
     588    result = execute(
     589        "test -f /var/run/udhcpc.%iface%.pid && "
     590        "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
     591        ifd, exec);
     592    /* Also bring the hardware interface down since
     593       killing the dhcp client alone doesn't do it.
     594       This enables consecutive ifup->ifdown->ifup */
     595    /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
     596       and it may come back up because udhcpc is still shutting down */
     597    usleep(100000);
     598    result += static_down(ifd, exec);
     599    return ((result == 3) ? 3 : 0);
     600}
     601# else
     602static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM,
     603        execfn *exec UNUSED_PARAM)
     604{
    527605    return 0; /* no dhcp support */
    528 #endif
    529 }
    530 
    531 static int manual_up_down(struct interface_defn_t *ifd, execfn *exec)
     606}
     607# endif
     608
     609static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
    532610{
    533611    return 1;
    534612}
    535613
    536 static int bootp_up(struct interface_defn_t *ifd, execfn *exec)
     614static int FAST_FUNC bootp_up(struct interface_defn_t *ifd, execfn *exec)
    537615{
    538616    return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
     
    541619}
    542620
    543 static int ppp_up(struct interface_defn_t *ifd, execfn *exec)
     621static int FAST_FUNC ppp_up(struct interface_defn_t *ifd, execfn *exec)
    544622{
    545623    return execute("pon[[ %provider%]]", ifd, exec);
    546624}
    547625
    548 static int ppp_down(struct interface_defn_t *ifd, execfn *exec)
     626static int FAST_FUNC ppp_down(struct interface_defn_t *ifd, execfn *exec)
    549627{
    550628    return execute("poff[[ %provider%]]", ifd, exec);
    551629}
    552630
    553 static int wvdial_up(struct interface_defn_t *ifd, execfn *exec)
     631static int FAST_FUNC wvdial_up(struct interface_defn_t *ifd, execfn *exec)
    554632{
    555633    return execute("start-stop-daemon --start -x wvdial "
     
    557635}
    558636
    559 static int wvdial_down(struct interface_defn_t *ifd, execfn *exec)
     637static int FAST_FUNC wvdial_down(struct interface_defn_t *ifd, execfn *exec)
    560638{
    561639    return execute("start-stop-daemon --stop -x wvdial "
     
    564642
    565643static const struct method_t methods[] = {
    566     { "manual", manual_up_down, manual_up_down, },
    567     { "wvdial", wvdial_up, wvdial_down, },
    568     { "ppp", ppp_up, ppp_down, },
    569     { "static", static_up, static_down, },
    570     { "bootp", bootp_up, static_down, },
    571     { "dhcp", dhcp_up, dhcp_down, },
    572     { "loopback", loopback_up, loopback_down, },
     644    { "manual"  , manual_up_down, manual_up_down, },
     645    { "wvdial"  , wvdial_up     , wvdial_down   , },
     646    { "ppp"     , ppp_up        , ppp_down      , },
     647    { "static"  , static_up     , static_down   , },
     648    { "bootp"   , bootp_up      , static_down   , },
     649    { "dhcp"    , dhcp_up       , dhcp_down     , },
     650    { "loopback", loopback_up   , loopback_down , },
    573651};
    574652
     
    579657};
    580658
    581 #endif  /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */
    582 
     659#endif  /* FEATURE_IFUPDOWN_IPV4 */
     660
     661
     662/* Returns pointer to the next word, or NULL.
     663 * In 1st case, advances *buf to the word after this one.
     664 */
    583665static char *next_word(char **buf)
    584666{
    585     unsigned short length;
     667    unsigned length;
    586668    char *word;
    587 
    588     if (!buf || !*buf || !**buf) {
    589         return NULL;
    590     }
    591669
    592670    /* Skip over leading whitespace */
    593671    word = skip_whitespace(*buf);
    594672
    595     /* Skip over comments */
    596     if (*word == '#') {
     673    /* Stop on EOL */
     674    if (*word == '\0')
    597675        return NULL;
    598     }
    599 
    600     /* Find the length of this word */
     676
     677    /* Find the length of this word (can't be 0) */
    601678    length = strcspn(word, " \t\n");
    602     if (length == 0) {
    603         return NULL;
    604     }
    605     *buf = word + length;
    606     /*DBU:[dave@cray.com] if we are already at EOL dont't increment beyond it */
    607     if (**buf) {
    608         **buf = '\0';
    609         (*buf)++;
    610     }
     679
     680    /* Unless we are already at NUL, store NUL and advance */
     681    if (word[length] != '\0')
     682        word[length++] = '\0';
     683
     684    *buf = skip_whitespace(word + length);
    611685
    612686    return word;
     
    634708    if (!name)
    635709        return NULL;
    636 
     710    /* TODO: use index_in_str_array() */
    637711    for (i = 0; i < af->n_methods; i++) {
    638712        if (strcmp(af->method[i].name, name) == 0) {
     
    643717}
    644718
    645 static const llist_t *find_list_string(const llist_t *list, const char *string)
    646 {
    647     if (string == NULL)
    648         return NULL;
    649 
    650     while (list) {
    651         if (strcmp(list->data, string) == 0) {
    652             return list;
    653         }
    654         list = list->link;
    655     }
    656     return NULL;
    657 }
    658 
    659719static struct interfaces_file_t *read_interfaces(const char *filename)
    660720{
     721    /* Let's try to be compatible.
     722     *
     723     * "man 5 interfaces" says:
     724     * Lines starting with "#" are ignored. Note that end-of-line
     725     * comments are NOT supported, comments must be on a line of their own.
     726     * A line may be extended across multiple lines by making
     727     * the last character a backslash.
     728     *
     729     * Seen elsewhere in example config file:
     730     * A first non-blank "#" character makes the rest of the line
     731     * be ignored. Blank lines are ignored. Lines may be indented freely.
     732     * A "\" character at the very end of the line indicates the next line
     733     * should be treated as a continuation of the current one.
     734     */
    661735#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    662736    struct mapping_defn_t *currmap = NULL;
     
    665739    struct interfaces_file_t *defn;
    666740    FILE *f;
    667     char *firstword;
    668741    char *buf;
    669 
     742    char *first_word;
     743    char *rest_of_line;
    670744    enum { NONE, IFACE, MAPPING } currently_processing = NONE;
    671745
    672     defn = xzalloc(sizeof(struct interfaces_file_t));
    673 
    674     f = xfopen(filename, "r");
    675 
    676     while ((buf = xmalloc_getline(f)) != NULL) {
    677         char *buf_ptr = buf;
    678 
    679         firstword = next_word(&buf_ptr);
    680         if (firstword == NULL) {
     746    defn = xzalloc(sizeof(*defn));
     747    f = xfopen_for_read(filename);
     748
     749    while ((buf = xmalloc_fgetline(f)) != NULL) {
     750#if ENABLE_DESKTOP
     751        /* Trailing "\" concatenates lines */
     752        char *p;
     753        while ((p = last_char_is(buf, '\\')) != NULL) {
     754            *p = '\0';
     755            rest_of_line = xmalloc_fgetline(f);
     756            if (!rest_of_line)
     757                break;
     758            p = xasprintf("%s%s", buf, rest_of_line);
    681759            free(buf);
    682             continue;   /* blank line */
    683         }
    684 
    685         if (strcmp(firstword, "mapping") == 0) {
     760            free(rest_of_line);
     761            buf = p;
     762        }
     763#endif
     764        rest_of_line = buf;
     765        first_word = next_word(&rest_of_line);
     766        if (!first_word || *first_word == '#') {
     767            free(buf);
     768            continue; /* blank/comment line */
     769        }
     770
     771        if (strcmp(first_word, "mapping") == 0) {
    686772#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    687             currmap = xzalloc(sizeof(struct mapping_defn_t));
    688 
    689             while ((firstword = next_word(&buf_ptr)) != NULL) {
    690                 if (currmap->max_matches == currmap->n_matches) {
    691                     currmap->max_matches = currmap->max_matches * 2 + 1;
    692                     currmap->match = xrealloc(currmap->match, sizeof(currmap->match) * currmap->max_matches);
    693                 }
    694 
    695                 currmap->match[currmap->n_matches++] = xstrdup(firstword);
    696             }
    697             currmap->max_mappings = 0;
    698             currmap->n_mappings = 0;
    699             currmap->mapping = NULL;
    700             currmap->script = NULL;
     773            currmap = xzalloc(sizeof(*currmap));
     774
     775            while ((first_word = next_word(&rest_of_line)) != NULL) {
     776                currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches);
     777                currmap->match[currmap->n_matches++] = xstrdup(first_word);
     778            }
     779            /*currmap->max_mappings = 0; - done by xzalloc */
     780            /*currmap->n_mappings = 0;*/
     781            /*currmap->mapping = NULL;*/
     782            /*currmap->script = NULL;*/
    701783            {
    702784                struct mapping_defn_t **where = &defn->mappings;
     
    705787                }
    706788                *where = currmap;
    707                 currmap->next = NULL;
     789                /*currmap->next = NULL;*/
    708790            }
    709791            debug_noise("Added mapping\n");
    710792#endif
    711793            currently_processing = MAPPING;
    712         } else if (strcmp(firstword, "iface") == 0) {
     794        } else if (strcmp(first_word, "iface") == 0) {
    713795            static const struct address_family_t *const addr_fams[] = {
    714796#if ENABLE_FEATURE_IFUPDOWN_IPV4
     
    720802                NULL
    721803            };
    722 
    723804            char *iface_name;
    724805            char *address_family_name;
     
    726807            llist_t *iface_list;
    727808
    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             }
     809            currif = xzalloc(sizeof(*currif));
     810            iface_name = next_word(&rest_of_line);
     811            address_family_name = next_word(&rest_of_line);
     812            method_name = next_word(&rest_of_line);
     813
     814            if (method_name == NULL)
     815                bb_error_msg_and_die("too few parameters for line \"%s\"", buf);
    737816
    738817            /* 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             }
     818            rest_of_line = skip_whitespace(rest_of_line);
     819
     820            if (rest_of_line[0] != '\0' /* && rest_of_line[0] != '#' */)
     821                bb_error_msg_and_die("too many parameters \"%s\"", buf);
    745822
    746823            currif->iface = xstrdup(iface_name);
    747824
    748825            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             }
     826            if (!currif->address_family)
     827                bb_error_msg_and_die("unknown address type \"%s\"", address_family_name);
    753828
    754829            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             }
     830            if (!currif->method)
     831                bb_error_msg_and_die("unknown method \"%s\"", method_name);
    759832
    760833            for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
    761834                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);
    765                     return NULL;
     835                if ((strcmp(tmp->iface, currif->iface) == 0)
     836                 && (tmp->address_family == currif->address_family)
     837                ) {
     838                    bb_error_msg_and_die("duplicate interface \"%s\"", tmp->iface);
    766839                }
    767840            }
     
    770843            debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
    771844            currently_processing = IFACE;
    772         } else if (strcmp(firstword, "auto") == 0) {
    773             while ((firstword = next_word(&buf_ptr)) != NULL) {
     845        } else if (strcmp(first_word, "auto") == 0) {
     846            while ((first_word = next_word(&rest_of_line)) != NULL) {
    774847
    775848                /* Check the interface isnt already listed */
    776                 if (find_list_string(defn->autointerfaces, firstword)) {
     849                if (llist_find_str(defn->autointerfaces, first_word)) {
    777850                    bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf);
    778851                }
    779852
    780853                /* Add the interface to the list */
    781                 llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword));
    782                 debug_noise("\nauto %s\n", firstword);
     854                llist_add_to_end(&(defn->autointerfaces), xstrdup(first_word));
     855                debug_noise("\nauto %s\n", first_word);
    783856            }
    784857            currently_processing = NONE;
     
    786859            switch (currently_processing) {
    787860            case IFACE:
    788                 {
     861                if (rest_of_line[0] == '\0')
     862                    bb_error_msg_and_die("option with empty value \"%s\"", buf);
     863
     864                if (strcmp(first_word, "up") != 0
     865                 && strcmp(first_word, "down") != 0
     866                 && strcmp(first_word, "pre-up") != 0
     867                 && strcmp(first_word, "post-down") != 0
     868                ) {
    789869                    int i;
    790 
    791                     if (strlen(buf_ptr) == 0) {
    792                         bb_error_msg("option with empty value \"%s\"", buf);
    793                         return NULL;
     870                    for (i = 0; i < currif->n_options; i++) {
     871                        if (strcmp(currif->option[i].name, first_word) == 0)
     872                            bb_error_msg_and_die("duplicate option \"%s\"", buf);
    794873                    }
    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;
    804                             }
    805                         }
    806                     }
    807874                }
    808875                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);
     876                    currif->max_options += 10;
     877                    currif->option = xrealloc(currif->option,
     878                        sizeof(*currif->option) * currif->max_options);
     879                }
     880                debug_noise("\t%s=%s\n", first_word, rest_of_line);
     881                currif->option[currif->n_options].name = xstrdup(first_word);
     882                currif->option[currif->n_options].value = xstrdup(rest_of_line);
    827883                currif->n_options++;
    828884                break;
    829885            case MAPPING:
    830886#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));
     887                if (strcmp(first_word, "script") == 0) {
     888                    if (currmap->script != NULL)
     889                        bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf);
     890                    currmap->script = xstrdup(next_word(&rest_of_line));
     891                } else if (strcmp(first_word, "map") == 0) {
     892                    if (currmap->n_mappings >= currmap->max_mappings) {
     893                        currmap->max_mappings = currmap->max_mappings * 2 + 1;
     894                        currmap->mapping = xrealloc(currmap->mapping,
     895                            sizeof(char *) * currmap->max_mappings);
    837896                    }
    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);
    842                     }
    843                     currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));
     897                    currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line));
    844898                    currmap->n_mappings++;
    845899                } else {
    846                     bb_error_msg("misplaced option \"%s\"", buf);
    847                     return NULL;
     900                    bb_error_msg_and_die("misplaced option \"%s\"", buf);
    848901                }
    849902#endif
     
    851904            case NONE:
    852905            default:
    853                 bb_error_msg("misplaced option \"%s\"", buf);
    854                 return NULL;
     906                bb_error_msg_and_die("misplaced option \"%s\"", buf);
    855907            }
    856908        }
    857909        free(buf);
    858     }
     910    } /* while (fgets) */
     911
    859912    if (ferror(f) != 0) {
    860913        /* ferror does NOT set errno! */
     
    869922{
    870923    char *result;
    871     char *here;
    872     char *there;
     924    char *dst;
     925    char *src;
     926    char c;
    873927
    874928    result = xasprintf(format, name, value);
    875929
    876     for (here = there = result; *there != '=' && *there; there++) {
    877         if (*there == '-')
    878             *there = '_';
    879         if (isalpha(*there))
    880             *there = toupper(*there);
    881 
    882         if (isalnum(*there) || *there == '_') {
    883             *here = *there;
    884             here++;
    885         }
    886     }
    887     memmove(here, there, strlen(there) + 1);
     930    for (dst = src = result; (c = *src) != '=' && c; src++) {
     931        if (c == '-')
     932            c = '_';
     933        if (c >= 'a' && c <= 'z')
     934            c -= ('a' - 'A');
     935        if (isalnum(c) || c == '_')
     936            *dst++ = c;
     937    }
     938    overlapping_strcpy(dst, src);
    888939
    889940    return result;
     
    892943static void set_environ(struct interface_defn_t *iface, const char *mode)
    893944{
    894     char **environend;
    895945    int i;
    896     const int n_env_entries = iface->n_options + 5;
    897     char **ppch;
    898 
    899     if (my_environ != NULL) {
    900         for (ppch = my_environ; *ppch; ppch++) {
    901             free(*ppch);
    902             *ppch = NULL;
    903         }
    904         free(my_environ);
    905     }
    906     my_environ = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
    907     environend = my_environ;
     946    char **pp;
     947
     948    if (G.my_environ != NULL) {
     949        for (pp = G.my_environ; *pp; pp++) {
     950            free(*pp);
     951        }
     952        free(G.my_environ);
     953    }
     954
     955    /* note: last element will stay NULL: */
     956    G.my_environ = xzalloc(sizeof(char *) * (iface->n_options + 6));
     957    pp = G.my_environ;
    908958
    909959    for (i = 0; i < iface->n_options; i++) {
     
    915965            continue;
    916966        }
    917         *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
    918     }
    919 
    920     *(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
    921     *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
    922     *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
    923     *(environend++) = setlocalenv("%s=%s", "MODE", mode);
    924     *(environend++) = setlocalenv("%s=%s", "PATH", startup_PATH);
     967        *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
     968    }
     969
     970    *pp++ = setlocalenv("%s=%s", "IFACE", iface->iface);
     971    *pp++ = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
     972    *pp++ = setlocalenv("%s=%s", "METHOD", iface->method->name);
     973    *pp++ = setlocalenv("%s=%s", "MODE", mode);
     974    if (G.startup_PATH)
     975        *pp++ = setlocalenv("%s=%s", "PATH", G.startup_PATH);
    925976}
    926977
     
    934985        int status;
    935986
    936         fflush(NULL);
    937         child = fork();
     987        fflush_all();
     988        child = vfork();
    938989        switch (child) {
    939990        case -1: /* failure */
    940991            return 0;
    941992        case 0: /* child */
    942             execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);
    943             exit(127);
    944         }
    945         waitpid(child, &status, 0);
     993            execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, (char *) NULL, G.my_environ);
     994            _exit(127);
     995        }
     996        safe_waitpid(child, &status, 0);
    946997        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
    947998            return 0;
     
    9941045
    9951046#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    996 static int popen2(FILE **in, FILE **out, char *command, ...)
    997 {
    998     va_list ap;
    999     char *argv[11] = { command };
    1000     int argc;
    1001     int infd[2], outfd[2];
     1047static int popen2(FILE **in, FILE **out, char *command, char *param)
     1048{
     1049    char *argv[3] = { command, param, NULL };
     1050    struct fd_pair infd, outfd;
    10021051    pid_t pid;
    10031052
    1004     argc = 1;
    1005     va_start(ap, command);
    1006     while ((argc < 10) && (argv[argc] = va_arg(ap, char *))) {
    1007         argc++;
    1008     }
    1009     argv[argc] = NULL;  /* make sure */
    1010     va_end(ap);
    1011 
    1012     if (pipe(infd) != 0) {
    1013         return 0;
    1014     }
    1015 
    1016     if (pipe(outfd) != 0) {
    1017         close(infd[0]);
    1018         close(infd[1]);
    1019         return 0;
    1020     }
    1021 
    1022     fflush(NULL);
    1023     switch (pid = fork()) {
    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;
    1045     }
    1046     /* unreached */
    1047 }
    1048 
    1049 static char *run_mapping(char *physical, struct mapping_defn_t * map)
     1053    xpiped_pair(infd);
     1054    xpiped_pair(outfd);
     1055
     1056    fflush_all();
     1057    pid = xvfork();
     1058
     1059    if (pid == 0) {
     1060        /* Child */
     1061        /* NB: close _first_, then move fds! */
     1062        close(infd.wr);
     1063        close(outfd.rd);
     1064        xmove_fd(infd.rd, 0);
     1065        xmove_fd(outfd.wr, 1);
     1066        BB_EXECVP_or_die(argv);
     1067    }
     1068    /* parent */
     1069    close(infd.rd);
     1070    close(outfd.wr);
     1071    *in = xfdopen_for_write(infd.wr);
     1072    *out = xfdopen_for_read(outfd.rd);
     1073    return pid;
     1074}
     1075
     1076static char *run_mapping(char *physical, struct mapping_defn_t *map)
    10501077{
    10511078    FILE *in, *out;
     
    10551082    char *logical = xstrdup(physical);
    10561083
    1057     /* Run the mapping script. */
    1058     pid = popen2(&in, &out, map->script, physical, NULL);
    1059 
    1060     /* popen2() returns 0 on failure. */
    1061     if (pid == 0)
    1062         return logical;
     1084    /* Run the mapping script. Never fails. */
     1085    pid = popen2(&in, &out, map->script, physical);
    10631086
    10641087    /* Write mappings to stdin of mapping script. */
     
    10671090    }
    10681091    fclose(in);
    1069     waitpid(pid, &status, 0);
     1092    safe_waitpid(pid, &status, 0);
    10701093
    10711094    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
     
    10731096         * grab a line of output and use that as the name of the
    10741097         * logical interface. */
    1075         char *new_logical = xmalloc(MAX_INTERFACE_LENGTH);
    1076 
    1077         if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) {
     1098        char *new_logical = xmalloc_fgetline(out);
     1099
     1100        if (new_logical) {
    10781101            /* If we are able to read a line of output from the script,
    10791102             * remove any trailing whitespace and use this value
     
    10861109            free(logical);
    10871110            logical = new_logical;
    1088         } else {
    1089             /* If we are UNABLE to read a line of output, discard our
    1090              * freshly allocated memory. */
    1091             free(new_logical);
    10921111        }
    10931112    }
     
    11011120static llist_t *find_iface_state(llist_t *state_list, const char *iface)
    11021121{
    1103     unsigned short iface_len = strlen(iface);
     1122    unsigned iface_len = strlen(iface);
    11041123    llist_t *search = state_list;
    11051124
    11061125    while (search) {
    11071126        if ((strncmp(search->data, iface, iface_len) == 0)
    1108          && (search->data[iface_len] == '=')) {
     1127         && (search->data[iface_len] == '=')
     1128        ) {
    11091129            return search;
    11101130        }
     
    11181138{
    11191139    llist_t *state_list = NULL;
    1120     FILE *state_fp = fopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "r");
     1140    FILE *state_fp = fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH);
    11211141
    11221142    if (state_fp) {
     
    11341154
    11351155
    1136 int ifupdown_main(int argc, char **argv);
    1137 int ifupdown_main(int argc, char **argv)
    1138 {
    1139     int (*cmds)(struct interface_defn_t *) = NULL;
     1156int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1157int ifupdown_main(int argc UNUSED_PARAM, char **argv)
     1158{
     1159    int (*cmds)(struct interface_defn_t *);
    11401160    struct interfaces_file_t *defn;
    11411161    llist_t *target_list = NULL;
     
    11431163    bool any_failures = 0;
    11441164
     1165    INIT_G();
     1166
     1167    G.startup_PATH = getenv("PATH");
     1168
    11451169    cmds = iface_down;
    11461170    if (applet_name[2] == 'u') {
     
    11501174
    11511175    getopt32(argv, OPTION_STR, &interfaces);
    1152     if (argc - optind > 0) {
     1176    argv += optind;
     1177    if (argv[0]) {
    11531178        if (DO_ALL) bb_show_usage();
    11541179    } else {
     
    11591184    defn = read_interfaces(interfaces);
    11601185    debug_noise("\ndone reading %s\n\n", interfaces);
    1161 
    1162     if (!defn) {
    1163         return EXIT_FAILURE;
    1164     }
    1165 
    1166     startup_PATH = getenv("PATH");
    1167     if (!startup_PATH) startup_PATH = "";
    11681186
    11691187    /* Create a list of interfaces to work on */
     
    11711189        target_list = defn->autointerfaces;
    11721190    } else {
    1173         llist_add_to_end(&target_list, argv[optind]);
     1191        llist_add_to_end(&target_list, argv[0]);
    11741192    }
    11751193
     
    11821200        char *pch;
    11831201        bool okay = 0;
    1184         unsigned cmds_ret;
     1202        int cmds_ret;
    11851203
    11861204        iface = xstrdup(target_list->data);
     
    12601278        }
    12611279        if (VERBOSE) {
    1262             puts("");
     1280            bb_putchar('\n');
    12631281        }
    12641282
     
    12881306
    12891307            /* Actually write the new state */
    1290             state_fp = xfopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "w");
     1308            state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH);
    12911309            state = state_list;
    12921310            while (state) {
  • branches/2.2.9/mindi-busybox/networking/inetd.c

    r1772 r2725  
    44/*      $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $       */
    55/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru>     */
     6/* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */
    67/*
    78 * Copyright (c) 1983,1991 The Regents of the University of California.
     
    3940/* Inetd - Internet super-server
    4041 *
    41  * This program invokes all internet services as needed.
    42  * connection-oriented services are invoked each time a
     42 * This program invokes configured services when a connection
     43 * from a peer is established or a datagram arrives.
     44 * Connection-oriented services are invoked each time a
    4345 * connection is made, by creating a process.  This process
    4446 * is passed the connection as file descriptor 0 and is
    45  * expected to do a getpeername to find out the source host
     47 * expected to do a getpeername to find out peer's host
    4648 * and port.
    47  *
    4849 * Datagram oriented services are invoked when a datagram
    4950 * arrives; a process is created and passed a pending message
    50  * on file descriptor 0.  Datagram servers may either connect
    51  * to their peer, freeing up the original socket for inetd
    52  * to receive further messages on, or "take over the socket",
    53  * 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".
     51 * on file descriptor 0. peer's address can be obtained
     52 * using recvfrom.
    5653 *
    5754 * Inetd uses a configuration file which is read at startup
     
    6158 * a space or tab.  All fields must be present in each entry.
    6259 *
    63  *      service name                    must be in /etc/services
    64  *      socket type                     stream/dgram/raw/rdm/seqpacket
     60 *      service_name                    must be in /etc/services
     61 *      socket_type                     stream/dgram/raw/rdm/seqpacket
    6562 *      protocol                        must be in /etc/protocols
     63 *                                      (usually "tcp" or "udp")
    6664 *      wait/nowait[.max]               single-threaded/multi-threaded, max #
    6765 *      user[.group] or user[:group]    user/group to run daemon as
    68  *      server program                  full path name
    69  *      server program arguments        maximum of MAXARGS (20)
     66 *      server_program                  full path name
     67 *      server_program_arguments        maximum of MAXARGS (20)
    7068 *
    7169 * For RPC services
    72  *      service name/version            must be in /etc/rpc
    73  *      socket type                     stream/dgram/raw/rdm/seqpacket
    74  *      protocol                        must be in /etc/protocols
     70 *      service_name/version            must be in /etc/rpc
     71 *      socket_type                     stream/dgram/raw/rdm/seqpacket
     72 *      rpc/protocol                    "rpc/tcp" etc
    7573 *      wait/nowait[.max]               single-threaded/multi-threaded
    7674 *      user[.group] or user[:group]    user to run daemon as
    77  *      server program                  full path name
    78  *      server program arguments        maximum of MAXARGS (20)
     75 *      server_program                  full path name
     76 *      server_program_arguments        maximum of MAXARGS (20)
    7977 *
    8078 * For non-RPC services, the "service name" can be of the form
    8179 * hostaddress:servicename, in which case the hostaddress is used
    8280 * as the host portion of the address to listen on.  If hostaddress
    83  * consists of a single `*' character, INADDR_ANY is used.
     81 * consists of a single '*' character, INADDR_ANY is used.
    8482 *
    8583 * A line can also consist of just
     
    102100 * specifiers are different.
    103101 *
    104  * Comment lines are indicated by a `#' in column 1.
     102 * Comment lines are indicated by a '#' in column 1.
    105103 */
    106104
     
    121119 * for new service requests to spawn new servers.  Datagram servers which
    122120 * 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)
     121 * said to be "single-threaded".  The comsat(8), biff(1) and talkd(8)
    124122 * utilities are both examples of the latter type of datagram server.  The
    125123 * tftpd(8) utility is an example of a multi-threaded datagram server.
     
    135133 */
    136134
    137 /* Here's the scoop concerning the user[.:]group feature:
    138  *
    139  * 1) set-group-option off.
    140  *
     135/* Despite of above doc saying that dgram services must use "wait",
     136 * "udp nowait" servers are implemented in busyboxed inetd.
     137 * IPv6 addresses are also implemented. However, they may look ugly -
     138 * ":::service..." means "address '::' (IPv6 wildcard addr)":"service"...
     139 * You have to put "tcp6"/"udp6" in protocol field to select IPv6.
     140 */
     141
     142/* Here's the scoop concerning the user[:group] feature:
     143 * 1) group is not specified:
    141144 *      a) user = root: NO setuid() or setgid() is done
    142  *
    143  *      b) other:       setgid(primary group as found in passwd)
    144  *                      initgroups(name, primary group)
     145 *      b) other:       initgroups(name, primary group)
     146 *                      setgid(primary group as found in passwd)
    145147 *                      setuid()
    146  *
    147  * 2) set-group-option on.
    148  *
     148 * 2) group is specified:
    149149 *      a) user = root: setgid(specified group)
    150150 *                      NO initgroups()
    151151 *                      NO setuid()
    152  *
    153  *      b) other:       setgid(specified group)
    154  *                      initgroups(name, specified group)
     152 *      b) other:       initgroups(name, specified group)
     153 *                      setgid(specified group)
    155154 *                      setuid()
    156155 */
    157156
    158 #include "libbb.h"
    159157#include <syslog.h>
    160158#include <sys/un.h>
    161159
    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
     160#include "libbb.h"
    169161
    170162#if ENABLE_FEATURE_INETD_RPC
     
    173165#endif
    174166
    175 extern char **environ;
    176 
     167#if !BB_MMU
     168/* stream version of chargen is forking but not execing,
     169 * can't do that (easily) on NOMMU */
     170#undef  ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     171#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
     172#endif
    177173
    178174#define _PATH_INETDPID  "/var/run/inetd.pid"
    179175
    180 #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
    181 #define RETRYTIME       (60*10)         /* retry after bind or server fail */
     176#define CNT_INTERVAL    60      /* servers in CNT_INTERVAL sec. */
     177#define RETRYTIME       60      /* retry after bind or server fail */
     178
     179// TODO: explain, or get rid of setrlimit games
    182180
    183181#ifndef RLIMIT_NOFILE
     
    191189/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
    192190#define FD_MARGIN       8
    193 static rlim_t rlim_ofile_cur = OPEN_MAX;
    194 static struct rlimit rlim_ofile;
    195 
    196 
    197 /* Check unsupporting builtin */
    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
    203 # define INETD_FEATURE_ENABLED
    204 #endif
    205 
    206 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    207     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
    208     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    209 # define INETD_SETPROCTITLE
    210 #endif
    211 
    212 typedef 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 */
     191
     192#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD \
     193 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO    \
     194 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN \
     195 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME    \
     196 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     197# define INETD_BUILTINS_ENABLED
     198#endif
     199
     200typedef struct servtab_t {
     201    /* The most frequently referenced one: */
     202    int se_fd;                            /* open descriptor */
     203    /* NB: 'biggest fields last' saves on code size (~250 bytes) */
     204    /* [addr:]service socktype proto wait user[:group] prog [args] */
     205    char *se_local_hostname;              /* addr to listen on */
     206    char *se_service;                     /* "80" or "www" or "mount/2[-3]" */
     207    /* socktype is in se_socktype */      /* "stream" "dgram" "raw" "rdm" "seqpacket" */
     208    char *se_proto;                       /* "unix" or "[rpc/]tcp[6]" */
    218209#if ENABLE_FEATURE_INETD_RPC
    219210    int se_rpcprog;                       /* rpc program number */
    220     int se_rpcversl;                      /* rpc program lowest version */
    221     int se_rpcversh;                      /* rpc program highest version */
    222 #define isrpcservice(sep)       ((sep)->se_rpcversl != 0)
     211    int se_rpcver_lo;                     /* rpc program lowest version */
     212    int se_rpcver_hi;                     /* rpc program highest version */
     213#define is_rpc_service(sep)       ((sep)->se_rpcver_lo != 0)
    223214#else
    224 #define isrpcservice(sep)       0
    225 #endif
    226     pid_t se_wait;                        /* single threaded server */
    227     short se_checked;                     /* looked at during merge */
     215#define is_rpc_service(sep)       0
     216#endif
     217    pid_t se_wait;                        /* 0:"nowait", 1:"wait", >1:"wait" */
     218                                          /* and waiting for this pid */
     219    socktype_t se_socktype;               /* SOCK_STREAM/DGRAM/RDM/... */
     220    family_t se_family;                   /* AF_UNIX/INET[6] */
     221    /* se_proto_no is used by RPC code only... hmm */
     222    smallint se_proto_no;                 /* IPPROTO_TCP/UDP, n/a for AF_UNIX */
     223    smallint se_checked;                  /* looked at during merge */
     224    unsigned se_max;                      /* allowed instances per minute */
     225    unsigned se_count;                    /* number started since se_time */
     226    unsigned se_time;                     /* when we started counting */
    228227    char *se_user;                        /* user name to run as */
    229     char *se_group;                       /* group name to run as */
    230 #ifdef INETD_FEATURE_ENABLED
    231     const struct builtin *se_bi;          /* if built-in, description */
    232 #endif
    233     char *se_server;                      /* server program */
     228    char *se_group;                       /* group name to run as, can be NULL */
     229#ifdef INETD_BUILTINS_ENABLED
     230    const struct builtin *se_builtin;     /* if built-in, description */
     231#endif
     232    struct servtab_t *se_next;
     233    len_and_sockaddr *se_lsa;
     234    char *se_program;                     /* server program */
    234235#define MAXARGV 20
    235236    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 */
    245 #define se_ctrladdr     se_un.se_un_ctrladdr
    246 #define se_ctrladdr_in  se_un.se_un_ctrladdr_in
    247 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
    248 #define se_ctrladdr_un  se_un.se_un_ctrladdr_un
    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;
    254237} servtab_t;
    255238
    256 static servtab_t *servtab;
    257 
    258 #ifdef INETD_FEATURE_ENABLED
     239#ifdef INETD_BUILTINS_ENABLED
     240/* Echo received data */
     241#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     242static void FAST_FUNC echo_stream(int, servtab_t *);
     243static void FAST_FUNC echo_dg(int, servtab_t *);
     244#endif
     245/* Internet /dev/null */
     246#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     247static void FAST_FUNC discard_stream(int, servtab_t *);
     248static void FAST_FUNC discard_dg(int, servtab_t *);
     249#endif
     250/* Return 32 bit time since 1900 */
     251#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     252static void FAST_FUNC machtime_stream(int, servtab_t *);
     253static void FAST_FUNC machtime_dg(int, servtab_t *);
     254#endif
     255/* Return human-readable time */
     256#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     257static void FAST_FUNC daytime_stream(int, servtab_t *);
     258static void FAST_FUNC daytime_dg(int, servtab_t *);
     259#endif
     260/* Familiar character generator */
     261#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     262static void FAST_FUNC chargen_stream(int, servtab_t *);
     263static void FAST_FUNC chargen_dg(int, servtab_t *);
     264#endif
     265
    259266struct 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 *);
     267    /* NB: not necessarily NUL terminated */
     268    char bi_service7[7];      /* internally provided service name */
     269    uint8_t bi_fork;          /* 1 if stream fn should run in child */
     270    void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC;
     271    void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC;
    265272};
    266 
    267         /* Echo received data */
    268 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    269 static void echo_stream(int, servtab_t *);
    270 static void echo_dg(int, servtab_t *);
    271 #endif
    272         /* Internet /dev/null */
    273 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    274 static void discard_stream(int, servtab_t *);
    275 static void discard_dg(int, servtab_t *);
    276 #endif
    277         /* Return 32 bit time since 1900 */
    278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    279 static void machtime_stream(int, servtab_t *);
    280 static void machtime_dg(int, servtab_t *);
    281 #endif
    282         /* Return human-readable time */
    283 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    284 static void daytime_stream(int, servtab_t *);
    285 static void daytime_dg(int, servtab_t *);
    286 #endif
    287         /* Familiar character generator */
    288 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    289 static void chargen_stream(int, servtab_t *);
    290 static void chargen_dg(int, servtab_t *);
    291 #endif
    292273
    293274static const struct builtin builtins[] = {
    294275#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    295     /* Echo received data */
    296     {"echo", SOCK_STREAM, 1, 0, echo_stream,},
    297     {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
     276    { "echo", 1, echo_stream, echo_dg },
    298277#endif
    299278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    300     /* Internet /dev/null */
    301     {"discard", SOCK_STREAM, 1, 0, discard_stream,},
    302     {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
     279    { "discard", 1, discard_stream, discard_dg },
     280#endif
     281#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     282    { "chargen", 1, chargen_stream, chargen_dg },
    303283#endif
    304284#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    305     /* Return 32 bit time since 1900 */
    306     {"time", SOCK_STREAM, 0, 0, machtime_stream,},
    307     {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
     285    { "time", 0, machtime_stream, machtime_dg },
    308286#endif
    309287#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    310     /* Return human-readable time */
    311     {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
    312     {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
    313 #endif
     288    { "daytime", 0, daytime_stream, daytime_dg },
     289#endif
     290};
     291#endif /* INETD_BUILTINS_ENABLED */
     292
     293struct globals {
     294    rlim_t rlim_ofile_cur;
     295    struct rlimit rlim_ofile;
     296    servtab_t *serv_list;
     297    int global_queuelen;
     298    int maxsock;         /* max fd# in allsock, -1: unknown */
     299    /* whenever maxsock grows, prev_maxsock is set to new maxsock,
     300     * but if maxsock is set to -1, prev_maxsock is not changed */
     301    int prev_maxsock;
     302    unsigned max_concurrency;
     303    smallint alarm_armed;
     304    uid_t real_uid; /* user ID who ran us */
     305    const char *config_filename;
     306    parser_t *parser;
     307    char *default_local_hostname;
    314308#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    315     /* Familiar character generator */
    316     {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
    317     {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
    318 #endif
    319     {NULL, 0, 0, 0, NULL}
     309    char *end_ring;
     310    char *ring_pos;
     311    char ring[128];
     312#endif
     313    fd_set allsock;
     314    /* Used in next_line(), and as scratch read buffer */
     315    char line[256];          /* _at least_ 256, see LINE_SIZE */
     316} FIX_ALIASING;
     317#define G (*(struct globals*)&bb_common_bufsiz1)
     318enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) };
     319struct BUG_G_too_big {
     320    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
    320321};
    321 #endif /* INETD_FEATURE_ENABLED */
    322 
    323 static int global_queuelen = 128;
    324 static int nsock, maxsock;
    325 static fd_set allsock;
    326 static int toomany;
    327 static int timingout;
    328 static struct servent *sp;
    329 static uid_t uid;
    330 
    331 static const char *config_filename = "/etc/inetd.conf";
    332 
    333 static FILE *fconfig;
    334 static char *defhost;
    335 
    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  */
    340 static char *xxstrdup(char *cp)
    341 {
    342     return xstrdup(cp ? cp : "");
    343 }
    344 
    345 static 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 
    357 static void endconfig(void)
    358 {
    359     if (fconfig) {
    360         (void) fclose(fconfig);
    361         fconfig = NULL;
    362     }
    363     free(defhost);
    364     defhost = 0;
     322#define rlim_ofile_cur  (G.rlim_ofile_cur )
     323#define rlim_ofile      (G.rlim_ofile     )
     324#define serv_list       (G.serv_list      )
     325#define global_queuelen (G.global_queuelen)
     326#define maxsock         (G.maxsock        )
     327#define prev_maxsock    (G.prev_maxsock   )
     328#define max_concurrency (G.max_concurrency)
     329#define alarm_armed     (G.alarm_armed    )
     330#define real_uid        (G.real_uid       )
     331#define config_filename (G.config_filename)
     332#define parser          (G.parser         )
     333#define default_local_hostname (G.default_local_hostname)
     334#define first_ps_byte   (G.first_ps_byte  )
     335#define last_ps_byte    (G.last_ps_byte   )
     336#define end_ring        (G.end_ring       )
     337#define ring_pos        (G.ring_pos       )
     338#define ring            (G.ring           )
     339#define allsock         (G.allsock        )
     340#define line            (G.line           )
     341#define INIT_G() do { \
     342    rlim_ofile_cur = OPEN_MAX; \
     343    global_queuelen = 128; \
     344    config_filename = "/etc/inetd.conf"; \
     345} while (0)
     346
     347static void maybe_close(int fd)
     348{
     349    if (fd >= 0)
     350        close(fd);
     351}
     352
     353// TODO: move to libbb?
     354static len_and_sockaddr *xzalloc_lsa(int family)
     355{
     356    len_and_sockaddr *lsa;
     357    int sz;
     358
     359    sz = sizeof(struct sockaddr_in);
     360    if (family == AF_UNIX)
     361        sz = sizeof(struct sockaddr_un);
     362#if ENABLE_FEATURE_IPV6
     363    if (family == AF_INET6)
     364        sz = sizeof(struct sockaddr_in6);
     365#endif
     366    lsa = xzalloc(LSA_LEN_SIZE + sz);
     367    lsa->len = sz;
     368    lsa->u.sa.sa_family = family;
     369    return lsa;
     370}
     371
     372static void rearm_alarm(void)
     373{
     374    if (!alarm_armed) {
     375        alarm_armed = 1;
     376        alarm(RETRYTIME);
     377    }
     378}
     379
     380static void block_CHLD_HUP_ALRM(sigset_t *m)
     381{
     382    sigemptyset(m);
     383    sigaddset(m, SIGCHLD);
     384    sigaddset(m, SIGHUP);
     385    sigaddset(m, SIGALRM);
     386    sigprocmask(SIG_BLOCK, m, m); /* old sigmask is stored in m */
     387}
     388
     389static void restore_sigmask(sigset_t *m)
     390{
     391    sigprocmask(SIG_SETMASK, m, NULL);
    365392}
    366393
     
    370397    int n;
    371398    struct sockaddr_in ir_sin;
    372     struct protoent *pp;
    373399    socklen_t size;
    374400
    375     if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) {
    376         bb_perror_msg("%s: getproto", sep->se_proto);
     401    size = sizeof(ir_sin);
     402    if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
     403        bb_perror_msg("getsockname");
    377404        return;
    378405    }
    379     size = sizeof ir_sin;
    380     if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
    381         bb_perror_msg("%s/%s: getsockname",
     406
     407    for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
     408        pmap_unset(sep->se_rpcprog, n);
     409        if (!pmap_set(sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port)))
     410            bb_perror_msg("%s %s: pmap_set(%u,%u,%u,%u)",
     411                sep->se_service, sep->se_proto,
     412                sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port));
     413    }
     414}
     415
     416static void unregister_rpc(servtab_t *sep)
     417{
     418    int n;
     419
     420    for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
     421        if (!pmap_unset(sep->se_rpcprog, n))
     422            bb_perror_msg("pmap_unset(%u,%u)", sep->se_rpcprog, n);
     423    }
     424}
     425#endif /* FEATURE_INETD_RPC */
     426
     427static void bump_nofile(void)
     428{
     429    enum { FD_CHUNK = 32 };
     430    struct rlimit rl;
     431
     432    /* Never fails under Linux (except if you pass it bad arguments) */
     433    getrlimit(RLIMIT_NOFILE, &rl);
     434    rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
     435    rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
     436    if (rl.rlim_cur <= rlim_ofile_cur) {
     437        bb_error_msg("can't extend file limit, max = %d",
     438                        (int) rl.rlim_cur);
     439        return;
     440    }
     441
     442    if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
     443        bb_perror_msg("setrlimit");
     444        return;
     445    }
     446
     447    rlim_ofile_cur = rl.rlim_cur;
     448}
     449
     450static void remove_fd_from_set(int fd)
     451{
     452    if (fd >= 0) {
     453        FD_CLR(fd, &allsock);
     454        maxsock = -1;
     455    }
     456}
     457
     458static void add_fd_to_set(int fd)
     459{
     460    if (fd >= 0) {
     461        FD_SET(fd, &allsock);
     462        if (maxsock >= 0 && fd > maxsock) {
     463            prev_maxsock = maxsock = fd;
     464            if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
     465                bump_nofile();
     466        }
     467    }
     468}
     469
     470static void recalculate_maxsock(void)
     471{
     472    int fd = 0;
     473
     474    /* We may have no services, in this case maxsock should still be >= 0
     475     * (code elsewhere is not happy with maxsock == -1) */
     476    maxsock = 0;
     477    while (fd <= prev_maxsock) {
     478        if (FD_ISSET(fd, &allsock))
     479            maxsock = fd;
     480        fd++;
     481    }
     482    prev_maxsock = maxsock;
     483    if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
     484        bump_nofile();
     485}
     486
     487static void prepare_socket_fd(servtab_t *sep)
     488{
     489    int r, fd;
     490
     491    fd = socket(sep->se_family, sep->se_socktype, 0);
     492    if (fd < 0) {
     493        bb_perror_msg("socket");
     494        return;
     495    }
     496    setsockopt_reuseaddr(fd);
     497
     498#if ENABLE_FEATURE_INETD_RPC
     499    if (is_rpc_service(sep)) {
     500        struct passwd *pwd;
     501
     502        /* zero out the port for all RPC services; let bind()
     503         * find one. */
     504        set_nport(sep->se_lsa, 0);
     505
     506        /* for RPC services, attempt to use a reserved port
     507         * if they are going to be running as root. */
     508        if (real_uid == 0 && sep->se_family == AF_INET
     509         && (pwd = getpwnam(sep->se_user)) != NULL
     510         && pwd->pw_uid == 0
     511        ) {
     512            r = bindresvport(fd, &sep->se_lsa->u.sin);
     513        } else {
     514            r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
     515        }
     516        if (r == 0) {
     517            int saveerrno = errno;
     518            /* update lsa with port# */
     519            getsockname(fd, &sep->se_lsa->u.sa, &sep->se_lsa->len);
     520            errno = saveerrno;
     521        }
     522    } else
     523#endif
     524    {
     525        if (sep->se_family == AF_UNIX) {
     526            struct sockaddr_un *sun;
     527            sun = (struct sockaddr_un*)&(sep->se_lsa->u.sa);
     528            unlink(sun->sun_path);
     529        }
     530        r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
     531    }
     532    if (r < 0) {
     533        bb_perror_msg("%s/%s: bind",
    382534                sep->se_service, sep->se_proto);
     535        close(fd);
     536        rearm_alarm();
    383537        return;
    384538    }
    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 
    395 static 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 
    406 static void freeconfig(servtab_t *cp)
     539    if (sep->se_socktype == SOCK_STREAM)
     540        listen(fd, global_queuelen);
     541
     542    add_fd_to_set(fd);
     543    sep->se_fd = fd;
     544}
     545
     546static int reopen_config_file(void)
     547{
     548    free(default_local_hostname);
     549    default_local_hostname = xstrdup("*");
     550    if (parser != NULL)
     551        config_close(parser);
     552    parser = config_open(config_filename);
     553    return (parser != NULL);
     554}
     555
     556static void close_config_file(void)
     557{
     558    if (parser) {
     559        config_close(parser);
     560        parser = NULL;
     561    }
     562}
     563
     564static void free_servtab_strings(servtab_t *cp)
    407565{
    408566    int i;
    409567
    410     free(cp->se_hostaddr);
     568    free(cp->se_local_hostname);
    411569    free(cp->se_service);
    412570    free(cp->se_proto);
    413571    free(cp->se_user);
    414572    free(cp->se_group);
    415     free(cp->se_server);
     573    free(cp->se_lsa); /* not a string in fact */
     574    free(cp->se_program);
    416575    for (i = 0; i < MAXARGV; i++)
    417576        free(cp->se_argv[i]);
    418577}
    419578
    420 static int bump_nofile(void)
    421 {
    422 #define FD_CHUNK        32
    423 
    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 
    447 static 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 
    511 static 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 
    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         /* 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 
    567579static servtab_t *new_servtab(void)
    568580{
    569     return xmalloc(sizeof(servtab_t));
    570 }
    571 
    572 static servtab_t *dupconfig(servtab_t *sep)
     581    servtab_t *newtab = xzalloc(sizeof(servtab_t));
     582    newtab->se_fd = -1; /* paranoia */
     583    return newtab;
     584}
     585
     586static servtab_t *dup_servtab(servtab_t *sep)
    573587{
    574588    servtab_t *newtab;
     
    576590
    577591    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 
     592    *newtab = *sep; /* struct copy */
     593    /* deep-copying strings */
     594    newtab->se_service = xstrdup(newtab->se_service);
     595    newtab->se_proto = xstrdup(newtab->se_proto);
     596    newtab->se_user = xstrdup(newtab->se_user);
     597    newtab->se_group = xstrdup(newtab->se_group);
     598    newtab->se_program = xstrdup(newtab->se_program);
    596599    for (argc = 0; argc <= MAXARGV; argc++)
    597         newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]);
    598     newtab->se_max = sep->se_max;
     600        newtab->se_argv[argc] = xstrdup(newtab->se_argv[argc]);
     601    /* NB: se_fd, se_hostaddr and se_next are always
     602     * overwrittend by callers, so we don't bother resetting them
     603     * to NULL/0/-1 etc */
    599604
    600605    return newtab;
    601606}
    602607
    603 static servtab_t *getconfigent(void)
    604 {
     608/* gcc generates much more code if this is inlined */
     609static servtab_t *parse_one_line(void)
     610{
     611    int argc;
     612    char *token[6+MAXARGV];
     613    char *p, *arg;
     614    char *hostdelim;
    605615    servtab_t *sep;
    606     int argc;
    607     char *cp, *arg;
    608     char *hostdelim;
    609616    servtab_t *nsep;
    610     servtab_t *psep;
    611 
     617 new:
    612618    sep = new_servtab();
    613 
    614     /* memset(sep, 0, sizeof *sep); */
    615619 more:
    616     /* freeconfig(sep); */
    617 
    618     while ((cp = nextline()) && *cp == '#') /* skip comment line */;
    619     if (cp == NULL) {
    620         /* free(sep); */
     620    argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL);
     621    if (!argc) {
     622        free(sep);
    621623        return NULL;
    622624    }
    623625
    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. */
     626    /* [host:]service socktype proto wait user[:group] prog [args] */
     627    /* Check for "host:...." line */
     628    arg = token[0];
    632629    hostdelim = strrchr(arg, ':');
    633630    if (hostdelim) {
    634631        *hostdelim = '\0';
    635         sep->se_hostaddr = xstrdup(arg);
     632        sep->se_local_hostname = xstrdup(arg);
    636633        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             }
     634        if (*arg == '\0' && argc == 1) {
     635            /* Line has just "host:", change the
     636             * default host for the following lines. */
     637            free(default_local_hostname);
     638            default_local_hostname = sep->se_local_hostname;
     639            goto more;
    648640        }
    649641    } 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) {
     642        sep->se_local_hostname = xstrdup(default_local_hostname);
     643
     644    /* service socktype proto wait user[:group] prog [args] */
     645    sep->se_service = xstrdup(arg);
     646
     647    /* socktype proto wait user[:group] prog [args] */
     648    if (argc < 6) {
     649 parse_err:
     650        bb_error_msg("parse error on line %u, line is ignored",
     651                parser->lineno);
     652        free_servtab_strings(sep);
     653        /* Just "goto more" can make sep to carry over e.g.
     654         * "rpc"-ness (by having se_rpcver_lo != 0).
     655         * We will be more paranoid: */
     656        free(sep);
     657        goto new;
     658    }
     659
     660    {
     661        static const int8_t SOCK_xxx[] ALIGN1 = {
     662            -1,
     663            SOCK_STREAM, SOCK_DGRAM, SOCK_RDM,
     664            SOCK_SEQPACKET, SOCK_RAW
     665        };
     666        sep->se_socktype = SOCK_xxx[1 + index_in_strings(
     667            "stream""\0" "dgram""\0" "rdm""\0"
     668            "seqpacket""\0" "raw""\0"
     669            , token[1])];
     670    }
     671
     672    /* {unix,[rpc/]{tcp,udp}[6]} wait user[:group] prog [args] */
     673    sep->se_proto = arg = xstrdup(token[2]);
     674    if (strcmp(arg, "unix") == 0) {
    671675        sep->se_family = AF_UNIX;
    672676    } else {
     677        char *six;
    673678        sep->se_family = AF_INET;
    674         if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
     679        six = last_char_is(arg, '6');
     680        if (six) {
    675681#if ENABLE_FEATURE_IPV6
     682            *six = '\0';
    676683            sep->se_family = AF_INET6;
    677684#else
    678             bb_error_msg("%s: IPV6 not supported", sep->se_proto);
    679 #endif
    680         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
     685            bb_error_msg("%s: no support for IPv6", sep->se_proto);
     686            goto parse_err;
     687#endif
     688        }
     689        if (strncmp(arg, "rpc/", 4) == 0) {
    681690#if ENABLE_FEATURE_INETD_RPC
    682             char *p, *ccp;
    683             long l;
    684 
     691            unsigned n;
     692            arg += 4;
    685693            p = strchr(sep->se_service, '/');
    686             if (p == 0) {
    687                 bb_error_msg("%s: no rpc version", sep->se_service);
    688                 goto more;
     694            if (p == NULL) {
     695                bb_error_msg("no rpc version: '%s'", sep->se_service);
     696                goto parse_err;
    689697            }
    690698            *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;
     699            n = bb_strtou(p, &p, 10);
     700            if (n > INT_MAX) {
     701 bad_ver_spec:
     702                bb_error_msg("bad rpc version");
     703                goto parse_err;
    696704            }
    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;
     705            sep->se_rpcver_lo = sep->se_rpcver_hi = n;
     706            if (*p == '-') {
     707                p++;
     708                n = bb_strtou(p, &p, 10);
     709                if (n > INT_MAX || (int)n < sep->se_rpcver_lo)
     710                    goto bad_ver_spec;
     711                sep->se_rpcver_hi = n;
     712            }
     713            if (*p != '\0')
     714                goto bad_ver_spec;
    706715#else
    707             bb_error_msg("%s: rpc services not supported", sep->se_service);
     716            bb_error_msg("no support for rpc services");
     717            goto parse_err;
    708718#endif
    709719        }
    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));
     720        /* we don't really need getprotobyname()! */
     721        if (strcmp(arg, "tcp") == 0)
     722            sep->se_proto_no = IPPROTO_TCP; /* = 6 */
     723        if (strcmp(arg, "udp") == 0)
     724            sep->se_proto_no = IPPROTO_UDP; /* = 17 */
     725        if (six)
     726            *six = '6';
     727        if (!sep->se_proto_no) /* not tcp/udp?? */
     728            goto parse_err;
     729    }
     730
     731    /* [no]wait[.max] user[:group] prog [args] */
     732    arg = token[3];
     733    sep->se_max = max_concurrency;
     734    p = strchr(arg, '.');
     735    if (p) {
     736        *p++ = '\0';
     737        sep->se_max = bb_strtou(p, NULL, 10);
     738        if (errno)
     739            goto parse_err;
     740    }
     741    sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
     742    if (!sep->se_wait) /* "no" seen */
     743        arg += 2;
     744    if (strcmp(arg, "wait") != 0)
     745        goto parse_err;
     746
     747    /* user[:group] prog [args] */
     748    sep->se_user = xstrdup(token[4]);
    727749    arg = strchr(sep->se_user, '.');
    728750    if (arg == NULL)
     
    732754        sep->se_group = xstrdup(arg);
    733755    }
    734     /* if ((arg = skip(&cp, 1)) == NULL) */
    735     /* goto more; */
    736 
    737     arg = skip(&cp);
    738     sep->se_server = xxstrdup(arg);
    739     if (strcmp(sep->se_server, "internal") == 0) {
    740 #ifdef INETD_FEATURE_ENABLED
    741         const struct builtin *bi;
    742 
    743         for (bi = builtins; bi->bi_service; bi++)
    744             if (bi->bi_socktype == sep->se_socktype &&
    745                     strcmp(bi->bi_service, sep->se_service) == 0)
    746                 break;
    747         if (bi->bi_service == 0) {
    748             bb_error_msg("internal service %s unknown", sep->se_service);
    749             goto more;
    750         }
    751         sep->se_bi = bi;
    752         sep->se_wait = bi->bi_wait;
    753 #else
    754         bb_perror_msg("internal service %s unknown", sep->se_service);
    755         goto more;
    756 #endif
    757     }
    758 #ifdef INETD_FEATURE_ENABLED
    759         else
    760         sep->se_bi = NULL;
     756
     757    /* prog [args] */
     758    sep->se_program = xstrdup(token[5]);
     759#ifdef INETD_BUILTINS_ENABLED
     760    if (strcmp(sep->se_program, "internal") == 0
     761     && strlen(sep->se_service) <= 7
     762     && (sep->se_socktype == SOCK_STREAM
     763         || sep->se_socktype == SOCK_DGRAM)
     764    ) {
     765        unsigned i;
     766        for (i = 0; i < ARRAY_SIZE(builtins); i++)
     767            if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
     768                goto found_bi;
     769        bb_error_msg("unknown internal service %s", sep->se_service);
     770        goto parse_err;
     771 found_bi:
     772        sep->se_builtin = &builtins[i];
     773        /* stream builtins must be "nowait", dgram must be "wait" */
     774        if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
     775            goto parse_err;
     776    }
    761777#endif
    762778    argc = 0;
    763     for (; cp; arg = skip(&cp)) {
    764         if (argc < MAXARGV)
    765             sep->se_argv[argc++] = xxstrdup(arg);
    766     }
    767     while (argc <= MAXARGV)
    768         sep->se_argv[argc++] = NULL;
    769 
    770     /*
    771      * Now that we've processed the entire line, check if the hostname
    772      * specifier was a comma separated list of hostnames. If so
    773      * we'll make new entries for each address.
    774      */
    775     while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) {
    776         nsep = dupconfig(sep);
    777 
    778         /*
    779          * NULL terminate the hostname field of the existing entry,
    780          * and make a dup for the new entry.
    781          */
     779    while ((arg = token[6+argc]) != NULL && argc < MAXARGV)
     780        sep->se_argv[argc++] = xstrdup(arg);
     781    /* Some inetd.conf files have no argv's, not even argv[0].
     782     * Fix them up.
     783     * (Technically, programs can be execed with argv[0] = NULL,
     784     * but many programs do not like that at all) */
     785    if (argc == 0)
     786        sep->se_argv[0] = xstrdup(sep->se_program);
     787
     788    /* catch mixups. "<service> stream udp ..." == wtf */
     789    if (sep->se_socktype == SOCK_STREAM) {
     790        if (sep->se_proto_no == IPPROTO_UDP)
     791            goto parse_err;
     792    }
     793    if (sep->se_socktype == SOCK_DGRAM) {
     794        if (sep->se_proto_no == IPPROTO_TCP)
     795            goto parse_err;
     796    }
     797
     798//  bb_info_msg(
     799//      "ENTRY[%s][%s][%s][%d][%d][%d][%d][%d][%s][%s][%s]",
     800//      sep->se_local_hostname, sep->se_service, sep->se_proto, sep->se_wait, sep->se_proto_no,
     801//      sep->se_max, sep->se_count, sep->se_time, sep->se_user, sep->se_group, sep->se_program);
     802
     803    /* check if the hostname specifier is a comma separated list
     804     * of hostnames. we'll make new entries for each address. */
     805    while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
     806        nsep = dup_servtab(sep);
     807        /* NUL terminate the hostname field of the existing entry,
     808         * and make a dup for the new entry. */
    782809        *hostdelim++ = '\0';
    783         nsep->se_hostaddr = xstrdup(hostdelim);
    784 
     810        nsep->se_local_hostname = xstrdup(hostdelim);
    785811        nsep->se_next = sep->se_next;
    786812        sep->se_next = nsep;
    787813    }
    788814
    789     nsep = sep;
    790     while (nsep != NULL) {
    791         nsep->se_checked = 1;
    792         if (nsep->se_family == AF_INET) {
    793             if (LONE_CHAR(nsep->se_hostaddr, '*'))
    794                 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
    795             else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
    796                 struct hostent *hp;
    797 
    798                 hp = gethostbyname(nsep->se_hostaddr);
    799                 if (hp == 0) {
    800                     bb_error_msg("%s: unknown host", nsep->se_hostaddr);
    801                     nsep->se_checked = 0;
    802                     goto skip;
    803                 } else if (hp->h_addrtype != AF_INET) {
    804                     bb_error_msg("%s: address isn't an Internet "
    805                                   "address", nsep->se_hostaddr);
    806                     nsep->se_checked = 0;
    807                     goto skip;
    808                 } else {
    809                     int i = 1;
    810 
    811                     memmove(&nsep->se_ctrladdr_in.sin_addr,
    812                                    hp->h_addr_list[0], sizeof(struct in_addr));
    813                     while (hp->h_addr_list[i] != NULL) {
    814                         psep = dupconfig(nsep);
    815                         psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
    816                         psep->se_checked = 1;
    817                         memmove(&psep->se_ctrladdr_in.sin_addr,
    818                                      hp->h_addr_list[i], sizeof(struct in_addr));
    819                         psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
    820                         i++;
    821                         /* Prepend to list, don't want to look up */
    822                         /* its hostname again. */
    823                         psep->se_next = sep;
    824                         sep = psep;
    825                     }
    826                 }
    827             }
    828         }
    829 /* XXX BUG?: is this skip: label supposed to remain? */
    830  skip:
    831         nsep = nsep->se_next;
    832     }
    833 
    834     /*
    835      * Finally, free any entries which failed the gethostbyname
    836      * check.
    837      */
    838     psep = NULL;
    839     nsep = sep;
    840     while (nsep != NULL) {
    841         servtab_t *tsep;
    842 
    843         if (nsep->se_checked == 0) {
    844             tsep = nsep;
    845             if (psep == NULL) {
    846                 sep = nsep->se_next;
    847                 nsep = sep;
    848             } else {
    849                 nsep = nsep->se_next;
    850                 psep->se_next = nsep;
    851             }
    852             freeconfig(tsep);
    853         } else {
    854             nsep->se_checked = 0;
    855             psep = nsep;
    856             nsep = nsep->se_next;
    857         }
    858     }
     815    /* was doing it here: */
     816    /* DNS resolution, create copies for each IP address */
     817    /* IPv6-ization destroyed it :( */
    859818
    860819    return sep;
    861820}
    862821
    863 #define Block_Using_Signals(m) do { \
    864     sigemptyset(&m); \
    865     sigaddset(&m, SIGCHLD); \
    866     sigaddset(&m, SIGHUP); \
    867     sigaddset(&m, SIGALRM); \
    868     sigprocmask(SIG_BLOCK, &m, NULL); \
    869 } while (0)
    870 
    871 static servtab_t *enter(servtab_t *cp)
     822static servtab_t *insert_in_servlist(servtab_t *cp)
    872823{
    873824    servtab_t *sep;
     
    875826
    876827    sep = new_servtab();
    877     *sep = *cp;
     828    *sep = *cp; /* struct copy */
    878829    sep->se_fd = -1;
    879830#if ENABLE_FEATURE_INETD_RPC
    880831    sep->se_rpcprog = -1;
    881832#endif
    882     Block_Using_Signals(omask);
    883     sep->se_next = servtab;
    884     servtab = sep;
    885     sigprocmask(SIG_UNBLOCK, &omask, NULL);
     833    block_CHLD_HUP_ALRM(&omask);
     834    sep->se_next = serv_list;
     835    serv_list = sep;
     836    restore_sigmask(&omask);
    886837    return sep;
    887838}
    888839
    889 static int matchconf(servtab_t *old, servtab_t *new)
    890 {
     840static int same_serv_addr_proto(servtab_t *old, servtab_t *new)
     841{
     842    if (strcmp(old->se_local_hostname, new->se_local_hostname) != 0)
     843        return 0;
    891844    if (strcmp(old->se_service, new->se_service) != 0)
    892845        return 0;
    893 
    894     if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
    895         return 0;
    896 
    897846    if (strcmp(old->se_proto, new->se_proto) != 0)
    898847        return 0;
    899 
    900     /*
    901      * If the new servtab is bound to a specific address, check that the
    902      * old servtab is bound to the same entry. If the new service is not
    903      * bound to a specific address then the check of se_hostaddr above
    904      * is sufficient.
    905      */
    906 
    907     if (old->se_family == AF_INET && new->se_family == AF_INET &&
    908             memcmp(&old->se_ctrladdr_in.sin_addr,
    909                     &new->se_ctrladdr_in.sin_addr,
    910                     sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
    911         return 0;
    912 
    913 #if ENABLE_FEATURE_IPV6
    914     if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
    915             memcmp(&old->se_ctrladdr_in6.sin6_addr,
    916                     &new->se_ctrladdr_in6.sin6_addr,
    917                     sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
    918         return 0;
    919 #endif
    920848    return 1;
    921849}
    922850
    923 static void config(int sig ATTRIBUTE_UNUSED)
     851static void reread_config_file(int sig UNUSED_PARAM)
    924852{
    925853    servtab_t *sep, *cp, **sepp;
     854    len_and_sockaddr *lsa;
    926855    sigset_t omask;
    927     size_t n;
    928     char protoname[10];
    929 
    930     if (!setconfig()) {
    931         bb_perror_msg("%s", config_filename);
    932         return;
    933     }
    934     for (sep = servtab; sep; sep = sep->se_next)
     856    unsigned n;
     857    uint16_t port;
     858    int save_errno = errno;
     859
     860    if (!reopen_config_file())
     861        goto ret;
     862    for (sep = serv_list; sep; sep = sep->se_next)
    935863        sep->se_checked = 0;
    936     cp = getconfigent();
    937     while (cp != NULL) {
    938         for (sep = servtab; sep; sep = sep->se_next)
    939             if (matchconf(sep, cp))
     864
     865    goto first_line;
     866    while (1) {
     867        if (cp == NULL) {
     868 first_line:
     869            cp = parse_one_line();
     870            if (cp == NULL)
    940871                break;
    941 
    942         if (sep != 0) {
     872        }
     873        for (sep = serv_list; sep; sep = sep->se_next)
     874            if (same_serv_addr_proto(sep, cp))
     875                goto equal_servtab;
     876        /* not an "equal" servtab */
     877        sep = insert_in_servlist(cp);
     878        goto after_check;
     879 equal_servtab:
     880        {
    943881            int i;
    944882
    945 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
    946 
    947             Block_Using_Signals(omask);
    948             /*
    949              * sep->se_wait may be holding the pid of a daemon
    950              * that we're waiting for.  If so, don't overwrite
    951              * it unless the config file explicitly says don't
    952              * wait.
    953              */
    954             if (
    955 #ifdef INETD_FEATURE_ENABLED
    956                 cp->se_bi == 0 &&
    957 #endif
    958                 (sep->se_wait == 1 || cp->se_wait == 0))
    959                 sep->se_wait = cp->se_wait;
    960             SWAP(int, cp->se_max, sep->se_max);
    961             SWAP(char *, sep->se_user, cp->se_user);
    962             SWAP(char *, sep->se_group, cp->se_group);
    963             SWAP(char *, sep->se_server, cp->se_server);
     883            block_CHLD_HUP_ALRM(&omask);
     884#if ENABLE_FEATURE_INETD_RPC
     885            if (is_rpc_service(sep))
     886                unregister_rpc(sep);
     887            sep->se_rpcver_lo = cp->se_rpcver_lo;
     888            sep->se_rpcver_hi = cp->se_rpcver_hi;
     889#endif
     890            if (cp->se_wait == 0) {
     891                /* New config says "nowait". If old one
     892                 * was "wait", we currently may be waiting
     893                 * for a child (and not accepting connects).
     894                 * Stop waiting, start listening again.
     895                 * (if it's not true, this op is harmless) */
     896                add_fd_to_set(sep->se_fd);
     897            }
     898            sep->se_wait = cp->se_wait;
     899            sep->se_max = cp->se_max;
     900            /* string fields need more love - we don't want to leak them */
     901#define SWAP(type, a, b) do { type c = (type)a; a = (type)b; b = (type)c; } while (0)
     902            SWAP(char*, sep->se_user, cp->se_user);
     903            SWAP(char*, sep->se_group, cp->se_group);
     904            SWAP(char*, sep->se_program, cp->se_program);
    964905            for (i = 0; i < MAXARGV; i++)
    965                 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
     906                SWAP(char*, sep->se_argv[i], cp->se_argv[i]);
    966907#undef SWAP
    967 
     908            restore_sigmask(&omask);
     909            free_servtab_strings(cp);
     910        }
     911 after_check:
     912        /* cp->string_fields are consumed by insert_in_servlist()
     913         * or freed at this point, cp itself is not yet freed. */
     914        sep->se_checked = 1;
     915
     916        /* create new len_and_sockaddr */
     917        switch (sep->se_family) {
     918            struct sockaddr_un *sun;
     919        case AF_UNIX:
     920            lsa = xzalloc_lsa(AF_UNIX);
     921            sun = (struct sockaddr_un*)&lsa->u.sa;
     922            safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
     923            break;
     924
     925        default: /* case AF_INET, case AF_INET6 */
     926            n = bb_strtou(sep->se_service, NULL, 10);
    968927#if ENABLE_FEATURE_INETD_RPC
    969             if (isrpcservice(sep))
    970                 unregister_rpc(sep);
    971             sep->se_rpcversl = cp->se_rpcversl;
    972             sep->se_rpcversh = cp->se_rpcversh;
    973 #endif
    974             sigprocmask(SIG_UNBLOCK, &omask, NULL);
    975             freeconfig(cp);
    976         } else {
    977             sep = enter(cp);
    978         }
    979         sep->se_checked = 1;
    980 
    981         switch (sep->se_family) {
    982         case AF_UNIX:
    983             if (sep->se_fd != -1)
    984                 break;
    985             (void) unlink(sep->se_service);
    986             n = strlen(sep->se_service);
    987             if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
    988                 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
    989             safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
    990             sep->se_ctrladdr_un.sun_family = AF_UNIX;
    991             sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
    992             setup(sep);
    993             break;
    994         case AF_INET:
    995             sep->se_ctrladdr_in.sin_family = AF_INET;
    996             /* se_ctrladdr_in was set in getconfigent */
    997             sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
    998 
    999 #if ENABLE_FEATURE_INETD_RPC
    1000             if (isrpcservice(sep)) {
    1001                 struct rpcent *rp;
    1002                 // FIXME: atoi_or_else(str, 0) would be handy here
    1003                 sep->se_rpcprog = atoi(sep->se_service);
    1004                 if (sep->se_rpcprog == 0) {
    1005                     rp = getrpcbyname(sep->se_service);
    1006                     if (rp == 0) {
     928            if (is_rpc_service(sep)) {
     929                sep->se_rpcprog = n;
     930                if (errno) { /* se_service is not numeric */
     931                    struct rpcent *rp = getrpcbyname(sep->se_service);
     932                    if (rp == NULL) {
    1007933                        bb_error_msg("%s: unknown rpc service", sep->se_service);
    1008                         goto serv_unknown;
     934                        goto next_cp;
    1009935                    }
    1010936                    sep->se_rpcprog = rp->r_number;
    1011937                }
    1012938                if (sep->se_fd == -1)
    1013                     setup(sep);
     939                    prepare_socket_fd(sep);
    1014940                if (sep->se_fd != -1)
    1015941                    register_rpc(sep);
    1016             } else
    1017 #endif
    1018             {
    1019                 uint16_t port = htons(atoi(sep->se_service));
    1020                 // FIXME: atoi_or_else(str, 0) would be handy here
    1021                 if (!port) {
    1022                      /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
    1023                     if (isdigit(protoname[strlen(protoname) - 1]))
    1024                         protoname[strlen(protoname) - 1] = '\0';
    1025                     sp = getservbyname(sep->se_service, protoname);
    1026                     if (sp == 0) {
    1027                         bb_error_msg("%s/%s: unknown service",
    1028                                 sep->se_service, sep->se_proto);
    1029                         goto serv_unknown;
    1030                     }
    1031                     port = sp->s_port;
     942                goto next_cp;
     943            }
     944#endif
     945            /* what port to listen on? */
     946            port = htons(n);
     947            if (errno || n > 0xffff) { /* se_service is not numeric */
     948                char protoname[4];
     949                struct servent *sp;
     950                /* can result only in "tcp" or "udp": */
     951                safe_strncpy(protoname, sep->se_proto, 4);
     952                sp = getservbyname(sep->se_service, protoname);
     953                if (sp == NULL) {
     954                    bb_error_msg("%s/%s: unknown service",
     955                            sep->se_service, sep->se_proto);
     956                    goto next_cp;
    1032957                }
    1033                 if (port != sep->se_ctrladdr_in.sin_port) {
    1034                     sep->se_ctrladdr_in.sin_port = port;
    1035                     if (sep->se_fd != -1) {
    1036                         FD_CLR(sep->se_fd, &allsock);
    1037                         nsock--;
    1038                         (void) close(sep->se_fd);
    1039                     }
    1040                     sep->se_fd = -1;
     958                port = sp->s_port;
     959            }
     960            if (LONE_CHAR(sep->se_local_hostname, '*')) {
     961                lsa = xzalloc_lsa(sep->se_family);
     962                set_nport(lsa, port);
     963            } else {
     964                lsa = host_and_af2sockaddr(sep->se_local_hostname,
     965                        ntohs(port), sep->se_family);
     966                if (!lsa) {
     967                    bb_error_msg("%s/%s: unknown host '%s'",
     968                        sep->se_service, sep->se_proto,
     969                        sep->se_local_hostname);
     970                    goto next_cp;
    1041971                }
    1042                 if (sep->se_fd == -1)
    1043                     setup(sep);
    1044972            }
    1045973            break;
    1046 #if ENABLE_FEATURE_IPV6
    1047         case AF_INET6:
    1048             sep->se_ctrladdr_in6.sin6_family = AF_INET6;
    1049             /* se_ctrladdr_in was set in getconfigent */
    1050             sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
    1051 
    1052 #if ENABLE_FEATURE_INETD_RPC
    1053             if (isrpcservice(sep)) {
    1054                 struct rpcent *rp;
    1055 
    1056                 sep->se_rpcprog = atoi(sep->se_service);
    1057                 if (sep->se_rpcprog == 0) {
    1058                     rp = getrpcbyname(sep->se_service);
    1059                     if (rp == 0) {
    1060                         bb_error_msg("%s: unknown rpc service", sep->se_service);
    1061                         goto serv_unknown;
    1062                     }
    1063                     sep->se_rpcprog = rp->r_number;
    1064                 }
    1065                 if (sep->se_fd == -1)
    1066                     setup(sep);
    1067                 if (sep->se_fd != -1)
    1068                     register_rpc(sep);
    1069             } else
    1070 #endif
    1071             {
    1072                 uint16_t port = htons(atoi(sep->se_service));
    1073 
    1074                 if (!port) {
    1075                      /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
    1076                     if (isdigit(protoname[strlen(protoname) - 1]))
    1077                         protoname[strlen(protoname) - 1] = '\0';
    1078                     sp = getservbyname(sep->se_service, protoname);
    1079                     if (sp == 0) {
    1080                         bb_error_msg("%s/%s: unknown service",
    1081                                 sep->se_service, sep->se_proto);
    1082                         goto serv_unknown;
    1083                     }
    1084                     port = sp->s_port;
    1085                 }
    1086                 if (port != sep->se_ctrladdr_in6.sin6_port) {
    1087                     sep->se_ctrladdr_in6.sin6_port = port;
    1088                     if (sep->se_fd != -1) {
    1089                         FD_CLR(sep->se_fd, &allsock);
    1090                         nsock--;
    1091                         (void) close(sep->se_fd);
    1092                     }
    1093                     sep->se_fd = -1;
    1094                 }
    1095                 if (sep->se_fd == -1)
    1096                     setup(sep);
    1097             }
    1098             break;
    1099 #endif /* FEATURE_IPV6 */
     974        } /* end of "switch (sep->se_family)" */
     975
     976        /* did lsa change? Then close/open */
     977        if (sep->se_lsa == NULL
     978         || lsa->len != sep->se_lsa->len
     979         || memcmp(&lsa->u.sa, &sep->se_lsa->u.sa, lsa->len) != 0
     980        ) {
     981            remove_fd_from_set(sep->se_fd);
     982            maybe_close(sep->se_fd);
     983            free(sep->se_lsa);
     984            sep->se_lsa = lsa;
     985            sep->se_fd = -1;
     986        } else {
     987            free(lsa);
    1100988        }
    1101  serv_unknown:
    1102         if (cp->se_next != NULL) {
    1103             servtab_t *tmp = cp;
    1104 
    1105             cp = cp->se_next;
    1106             free(tmp);
    1107         } else {
    1108             free(cp);
    1109             cp = getconfigent();
    1110         }
    1111     }
    1112     endconfig();
    1113     /*
    1114      * Purge anything not looked at above.
    1115      */
    1116     Block_Using_Signals(omask);
    1117     sepp = &servtab;
     989        if (sep->se_fd == -1)
     990            prepare_socket_fd(sep);
     991 next_cp:
     992        sep = cp->se_next;
     993        free(cp);
     994        cp = sep;
     995    } /* end of "while (1) parse lines" */
     996    close_config_file();
     997
     998    /* Purge anything not looked at above - these are stale entries,
     999     * new config file doesnt have them. */
     1000    block_CHLD_HUP_ALRM(&omask);
     1001    sepp = &serv_list;
    11181002    while ((sep = *sepp)) {
    11191003        if (sep->se_checked) {
     
    11221006        }
    11231007        *sepp = sep->se_next;
    1124         if (sep->se_fd != -1) {
    1125             FD_CLR(sep->se_fd, &allsock);
    1126             nsock--;
    1127             (void) close(sep->se_fd);
    1128         }
     1008        remove_fd_from_set(sep->se_fd);
     1009        maybe_close(sep->se_fd);
    11291010#if ENABLE_FEATURE_INETD_RPC
    1130         if (isrpcservice(sep))
     1011        if (is_rpc_service(sep))
    11311012            unregister_rpc(sep);
    11321013#endif
    11331014        if (sep->se_family == AF_UNIX)
    1134             (void) unlink(sep->se_service);
    1135         freeconfig(sep);
     1015            unlink(sep->se_service);
     1016        free_servtab_strings(sep);
    11361017        free(sep);
    11371018    }
    1138     sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1139 }
    1140 
    1141 
    1142 static void reapchild(int sig ATTRIBUTE_UNUSED)
     1019    restore_sigmask(&omask);
     1020 ret:
     1021    errno = save_errno;
     1022}
     1023
     1024static void reap_child(int sig UNUSED_PARAM)
    11431025{
    11441026    pid_t pid;
    1145     int save_errno = errno, status;
     1027    int status;
    11461028    servtab_t *sep;
     1029    int save_errno = errno;
    11471030
    11481031    for (;;) {
    1149         pid = wait3(&status, WNOHANG, NULL);
     1032        pid = wait_any_nohang(&status);
    11501033        if (pid <= 0)
    11511034            break;
    1152         for (sep = servtab; sep; sep = sep->se_next)
    1153             if (sep->se_wait == pid) {
    1154                 if (WIFEXITED(status) && WEXITSTATUS(status))
    1155                     bb_error_msg("%s: exit status 0x%x",
    1156                             sep->se_server, WEXITSTATUS(status));
    1157                 else if (WIFSIGNALED(status))
    1158                     bb_error_msg("%s: exit signal 0x%x",
    1159                             sep->se_server, WTERMSIG(status));
    1160                 sep->se_wait = 1;
    1161                 FD_SET(sep->se_fd, &allsock);
    1162                 nsock++;
    1163             }
     1035        for (sep = serv_list; sep; sep = sep->se_next) {
     1036            if (sep->se_wait != pid)
     1037                continue;
     1038            /* One of our "wait" services */
     1039            if (WIFEXITED(status) && WEXITSTATUS(status))
     1040                bb_error_msg("%s: exit status %u",
     1041                        sep->se_program, WEXITSTATUS(status));
     1042            else if (WIFSIGNALED(status))
     1043                bb_error_msg("%s: exit signal %u",
     1044                        sep->se_program, WTERMSIG(status));
     1045            sep->se_wait = 1;
     1046            add_fd_to_set(sep->se_fd);
     1047            break;
     1048        }
    11641049    }
    11651050    errno = save_errno;
    11661051}
    11671052
    1168 static void retry(int sig ATTRIBUTE_UNUSED)
    1169 {
     1053static void retry_network_setup(int sig UNUSED_PARAM)
     1054{
     1055    int save_errno = errno;
    11701056    servtab_t *sep;
    11711057
    1172     timingout = 0;
    1173     for (sep = servtab; sep; sep = sep->se_next) {
     1058    alarm_armed = 0;
     1059    for (sep = serv_list; sep; sep = sep->se_next) {
    11741060        if (sep->se_fd == -1) {
    1175             switch (sep->se_family) {
    1176             case AF_UNIX:
    1177             case AF_INET:
    1178 #if ENABLE_FEATURE_IPV6
    1179             case AF_INET6:
    1180 #endif
    1181                 setup(sep);
     1061            prepare_socket_fd(sep);
    11821062#if ENABLE_FEATURE_INETD_RPC
    1183                 if (sep->se_fd != -1 && isrpcservice(sep))
    1184                     register_rpc(sep);
    1185 #endif
    1186                 break;
    1187             }
     1063            if (sep->se_fd != -1 && is_rpc_service(sep))
     1064                register_rpc(sep);
     1065#endif
    11881066        }
    11891067    }
    1190 }
    1191 
    1192 static void goaway(int sig ATTRIBUTE_UNUSED)
     1068    errno = save_errno;
     1069}
     1070
     1071static void clean_up_and_exit(int sig UNUSED_PARAM)
    11931072{
    11941073    servtab_t *sep;
    11951074
    11961075    /* XXX signal race walking sep list */
    1197     for (sep = servtab; sep; sep = sep->se_next) {
     1076    for (sep = serv_list; sep; sep = sep->se_next) {
    11981077        if (sep->se_fd == -1)
    11991078            continue;
     
    12011080        switch (sep->se_family) {
    12021081        case AF_UNIX:
    1203             (void) unlink(sep->se_service);
     1082            unlink(sep->se_service);
    12041083            break;
    1205         case AF_INET:
    1206 #if ENABLE_FEATURE_IPV6
    1207         case AF_INET6:
    1208 #endif
     1084        default: /* case AF_INET, AF_INET6 */
    12091085#if ENABLE_FEATURE_INETD_RPC
    1210             if (sep->se_wait == 1 && isrpcservice(sep))
     1086            if (sep->se_wait == 1 && is_rpc_service(sep))
    12111087                unregister_rpc(sep);   /* XXX signal race */
    12121088#endif
    12131089            break;
    12141090        }
    1215         (void) close(sep->se_fd);
     1091        if (ENABLE_FEATURE_CLEAN_UP)
     1092            close(sep->se_fd);
    12161093    }
    12171094    remove_pidfile(_PATH_INETDPID);
    1218     exit(0);
    1219 }
    1220 
    1221 
    1222 #ifdef INETD_SETPROCTITLE
    1223 static char **Argv;
    1224 static char *LastArg;
    1225 
    1226 static void
    1227 inetd_setproctitle(char *a, int s)
    1228 {
    1229     socklen_t size;
    1230     char *cp;
    1231     struct sockaddr_in prt_sin;
    1232     char buf[80];
    1233 
    1234     cp = Argv[0];
    1235     size = sizeof(prt_sin);
    1236     (void) snprintf(buf, sizeof buf, "-%s", a);
    1237     if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {
    1238         char *sa = inet_ntoa(prt_sin.sin_addr);
    1239 
    1240         buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0';
    1241         strcat(buf, " [");
    1242         strcat(buf, sa);
    1243         strcat(buf, "]");
    1244     }
    1245     strncpy(cp, buf, LastArg - cp);
    1246     cp += strlen(cp);
    1247     while (cp < LastArg)
    1248         *cp++ = ' ';
    1249 }
    1250 #endif
    1251 
    1252 
    1253 int inetd_main(int argc, char **argv);
    1254 int inetd_main(int argc, char **argv)
    1255 {
    1256     servtab_t *sep;
     1095    exit(EXIT_SUCCESS);
     1096}
     1097
     1098int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1099int inetd_main(int argc UNUSED_PARAM, char **argv)
     1100{
     1101    struct sigaction sa, saved_pipe_handler;
     1102    servtab_t *sep, *sep2;
    12571103    struct passwd *pwd;
    1258     struct group *grp = NULL;
    1259     int tmpint;
    1260     struct sigaction sa, sapipe;
     1104    struct group *grp = grp; /* for compiler */
    12611105    int opt;
    12621106    pid_t pid;
    1263     char buf[50];
    1264     char *stoomany;
    1265     sigset_t omask, wait_mask;
    1266 
    1267 #ifdef INETD_SETPROCTITLE
    1268     char **envp = environ;
    1269 
    1270     Argv = argv;
    1271     if (envp == 0 || *envp == 0)
    1272         envp = argv;
    1273     while (*envp)
    1274         envp++;
    1275     LastArg = envp[-1] + strlen(envp[-1]);
    1276 #endif
    1277 
    1278     uid = getuid();
    1279     if (uid != 0)
     1107    sigset_t omask;
     1108
     1109    INIT_G();
     1110
     1111    real_uid = getuid();
     1112    if (real_uid != 0) /* run by non-root user */
    12801113        config_filename = NULL;
    12811114
    1282     opt = getopt32(argv, "R:f", &stoomany);
    1283     if (opt & 1)
    1284         toomany = xatoi_u(stoomany);
     1115    opt_complementary = "R+:q+"; /* -q N, -R N */
     1116    opt = getopt32(argv, "R:feq:", &max_concurrency, &global_queuelen);
    12851117    argv += optind;
    1286     argc -= optind;
    1287     if (argc)
     1118    //argc -= optind;
     1119    if (argv[0])
    12881120        config_filename = argv[0];
    12891121    if (config_filename == NULL)
    1290         bb_error_msg_and_die("non-root must specify a config file");
    1291 
     1122        bb_error_msg_and_die("non-root must specify config file");
    12921123    if (!(opt & 2))
    12931124        bb_daemonize_or_rexec(0, argv - optind);
    12941125    else
    12951126        bb_sanitize_stdio();
    1296     openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
    1297     logmode = LOGMODE_SYSLOG;
    1298 
    1299     if (uid == 0) {
    1300         /* If run by hand, ensure groups vector gets trashed */
     1127    if (!(opt & 4)) {
     1128        /* LOG_NDELAY: connect to syslog daemon NOW.
     1129         * Otherwise, we may open syslog socket
     1130         * in vforked child, making opened fds and syslog()
     1131         * internal state inconsistent.
     1132         * This was observed to leak file descriptors. */
     1133        openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON);
     1134        logmode = LOGMODE_SYSLOG;
     1135    }
     1136
     1137    if (real_uid == 0) {
     1138        /* run by root, ensure groups vector gets trashed */
    13011139        gid_t gid = getgid();
    13021140        setgroups(1, &gid);
     
    13051143    write_pidfile(_PATH_INETDPID);
    13061144
    1307     if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
    1308         bb_perror_msg("getrlimit");
    1309     } else {
    1310         rlim_ofile_cur = rlim_ofile.rlim_cur;
    1311         if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
    1312             rlim_ofile_cur = OPEN_MAX;
    1313     }
    1314 
    1315     memset((char *) &sa, 0, sizeof(sa));
    1316     sigemptyset(&sa.sa_mask);
     1145    /* never fails under Linux (except if you pass it bad arguments) */
     1146    getrlimit(RLIMIT_NOFILE, &rlim_ofile);
     1147    rlim_ofile_cur = rlim_ofile.rlim_cur;
     1148    if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
     1149        rlim_ofile_cur = OPEN_MAX;
     1150
     1151    memset(&sa, 0, sizeof(sa));
     1152    /*sigemptyset(&sa.sa_mask); - memset did it */
    13171153    sigaddset(&sa.sa_mask, SIGALRM);
    13181154    sigaddset(&sa.sa_mask, SIGCHLD);
    13191155    sigaddset(&sa.sa_mask, SIGHUP);
    1320     sa.sa_handler = retry;
    1321     sigaction(SIGALRM, &sa, NULL);
    1322     config(SIGHUP);
    1323     sa.sa_handler = config;
    1324     sigaction(SIGHUP, &sa, NULL);
    1325     sa.sa_handler = reapchild;
    1326     sigaction(SIGCHLD, &sa, NULL);
    1327     sa.sa_handler = goaway;
    1328     sigaction(SIGTERM, &sa, NULL);
    1329     sa.sa_handler = goaway;
    1330     sigaction(SIGINT, &sa, NULL);
     1156    sa.sa_handler = retry_network_setup;
     1157    sigaction_set(SIGALRM, &sa);
     1158    sa.sa_handler = reread_config_file;
     1159    sigaction_set(SIGHUP, &sa);
     1160    sa.sa_handler = reap_child;
     1161    sigaction_set(SIGCHLD, &sa);
     1162    sa.sa_handler = clean_up_and_exit;
     1163    sigaction_set(SIGTERM, &sa);
     1164    sa.sa_handler = clean_up_and_exit;
     1165    sigaction_set(SIGINT, &sa);
    13311166    sa.sa_handler = SIG_IGN;
    1332     sigaction(SIGPIPE, &sa, &sapipe);
    1333     memset(&wait_mask, 0, sizeof(wait_mask));
    1334     {
    1335         /* space for daemons to overwrite environment for ps */
    1336 #define DUMMYSIZE       100
    1337         char dummy[DUMMYSIZE];
    1338 
    1339         (void) memset(dummy, 'x', DUMMYSIZE - 1);
    1340         dummy[DUMMYSIZE - 1] = '\0';
    1341 
    1342         (void) setenv("inetd_dummy", dummy, 1);
    1343     }
     1167    sigaction(SIGPIPE, &sa, &saved_pipe_handler);
     1168
     1169    reread_config_file(SIGHUP); /* load config from file */
    13441170
    13451171    for (;;) {
    1346         int n, ctrl = -1;
     1172        int ready_fd_cnt;
     1173        int ctrl, accepted_fd, new_udp_fd;
    13471174        fd_set readable;
    13481175
    1349         if (nsock == 0) {
    1350             Block_Using_Signals(omask);
    1351             while (nsock == 0)
    1352                 sigsuspend(&wait_mask);
    1353             sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1354         }
    1355 
    1356         readable = allsock;
    1357         n = select(maxsock + 1, &readable, NULL, NULL, NULL);
    1358         if (n <= 0) {
    1359             if (n < 0 && errno != EINTR) {
     1176        if (maxsock < 0)
     1177            recalculate_maxsock();
     1178
     1179        readable = allsock; /* struct copy */
     1180        /* if there are no fds to wait on, we will block
     1181         * until signal wakes us up (maxsock == 0, but readable
     1182         * never contains fds 0 and 1...) */
     1183        ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL);
     1184        if (ready_fd_cnt < 0) {
     1185            if (errno != EINTR) {
    13601186                bb_perror_msg("select");
    13611187                sleep(1);
     
    13641190        }
    13651191
    1366         for (sep = servtab; n && sep; sep = sep->se_next) {
     1192        for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
    13671193            if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
    13681194                continue;
    13691195
    1370             n--;
    1371             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
    1372                 ctrl = accept(sep->se_fd, NULL, NULL);
    1373                 if (ctrl < 0) {
    1374                     if (errno == EINTR)
    1375                         continue;
    1376                     bb_perror_msg("accept (for %s)", sep->se_service);
    1377                     continue;
    1378                 }
    1379                 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
    1380                     struct sockaddr_in peer;
    1381                     socklen_t plen = sizeof(peer);
    1382 
    1383                     if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) {
    1384                         bb_error_msg("cannot getpeername");
    1385                         close(ctrl);
    1386                         continue;
    1387                     }
    1388                     if (ntohs(peer.sin_port) == 20) {
    1389                         /* XXX ftp bounce */
    1390                         close(ctrl);
     1196            ready_fd_cnt--;
     1197            ctrl = sep->se_fd;
     1198            accepted_fd = -1;
     1199            new_udp_fd = -1;
     1200            if (!sep->se_wait) {
     1201                if (sep->se_socktype == SOCK_STREAM) {
     1202                    ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
     1203                    if (ctrl < 0) {
     1204                        if (errno != EINTR)
     1205                            bb_perror_msg("accept (for %s)", sep->se_service);
    13911206                        continue;
    13921207                    }
    13931208                }
    1394             } else
    1395                 ctrl = sep->se_fd;
    1396 
    1397             Block_Using_Signals(omask);
    1398             pid = 0;
    1399 #ifdef INETD_FEATURE_ENABLED
    1400             if (sep->se_bi == 0 || sep->se_bi->bi_fork)
    1401 #endif
    1402             {
    1403                 if (sep->se_count++ == 0)
    1404                     (void) gettimeofday(&sep->se_time, NULL);
    1405                 else if (toomany > 0 && sep->se_count >= sep->se_max) {
    1406                     struct timeval now;
    1407 
    1408                     (void) gettimeofday(&now, NULL);
    1409                     if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
    1410                         sep->se_time = now;
    1411                         sep->se_count = 1;
    1412                     } else {
    1413                         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1414                             close(ctrl);
    1415                         if (sep->se_family == AF_INET &&
    1416                               ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
    1417                             /*
    1418                              * Cannot close it -- there are
    1419                              * thieves on the system.
    1420                              * Simply ignore the connection.
    1421                              */
    1422                             --sep->se_count;
    1423                             continue;
    1424                         }
    1425                         bb_error_msg("%s/%s server failing (looping), service terminated",
    1426                                   sep->se_service, sep->se_proto);
    1427                         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1428                             close(ctrl);
    1429                         FD_CLR(sep->se_fd, &allsock);
    1430                         (void) close(sep->se_fd);
    1431                         sep->se_fd = -1;
    1432                         sep->se_count = 0;
    1433                         nsock--;
    1434                         sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1435                         if (!timingout) {
    1436                             timingout = 1;
    1437                             alarm(RETRYTIME);
    1438                         }
     1209                /* "nowait" udp */
     1210                if (sep->se_socktype == SOCK_DGRAM
     1211                 && sep->se_family != AF_UNIX
     1212                ) {
     1213/* How udp "nowait" works:
     1214 * child peeks at (received and buffered by kernel) UDP packet,
     1215 * performs connect() on the socket so that it is linked only
     1216 * to this peer. But this also affects parent, because descriptors
     1217 * are shared after fork() a-la dup(). When parent performs
     1218 * select(), it will see this descriptor connected to the peer (!)
     1219 * and still readable, will act on it and mess things up
     1220 * (can create many copies of same child, etc).
     1221 * Parent must create and use new socket instead. */
     1222                    new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
     1223                    if (new_udp_fd < 0) { /* error: eat packet, forget about it */
     1224 udp_err:
     1225                        recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
    14391226                        continue;
    14401227                    }
    1441                 }
    1442                 pid = fork();
    1443             }
    1444             if (pid < 0) {
    1445                 bb_perror_msg("fork");
    1446                 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1447                     close(ctrl);
    1448                 sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1449                 sleep(1);
    1450                 continue;
    1451             }
    1452             if (pid && sep->se_wait) {
    1453                 sep->se_wait = pid;
    1454                 FD_CLR(sep->se_fd, &allsock);
    1455                 nsock--;
    1456             }
    1457             sigprocmask(SIG_UNBLOCK, &omask, NULL);
    1458             if (pid == 0) {
    1459 #ifdef INETD_FEATURE_ENABLED
    1460                 if (sep->se_bi) {
    1461                     (*sep->se_bi->bi_fn)(ctrl, sep);
    1462                 } else
    1463 #endif
    1464                 {
    1465                     pwd = getpwnam(sep->se_user);
    1466                     if (pwd == NULL) {
    1467                         bb_error_msg("getpwnam: %s: no such user", sep->se_user);
    1468                         goto do_exit1;
     1228                    setsockopt_reuseaddr(new_udp_fd);
     1229                    /* TODO: better do bind after vfork in parent,
     1230                     * so that we don't have two wildcard bound sockets
     1231                     * even for a brief moment? */
     1232                    if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
     1233                        close(new_udp_fd);
     1234                        goto udp_err;
    14691235                    }
    1470                     if (setsid() < 0)
    1471                         bb_perror_msg("%s: setsid", sep->se_service);
    1472                     if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
    1473                         bb_error_msg("getgrnam: %s: no such group", sep->se_group);
    1474                         goto do_exit1;
    1475                     }
    1476                     if (uid != 0) {
    1477                         /* a user running private inetd */
    1478                         if (uid != pwd->pw_uid)
    1479                             _exit(1);
    1480                     } else if (pwd->pw_uid) {
    1481                         if (sep->se_group)
    1482                             pwd->pw_gid = grp->gr_gid;
    1483                         xsetgid((gid_t) pwd->pw_gid);
    1484                         initgroups(pwd->pw_name, pwd->pw_gid);
    1485                         xsetuid((uid_t) pwd->pw_uid);
    1486                     } else if (sep->se_group) {
    1487                         xsetgid(grp->gr_gid);
    1488                         setgroups(1, &grp->gr_gid);
    1489                     }
    1490                     dup2(ctrl, 0);
    1491                     if (ctrl) close(ctrl);
    1492                     dup2(0, 1);
    1493                     dup2(0, 2);
    1494                     if (rlim_ofile.rlim_cur != rlim_ofile_cur)
    1495                         if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
    1496                             bb_perror_msg("setrlimit");
    1497                     closelog();
    1498                     for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
    1499                         (void) close(tmpint);
    1500                     sigaction(SIGPIPE, &sapipe, NULL);
    1501                     execv(sep->se_server, sep->se_argv);
    1502                     bb_perror_msg("execv %s", sep->se_server);
    1503  do_exit1:
    1504                     if (sep->se_socktype != SOCK_STREAM)
    1505                         recv(0, buf, sizeof(buf), 0);
    1506                     _exit(1);
    15071236                }
    15081237            }
    1509             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    1510                 close(ctrl);
     1238
     1239            block_CHLD_HUP_ALRM(&omask);
     1240            pid = 0;
     1241#ifdef INETD_BUILTINS_ENABLED
     1242            /* do we need to fork? */
     1243            if (sep->se_builtin == NULL
     1244             || (sep->se_socktype == SOCK_STREAM
     1245                 && sep->se_builtin->bi_fork))
     1246#endif
     1247            {
     1248                if (sep->se_max != 0) {
     1249                    if (++sep->se_count == 1)
     1250                        sep->se_time = monotonic_sec();
     1251                    else if (sep->se_count >= sep->se_max) {
     1252                        unsigned now = monotonic_sec();
     1253                        /* did we accumulate se_max connects too quickly? */
     1254                        if (now - sep->se_time <= CNT_INTERVAL) {
     1255                            bb_error_msg("%s/%s: too many connections, pausing",
     1256                                    sep->se_service, sep->se_proto);
     1257                            remove_fd_from_set(sep->se_fd);
     1258                            close(sep->se_fd);
     1259                            sep->se_fd = -1;
     1260                            sep->se_count = 0;
     1261                            rearm_alarm(); /* will revive it in RETRYTIME sec */
     1262                            restore_sigmask(&omask);
     1263                            maybe_close(accepted_fd);
     1264                            continue; /* -> check next fd in fd set */
     1265                        }
     1266                        sep->se_count = 0;
     1267                    }
     1268                }
     1269                /* on NOMMU, streamed chargen
     1270                 * builtin wouldn't work, but it is
     1271                 * not allowed on NOMMU (ifdefed out) */
     1272#ifdef INETD_BUILTINS_ENABLED
     1273                if (BB_MMU && sep->se_builtin)
     1274                    pid = fork();
     1275                else
     1276#endif
     1277                    pid = vfork();
     1278
     1279                if (pid < 0) { /* fork error */
     1280                    bb_perror_msg("vfork"+1);
     1281                    sleep(1);
     1282                    restore_sigmask(&omask);
     1283                    maybe_close(accepted_fd);
     1284                    continue; /* -> check next fd in fd set */
     1285                }
     1286                if (pid == 0)
     1287                    pid--; /* -1: "we did fork and we are child" */
     1288            }
     1289            /* if pid == 0 here, we never forked */
     1290
     1291            if (pid > 0) { /* parent */
     1292                if (sep->se_wait) {
     1293                    /* tcp wait: we passed listening socket to child,
     1294                     * will wait for child to terminate */
     1295                    sep->se_wait = pid;
     1296                    remove_fd_from_set(sep->se_fd);
     1297                }
     1298                if (new_udp_fd >= 0) {
     1299                    /* udp nowait: child connected the socket,
     1300                     * we created and will use new, unconnected one */
     1301                    xmove_fd(new_udp_fd, sep->se_fd);
     1302                }
     1303                restore_sigmask(&omask);
     1304                maybe_close(accepted_fd);
     1305                continue; /* -> check next fd in fd set */
     1306            }
     1307
     1308            /* we are either child or didn't vfork at all */
     1309#ifdef INETD_BUILTINS_ENABLED
     1310            if (sep->se_builtin) {
     1311                if (pid) { /* "pid" is -1: we did vfork */
     1312                    close(sep->se_fd); /* listening socket */
     1313                    logmode = LOGMODE_NONE; /* make xwrite etc silent */
     1314                }
     1315                restore_sigmask(&omask);
     1316                if (sep->se_socktype == SOCK_STREAM)
     1317                    sep->se_builtin->bi_stream_fn(ctrl, sep);
     1318                else
     1319                    sep->se_builtin->bi_dgram_fn(ctrl, sep);
     1320                if (pid) /* we did vfork */
     1321                    _exit(EXIT_FAILURE);
     1322                maybe_close(accepted_fd);
     1323                continue; /* -> check next fd in fd set */
     1324            }
     1325#endif
     1326            /* child */
     1327            setsid();
     1328            /* "nowait" udp */
     1329            if (new_udp_fd >= 0) {
     1330                len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
     1331                /* peek at the packet and remember peer addr */
     1332                int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
     1333                    &lsa->u.sa, &lsa->len);
     1334                if (r < 0)
     1335                    goto do_exit1;
     1336                /* make this socket "connected" to peer addr:
     1337                 * only packets from this peer will be recv'ed,
     1338                 * and bare write()/send() will work on it */
     1339                connect(ctrl, &lsa->u.sa, lsa->len);
     1340                free(lsa);
     1341            }
     1342            /* prepare env and exec program */
     1343            pwd = getpwnam(sep->se_user);
     1344            if (pwd == NULL) {
     1345                bb_error_msg("%s: no such %s", sep->se_user, "user");
     1346                goto do_exit1;
     1347            }
     1348            if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
     1349                bb_error_msg("%s: no such %s", sep->se_group, "group");
     1350                goto do_exit1;
     1351            }
     1352            if (real_uid != 0 && real_uid != pwd->pw_uid) {
     1353                /* a user running private inetd */
     1354                bb_error_msg("non-root must run services as himself");
     1355                goto do_exit1;
     1356            }
     1357            if (pwd->pw_uid) {
     1358                if (sep->se_group)
     1359                    pwd->pw_gid = grp->gr_gid;
     1360                /* initgroups, setgid, setuid: */
     1361                change_identity(pwd);
     1362            } else if (sep->se_group) {
     1363                xsetgid(grp->gr_gid);
     1364                setgroups(1, &grp->gr_gid);
     1365            }
     1366            if (rlim_ofile.rlim_cur != rlim_ofile_cur)
     1367                if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
     1368                    bb_perror_msg("setrlimit");
     1369
     1370            /* closelog(); - WRONG. we are after vfork,
     1371             * this may confuse syslog() internal state.
     1372             * Let's hope libc sets syslog fd to CLOEXEC...
     1373             */
     1374            xmove_fd(ctrl, STDIN_FILENO);
     1375            xdup2(STDIN_FILENO, STDOUT_FILENO);
     1376            /* manpages of inetd I managed to find either say
     1377             * that stderr is also redirected to the network,
     1378             * or do not talk about redirection at all (!) */
     1379            if (!sep->se_wait) /* only for usual "tcp nowait" */
     1380                xdup2(STDIN_FILENO, STDERR_FILENO);
     1381            /* NB: among others, this loop closes listening sockets
     1382             * for nowait stream children */
     1383            for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
     1384                if (sep2->se_fd != ctrl)
     1385                    maybe_close(sep2->se_fd);
     1386            sigaction_set(SIGPIPE, &saved_pipe_handler);
     1387            restore_sigmask(&omask);
     1388            BB_EXECVP(sep->se_program, sep->se_argv);
     1389            bb_perror_msg("can't execute '%s'", sep->se_program);
     1390 do_exit1:
     1391            /* eat packet in udp case */
     1392            if (sep->se_socktype != SOCK_STREAM)
     1393                recv(0, line, LINE_SIZE, MSG_DONTWAIT);
     1394            _exit(EXIT_FAILURE);
    15111395        } /* for (sep = servtab...) */
    15121396    } /* for (;;) */
    15131397}
     1398
     1399#if !BB_MMU
     1400static const char *const cat_args[] = { "cat", NULL };
     1401#endif
    15141402
    15151403/*
    15161404 * Internet services provided internally by inetd:
    15171405 */
    1518 #define BUFSIZE 4096
    1519 
    1520 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
    1521     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
    1522     ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    1523 static int dg_badinput(struct sockaddr_in *dg_sin)
    1524 {
    1525     if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
    1526         return 1;
    1527     if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))
    1528         return 1;
    1529     /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
    1530     return 0;
    1531 }
    1532 #endif
    1533 
    15341406#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    1535 /* Echo service -- echo data back */
     1407/* Echo service -- echo data back. */
    15361408/* ARGSUSED */
    1537 static void
    1538 echo_stream(int s, servtab_t *sep)
    1539 {
    1540     char buffer[BUFSIZE];
    1541     int i;
    1542 
    1543     inetd_setproctitle(sep->se_service, s);
     1409static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM)
     1410{
     1411#if BB_MMU
    15441412    while (1) {
    1545         i = read(s, buffer, sizeof(buffer));
    1546         if (i <= 0) break;
    1547         /* FIXME: this isnt correct - safe_write()? */
    1548         if (write(s, buffer, i) <= 0) break;
    1549     }
    1550     exit(0);
    1551 }
    1552 
    1553 /* Echo service -- echo data back */
     1413        ssize_t sz = safe_read(s, line, LINE_SIZE);
     1414        if (sz <= 0)
     1415            break;
     1416        xwrite(s, line, sz);
     1417    }
     1418#else
     1419    /* We are after vfork here! */
     1420    /* move network socket to stdin/stdout */
     1421    xmove_fd(s, STDIN_FILENO);
     1422    xdup2(STDIN_FILENO, STDOUT_FILENO);
     1423    /* no error messages please... */
     1424    close(STDERR_FILENO);
     1425    xopen(bb_dev_null, O_WRONLY);
     1426    BB_EXECVP("cat", (char**)cat_args);
     1427    /* on failure we return to main, which does exit(EXIT_FAILURE) */
     1428#endif
     1429}
     1430static void FAST_FUNC echo_dg(int s, servtab_t *sep)
     1431{
     1432    enum { BUFSIZE = 12*1024 }; /* for jumbo sized packets! :) */
     1433    char *buf = xmalloc(BUFSIZE); /* too big for stack */
     1434    int sz;
     1435    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1436
     1437    lsa->len = sep->se_lsa->len;
     1438    /* dgram builtins are non-forking - DONT BLOCK! */
     1439    sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len);
     1440    if (sz > 0)
     1441        sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len);
     1442    free(buf);
     1443}
     1444#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
     1445
     1446
     1447#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     1448/* Discard service -- ignore data. */
    15541449/* ARGSUSED */
    1555 static void
    1556 echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1557 {
    1558     char buffer[BUFSIZE];
    1559     int i;
    1560     socklen_t size;
    1561     /* struct sockaddr_storage ss; */
    1562     struct sockaddr sa;
    1563 
    1564     size = sizeof(sa);
    1565     i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size);
    1566     if (i < 0)
    1567         return;
    1568     if (dg_badinput((struct sockaddr_in *) &sa))
    1569         return;
    1570     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
    1571 }
    1572 #endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
    1573 
    1574 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    1575 /* Discard service -- ignore data */
     1450static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM)
     1451{
     1452#if BB_MMU
     1453    while (safe_read(s, line, LINE_SIZE) > 0)
     1454        continue;
     1455#else
     1456    /* We are after vfork here! */
     1457    /* move network socket to stdin */
     1458    xmove_fd(s, STDIN_FILENO);
     1459    /* discard output */
     1460    close(STDOUT_FILENO);
     1461    xopen(bb_dev_null, O_WRONLY);
     1462    /* no error messages please... */
     1463    xdup2(STDOUT_FILENO, STDERR_FILENO);
     1464    BB_EXECVP("cat", (char**)cat_args);
     1465    /* on failure we return to main, which does exit(EXIT_FAILURE) */
     1466#endif
     1467}
    15761468/* ARGSUSED */
    1577 static void
    1578 discard_stream(int s, servtab_t *sep)
    1579 {
    1580     char buffer[BUFSIZE];
    1581 
    1582     inetd_setproctitle(sep->se_service, s);
    1583     while (1) {
    1584         errno = 0;
    1585         if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR)
    1586             exit(0);
    1587     }
    1588 }
    1589 
    1590 /* Discard service -- ignore data */
    1591 /* ARGSUSED */
    1592 static void
    1593 discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1594 {
    1595     char buffer[BUFSIZE];
    1596 
    1597     (void) read(s, buffer, sizeof(buffer));
     1469static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM)
     1470{
     1471    /* dgram builtins are non-forking - DONT BLOCK! */
     1472    recv(s, line, LINE_SIZE, MSG_DONTWAIT);
    15981473}
    15991474#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
     
    16021477#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    16031478#define LINESIZ 72
    1604 static char ring[128];
    1605 static char *endring;
    1606 
    1607 static void
    1608 initring(void)
     1479static void init_ring(void)
    16091480{
    16101481    int i;
    16111482
    1612     endring = ring;
    1613 
    1614     for (i = 0; i <= 128; ++i)
    1615         if (isprint(i))
    1616             *endring++ = i;
    1617 }
    1618 
    1619 /* Character generator */
     1483    end_ring = ring;
     1484    for (i = ' '; i < 127; i++)
     1485        *end_ring++ = i;
     1486}
     1487/* Character generator. MMU arches only. */
    16201488/* ARGSUSED */
    1621 static void
    1622 chargen_stream(int s, servtab_t *sep)
     1489static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM)
    16231490{
    16241491    char *rs;
     
    16261493    char text[LINESIZ + 2];
    16271494
    1628     inetd_setproctitle(sep->se_service, s);
    1629 
    1630     if (!endring) {
    1631         initring();
     1495    if (!end_ring) {
     1496        init_ring();
    16321497        rs = ring;
    16331498    }
     
    16371502    rs = ring;
    16381503    for (;;) {
    1639         len = endring - rs;
     1504        len = end_ring - rs;
    16401505        if (len >= LINESIZ)
    16411506            memmove(text, rs, LINESIZ);
     
    16441509            memmove(text + len, ring, LINESIZ - len);
    16451510        }
    1646         if (++rs == endring)
     1511        if (++rs == end_ring)
    16471512            rs = ring;
    1648         if (write(s, text, sizeof(text)) != sizeof(text))
    1649             break;
    1650     }
    1651     exit(0);
    1652 }
    1653 
    1654 /* Character generator */
     1513        xwrite(s, text, sizeof(text));
     1514    }
     1515}
    16551516/* ARGSUSED */
    1656 static void
    1657 chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1658 {
    1659     /* struct sockaddr_storage ss; */
    1660     struct sockaddr sa;
    1661     static char *rs;
     1517static void FAST_FUNC chargen_dg(int s, servtab_t *sep)
     1518{
    16621519    int len;
    16631520    char text[LINESIZ + 2];
    1664     socklen_t size;
    1665 
    1666     if (endring == 0) {
    1667         initring();
    1668         rs = ring;
    1669     }
    1670 
    1671     size = sizeof(sa);
    1672     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
     1521    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1522
     1523    /* Eat UDP packet which started it all */
     1524    /* dgram builtins are non-forking - DONT BLOCK! */
     1525    lsa->len = sep->se_lsa->len;
     1526    if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
    16731527        return;
    1674     if (dg_badinput((struct sockaddr_in *) &sa))
    1675         return;
    1676 
    1677     if ((len = endring - rs) >= LINESIZ)
    1678         memmove(text, rs, LINESIZ);
     1528
     1529    if (!end_ring) {
     1530        init_ring();
     1531        ring_pos = ring;
     1532    }
     1533
     1534    len = end_ring - ring_pos;
     1535    if (len >= LINESIZ)
     1536        memmove(text, ring_pos, LINESIZ);
    16791537    else {
    1680         memmove(text, rs, len);
     1538        memmove(text, ring_pos, len);
    16811539        memmove(text + len, ring, LINESIZ - len);
    16821540    }
    1683     if (++rs == endring)
    1684         rs = ring;
     1541    if (++ring_pos == end_ring)
     1542        ring_pos = ring;
    16851543    text[LINESIZ] = '\r';
    16861544    text[LINESIZ + 1] = '\n';
    1687     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
     1545    sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
    16881546}
    16891547#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
     
    16981556 * some seventy years Bell Labs was asleep.
    16991557 */
    1700 
    1701 static unsigned machtime(void)
     1558static uint32_t machtime(void)
    17021559{
    17031560    struct timeval tv;
    17041561
    1705     if (gettimeofday(&tv, NULL) < 0) {
    1706         fprintf(stderr, "Unable to get time of day\n");
    1707         return 0L;
    1708     }
    1709     return htonl((unsigned) tv.tv_sec + 2208988800UL);
    1710 }
    1711 
     1562    gettimeofday(&tv, NULL);
     1563    return htonl((uint32_t)(tv.tv_sec + 2208988800));
     1564}
    17121565/* ARGSUSED */
    1713 static void
    1714 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1715 {
    1716     unsigned result;
     1566static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
     1567{
     1568    uint32_t result;
    17171569
    17181570    result = machtime();
    1719     (void) write(s, (char *) &result, sizeof(result));
    1720 }
    1721 
    1722 /* ARGSUSED */
    1723 static void
    1724 machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1725 {
    1726     unsigned result;
    1727     /* struct sockaddr_storage ss; */
    1728     struct sockaddr sa;
    1729     struct sockaddr_in *dg_sin;
    1730     socklen_t size;
    1731 
    1732     size = sizeof(sa);
    1733     if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)
     1571    full_write(s, &result, sizeof(result));
     1572}
     1573static void FAST_FUNC machtime_dg(int s, servtab_t *sep)
     1574{
     1575    uint32_t result;
     1576    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1577
     1578    lsa->len = sep->se_lsa->len;
     1579    if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
    17341580        return;
    1735     /* if (dg_badinput((struct sockaddr *)&ss)) */
    1736     dg_sin = (struct sockaddr_in *) &sa;
    1737     if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
    1738             ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)
    1739         return;
     1581
    17401582    result = machtime();
    1741     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
     1583    sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len);
    17421584}
    17431585#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
     
    17471589/* Return human-readable time of day */
    17481590/* ARGSUSED */
    1749 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1750 {
    1751     char buffer[32];
     1591static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM)
     1592{
    17521593    time_t t;
    17531594
    17541595    t = time(NULL);
    1755 
    1756 // fdprintf instead?
    1757     (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
    1758     (void) write(s, buffer, strlen(buffer));
    1759 }
    1760 
    1761 /* Return human-readable time of day */
    1762 /* ARGSUSED */
    1763 void
    1764 daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
    1765 {
    1766     char buffer[256];
     1596    fdprintf(s, "%.24s\r\n", ctime(&t));
     1597}
     1598static void FAST_FUNC daytime_dg(int s, servtab_t *sep)
     1599{
    17671600    time_t t;
    1768     /* struct sockaddr_storage ss; */
    1769     struct sockaddr sa;
    1770     socklen_t size;
     1601    len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
     1602
     1603    lsa->len = sep->se_lsa->len;
     1604    if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
     1605        return;
    17711606
    17721607    t = time(NULL);
    1773 
    1774     size = sizeof(sa);
    1775     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
    1776         return;
    1777     if (dg_badinput((struct sockaddr_in *) &sa))
    1778         return;
    1779     (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
    1780     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
     1608    sprintf(line, "%.24s\r\n", ctime(&t));
     1609    sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len);
    17811610}
    17821611#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
  • branches/2.2.9/mindi-busybox/networking/interface.c

    r1765 r2725  
    2020 *              and others.  Copyright 1993 MicroWalt Corporation
    2121 *
    22  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     22 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    2323 *
    2424 * Patched to support 'add' and 'del' keywords for INET(4) addresses
     
    3131 *          (default AF was wrong)
    3232 */
    33 
    3433#include <net/if.h>
    3534#include <net/if_arp.h>
     35#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
     36# include <net/ethernet.h>
     37#else
     38# include <linux/if_ether.h>
     39#endif
     40#include "libbb.h"
    3641#include "inet_common.h"
    37 #include "libbb.h"
     42
     43#if ENABLE_FEATURE_HWIB
     44/* #include <linux/if_infiniband.h> */
     45# undef INFINIBAND_ALEN
     46# define INFINIBAND_ALEN 20
     47#endif
    3848
    3949#if ENABLE_FEATURE_IPV6
     
    4757
    4858#ifdef HAVE_AFINET6
    49 
    50 #ifndef _LINUX_IN6_H
     59# ifndef _LINUX_IN6_H
    5160/*
    52  *    This is in linux/include/net/ipv6.h.
     61 * This is from linux/include/net/ipv6.h
    5362 */
    54 
    5563struct in6_ifreq {
    5664    struct in6_addr ifr6_addr;
     
    5866    unsigned int ifr6_ifindex;
    5967};
    60 
    61 #endif
    62 
     68# endif
    6369#endif /* HAVE_AFINET6 */
    6470
    6571/* Defines for glibc2.0 users. */
    6672#ifndef SIOCSIFTXQLEN
    67 #define SIOCSIFTXQLEN      0x8943
    68 #define SIOCGIFTXQLEN      0x8942
     73# define SIOCSIFTXQLEN      0x8943
     74# define SIOCGIFTXQLEN      0x8942
    6975#endif
    7076
    7177/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
    7278#ifndef ifr_qlen
    73 #define ifr_qlen        ifr_ifru.ifru_mtu
     79# define ifr_qlen        ifr_ifru.ifru_mtu
    7480#endif
    7581
    7682#ifndef HAVE_TXQUEUELEN
    77 #define HAVE_TXQUEUELEN 1
     83# define HAVE_TXQUEUELEN 1
    7884#endif
    7985
    8086#ifndef IFF_DYNAMIC
    81 #define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
     87# define IFF_DYNAMIC     0x8000 /* dialup device with changing addresses */
    8288#endif
    8389
    8490/* Display an Internet socket address. */
    85 static const char *INET_sprint(struct sockaddr *sap, int numeric)
    86 {
    87     static char *buff;
     91static const char* FAST_FUNC INET_sprint(struct sockaddr *sap, int numeric)
     92{
     93    static char *buff; /* defaults to NULL */
    8894
    8995    free(buff);
     
    137143#endif
    138144
    139 static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
     145static int FAST_FUNC INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
    140146{
    141147    return INET_resolve(bufp, (struct sockaddr_in *) sap, 0);
     
    153159
    154160static const struct aftype inet_aftype = {
    155     .name =     "inet",
    156     .title =    "DARPA Internet",
    157     .af =       AF_INET,
    158     .alen =     4,
    159     .sprint =   INET_sprint,
    160     .input =    INET_input,
     161    .name   = "inet",
     162    .title  = "DARPA Internet",
     163    .af     = AF_INET,
     164    .alen   = 4,
     165    .sprint = INET_sprint,
     166    .input  = INET_input,
    161167};
    162168
     
    165171/* Display an Internet socket address. */
    166172/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
    167 static const char *INET6_sprint(struct sockaddr *sap, int numeric)
     173static const char* FAST_FUNC INET6_sprint(struct sockaddr *sap, int numeric)
    168174{
    169175    static char *buff;
     
    192198#endif
    193199
    194 static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
     200static int FAST_FUNC INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
    195201{
    196202    return INET6_resolve(bufp, (struct sockaddr_in6 *) sap);
     
    206212
    207213static const struct aftype inet6_aftype = {
    208     .name =     "inet6",
    209     .title =    "IPv6",
    210     .af =       AF_INET6,
    211     .alen =     sizeof(struct in6_addr),
    212     .sprint =   INET6_sprint,
    213     .input =    INET6_input,
     214    .name   = "inet6",
     215    .title  = "IPv6",
     216    .af     = AF_INET6,
     217    .alen   = sizeof(struct in6_addr),
     218    .sprint = INET6_sprint,
     219    .input  = INET6_input,
    214220};
    215221
     
    217223
    218224/* Display an UNSPEC address. */
    219 static char *UNSPEC_print(unsigned char *ptr)
     225static char* FAST_FUNC UNSPEC_print(unsigned char *ptr)
    220226{
    221227    static char *buff;
     
    224230    unsigned int i;
    225231
    226     if (!buff);
     232    if (!buff)
    227233        buff = xmalloc(sizeof(struct sockaddr) * 3 + 1);
    228234    pos = buff;
     
    238244
    239245/* Display an UNSPEC socket address. */
    240 static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
     246static const char* FAST_FUNC UNSPEC_sprint(struct sockaddr *sap, int numeric UNUSED_PARAM)
    241247{
    242248    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
     
    249255    .title  = "UNSPEC",
    250256    .af     = AF_UNSPEC,
    251     .alen    = 0,
     257    .alen   = 0,
    252258    .print  = UNSPEC_print,
    253259    .sprint = UNSPEC_sprint,
     
    264270
    265271/* Check our protocol family table for this family. */
    266 const struct aftype *get_aftype(const char *name)
     272const struct aftype* FAST_FUNC get_aftype(const char *name)
    267273{
    268274    const struct aftype *const *afp;
     
    322328struct interface {
    323329    struct interface *next, *prev;
    324     char name[IFNAMSIZ];    /* interface name        */
    325     short type;         /* if type               */
    326     short flags;        /* various flags         */
    327     int metric;         /* routing metric        */
    328     int mtu;            /* MTU value             */
    329     int tx_queue_len;   /* transmit queue length */
    330     struct ifmap map;   /* hardware setup        */
    331     struct sockaddr addr;   /* IP address            */
    332     struct sockaddr dstaddr;    /* P-P IP address        */
    333     struct sockaddr broadaddr;  /* IP broadcast address  */
    334     struct sockaddr netmask;    /* IP network mask       */
     330    char name[IFNAMSIZ];                    /* interface name        */
     331    short type;                             /* if type               */
     332    short flags;                            /* various flags         */
     333    int metric;                             /* routing metric        */
     334    int mtu;                                /* MTU value             */
     335    int tx_queue_len;                       /* transmit queue length */
     336    struct ifmap map;                       /* hardware setup        */
     337    struct sockaddr addr;                   /* IP address            */
     338    struct sockaddr dstaddr;                /* P-P IP address        */
     339    struct sockaddr broadaddr;              /* IP broadcast address  */
     340    struct sockaddr netmask;                /* IP network mask       */
    335341    int has_ip;
    336     char hwaddr[32];    /* HW address            */
     342    char hwaddr[32];                        /* HW address            */
    337343    int statistics_valid;
    338     struct user_net_device_stats stats; /* statistics            */
    339     int keepalive;      /* keepalive value for SLIP */
    340     int outfill;        /* outfill value for SLIP */
     344    struct user_net_device_stats stats;     /* statistics            */
     345    int keepalive;                          /* keepalive value for SLIP */
     346    int outfill;                            /* outfill value for SLIP */
    341347};
    342348
     
    389395
    390396    new = xzalloc(sizeof(*new));
    391     safe_strncpy(new->name, name, IFNAMSIZ);
     397    strncpy_IFNAMSIZ(new->name, name);
    392398    nextp = ife ? &ife->next : &int_list;
    393399    new->prev = ife;
     
    404410{
    405411    /* Extract <name> from nul-terminated p where p matches
    406        <name>: after leading whitespace.
    407        If match is not made, set name empty and return unchanged p */
    408     int namestart=0, nameend=0;
    409     while (isspace(p[namestart]))
    410         namestart++;
    411     nameend=namestart;
    412     while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
     412     * <name>: after leading whitespace.
     413     * If match is not made, set name empty and return unchanged p
     414     */
     415    char *nameend;
     416    char *namestart = skip_whitespace(p);
     417
     418    nameend = namestart;
     419    while (*nameend && *nameend != ':' && !isspace(*nameend))
    413420        nameend++;
    414     if (p[nameend]==':') {
    415         if ((nameend-namestart)<IFNAMSIZ) {
    416             memcpy(name,&p[namestart],nameend-namestart);
    417             name[nameend-namestart]='\0';
    418             p=&p[nameend];
     421    if (*nameend == ':') {
     422        if ((nameend - namestart) < IFNAMSIZ) {
     423            memcpy(name, namestart, nameend - namestart);
     424            name[nameend - namestart] = '\0';
     425            p = nameend;
    419426        } else {
    420427            /* Interface name too large */
    421             name[0]='\0';
     428            name[0] = '\0';
    422429        }
    423430    } else {
    424431        /* trailing ':' not found - return empty */
    425         name[0]='\0';
     432        name[0] = '\0';
    426433    }
    427434    return p + 1;
     
    491498}
    492499
    493 static inline int procnetdev_version(char *buf)
     500static int procnetdev_version(char *buf)
    494501{
    495502    if (strstr(buf, "compressed"))
     
    525532            goto out;
    526533        }
    527         if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
     534        if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) {
    528535            /* assume it overflowed and try again */
    529536            numreqs += 10;
     
    560567        proc_read = 1;
    561568
    562     fh = fopen(_PATH_PROCNET_DEV, "r");
     569    fh = fopen_or_warn(_PATH_PROCNET_DEV, "r");
    563570    if (!fh) {
    564         bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
    565571        return if_readconf();
    566572    }
     
    608614    skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
    609615
    610     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     616    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    611617    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
    612618        close(skfd);
     
    615621    ife->flags = ifr.ifr_flags;
    616622
    617     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     623    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    618624    memset(ife->hwaddr, 0, 32);
    619625    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
     
    622628    ife->type = ifr.ifr_hwaddr.sa_family;
    623629
    624     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     630    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    625631    ife->metric = 0;
    626632    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
    627633        ife->metric = ifr.ifr_metric;
    628634
    629     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     635    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    630636    ife->mtu = 0;
    631637    if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
     
    634640    memset(&ife->map, 0, sizeof(struct ifmap));
    635641#ifdef SIOCGIFMAP
    636     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     642    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    637643    if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
    638644        ife->map = ifr.ifr_map;
     
    640646
    641647#ifdef HAVE_TXQUEUELEN
    642     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     648    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    643649    ife->tx_queue_len = -1; /* unknown value */
    644650    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
     
    648654#endif
    649655
    650     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     656    strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    651657    ifr.ifr_addr.sa_family = AF_INET;
    652658    memset(&ife->addr, 0, sizeof(struct sockaddr));
     
    654660        ife->has_ip = 1;
    655661        ife->addr = ifr.ifr_addr;
    656         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     662        strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    657663        memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
    658664        if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
    659665            ife->dstaddr = ifr.ifr_dstaddr;
    660666
    661         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     667        strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    662668        memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
    663669        if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
    664670            ife->broadaddr = ifr.ifr_broadaddr;
    665671
    666         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     672        strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
    667673        memset(&ife->netmask, 0, sizeof(struct sockaddr));
    668674        if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
     
    673679    return 0;
    674680}
    675 
    676681
    677682static int do_if_fetch(struct interface *ife)
     
    706711};
    707712
    708 #include <net/if_arp.h>
    709 
    710 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
    711 #include <net/ethernet.h>
    712 #else
    713 #include <linux/if_ether.h>
    714 #endif
    715 
    716713/* Display an Ethernet address in readable format. */
    717 static char *pr_ether(unsigned char *ptr)
     714static char* FAST_FUNC ether_print(unsigned char *ptr)
    718715{
    719716    static char *buff;
     
    727724}
    728725
    729 static int in_ether(const char *bufp, struct sockaddr *sap);
     726static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap);
    730727
    731728static const struct hwtype ether_hwtype = {
    732     .name =     "ether",
    733     .title =    "Ethernet",
    734     .type =     ARPHRD_ETHER,
    735     .alen =     ETH_ALEN,
    736     .print =    pr_ether,
    737     .input =    in_ether
     729    .name  = "ether",
     730    .title = "Ethernet",
     731    .type  = ARPHRD_ETHER,
     732    .alen  = ETH_ALEN,
     733    .print = ether_print,
     734    .input = ether_input
    738735};
    739736
     
    749746
    750747/* Input an Ethernet address and convert to binary. */
    751 static int in_ether(const char *bufp, struct sockaddr *sap)
     748static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap)
    752749{
    753750    unsigned char *ptr;
     
    789786}
    790787
    791 #include <net/if_arp.h>
    792 
    793788static const struct hwtype ppp_hwtype = {
    794789    .name =     "ppp",
     
    806801};
    807802#endif
     803#if ENABLE_FEATURE_HWIB
     804static const struct hwtype ib_hwtype = {
     805    .name  = "infiniband",
     806    .title = "InfiniBand",
     807    .type  = ARPHRD_INFINIBAND,
     808    .alen  = INFINIBAND_ALEN,
     809    .print = UNSPEC_print,
     810    .input = in_ib,
     811};
     812#endif
     813
    808814
    809815static const struct hwtype *const hwtypes[] = {
     
    814820#if ENABLE_FEATURE_IPV6
    815821    &sit_hwtype,
     822#endif
     823#if ENABLE_FEATURE_HWIB
     824    &ib_hwtype,
    816825#endif
    817826    NULL
     
    833842
    834843/* Check our hardware type table for this type. */
    835 const struct hwtype *get_hwtype(const char *name)
     844const struct hwtype* FAST_FUNC get_hwtype(const char *name)
    836845{
    837846    const struct hwtype *const *hwp;
     
    847856
    848857/* Check our hardware type table for this type. */
    849 const struct hwtype *get_hwntype(int type)
     858const struct hwtype* FAST_FUNC get_hwntype(int type)
    850859{
    851860    const struct hwtype *const *hwp;
     
    863872static int hw_null_address(const struct hwtype *hw, void *ap)
    864873{
    865     unsigned int i;
     874    int i;
    866875    unsigned char *address = (unsigned char *) ap;
    867876
     
    897906}
    898907
    899 static void ife_print(struct interface *ptr)
    900 {
    901     const struct aftype *ap;
    902     const struct hwtype *hw;
    903     int hf;
    904     int can_compress = 0;
    905908
    906909#ifdef HAVE_AFINET6
     910#define IPV6_ADDR_ANY           0x0000U
     911
     912#define IPV6_ADDR_UNICAST       0x0001U
     913#define IPV6_ADDR_MULTICAST     0x0002U
     914#define IPV6_ADDR_ANYCAST       0x0004U
     915
     916#define IPV6_ADDR_LOOPBACK      0x0010U
     917#define IPV6_ADDR_LINKLOCAL     0x0020U
     918#define IPV6_ADDR_SITELOCAL     0x0040U
     919
     920#define IPV6_ADDR_COMPATv4      0x0080U
     921
     922#define IPV6_ADDR_SCOPE_MASK    0x00f0U
     923
     924#define IPV6_ADDR_MAPPED        0x1000U
     925#define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
     926
     927
     928static void ife_print6(struct interface *ptr)
     929{
    907930    FILE *f;
    908931    char addr6[40], devname[20];
     
    910933    int plen, scope, dad_status, if_idx;
    911934    char addr6p[8][5];
    912 #endif
     935
     936    f = fopen_for_read(_PATH_PROCNET_IFINET6);
     937    if (f == NULL)
     938        return;
     939
     940    while (fscanf
     941           (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
     942            addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
     943            addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
     944            &dad_status, devname) != EOF
     945    ) {
     946        if (!strcmp(devname, ptr->name)) {
     947            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
     948                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
     949                    addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
     950            inet_pton(AF_INET6, addr6,
     951                      (struct sockaddr *) &sap.sin6_addr);
     952            sap.sin6_family = AF_INET6;
     953            printf("          inet6 addr: %s/%d",
     954                   INET6_sprint((struct sockaddr *) &sap, 1),
     955                   plen);
     956            printf(" Scope:");
     957            switch (scope & IPV6_ADDR_SCOPE_MASK) {
     958            case 0:
     959                puts("Global");
     960                break;
     961            case IPV6_ADDR_LINKLOCAL:
     962                puts("Link");
     963                break;
     964            case IPV6_ADDR_SITELOCAL:
     965                puts("Site");
     966                break;
     967            case IPV6_ADDR_COMPATv4:
     968                puts("Compat");
     969                break;
     970            case IPV6_ADDR_LOOPBACK:
     971                puts("Host");
     972                break;
     973            default:
     974                puts("Unknown");
     975            }
     976        }
     977    }
     978    fclose(f);
     979}
     980#else
     981#define ife_print6(a) ((void)0)
     982#endif
     983
     984static void ife_print(struct interface *ptr)
     985{
     986    const struct aftype *ap;
     987    const struct hwtype *hw;
     988    int hf;
     989    int can_compress = 0;
    913990
    914991    ap = get_afntype(ptr->addr.sa_family);
     
    9251002        hw = get_hwntype(-1);
    9261003
    927     printf("%-9.9s Link encap:%s  ", ptr->name, hw->title);
     1004    printf("%-9s Link encap:%s  ", ptr->name, hw->title);
    9281005    /* For some hardware types (eg Ash, ATM) we don't print the
    9291006       hardware address if it's null.  */
    930     if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
    931                                 hw->suppress_null_addr)))
     1007    if (hw->print != NULL
     1008     && !(hw_null_address(hw, ptr->hwaddr) && hw->suppress_null_addr)
     1009    ) {
    9321010        printf("HWaddr %s  ", hw->print((unsigned char *)ptr->hwaddr));
     1011    }
    9331012#ifdef IFF_PORTSEL
    9341013    if (ptr->flags & IFF_PORTSEL) {
     
    9381017    }
    9391018#endif
    940     puts("");
     1019    bb_putchar('\n');
    9411020
    9421021    if (ptr->has_ip) {
     
    9521031    }
    9531032
    954 #ifdef HAVE_AFINET6
    955 
    956 #define IPV6_ADDR_ANY           0x0000U
    957 
    958 #define IPV6_ADDR_UNICAST       0x0001U
    959 #define IPV6_ADDR_MULTICAST     0x0002U
    960 #define IPV6_ADDR_ANYCAST       0x0004U
    961 
    962 #define IPV6_ADDR_LOOPBACK      0x0010U
    963 #define IPV6_ADDR_LINKLOCAL     0x0020U
    964 #define IPV6_ADDR_SITELOCAL     0x0040U
    965 
    966 #define IPV6_ADDR_COMPATv4      0x0080U
    967 
    968 #define IPV6_ADDR_SCOPE_MASK    0x00f0U
    969 
    970 #define IPV6_ADDR_MAPPED        0x1000U
    971 #define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
    972 
    973     f = fopen(_PATH_PROCNET_IFINET6, "r");
    974     if (f != NULL) {
    975         while (fscanf
    976                (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
    977                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
    978                 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
    979                 &dad_status, devname) != EOF
    980         ) {
    981             if (!strcmp(devname, ptr->name)) {
    982                 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
    983                         addr6p[0], addr6p[1], addr6p[2], addr6p[3],
    984                         addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
    985                 inet_pton(AF_INET6, addr6,
    986                           (struct sockaddr *) &sap.sin6_addr);
    987                 sap.sin6_family = AF_INET6;
    988                 printf("          inet6 addr: %s/%d",
    989                        INET6_sprint((struct sockaddr *) &sap, 1),
    990                        plen);
    991                 printf(" Scope:");
    992                 switch (scope & IPV6_ADDR_SCOPE_MASK) {
    993                 case 0:
    994                     puts("Global");
    995                     break;
    996                 case IPV6_ADDR_LINKLOCAL:
    997                     puts("Link");
    998                     break;
    999                 case IPV6_ADDR_SITELOCAL:
    1000                     puts("Site");
    1001                     break;
    1002                 case IPV6_ADDR_COMPATv4:
    1003                     puts("Compat");
    1004                     break;
    1005                 case IPV6_ADDR_LOOPBACK:
    1006                     puts("Host");
    1007                     break;
    1008                 default:
    1009                     puts("Unknown");
    1010                 }
    1011             }
    1012         }
    1013         fclose(f);
    1014     }
    1015 #endif
     1033    ife_print6(ptr);
    10161034
    10171035    printf("          ");
     
    10741092        printf("  Outfill:%d  Keepalive:%d", ptr->outfill, ptr->keepalive);
    10751093#endif
    1076     puts("");
     1094    bb_putchar('\n');
    10771095
    10781096    /* If needed, display the interface statistics. */
     
    11051123        print_bytes_scaled(ptr->stats.rx_bytes, "  T");
    11061124        print_bytes_scaled(ptr->stats.tx_bytes, "\n");
    1107 
    1108     }
    1109 
    1110     if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
    1111          ptr->map.base_addr)) {
     1125    }
     1126
     1127    if (ptr->map.irq || ptr->map.mem_start
     1128     || ptr->map.dma || ptr->map.base_addr
     1129    ) {
    11121130        printf("          ");
    11131131        if (ptr->map.irq)
     
    11231141        if (ptr->map.dma)
    11241142            printf("DMA chan:%x ", ptr->map.dma);
    1125         puts("");
    1126     }
    1127     puts("");
    1128 }
    1129 
     1143        bb_putchar('\n');
     1144    }
     1145    bb_putchar('\n');
     1146}
    11301147
    11311148static int do_if_print(struct interface *ife) /*, int *opt_a)*/
     
    11611178    for (ife = int_list; ife; ife = ife->next) {
    11621179        int err = doit(ife, cookie);
    1163 
    11641180        if (err)
    11651181            return err;
     
    11931209}
    11941210
    1195 int display_interfaces(char *ifname)
     1211#if ENABLE_FEATURE_HWIB
     1212/* Input an Infiniband address and convert to binary. */
     1213int FAST_FUNC in_ib(const char *bufp, struct sockaddr *sap)
     1214{
     1215    sap->sa_family = ib_hwtype.type;
     1216//TODO: error check?
     1217    hex2bin((char*)sap->sa_data, bufp, INFINIBAND_ALEN);
     1218# ifdef HWIB_DEBUG
     1219    fprintf(stderr, "in_ib(%s): %s\n", bufp, UNSPEC_print(sap->sa_data));
     1220# endif
     1221    return 0;
     1222}
     1223#endif
     1224
     1225int FAST_FUNC display_interfaces(char *ifname)
    11961226{
    11971227    int status;
  • branches/2.2.9/mindi-busybox/networking/ip.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ip.c     "ip" utility frontend.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 *
    5  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    6  *
    7  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    8  *
     5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    96 *
    107 * Changes:
    11  *
    12  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
    13  * Bernhard Fischer rewrote to use index_in_substr_array
     8 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     9 * Bernhard Reutner-Fischer rewrote to use index_in_substr_array
    1410 */
    1511
     
    2521 || ENABLE_FEATURE_IP_RULE
    2622
    27 static int ATTRIBUTE_NORETURN ip_print_help(int ATTRIBUTE_UNUSED ac, char ATTRIBUTE_UNUSED **av)
     23static int FAST_FUNC ip_print_help(char **argv UNUSED_PARAM)
    2824{
    2925    bb_show_usage();
    3026}
    3127
    32 static int (*ip_func)(int argc, char **argv) = ip_print_help;
     28typedef int FAST_FUNC (*ip_func_ptr_t)(char**);
    3329
    34 static int ip_do(int argc, char **argv)
     30static int ip_do(ip_func_ptr_t ip_func, char **argv)
    3531{
    36     ip_parse_common_args(&argc, &argv);
    37     return ip_func(argc-1, argv+1);
     32    argv = ip_parse_common_args(argv + 1);
     33    return ip_func(argv);
    3834}
    3935
    4036#if ENABLE_FEATURE_IP_ADDRESS
    41 int ipaddr_main(int argc, char **argv);
    42 int ipaddr_main(int argc, char **argv)
     37int ipaddr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     38int ipaddr_main(int argc UNUSED_PARAM, char **argv)
    4339{
    44     ip_func = do_ipaddr;
    45     return ip_do(argc, argv);
     40    return ip_do(do_ipaddr, argv);
    4641}
    4742#endif
    4843#if ENABLE_FEATURE_IP_LINK
    49 int iplink_main(int argc, char **argv);
    50 int iplink_main(int argc, char **argv)
     44int iplink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     45int iplink_main(int argc UNUSED_PARAM, char **argv)
    5146{
    52     ip_func = do_iplink;
    53     return ip_do(argc, argv);
     47    return ip_do(do_iplink, argv);
    5448}
    5549#endif
    5650#if ENABLE_FEATURE_IP_ROUTE
    57 int iproute_main(int argc, char **argv);
    58 int iproute_main(int argc, char **argv)
     51int iproute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     52int iproute_main(int argc UNUSED_PARAM, char **argv)
    5953{
    60     ip_func = do_iproute;
    61     return ip_do(argc, argv);
     54    return ip_do(do_iproute, argv);
    6255}
    6356#endif
    6457#if ENABLE_FEATURE_IP_RULE
    65 int iprule_main(int argc, char **argv);
    66 int iprule_main(int argc, char **argv)
     58int iprule_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     59int iprule_main(int argc UNUSED_PARAM, char **argv)
    6760{
    68     ip_func = do_iprule;
    69     return ip_do(argc, argv);
     61    return ip_do(do_iprule, argv);
    7062}
    7163#endif
    7264#if ENABLE_FEATURE_IP_TUNNEL
    73 int iptunnel_main(int argc, char **argv);
    74 int iptunnel_main(int argc, char **argv)
     65int iptunnel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     66int iptunnel_main(int argc UNUSED_PARAM, char **argv)
    7567{
    76     ip_func = do_iptunnel;
    77     return ip_do(argc, argv);
     68    return ip_do(do_iptunnel, argv);
    7869}
    7970#endif
    8071
    8172
    82 int ip_main(int argc, char **argv);
    83 int ip_main(int argc, char **argv)
     73int ip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     74int ip_main(int argc UNUSED_PARAM, char **argv)
    8475{
    8576    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")
     77        IF_FEATURE_IP_ADDRESS("address\0")
     78        IF_FEATURE_IP_ROUTE("route\0")
     79        IF_FEATURE_IP_ROUTE("r\0")
     80        IF_FEATURE_IP_LINK("link\0")
     81        IF_FEATURE_IP_TUNNEL("tunnel\0")
     82        IF_FEATURE_IP_TUNNEL("tunl\0")
     83        IF_FEATURE_IP_RULE("rule\0")
    9184        ;
    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
     85    static const ip_func_ptr_t ip_func_ptrs[] = {
     86        ip_print_help,
     87        IF_FEATURE_IP_ADDRESS(do_ipaddr,)
     88        IF_FEATURE_IP_ROUTE(do_iproute,)
     89        IF_FEATURE_IP_ROUTE(do_iproute,)
     90        IF_FEATURE_IP_LINK(do_iplink,)
     91        IF_FEATURE_IP_TUNNEL(do_iptunnel,)
     92        IF_FEATURE_IP_TUNNEL(do_iptunnel,)
     93        IF_FEATURE_IP_RULE(do_iprule,)
    9994    };
     95    ip_func_ptr_t ip_func;
     96    int key;
    10097
    101     ip_parse_common_args(&argc, &argv);
    102     if (argc > 1) {
    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;
    109 #endif
    110 #if ENABLE_FEATURE_IP_ROUTE
    111         if (key == IP_route)
    112             ip_func = do_iproute;
    113 #endif
    114 #if ENABLE_FEATURE_IP_LINK
    115         if (key == IP_link)
    116             ip_func = do_iplink;
    117 #endif
    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;
    125 #endif
    126     }
    127     return ip_func(argc, argv);
     98    argv = ip_parse_common_args(argv + 1);
     99    key = *argv ? index_in_substrings(keywords, *argv++) : -1;
     100    ip_func = ip_func_ptrs[key + 1];
     101
     102    return ip_func(argv);
    128103}
    129104
  • branches/2.2.9/mindi-busybox/networking/ipcalc.c

    r1765 r2725  
    1010 * is no denying that this is a loving reimplementation
    1111 *
    12  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     12 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1313 */
    14 
    15 #include <getopt.h>
    16 #include <sys/socket.h>
     14#include "libbb.h"
     15/* After libbb.h, because on some systems it needs other includes */
    1716#include <arpa/inet.h>
    1817
    19 #include "libbb.h"
    20 
    21 #define CLASS_A_NETMASK ntohl(0xFF000000)
    22 #define CLASS_B_NETMASK ntohl(0xFFFF0000)
    23 #define CLASS_C_NETMASK ntohl(0xFFFFFF00)
     18#define CLASS_A_NETMASK ntohl(0xFF000000)
     19#define CLASS_B_NETMASK ntohl(0xFFFF0000)
     20#define CLASS_C_NETMASK ntohl(0xFFFFFF00)
    2421
    2522static unsigned long get_netmask(unsigned long ipaddr)
     
    6562#if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
    6663    static const char ipcalc_longopts[] ALIGN1 =
    67         "netmask\0"   No_argument "m"
    68         "broadcast\0" No_argument "b"
    69         "network\0"   No_argument "n"
     64        "netmask\0"   No_argument "m" // netmask from IP (assuming complete class A, B, or C network)
     65        "broadcast\0" No_argument "b" // broadcast from IP [netmask]
     66        "network\0"   No_argument "n" // network from IP [netmask]
    7067# if ENABLE_FEATURE_IPCALC_FANCY
    71         "prefix\0"    No_argument "p"
    72         "hostname\0"  No_argument "h"
    73         "silent\0"    No_argument "s"
     68        "prefix\0"    No_argument "p" // prefix from IP[/prefix] [netmask]
     69        "hostname\0"  No_argument "h" // hostname from IP
     70        "silent\0"    No_argument "s" // don’t ever display error messages
    7471# endif
    7572        ;
    7673#endif
    7774
    78 int ipcalc_main(int argc, char **argv);
    79 int ipcalc_main(int argc, char **argv)
     75int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     76int ipcalc_main(int argc UNUSED_PARAM, char **argv)
    8077{
    8178    unsigned opt;
    82     int have_netmask = 0;
    83     in_addr_t netmask, broadcast, network, ipaddr;
    84     struct in_addr a;
     79    bool have_netmask = 0;
     80    struct in_addr s_netmask, s_broadcast, s_network, s_ipaddr;
     81    /* struct in_addr { in_addr_t s_addr; }  and  in_addr_t
     82     * (which in turn is just a typedef to uint32_t)
     83     * are essentially the same type. A few macros for less verbosity: */
     84#define netmask   (s_netmask.s_addr)
     85#define broadcast (s_broadcast.s_addr)
     86#define network   (s_network.s_addr)
     87#define ipaddr    (s_ipaddr.s_addr)
    8588    char *ipstr;
    8689
     
    8891    applet_long_options = ipcalc_longopts;
    8992#endif
    90     opt = getopt32(argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs"));
    91     argc -= optind;
     93    opt_complementary = "-1:?2"; /* minimum 1 arg, maximum 2 args */
     94    opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs"));
    9295    argv += optind;
    93     if (opt & (BROADCAST | NETWORK | NETPREFIX)) {
    94         if (argc > 2 || argc <= 0)
    95             bb_show_usage();
    96     } else {
    97         if (argc != 1)
     96    if (opt & SILENT)
     97        logmode = LOGMODE_NONE; /* suppress error_msg() output */
     98    opt &= ~SILENT;
     99    if (!(opt & (BROADCAST | NETWORK | NETPREFIX))) {
     100        /* if no options at all or
     101         * (no broadcast,network,prefix) and (two args)... */
     102        if (!opt || argv[1])
    98103            bb_show_usage();
    99104    }
    100     if (opt & SILENT)
    101         logmode = LOGMODE_NONE; /* Suppress error_msg() output */
    102105
    103106    ipstr = argv[0];
     
    110113        while (*prefixstr) {
    111114            if (*prefixstr == '/') {
    112                 *prefixstr = (char)0;
    113                 prefixstr++;
     115                *prefixstr++ = '\0';
    114116                if (*prefixstr) {
    115117                    unsigned msk;
     
    132134        }
    133135    }
    134     ipaddr = inet_aton(ipstr, &a);
    135136
    136     if (ipaddr == 0) {
     137    if (inet_aton(ipstr, &s_ipaddr) == 0) {
    137138        bb_error_msg_and_die("bad IP address: %s", argv[0]);
    138139    }
    139     ipaddr = a.s_addr;
    140140
    141     if (argc == 2) {
     141    if (argv[1]) {
    142142        if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) {
    143143            bb_error_msg_and_die("use prefix or netmask, not both");
    144144        }
    145 
    146         netmask = inet_aton(argv[1], &a);
    147         if (netmask == 0) {
     145        if (inet_aton(argv[1], &s_netmask) == 0) {
    148146            bb_error_msg_and_die("bad netmask: %s", argv[1]);
    149147        }
    150         netmask = a.s_addr;
    151148    } else {
    152 
    153149        /* JHC - If the netmask wasn't provided then calculate it */
    154150        if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask)
     
    157153
    158154    if (opt & NETMASK) {
    159         printf("NETMASK=%s\n", inet_ntoa((*(struct in_addr *) &netmask)));
     155        printf("NETMASK=%s\n", inet_ntoa(s_netmask));
    160156    }
    161157
    162158    if (opt & BROADCAST) {
    163159        broadcast = (ipaddr & netmask) | ~netmask;
    164         printf("BROADCAST=%s\n", inet_ntoa((*(struct in_addr *) &broadcast)));
     160        printf("BROADCAST=%s\n", inet_ntoa(s_broadcast));
    165161    }
    166162
    167163    if (opt & NETWORK) {
    168164        network = ipaddr & netmask;
    169         printf("NETWORK=%s\n", inet_ntoa((*(struct in_addr *) &network)));
     165        printf("NETWORK=%s\n", inet_ntoa(s_network));
    170166    }
    171167
     
    177173        if (opt & HOSTNAME) {
    178174            struct hostent *hostinfo;
    179             int x;
    180175
    181176            hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET);
    182177            if (!hostinfo) {
    183                 bb_herror_msg_and_die("cannot find hostname for %s", argv[0]);
     178                bb_herror_msg_and_die("can't find hostname for %s", argv[0]);
    184179            }
    185             for (x = 0; hostinfo->h_name[x]; x++) {
    186                 hostinfo->h_name[x] = tolower(hostinfo->h_name[x]);
    187             }
     180            str_tolower(hostinfo->h_name);
    188181
    189182            printf("HOSTNAME=%s\n", hostinfo->h_name);
  • branches/2.2.9/mindi-busybox/networking/isrv.c

    r1765 r2725  
    44 * Intended to make writing telnetd-type servers easier.
    55 *
    6  * Copyright (C) 2007 Denis Vlasenko
     6 * Copyright (C) 2007 Denys Vlasenko
    77 *
    8  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2, see file LICENSE in this source tree.
    99 */
    1010
  • branches/2.2.9/mindi-busybox/networking/isrv.h

    r1765 r2725  
    44 * Intended to make writing telnetd-type servers easier.
    55 *
    6  * Copyright (C) 2007 Denis Vlasenko
     6 * Copyright (C) 2007 Denys Vlasenko
    77 *
    8  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     8 * Licensed under GPLv2, see file LICENSE in this source tree.
    99 */
     10
     11PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    1012
    1113/* opaque structure */
     
    3234    int linger_timeout
    3335);
     36
     37POP_SAVED_FUNCTION_VISIBILITY
  • branches/2.2.9/mindi-busybox/networking/isrv_identd.c

    r1765 r2725  
    33 * Fake identd server.
    44 *
    5  * Copyright (C) 2007 Denis Vlasenko
     5 * Copyright (C) 2007 Denys Vlasenko
    66 *
    7  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    99
     10#include "libbb.h"
    1011#include <syslog.h>
    11 #include "libbb.h"
    1212#include "isrv.h"
    1313
     
    6262    if (p)
    6363        *p = '\0';
    64     if (!p && sz && buf->pos <= sizeof(buf->buf))
     64    if (!p && sz && buf->pos <= (int)sizeof(buf->buf))
    6565        goto ok;
    6666    /* Terminate session. If we are in server mode, then
     
    7777}
    7878
    79 static int do_timeout(void **paramp)
     79static int do_timeout(void **paramp UNUSED_PARAM)
    8080{
    8181    return 1; /* terminate session */
     
    9393}
    9494
    95 int fakeidentd_main(int argc, char **argv);
    96 int fakeidentd_main(int argc, char **argv)
     95int fakeidentd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     96int fakeidentd_main(int argc UNUSED_PARAM, char **argv)
    9797{
    9898    enum {
     
    114114
    115115    /* Daemonize if no -f and no -i and no -w */
    116     if (!(opt & OPT_fiw));
     116    if (!(opt & OPT_fiw))
    117117        bb_daemonize_or_rexec(0, argv);
    118118
     
    123123     * (Or maybe we need yet another option "log to syslog") */
    124124    if (!(opt & OPT_fiw) /* || (opt & OPT_syslog) */) {
    125         openlog(applet_name, 0, LOG_DAEMON);
     125        openlog(applet_name, LOG_PID, LOG_DAEMON);
    126126        logmode = LOGMODE_SYSLOG;
    127127    }
  • branches/2.2.9/mindi-busybox/networking/libiproute/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     6# Licensed under GPLv2 or later, see file LICENSE in this source tree.
    67#
    78
    89lib-y:=
     10
     11
    912
    1013lib-$(CONFIG_SLATTACH) += \
     
    6366    rt_names.o \
    6467    utils.o
    65 
  • branches/2.2.9/mindi-busybox/networking/libiproute/ip_common.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 #ifndef _IP_COMMON_H
    3 #define _IP_COMMON_H 1
     2#ifndef IP_COMMON_H
     3#define IP_COMMON_H 1
    44
    55#include "libbb.h"
     
    1414#endif
    1515
    16 extern void ip_parse_common_args(int *argcp, char ***argvp);
    17 extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
    18 extern int ipaddr_list_or_flush(int argc, char **argv, int flush);
    19 extern int iproute_monitor(int argc, char **argv);
    20 extern void iplink_usage(void) ATTRIBUTE_NORETURN;
    21 extern void ipneigh_reset_filter(void);
     16PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    2217
    23 extern int do_ipaddr(int argc, char **argv);
    24 extern int do_iproute(int argc, char **argv);
    25 extern int do_iprule(int argc, char **argv);
    26 extern int do_ipneigh(int argc, char **argv);
    27 extern int do_iptunnel(int argc, char **argv);
    28 extern int do_iplink(int argc, char **argv);
    29 extern int do_ipmonitor(int argc, char **argv);
    30 extern int do_multiaddr(int argc, char **argv);
    31 extern int do_multiroute(int argc, char **argv);
    32 #endif /* ip_common.h */
     18char FAST_FUNC **ip_parse_common_args(char **argv);
     19//int FAST_FUNC print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
     20int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush);
     21//int FAST_FUNC iproute_monitor(char **argv);
     22//void FAST_FUNC ipneigh_reset_filter(void);
     23
     24int FAST_FUNC do_ipaddr(char **argv);
     25int FAST_FUNC do_iproute(char **argv);
     26int FAST_FUNC do_iprule(char **argv);
     27//int FAST_FUNC do_ipneigh(char **argv);
     28int FAST_FUNC do_iptunnel(char **argv);
     29int FAST_FUNC do_iplink(char **argv);
     30//int FAST_FUNC do_ipmonitor(char **argv);
     31//int FAST_FUNC do_multiaddr(char **argv);
     32//int FAST_FUNC do_multiroute(char **argv);
     33
     34POP_SAVED_FUNCTION_VISIBILITY
     35
     36#endif
  • branches/2.2.9/mindi-busybox/networking/libiproute/ip_parse_common_args.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ip.c     "ip" utility frontend.
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    11  *
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    129 *
    1310 * Changes:
    1411 *
    15  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
    1613 */
    1714
     
    1916#include "utils.h"
    2017
    21 int preferred_family = AF_UNSPEC;
     18family_t preferred_family = AF_UNSPEC;
    2219smallint oneline;
    2320char _SL_;
    2421
    25 void ip_parse_common_args(int *argcp, char ***argvp)
     22char** FAST_FUNC ip_parse_common_args(char **argv)
    2623{
    27     int argc = *argcp;
    28     char **argv = *argvp;
    2924    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";
     25        "oneline" "\0"
     26        "family" "\0"
     27        "4" "\0"
     28        "6" "\0"
     29        "0" "\0"
     30        ;
    3231    enum {
    33         ARG_family = 1,
    34         ARG_inet,
    35         ARG_inet6,
    36         ARG_link,
     32        ARG_oneline,
     33        ARG_family,
    3734        ARG_IPv4,
    3835        ARG_IPv6,
    3936        ARG_packet,
    40         ARG_oneline
    4137    };
    42     smalluint arg;
     38    static const family_t af_numbers[] = { AF_INET, AF_INET6, AF_PACKET };
     39    int arg;
    4340
    44     while (argc > 1) {
    45         char *opt = argv[1];
     41    while (*argv) {
     42        char *opt = *argv;
    4643
    47         if (strcmp(opt,"--") == 0) {
    48             argc--;
    49             argv++;
    50             break;
    51         }
    5244        if (opt[0] != '-')
    5345            break;
    54         if (opt[1] == '-')
     46        opt++;
     47        if (opt[0] == '-') {
    5548            opt++;
    56         arg = index_in_strings(ip_common_commands, opt) + 1;
     49            if (!opt[0]) { /* "--" */
     50                argv++;
     51                break;
     52            }
     53        }
     54        arg = index_in_substrings(ip_common_commands, opt);
     55        if (arg < 0)
     56            bb_show_usage();
     57        if (arg == ARG_oneline) {
     58            oneline = 1;
     59            argv++;
     60            continue;
     61        }
    5762        if (arg == ARG_family) {
    58             argc--;
     63            static const char families[] ALIGN1 =
     64                "inet" "\0" "inet6" "\0" "link" "\0";
    5965            argv++;
    60             if (!argv[1])
     66            if (!*argv)
    6167                bb_show_usage();
    62             arg = index_in_strings(ip_common_commands, argv[1]) + 1;
    63             if (arg == ARG_inet)
    64                 preferred_family = AF_INET;
    65             else if (arg == ARG_inet6)
    66                 preferred_family = AF_INET6;
    67             else if (arg == ARG_link)
    68                 preferred_family = AF_PACKET;
    69             else
    70                 invarg(argv[1], "protocol family");
    71         } else if (arg == ARG_IPv4) {
    72             preferred_family = AF_INET;
    73         } else if (arg == ARG_IPv6) {
    74             preferred_family = AF_INET6;
    75         } else if (arg == ARG_packet) {
    76             preferred_family = AF_PACKET;
    77         } else if (arg == ARG_oneline) {
    78             ++oneline;
     68            arg = index_in_strings(families, *argv);
     69            if (arg < 0)
     70                invarg(*argv, "protocol family");
     71            /* now arg == 0, 1 or 2 */
    7972        } else {
    80             bb_show_usage();
     73            arg -= ARG_IPv4;
     74            /* now arg == 0, 1 or 2 */
    8175        }
    82         argc--;
     76        preferred_family = af_numbers[arg];
    8377        argv++;
    8478    }
    8579    _SL_ = oneline ? '\\' : '\n';
    86     *argcp = argc;
    87     *argvp = argv;
     80    return argv;
    8881}
  • branches/2.2.9/mindi-busybox/networking/libiproute/ipaddress.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ipaddress.c      "ip address".
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    6  *
    7  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    86 *
    97 * Changes:
    10  *  Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
     8 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
    119 */
    1210
    13 //#include <sys/socket.h>
    14 //#include <sys/ioctl.h>
    1511#include <fnmatch.h>
    1612#include <net/if.h>
     
    2117#include "utils.h"
    2218
    23 
    24 typedef struct filter_t {
    25     int ifindex;
    26     int family;
    27     int oneline;
    28     int showqueue;
    29     inet_prefix pfx;
     19#ifndef IFF_LOWER_UP
     20/* from linux/if.h */
     21#define IFF_LOWER_UP  0x10000  /* driver signals L1 up */
     22#endif
     23
     24struct filter_t {
     25    char *label;
     26    char *flushb;
     27    struct rtnl_handle *rth;
    3028    int scope, scopemask;
    3129    int flags, flagmask;
    32     int up;
    33     char *label;
    34     int flushed;
    35     char *flushb;
    3630    int flushp;
    3731    int flushe;
    38     struct rtnl_handle *rth;
    39 } filter_t;
    40 
    41 #define filter (*(filter_t*)&bb_common_bufsiz1)
    42 
    43 
    44 static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
    45 {
    46     fprintf(fp, "<");
     32    int ifindex;
     33    family_t family;
     34    smallint showqueue;
     35    smallint oneline;
     36    smallint up;
     37    smallint flushed;
     38    inet_prefix pfx;
     39} FIX_ALIASING;
     40typedef struct filter_t filter_t;
     41
     42#define G_filter (*(filter_t*)&bb_common_bufsiz1)
     43
     44
     45static void print_link_flags(unsigned flags, unsigned mdown)
     46{
     47    static const int flag_masks[] = {
     48        IFF_LOOPBACK, IFF_BROADCAST, IFF_POINTOPOINT,
     49        IFF_MULTICAST, IFF_NOARP, IFF_UP, IFF_LOWER_UP };
     50    static const char flag_labels[] ALIGN1 =
     51        "LOOPBACK\0""BROADCAST\0""POINTOPOINT\0"
     52        "MULTICAST\0""NOARP\0""UP\0""LOWER_UP\0";
     53
     54    bb_putchar('<');
     55    if (flags & IFF_UP && !(flags & IFF_RUNNING))
     56        printf("NO-CARRIER,");
    4757    flags &= ~IFF_RUNNING;
    48 #define _PF(f) if (flags&IFF_##f) { \
    49           flags &= ~IFF_##f; \
    50           fprintf(fp, #f "%s", flags ? "," : ""); }
    51     _PF(LOOPBACK);
    52     _PF(BROADCAST);
    53     _PF(POINTOPOINT);
    54     _PF(MULTICAST);
    55     _PF(NOARP);
    5658#if 0
    5759    _PF(ALLMULTI);
     
    6567    _PF(NOTRAILERS);
    6668#endif
    67     _PF(UP);
    68 #undef _PF
     69    flags = print_flags_separated(flag_masks, flag_labels, flags, ",");
    6970    if (flags)
    70         fprintf(fp, "%x", flags);
     71        printf("%x", flags);
    7172    if (mdown)
    72         fprintf(fp, ",M-DOWN");
    73     fprintf(fp, "> ");
     73        printf(",M-DOWN");
     74    printf("> ");
    7475}
    7576
     
    8485
    8586    memset(&ifr, 0, sizeof(ifr));
    86     strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
     87    strncpy_IFNAMSIZ(ifr.ifr_name, name);
    8788    if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) {
    8889        close(s);
     
    9596}
    9697
    97 static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
    98         const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
    99 {
    100     FILE *fp = (FILE*)arg;
     98static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
     99{
    101100    struct ifinfomsg *ifi = NLMSG_DATA(n);
    102     struct rtattr * tb[IFLA_MAX+1];
     101    struct rtattr *tb[IFLA_MAX+1];
    103102    int len = n->nlmsg_len;
    104     unsigned m_flag = 0;
    105103
    106104    if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
     
    111109        return -1;
    112110
    113     if (filter.ifindex && ifi->ifi_index != filter.ifindex)
    114         return 0;
    115     if (filter.up && !(ifi->ifi_flags&IFF_UP))
     111    if (G_filter.ifindex && ifi->ifi_index != G_filter.ifindex)
     112        return 0;
     113    if (G_filter.up && !(ifi->ifi_flags & IFF_UP))
    116114        return 0;
    117115
     
    122120        return -1;
    123121    }
    124     if (filter.label
    125      && (!filter.family || filter.family == AF_PACKET)
    126      && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)
     122    if (G_filter.label
     123     && (!G_filter.family || G_filter.family == AF_PACKET)
     124     && fnmatch(G_filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)
    127125    ) {
    128126        return 0;
     
    130128
    131129    if (n->nlmsg_type == RTM_DELLINK)
    132         fprintf(fp, "Deleted ");
    133 
    134     fprintf(fp, "%d: %s", ifi->ifi_index,
    135         tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>");
    136 
    137     if (tb[IFLA_LINK]) {
    138         SPRINT_BUF(b1);
    139         int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
    140         if (iflink == 0)
    141             fprintf(fp, "@NONE: ");
    142         else {
    143             fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
    144             m_flag = ll_index_to_flags(iflink);
    145             m_flag = !(m_flag & IFF_UP);
    146         }
    147     } else {
    148         fprintf(fp, ": ");
    149     }
    150     print_link_flags(fp, ifi->ifi_flags, m_flag);
     130        printf("Deleted ");
     131
     132    printf("%d: %s", ifi->ifi_index,
     133        /*tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>" - we checked tb[IFLA_IFNAME] above*/
     134        (char*)RTA_DATA(tb[IFLA_IFNAME])
     135    );
     136
     137    {
     138        unsigned m_flag = 0;
     139        if (tb[IFLA_LINK]) {
     140            SPRINT_BUF(b1);
     141            int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
     142            if (iflink == 0)
     143                printf("@NONE: ");
     144            else {
     145                printf("@%s: ", ll_idx_n2a(iflink, b1));
     146                m_flag = ll_index_to_flags(iflink);
     147                m_flag = !(m_flag & IFF_UP);
     148            }
     149        } else {
     150            printf(": ");
     151        }
     152        print_link_flags(ifi->ifi_flags, m_flag);
     153    }
    151154
    152155    if (tb[IFLA_MTU])
    153         fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
     156        printf("mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
    154157    if (tb[IFLA_QDISC])
    155         fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
     158        printf("qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
    156159#ifdef IFLA_MASTER
    157160    if (tb[IFLA_MASTER]) {
    158161        SPRINT_BUF(b1);
    159         fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
     162        printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
    160163    }
    161164#endif
    162     if (filter.showqueue)
     165    if (tb[IFLA_OPERSTATE]) {
     166        static const char operstate_labels[] ALIGN1 =
     167            "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0"
     168            "TESTING\0""DORMANT\0""UP\0";
     169        printf("state %s ", nth_string(operstate_labels,
     170                    *(uint8_t *)RTA_DATA(tb[IFLA_OPERSTATE])));
     171    }
     172    if (G_filter.showqueue)
    163173        print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
    164174
    165     if (!filter.family || filter.family == AF_PACKET) {
     175    if (!G_filter.family || G_filter.family == AF_PACKET) {
    166176        SPRINT_BUF(b1);
    167         fprintf(fp, "%c    link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
     177        printf("%c    link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1));
    168178
    169179        if (tb[IFLA_ADDRESS]) {
    170             fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
     180            fputs(ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
    171181                              RTA_PAYLOAD(tb[IFLA_ADDRESS]),
    172182                              ifi->ifi_type,
    173                               b1, sizeof(b1)));
     183                              b1, sizeof(b1)), stdout);
    174184        }
    175185        if (tb[IFLA_BROADCAST]) {
    176             if (ifi->ifi_flags&IFF_POINTOPOINT)
    177                 fprintf(fp, " peer ");
     186            if (ifi->ifi_flags & IFF_POINTOPOINT)
     187                printf(" peer ");
    178188            else
    179                 fprintf(fp, " brd ");
    180             fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
     189                printf(" brd ");
     190            fputs(ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
    181191                              RTA_PAYLOAD(tb[IFLA_BROADCAST]),
    182192                              ifi->ifi_type,
    183                               b1, sizeof(b1)));
    184         }
    185     }
    186     fputc('\n', fp);
    187     fflush(fp);
     193                              b1, sizeof(b1)), stdout);
     194        }
     195    }
     196    bb_putchar('\n');
     197    /*fflush_all();*/
    188198    return 0;
    189199}
     
    191201static int flush_update(void)
    192202{
    193     if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
    194         bb_perror_msg("failed to send flush request");
     203    if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
     204        bb_perror_msg("can't send flush request");
    195205        return -1;
    196206    }
    197     filter.flushp = 0;
     207    G_filter.flushp = 0;
    198208    return 0;
    199209}
    200210
    201 static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
    202         struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
    203 {
    204     FILE *fp = (FILE*)arg;
     211static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
     212        struct nlmsghdr *n, void *arg UNUSED_PARAM)
     213{
    205214    struct ifaddrmsg *ifa = NLMSG_DATA(n);
    206215    int len = n->nlmsg_len;
     
    217226    }
    218227
    219     if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
     228    if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR)
    220229        return 0;
    221230
     
    228237        rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
    229238
    230     if (filter.ifindex && filter.ifindex != ifa->ifa_index)
    231         return 0;
    232     if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
    233         return 0;
    234     if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
    235         return 0;
    236     if (filter.label) {
     239    if (G_filter.ifindex && G_filter.ifindex != ifa->ifa_index)
     240        return 0;
     241    if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask)
     242        return 0;
     243    if ((G_filter.flags ^ ifa->ifa_flags) & G_filter.flagmask)
     244        return 0;
     245    if (G_filter.label) {
    237246        const char *label;
    238247        if (rta_tb[IFA_LABEL])
     
    240249        else
    241250            label = ll_idx_n2a(ifa->ifa_index, b1);
    242         if (fnmatch(filter.label, label, 0) != 0)
     251        if (fnmatch(G_filter.label, label, 0) != 0)
    243252            return 0;
    244253    }
    245     if (filter.pfx.family) {
     254    if (G_filter.pfx.family) {
    246255        if (rta_tb[IFA_LOCAL]) {
    247256            inet_prefix dst;
     
    249258            dst.family = ifa->ifa_family;
    250259            memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
    251             if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
     260            if (inet_addr_match(&dst, &G_filter.pfx, G_filter.pfx.bitlen))
    252261                return 0;
    253262        }
    254263    }
    255264
    256     if (filter.flushb) {
     265    if (G_filter.flushb) {
    257266        struct nlmsghdr *fn;
    258         if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
     267        if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
    259268            if (flush_update())
    260269                return -1;
    261270        }
    262         fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
     271        fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
    263272        memcpy(fn, n, n->nlmsg_len);
    264273        fn->nlmsg_type = RTM_DELADDR;
    265274        fn->nlmsg_flags = NLM_F_REQUEST;
    266         fn->nlmsg_seq = ++filter.rth->seq;
    267         filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
    268         filter.flushed++;
     275        fn->nlmsg_seq = ++G_filter.rth->seq;
     276        G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
     277        G_filter.flushed = 1;
    269278        return 0;
    270279    }
    271280
    272281    if (n->nlmsg_type == RTM_DELADDR)
    273         fprintf(fp, "Deleted ");
    274 
    275     if (filter.oneline)
    276         fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
     282        printf("Deleted ");
     283
     284    if (G_filter.oneline)
     285        printf("%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
    277286    if (ifa->ifa_family == AF_INET)
    278         fprintf(fp, "    inet ");
     287        printf("    inet ");
    279288    else if (ifa->ifa_family == AF_INET6)
    280         fprintf(fp, "    inet6 ");
     289        printf("    inet6 ");
    281290    else
    282         fprintf(fp, "    family %d ", ifa->ifa_family);
     291        printf("    family %d ", ifa->ifa_family);
    283292
    284293    if (rta_tb[IFA_LOCAL]) {
    285         fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
    286                           RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
     294        fputs(rt_addr_n2a(ifa->ifa_family,
    287295                          RTA_DATA(rta_tb[IFA_LOCAL]),
    288                           abuf, sizeof(abuf)));
    289 
    290         if (rta_tb[IFA_ADDRESS] == NULL ||
    291             memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
    292             fprintf(fp, "/%d ", ifa->ifa_prefixlen);
     296                          abuf, sizeof(abuf)), stdout);
     297
     298        if (rta_tb[IFA_ADDRESS] == NULL
     299         || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0
     300        ) {
     301            printf("/%d ", ifa->ifa_prefixlen);
    293302        } else {
    294             fprintf(fp, " peer %s/%d ",
     303            printf(" peer %s/%d ",
    295304                rt_addr_n2a(ifa->ifa_family,
    296                         RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
    297305                        RTA_DATA(rta_tb[IFA_ADDRESS]),
    298306                        abuf, sizeof(abuf)),
     
    302310
    303311    if (rta_tb[IFA_BROADCAST]) {
    304         fprintf(fp, "brd %s ",
     312        printf("brd %s ",
    305313            rt_addr_n2a(ifa->ifa_family,
    306                     RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
    307314                    RTA_DATA(rta_tb[IFA_BROADCAST]),
    308315                    abuf, sizeof(abuf)));
    309316    }
    310317    if (rta_tb[IFA_ANYCAST]) {
    311         fprintf(fp, "any %s ",
     318        printf("any %s ",
    312319            rt_addr_n2a(ifa->ifa_family,
    313                     RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
    314320                    RTA_DATA(rta_tb[IFA_ANYCAST]),
    315321                    abuf, sizeof(abuf)));
    316322    }
    317     fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
    318     if (ifa->ifa_flags&IFA_F_SECONDARY) {
     323    printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1));
     324    if (ifa->ifa_flags & IFA_F_SECONDARY) {
    319325        ifa->ifa_flags &= ~IFA_F_SECONDARY;
    320         fprintf(fp, "secondary ");
    321     }
    322     if (ifa->ifa_flags&IFA_F_TENTATIVE) {
     326        printf("secondary ");
     327    }
     328    if (ifa->ifa_flags & IFA_F_TENTATIVE) {
    323329        ifa->ifa_flags &= ~IFA_F_TENTATIVE;
    324         fprintf(fp, "tentative ");
    325     }
    326     if (ifa->ifa_flags&IFA_F_DEPRECATED) {
     330        printf("tentative ");
     331    }
     332    if (ifa->ifa_flags & IFA_F_DEPRECATED) {
    327333        ifa->ifa_flags &= ~IFA_F_DEPRECATED;
    328         fprintf(fp, "deprecated ");
    329     }
    330     if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
    331         fprintf(fp, "dynamic ");
     334        printf("deprecated ");
     335    }
     336    if (!(ifa->ifa_flags & IFA_F_PERMANENT)) {
     337        printf("dynamic ");
    332338    } else
    333339        ifa->ifa_flags &= ~IFA_F_PERMANENT;
    334340    if (ifa->ifa_flags)
    335         fprintf(fp, "flags %02x ", ifa->ifa_flags);
     341        printf("flags %02x ", ifa->ifa_flags);
    336342    if (rta_tb[IFA_LABEL])
    337         fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
     343        fputs((char*)RTA_DATA(rta_tb[IFA_LABEL]), stdout);
    338344    if (rta_tb[IFA_CACHEINFO]) {
    339345        struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
    340346        char buf[128];
    341         fputc(_SL_, fp);
     347        bb_putchar(_SL_);
    342348        if (ci->ifa_valid == 0xFFFFFFFFU)
    343349            sprintf(buf, "valid_lft forever");
     
    348354        else
    349355            sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
    350         fprintf(fp, "       %s", buf);
    351     }
    352     fputc('\n', fp);
    353     fflush(fp);
     356        printf("       %s", buf);
     357    }
     358    bb_putchar('\n');
     359    /*fflush_all();*/
    354360    return 0;
    355361}
    356362
    357363
    358 struct nlmsg_list
    359 {
     364struct nlmsg_list {
    360365    struct nlmsg_list *next;
    361     struct nlmsghdr   h;
     366    struct nlmsghdr   h;
    362367};
    363368
    364 static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
     369static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo)
    365370{
    366371    for (; ainfo; ainfo = ainfo->next) {
     
    370375        if (n->nlmsg_type != RTM_NEWADDR)
    371376            continue;
    372 
    373377        if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
    374378            return -1;
    375 
    376         if (ifa->ifa_index != ifindex ||
    377             (filter.family && filter.family != ifa->ifa_family))
     379        if (ifa->ifa_index != ifindex
     380         || (G_filter.family && G_filter.family != ifa->ifa_family)
     381        ) {
    378382            continue;
    379 
    380         print_addrinfo(NULL, n, fp);
     383        }
     384        print_addrinfo(NULL, n, NULL);
    381385    }
    382386    return 0;
     
    384388
    385389
    386 static int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
     390static int FAST_FUNC store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
    387391{
    388392    struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
     
    390394    struct nlmsg_list **lp;
    391395
    392     h = malloc(n->nlmsg_len+sizeof(void*));
    393     if (h == NULL)
    394         return -1;
     396    h = xzalloc(n->nlmsg_len + sizeof(void*));
    395397
    396398    memcpy(&h->h, n, n->nlmsg_len);
    397     h->next = NULL;
    398 
    399     for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
     399    /*h->next = NULL; - xzalloc did it */
     400
     401    for (lp = linfo; *lp; lp = &(*lp)->next)
     402        continue;
    400403    *lp = h;
    401404
     
    406409static void ipaddr_reset_filter(int _oneline)
    407410{
    408     memset(&filter, 0, sizeof(filter));
    409     filter.oneline = _oneline;
     411    memset(&G_filter, 0, sizeof(G_filter));
     412    G_filter.oneline = _oneline;
    410413}
    411414
    412415/* Return value becomes exitcode. It's okay to not return at all */
    413 int ipaddr_list_or_flush(int argc, char **argv, int flush)
     416int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
    414417{
    415418    static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0";
     
    423426
    424427    ipaddr_reset_filter(oneline);
    425     filter.showqueue = 1;
    426 
    427     if (filter.family == AF_UNSPEC)
    428         filter.family = preferred_family;
     428    G_filter.showqueue = 1;
     429
     430    if (G_filter.family == AF_UNSPEC)
     431        G_filter.family = preferred_family;
    429432
    430433    if (flush) {
    431         if (argc <= 0) {
     434        if (!*argv) {
    432435            bb_error_msg_and_die(bb_msg_requires_arg, "flush");
    433436        }
    434         if (filter.family == AF_PACKET) {
    435             bb_error_msg_and_die("cannot flush link addresses");
    436         }
    437     }
    438 
    439     while (argc > 0) {
    440         const int option_num = index_in_strings(option, *argv);
    441         switch (option_num) {
    442             case 0: /* to */
     437        if (G_filter.family == AF_PACKET) {
     438            bb_error_msg_and_die("can't flush link addresses");
     439        }
     440    }
     441
     442    while (*argv) {
     443        const smalluint key = index_in_strings(option, *argv);
     444        if (key == 0) { /* to */
     445            NEXT_ARG();
     446            get_prefix(&G_filter.pfx, *argv, G_filter.family);
     447            if (G_filter.family == AF_UNSPEC) {
     448                G_filter.family = G_filter.pfx.family;
     449            }
     450        } else if (key == 1) { /* scope */
     451            uint32_t scope = 0;
     452            NEXT_ARG();
     453            G_filter.scopemask = -1;
     454            if (rtnl_rtscope_a2n(&scope, *argv)) {
     455                if (strcmp(*argv, "all") != 0) {
     456                    invarg(*argv, "scope");
     457                }
     458                scope = RT_SCOPE_NOWHERE;
     459                G_filter.scopemask = 0;
     460            }
     461            G_filter.scope = scope;
     462        } else if (key == 2) { /* up */
     463            G_filter.up = 1;
     464        } else if (key == 3) { /* label */
     465            NEXT_ARG();
     466            G_filter.label = *argv;
     467        } else {
     468            if (key == 4) /* dev */
    443469                NEXT_ARG();
    444                 get_prefix(&filter.pfx, *argv, filter.family);
    445                 if (filter.family == AF_UNSPEC) {
    446                     filter.family = filter.pfx.family;
    447                 }
    448                 break;
    449             case 1: /* scope */
    450             {
    451                 uint32_t scope = 0;
    452                 NEXT_ARG();
    453                 filter.scopemask = -1;
    454                 if (rtnl_rtscope_a2n(&scope, *argv)) {
    455                     if (strcmp(*argv, "all") != 0) {
    456                         invarg(*argv, "scope");
    457                     }
    458                     scope = RT_SCOPE_NOWHERE;
    459                     filter.scopemask = 0;
    460                 }
    461                 filter.scope = scope;
    462                 break;
    463             }
    464             case 2: /* up */
    465                 filter.up = 1;
    466                 break;
    467             case 3: /* label */
    468                 NEXT_ARG();
    469                 filter.label = *argv;
    470                 break;
    471             case 4: /* dev */
    472                 NEXT_ARG();
    473             default:
    474                 if (filter_dev) {
    475                     duparg2("dev", *argv);
    476                 }
    477                 filter_dev = *argv;
     470            if (filter_dev)
     471                duparg2("dev", *argv);
     472            filter_dev = *argv;
    478473        }
    479474        argv++;
    480         argc--;
    481475    }
    482476
     
    487481
    488482    if (filter_dev) {
    489         filter.ifindex = xll_name_to_index(filter_dev);
     483        G_filter.ifindex = xll_name_to_index(filter_dev);
    490484    }
    491485
     
    493487        char flushb[4096-512];
    494488
    495         filter.flushb = flushb;
    496         filter.flushp = 0;
    497         filter.flushe = sizeof(flushb);
    498         filter.rth = &rth;
     489        G_filter.flushb = flushb;
     490        G_filter.flushp = 0;
     491        G_filter.flushe = sizeof(flushb);
     492        G_filter.rth = &rth;
    499493
    500494        for (;;) {
    501             xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR);
    502             filter.flushed = 0;
    503             xrtnl_dump_filter(&rth, print_addrinfo, stdout);
    504             if (filter.flushed == 0) {
     495            xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETADDR);
     496            G_filter.flushed = 0;
     497            xrtnl_dump_filter(&rth, print_addrinfo, NULL);
     498            if (G_filter.flushed == 0) {
    505499                return 0;
    506500            }
    507             if (flush_update() < 0)
     501            if (flush_update() < 0) {
    508502                return 1;
    509         }
    510     }
    511 
    512     if (filter.family != AF_PACKET) {
    513         xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR);
     503            }
     504        }
     505    }
     506
     507    if (G_filter.family != AF_PACKET) {
     508        xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETADDR);
    514509        xrtnl_dump_filter(&rth, store_nlmsg, &ainfo);
    515510    }
    516511
    517512
    518     if (filter.family && filter.family != AF_PACKET) {
     513    if (G_filter.family && G_filter.family != AF_PACKET) {
    519514        struct nlmsg_list **lp;
    520         lp=&linfo;
    521 
    522         if (filter.oneline)
     515        lp = &linfo;
     516
     517        if (G_filter.oneline)
    523518            no_link = 1;
    524519
    525         while ((l=*lp)!=NULL) {
     520        while ((l = *lp) != NULL) {
    526521            int ok = 0;
    527522            struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
    528523            struct nlmsg_list *a;
    529524
    530             for (a=ainfo; a; a=a->next) {
     525            for (a = ainfo; a; a = a->next) {
    531526                struct nlmsghdr *n = &a->h;
    532527                struct ifaddrmsg *ifa = NLMSG_DATA(n);
    533528
    534                 if (ifa->ifa_index != ifi->ifi_index ||
    535                     (filter.family && filter.family != ifa->ifa_family))
     529                if (ifa->ifa_index != ifi->ifi_index
     530                 || (G_filter.family && G_filter.family != ifa->ifa_family)
     531                ) {
    536532                    continue;
    537                 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
     533                }
     534                if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask)
    538535                    continue;
    539                 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
     536                if ((G_filter.flags ^ ifa->ifa_flags) & G_filter.flagmask)
    540537                    continue;
    541                 if (filter.pfx.family || filter.label) {
     538                if (G_filter.pfx.family || G_filter.label) {
    542539                    struct rtattr *tb[IFA_MAX+1];
    543540                    memset(tb, 0, sizeof(tb));
     
    546543                        tb[IFA_LOCAL] = tb[IFA_ADDRESS];
    547544
    548                     if (filter.pfx.family && tb[IFA_LOCAL]) {
     545                    if (G_filter.pfx.family && tb[IFA_LOCAL]) {
    549546                        inet_prefix dst;
    550547                        memset(&dst, 0, sizeof(dst));
    551548                        dst.family = ifa->ifa_family;
    552549                        memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
    553                         if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
     550                        if (inet_addr_match(&dst, &G_filter.pfx, G_filter.pfx.bitlen))
    554551                            continue;
    555552                    }
    556                     if (filter.label) {
     553                    if (G_filter.label) {
    557554                        SPRINT_BUF(b1);
    558555                        const char *label;
     
    561558                        else
    562559                            label = ll_idx_n2a(ifa->ifa_index, b1);
    563                         if (fnmatch(filter.label, label, 0) != 0)
     560                        if (fnmatch(G_filter.label, label, 0) != 0)
    564561                            continue;
    565562                    }
     
    577574
    578575    for (l = linfo; l; l = l->next) {
    579         if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
     576        if (no_link || print_linkinfo(&l->h) == 0) {
    580577            struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
    581             if (filter.family != AF_PACKET)
    582                 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
    583         }
    584         fflush(stdout); /* why? */
     578            if (G_filter.family != AF_PACKET)
     579                print_selected_addrinfo(ifi->ifi_index, ainfo);
     580        }
    585581    }
    586582
     
    598594
    599595/* Return value becomes exitcode. It's okay to not return at all */
    600 static int ipaddr_modify(int cmd, int argc, char **argv)
     596static int ipaddr_modify(int cmd, char **argv)
    601597{
    602598    static const char option[] ALIGN1 =
     
    626622    req.ifa.ifa_family = preferred_family;
    627623
    628     while (argc > 0) {
    629         const int option_num = index_in_strings(option, *argv);
    630         switch (option_num) {
    631             case 0: /* peer */
    632             case 1: /* remote */
     624    while (*argv) {
     625        const smalluint arg = index_in_strings(option, *argv);
     626        if (arg <= 1) { /* peer, remote */
     627            NEXT_ARG();
     628
     629            if (peer_len) {
     630                duparg("peer", *argv);
     631            }
     632            get_prefix(&peer, *argv, req.ifa.ifa_family);
     633            peer_len = peer.bytelen;
     634            if (req.ifa.ifa_family == AF_UNSPEC) {
     635                req.ifa.ifa_family = peer.family;
     636            }
     637            addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
     638            req.ifa.ifa_prefixlen = peer.bitlen;
     639        } else if (arg <= 3) { /* broadcast, brd */
     640            inet_prefix addr;
     641            NEXT_ARG();
     642            if (brd_len) {
     643                duparg("broadcast", *argv);
     644            }
     645            if (LONE_CHAR(*argv, '+')) {
     646                brd_len = -1;
     647            } else if (LONE_DASH(*argv)) {
     648                brd_len = -2;
     649            } else {
     650                get_addr(&addr, *argv, req.ifa.ifa_family);
     651                if (req.ifa.ifa_family == AF_UNSPEC)
     652                    req.ifa.ifa_family = addr.family;
     653                addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
     654                brd_len = addr.bytelen;
     655            }
     656        } else if (arg == 4) { /* anycast */
     657            inet_prefix addr;
     658            NEXT_ARG();
     659            if (any_len) {
     660                duparg("anycast", *argv);
     661            }
     662            get_addr(&addr, *argv, req.ifa.ifa_family);
     663            if (req.ifa.ifa_family == AF_UNSPEC) {
     664                req.ifa.ifa_family = addr.family;
     665            }
     666            addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
     667            any_len = addr.bytelen;
     668        } else if (arg == 5) { /* scope */
     669            uint32_t scope = 0;
     670            NEXT_ARG();
     671            if (rtnl_rtscope_a2n(&scope, *argv)) {
     672                invarg(*argv, "scope");
     673            }
     674            req.ifa.ifa_scope = scope;
     675            scoped = 1;
     676        } else if (arg == 6) { /* dev */
     677            NEXT_ARG();
     678            d = *argv;
     679        } else if (arg == 7) { /* label */
     680            NEXT_ARG();
     681            l = *argv;
     682            addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
     683        } else {
     684            if (arg == 8) /* local */
    633685                NEXT_ARG();
    634 
    635                 if (peer_len) {
    636                     duparg("peer", *argv);
    637                 }
    638                 get_prefix(&peer, *argv, req.ifa.ifa_family);
    639                 peer_len = peer.bytelen;
    640                 if (req.ifa.ifa_family == AF_UNSPEC) {
    641                     req.ifa.ifa_family = peer.family;
    642                 }
    643                 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
    644                 req.ifa.ifa_prefixlen = peer.bitlen;
    645                 break;
    646             case 2: /* broadcast */
    647             case 3: /* brd */
    648             {
    649                 inet_prefix addr;
    650                 NEXT_ARG();
    651                 if (brd_len) {
    652                     duparg("broadcast", *argv);
    653                 }
    654                 if (LONE_CHAR(*argv, '+')) {
    655                     brd_len = -1;
    656                 }
    657                 else if (LONE_DASH(*argv)) {
    658                     brd_len = -2;
    659                 } else {
    660                     get_addr(&addr, *argv, req.ifa.ifa_family);
    661                     if (req.ifa.ifa_family == AF_UNSPEC)
    662                         req.ifa.ifa_family = addr.family;
    663                     addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
    664                     brd_len = addr.bytelen;
    665                 }
    666                 break;
    667             }
    668             case 4: /* anycast */
    669             {
    670                 inet_prefix addr;
    671                 NEXT_ARG();
    672                 if (any_len) {
    673                     duparg("anycast", *argv);
    674                 }
    675                 get_addr(&addr, *argv, req.ifa.ifa_family);
    676                 if (req.ifa.ifa_family == AF_UNSPEC) {
    677                     req.ifa.ifa_family = addr.family;
    678                 }
    679                 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
    680                 any_len = addr.bytelen;
    681                 break;
    682             }
    683             case 5: /* scope */
    684             {
    685                 uint32_t scope = 0;
    686                 NEXT_ARG();
    687                 if (rtnl_rtscope_a2n(&scope, *argv)) {
    688                     invarg(*argv, "scope");
    689                 }
    690                 req.ifa.ifa_scope = scope;
    691                 scoped = 1;
    692                 break;
    693             }
    694             case 6: /* dev */
    695                 NEXT_ARG();
    696                 d = *argv;
    697                 break;
    698             case 7: /* label */
    699                 NEXT_ARG();
    700                 l = *argv;
    701                 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
    702                 break;
    703             case 8: /* local */
    704                 NEXT_ARG();
    705             default:
    706                 if (local_len) {
    707                     duparg2("local", *argv);
    708                 }
    709                 get_prefix(&lcl, *argv, req.ifa.ifa_family);
    710                 if (req.ifa.ifa_family == AF_UNSPEC) {
    711                     req.ifa.ifa_family = lcl.family;
    712                 }
    713                 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
    714                 local_len = lcl.bytelen;
    715         }
    716         argc--;
     686            if (local_len) {
     687                duparg2("local", *argv);
     688            }
     689            get_prefix(&lcl, *argv, req.ifa.ifa_family);
     690            if (req.ifa.ifa_family == AF_UNSPEC) {
     691                req.ifa.ifa_family = lcl.family;
     692            }
     693            addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
     694            local_len = lcl.bytelen;
     695        }
    717696        argv++;
    718697    }
    719698
    720     if (d == NULL) {
    721         bb_error_msg(bb_msg_requires_arg,"\"dev\"");
    722         return -1;
     699    if (!d) {
     700        /* There was no "dev IFACE", but we need that */
     701        bb_error_msg_and_die("need \"dev IFACE\"");
    723702    }
    724703    if (l && strncmp(d, l, strlen(d)) != 0) {
     
    767746
    768747/* Return value becomes exitcode. It's okay to not return at all */
    769 int do_ipaddr(int argc, char **argv)
     748int FAST_FUNC do_ipaddr(char **argv)
    770749{
    771750    static const char commands[] ALIGN1 =
    772751        "add\0""delete\0""list\0""show\0""lst\0""flush\0";
    773 
    774     int command_num = 2; /* default command is list */
    775 
     752    smalluint cmd = 2;
    776753    if (*argv) {
    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 }
     754        cmd = index_in_substrings(commands, *argv);
     755        if (cmd > 5)
     756            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
     757        argv++;
     758        if (cmd <= 1)
     759            return ipaddr_modify((cmd == 0) ? RTM_NEWADDR : RTM_DELADDR, argv);
     760    }
     761    /* 2 == list, 3 == show, 4 == lst */
     762    return ipaddr_list_or_flush(argv, cmd == 5);
     763}
  • branches/2.2.9/mindi-busybox/networking/libiproute/iplink.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * iplink.c "ip link".
    4  *
    53 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    64 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    86 */
    9 
    10 //#include <sys/ioctl.h>
    11 //#include <sys/socket.h>
    127#include <net/if.h>
    138#include <net/if_packet.h>
     
    1914#include "utils.h"
    2015
     16#ifndef IFLA_LINKINFO
     17# define IFLA_LINKINFO 18
     18# define IFLA_INFO_KIND 1
     19#endif
     20
    2121/* taken from linux/sockios.h */
    22 #define SIOCSIFNAME 0x8923      /* set interface name */
    23 
    24 static void on_off(const char *msg) ATTRIBUTE_NORETURN;
    25 static void on_off(const char *msg)
    26 {
    27     bb_error_msg_and_die("error: argument of \"%s\" must be \"on\" or \"off\"", msg);
    28 }
     22#define SIOCSIFNAME  0x8923  /* set interface name */
    2923
    3024/* Exits on error */
     
    4842    int fd;
    4943
    50     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     44    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
    5145    fd = get_ctl_fd();
    5246    xioctl(fd, SIOCGIFFLAGS, &ifr);
     
    6559    int fd;
    6660
    67     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
    68     strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));
     61    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
     62    strncpy_IFNAMSIZ(ifr.ifr_newname, newdev);
    6963    fd = get_ctl_fd();
    7064    xioctl(fd, SIOCSIFNAME, &ifr);
     
    8074    s = get_ctl_fd();
    8175    memset(&ifr, 0, sizeof(ifr));
    82     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     76    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
    8377    ifr.ifr_qlen = qlen;
    8478    xioctl(s, SIOCSIFTXQLEN, &ifr);
     
    9488    s = get_ctl_fd();
    9589    memset(&ifr, 0, sizeof(ifr));
    96     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     90    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
    9791    ifr.ifr_mtu = mtu;
    9892    xioctl(s, SIOCSIFMTU, &ifr);
     
    111105
    112106    memset(&ifr, 0, sizeof(ifr));
    113     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     107    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
    114108    xioctl(s, SIOCGIFINDEX, &ifr);
    115109
     
    119113    me.sll_protocol = htons(ETH_P_LOOP);
    120114    xbind(s, (struct sockaddr*)&me, sizeof(me));
    121 
    122115    alen = sizeof(me);
    123     if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
    124         bb_perror_msg_and_die("getsockname");
    125     }
     116    getsockname(s, (struct sockaddr*)&me, &alen);
     117    //never happens:
     118    //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
     119    //  bb_perror_msg_and_die("getsockname");
    126120    close(s);
    127121    *htype = me.sll_hatype;
     
    135129
    136130    memset(ifr, 0, sizeof(*ifr));
    137     strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name));
     131    strncpy_IFNAMSIZ(ifr->ifr_name, dev);
    138132    ifr->ifr_hwaddr.sa_family = hatype;
    139     alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla);
     133
     134    alen = hatype == 1/*ARPHRD_ETHER*/ ? 14/*ETH_HLEN*/ : 19/*INFINIBAND_HLEN*/;
     135    alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), alen, lla);
    140136    if (alen < 0)
    141         exit(1);
     137        exit(EXIT_FAILURE);
    142138    if (alen != halen) {
    143139        bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
     
    159155
    160156
     157static void die_must_be_on_off(const char *msg) NORETURN;
     158static void die_must_be_on_off(const char *msg)
     159{
     160    bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
     161}
     162
    161163/* Return value becomes exitcode. It's okay to not return at all */
    162 static int do_set(int argc, char **argv)
     164static int do_set(char **argv)
    163165{
    164166    char *dev = NULL;
     
    173175    int htype, halen;
    174176    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 };
     177        "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
     178        "arp\0""address\0""dev\0";
     179    enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
     180        ARG_arp, ARG_addr, ARG_dev };
     181    static const char str_on_off[] ALIGN1 = "on\0""off\0";
     182    enum { PARM_on = 0, PARM_off };
    179183    smalluint key;
    180184
    181     while (argc > 0) {
    182         key = index_in_strings(keywords, *argv) + 1;
     185    while (*argv) {
     186        /* substring search ensures that e.g. "addr" and "address"
     187         * are both accepted */
     188        key = index_in_substrings(keywords, *argv);
    183189        if (key == ARG_up) {
    184190            mask |= IFF_UP;
     
    194200            if (mtu != -1)
    195201                duparg("mtu", *argv);
    196             if (get_integer(&mtu, *argv, 0))
    197                 invarg(*argv, "mtu");
    198         } else if (key == ARG_multicast) {
    199             NEXT_ARG();
    200             mask |= IFF_MULTICAST;
    201             key = index_in_strings(keywords, *argv) + 1;
    202             if (key == PARM_on) {
    203                 flags |= IFF_MULTICAST;
    204             } else if (key == PARM_off) {
    205                 flags &= ~IFF_MULTICAST;
    206             } else
    207                 on_off("multicast");
    208         } else if (key == ARG_arp) {
    209             NEXT_ARG();
    210             mask |= IFF_NOARP;
    211             key = index_in_strings(keywords, *argv) + 1;
    212             if (key == PARM_on) {
    213                 flags &= ~IFF_NOARP;
    214             } else if (key == PARM_off) {
    215                 flags |= IFF_NOARP;
    216             } else
    217                 on_off("arp");
     202            mtu = get_unsigned(*argv, "mtu");
     203        } else if (key == ARG_qlen) {
     204            NEXT_ARG();
     205            if (qlen != -1)
     206                duparg("qlen", *argv);
     207            qlen = get_unsigned(*argv, "qlen");
    218208        } else if (key == ARG_addr) {
    219209            NEXT_ARG();
    220210            newaddr = *argv;
    221         } else {
     211        } else if (key >= ARG_dev) {
    222212            if (key == ARG_dev) {
    223213                NEXT_ARG();
     
    226216                duparg2("dev", *argv);
    227217            dev = *argv;
    228         }
    229         argc--; argv++;
     218        } else {
     219            int param;
     220            NEXT_ARG();
     221            param = index_in_strings(str_on_off, *argv);
     222            if (key == ARG_multicast) {
     223                if (param < 0)
     224                    die_must_be_on_off("multicast");
     225                mask |= IFF_MULTICAST;
     226                if (param == PARM_on)
     227                    flags |= IFF_MULTICAST;
     228                else
     229                    flags &= ~IFF_MULTICAST;
     230            } else if (key == ARG_arp) {
     231                if (param < 0)
     232                    die_must_be_on_off("arp");
     233                mask |= IFF_NOARP;
     234                if (param == PARM_on)
     235                    flags &= ~IFF_NOARP;
     236                else
     237                    flags |= IFF_NOARP;
     238            }
     239        }
     240        argv++;
    230241    }
    231242
     
    238249        if (newaddr) {
    239250            parse_address(dev, htype, halen, newaddr, &ifr0);
     251            set_address(&ifr0, 0);
    240252        }
    241253        if (newbrd) {
    242254            parse_address(dev, htype, halen, newbrd, &ifr1);
     255            set_address(&ifr1, 1);
    243256        }
    244257    }
     
    254267        set_mtu(dev, mtu);
    255268    }
    256     if (newaddr || newbrd) {
    257         if (newbrd) {
    258             set_address(&ifr1, 1);
    259         }
    260         if (newaddr) {
    261             set_address(&ifr0, 0);
    262         }
    263     }
    264269    if (mask)
    265270        do_chflags(dev, flags, mask);
     
    267272}
    268273
    269 static int ipaddr_list_link(int argc, char **argv)
     274static int ipaddr_list_link(char **argv)
    270275{
    271276    preferred_family = AF_PACKET;
    272     return ipaddr_list_or_flush(argc, argv, 0);
    273 }
    274 
     277    return ipaddr_list_or_flush(argv, 0);
     278}
     279
     280#ifndef NLMSG_TAIL
     281#define NLMSG_TAIL(nmsg) \
     282    ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
     283#endif
    275284/* Return value becomes exitcode. It's okay to not return at all */
    276 int do_iplink(int argc, char **argv)
     285static int do_change(char **argv, const unsigned rtm)
    277286{
    278287    static const char keywords[] ALIGN1 =
    279         "set\0""show\0""lst\0""list\0";
    280     smalluint key;
    281     if (argc <= 0)
    282         return ipaddr_list_link(0, NULL);
    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 }
     288        "link\0""name\0""type\0""dev\0";
     289    enum {
     290        ARG_link,
     291        ARG_name,
     292        ARG_type,
     293        ARG_dev,
     294    };
     295    struct rtnl_handle rth;
     296    struct {
     297        struct nlmsghdr  n;
     298        struct ifinfomsg i;
     299        char             buf[1024];
     300    } req;
     301    smalluint arg;
     302    char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL;
     303
     304    memset(&req, 0, sizeof(req));
     305
     306    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
     307    req.n.nlmsg_flags = NLM_F_REQUEST;
     308    req.n.nlmsg_type = rtm;
     309    req.i.ifi_family = preferred_family;
     310    if (rtm == RTM_NEWLINK)
     311        req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
     312
     313    while (*argv) {
     314        arg = index_in_substrings(keywords, *argv);
     315        if (arg == ARG_link) {
     316            NEXT_ARG();
     317            link_str = *argv;
     318        } else if (arg == ARG_name) {
     319            NEXT_ARG();
     320            name_str = *argv;
     321        } else if (arg == ARG_type) {
     322            NEXT_ARG();
     323            type_str = *argv;
     324        } else {
     325            if (arg == ARG_dev) {
     326                if (dev_str)
     327                    duparg(*argv, "dev");
     328                NEXT_ARG();
     329            }
     330            dev_str = *argv;
     331        }
     332        argv++;
     333    }
     334    xrtnl_open(&rth);
     335    ll_init_map(&rth);
     336    if (type_str) {
     337        struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
     338
     339        addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
     340        addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
     341                strlen(type_str));
     342        linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
     343    }
     344    if (rtm != RTM_NEWLINK) {
     345        if (!dev_str)
     346            return 1; /* Need a device to delete */
     347        req.i.ifi_index = xll_name_to_index(dev_str);
     348    } else {
     349        if (!name_str)
     350            name_str = dev_str;
     351        if (link_str) {
     352            int idx = xll_name_to_index(link_str);
     353            addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
     354        }
     355    }
     356    if (name_str) {
     357        const size_t name_len = strlen(name_str) + 1;
     358        if (name_len < 2 || name_len > IFNAMSIZ)
     359            invarg(name_str, "name");
     360        addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len);
     361    }
     362    if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
     363        return 2;
     364    return 0;
     365}
     366
     367/* Return value becomes exitcode. It's okay to not return at all */
     368int FAST_FUNC do_iplink(char **argv)
     369{
     370    static const char keywords[] ALIGN1 =
     371        "add\0""delete\0""set\0""show\0""lst\0""list\0";
     372    if (*argv) {
     373        smalluint key = index_in_substrings(keywords, *argv);
     374        if (key > 5) /* invalid argument */
     375            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
     376        argv++;
     377        if (key <= 1) /* add/delete */
     378            return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK);
     379        else if (key == 2) /* set */
     380            return do_set(argv);
     381    }
     382    /* show, lst, list */
     383    return ipaddr_list_link(argv);
     384}
  • branches/2.2.9/mindi-busybox/networking/libiproute/iproute.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * iproute.c        "ip route".
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 *
    5  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    6  *
    7  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    8  *
     5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    96 *
    107 * Changes:
    118 *
    12  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
    1310 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
    1411 */
    1512
    16 #include "ip_common.h"  /* #include "libbb.h" is inside */
     13#include "ip_common.h"  /* #include "libbb.h" is inside */
    1714#include "rt_names.h"
    1815#include "utils.h"
     
    2320
    2421
    25 typedef struct filter_t {
     22struct filter_t {
    2623    int tb;
    27     int flushed;
     24    smallint flushed;
    2825    char *flushb;
    2926    int flushp;
    3027    int flushe;
    3128    struct rtnl_handle *rth;
    32     int protocol, protocolmask;
    33     int scope, scopemask;
    34     int type, typemask;
    35     int tos, tosmask;
     29    //int protocol, protocolmask; - write-only fields?!
     30    //int scope, scopemask; - unused
     31    //int type; - read-only
     32    //int typemask; - unused
     33    //int tos, tosmask; - unused
    3634    int iif, iifmask;
    3735    int oif, oifmask;
    38     int realm, realmmask;
    39     inet_prefix rprefsrc;
     36    //int realm, realmmask; - unused
     37    //inet_prefix rprefsrc; - read-only
    4038    inet_prefix rvia;
    4139    inet_prefix rdst;
     
    4341    inet_prefix rsrc;
    4442    inet_prefix msrc;
    45 } filter_t;
    46 
    47 #define filter (*(filter_t*)&bb_common_bufsiz1)
     43} FIX_ALIASING;
     44typedef struct filter_t filter_t;
     45
     46#define G_filter (*(filter_t*)&bb_common_bufsiz1)
    4847
    4948static int flush_update(void)
    5049{
    51     if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
    52         bb_perror_msg("failed to send flush request");
     50    if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
     51        bb_perror_msg("can't send flush request");
    5352        return -1;
    5453    }
    55     filter.flushp = 0;
     54    G_filter.flushp = 0;
    5655    return 0;
    5756}
     
    6564        return hz_internal;
    6665
    67     fp = fopen("/proc/net/psched", "r");
     66    fp = fopen_for_read("/proc/net/psched");
    6867    if (fp) {
    6968        unsigned nom, denom;
     
    7978}
    8079
    81 static int print_route(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
    82         struct nlmsghdr *n, void *arg)
     80static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
     81        struct nlmsghdr *n, void *arg UNUSED_PARAM)
    8382{
    84     FILE *fp = (FILE*)arg;
    8583    struct rtmsg *r = NLMSG_DATA(n);
    8684    int len = n->nlmsg_len;
     
    9290    SPRINT_BUF(b1);
    9391
    94 
    9592    if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
    9693        fprintf(stderr, "Not a route: %08x %08x %08x\n",
     
    9895        return 0;
    9996    }
    100     if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
     97    if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
    10198        return 0;
    10299    len -= NLMSG_LENGTH(sizeof(*r));
     
    110107
    111108    if (r->rtm_family == AF_INET6) {
    112         if (filter.tb) {
    113             if (filter.tb < 0) {
    114                 if (!(r->rtm_flags&RTM_F_CLONED)) {
     109        if (G_filter.tb) {
     110            if (G_filter.tb < 0) {
     111                if (!(r->rtm_flags & RTM_F_CLONED)) {
    115112                    return 0;
    116113                }
    117114            } else {
    118                 if (r->rtm_flags&RTM_F_CLONED) {
     115                if (r->rtm_flags & RTM_F_CLONED) {
    119116                    return 0;
    120117                }
    121                 if (filter.tb == RT_TABLE_LOCAL) {
     118                if (G_filter.tb == RT_TABLE_LOCAL) {
    122119                    if (r->rtm_type != RTN_LOCAL) {
    123120                        return 0;
    124121                    }
    125                 } else if (filter.tb == RT_TABLE_MAIN) {
     122                } else if (G_filter.tb == RT_TABLE_MAIN) {
    126123                    if (r->rtm_type == RTN_LOCAL) {
    127124                        return 0;
     
    133130        }
    134131    } else {
    135         if (filter.tb > 0 && filter.tb != r->rtm_table) {
     132        if (G_filter.tb > 0 && G_filter.tb != r->rtm_table) {
    136133            return 0;
    137134        }
    138135    }
    139     if (filter.rdst.family &&
    140         (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
    141         return 0;
    142     }
    143     if (filter.mdst.family &&
    144         (r->rtm_family != filter.mdst.family ||
    145          (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
    146         return 0;
    147     }
    148     if (filter.rsrc.family &&
    149         (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
    150         return 0;
    151     }
    152     if (filter.msrc.family &&
    153         (r->rtm_family != filter.msrc.family ||
    154          (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
     136    if (G_filter.rdst.family
     137     && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
     138    ) {
     139        return 0;
     140    }
     141    if (G_filter.mdst.family
     142     && (r->rtm_family != G_filter.mdst.family
     143        || (G_filter.mdst.bitlen >= 0 && G_filter.mdst.bitlen < r->rtm_dst_len)
     144        )
     145    ) {
     146        return 0;
     147    }
     148    if (G_filter.rsrc.family
     149     && (r->rtm_family != G_filter.rsrc.family || G_filter.rsrc.bitlen > r->rtm_src_len)
     150    ) {
     151        return 0;
     152    }
     153    if (G_filter.msrc.family
     154     && (r->rtm_family != G_filter.msrc.family
     155        || (G_filter.msrc.bitlen >= 0 && G_filter.msrc.bitlen < r->rtm_src_len)
     156        )
     157    ) {
    155158        return 0;
    156159    }
     
    159162    parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
    160163
    161     if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
    162         return 0;
    163     if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
    164         inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
    165         return 0;
    166 
    167     if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
    168         return 0;
    169     if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
    170         inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
    171         return 0;
    172 
    173     if (filter.flushb &&
    174         r->rtm_family == AF_INET6 &&
    175         r->rtm_dst_len == 0 &&
    176         r->rtm_type == RTN_UNREACHABLE &&
    177         tb[RTA_PRIORITY] &&
    178         *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
    179         return 0;
    180 
    181     if (filter.flushb) {
     164    if (G_filter.rdst.family
     165     && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
     166    ) {
     167        return 0;
     168    }
     169    if (G_filter.mdst.family
     170     && G_filter.mdst.bitlen >= 0
     171     && inet_addr_match(&dst, &G_filter.mdst, r->rtm_dst_len)
     172    ) {
     173        return 0;
     174    }
     175    if (G_filter.rsrc.family
     176     && inet_addr_match(&src, &G_filter.rsrc, G_filter.rsrc.bitlen)
     177    ) {
     178        return 0;
     179    }
     180    if (G_filter.msrc.family && G_filter.msrc.bitlen >= 0
     181     && inet_addr_match(&src, &G_filter.msrc, r->rtm_src_len)
     182    ) {
     183        return 0;
     184    }
     185    if (G_filter.flushb
     186     && r->rtm_family == AF_INET6
     187     && r->rtm_dst_len == 0
     188     && r->rtm_type == RTN_UNREACHABLE
     189     && tb[RTA_PRIORITY]
     190     && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
     191    ) {
     192        return 0;
     193    }
     194
     195    if (G_filter.flushb) {
    182196        struct nlmsghdr *fn;
    183         if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
     197        if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
    184198            if (flush_update())
    185199                bb_error_msg_and_die("flush");
    186200        }
    187         fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
     201        fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
    188202        memcpy(fn, n, n->nlmsg_len);
    189203        fn->nlmsg_type = RTM_DELROUTE;
    190204        fn->nlmsg_flags = NLM_F_REQUEST;
    191         fn->nlmsg_seq = ++filter.rth->seq;
    192         filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
    193         filter.flushed++;
     205        fn->nlmsg_seq = ++G_filter.rth->seq;
     206        G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
     207        G_filter.flushed = 1;
    194208        return 0;
    195209    }
    196210
    197211    if (n->nlmsg_type == RTM_DELROUTE) {
    198         fprintf(fp, "Deleted ");
    199     }
    200     if (r->rtm_type != RTN_UNICAST && !filter.type) {
    201         fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
     212        printf("Deleted ");
     213    }
     214    if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
     215        printf("%s ", rtnl_rtntype_n2a(r->rtm_type, b1));
    202216    }
    203217
    204218    if (tb[RTA_DST]) {
    205219        if (r->rtm_dst_len != host_len) {
    206             fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
    207                              RTA_PAYLOAD(tb[RTA_DST]),
    208                              RTA_DATA(tb[RTA_DST]),
    209                              abuf, sizeof(abuf)),
    210                 r->rtm_dst_len
    211                 );
     220            printf("%s/%u ", rt_addr_n2a(r->rtm_family,
     221                        RTA_DATA(tb[RTA_DST]),
     222                        abuf, sizeof(abuf)),
     223                    r->rtm_dst_len
     224                    );
    212225        } else {
    213             fprintf(fp, "%s ", format_host(r->rtm_family,
    214                                RTA_PAYLOAD(tb[RTA_DST]),
    215                                RTA_DATA(tb[RTA_DST]),
    216                                abuf, sizeof(abuf))
    217                 );
     226            printf("%s ", format_host(r->rtm_family,
     227                        RTA_PAYLOAD(tb[RTA_DST]),
     228                        RTA_DATA(tb[RTA_DST]),
     229                        abuf, sizeof(abuf))
     230                    );
    218231        }
    219232    } else if (r->rtm_dst_len) {
    220         fprintf(fp, "0/%d ", r->rtm_dst_len);
     233        printf("0/%d ", r->rtm_dst_len);
    221234    } else {
    222         fprintf(fp, "default ");
     235        printf("default ");
    223236    }
    224237    if (tb[RTA_SRC]) {
    225238        if (r->rtm_src_len != host_len) {
    226             fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
    227                              RTA_PAYLOAD(tb[RTA_SRC]),
    228                              RTA_DATA(tb[RTA_SRC]),
    229                              abuf, sizeof(abuf)),
    230                 r->rtm_src_len
    231                 );
     239            printf("from %s/%u ", rt_addr_n2a(r->rtm_family,
     240                        RTA_DATA(tb[RTA_SRC]),
     241                        abuf, sizeof(abuf)),
     242                    r->rtm_src_len
     243                    );
    232244        } else {
    233             fprintf(fp, "from %s ", format_host(r->rtm_family,
    234                                RTA_PAYLOAD(tb[RTA_SRC]),
    235                                RTA_DATA(tb[RTA_SRC]),
    236                                abuf, sizeof(abuf))
    237                 );
     245            printf("from %s ", format_host(r->rtm_family,
     246                        RTA_PAYLOAD(tb[RTA_SRC]),
     247                        RTA_DATA(tb[RTA_SRC]),
     248                        abuf, sizeof(abuf))
     249                    );
    238250        }
    239251    } else if (r->rtm_src_len) {
    240         fprintf(fp, "from 0/%u ", r->rtm_src_len);
    241     }
    242     if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
    243         fprintf(fp, "via %s ",
    244             format_host(r->rtm_family,
    245                     RTA_PAYLOAD(tb[RTA_GATEWAY]),
    246                     RTA_DATA(tb[RTA_GATEWAY]),
    247                     abuf, sizeof(abuf)));
    248     }
    249     if (tb[RTA_OIF] && filter.oifmask != -1) {
    250         fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
    251     }
    252 
    253     if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
     252        printf("from 0/%u ", r->rtm_src_len);
     253    }
     254    if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
     255        printf("via %s ", format_host(r->rtm_family,
     256                    RTA_PAYLOAD(tb[RTA_GATEWAY]),
     257                    RTA_DATA(tb[RTA_GATEWAY]),
     258                    abuf, sizeof(abuf)));
     259    }
     260    if (tb[RTA_OIF] && G_filter.oifmask != -1) {
     261        printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
     262    }
     263
     264    if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
    254265        /* Do not use format_host(). It is our local addr
    255266           and symbolic name will not be useful.
    256267         */
    257         fprintf(fp, " src %s ",
    258             rt_addr_n2a(r->rtm_family,
    259                     RTA_PAYLOAD(tb[RTA_PREFSRC]),
    260                     RTA_DATA(tb[RTA_PREFSRC]),
    261                     abuf, sizeof(abuf)));
     268        printf(" src %s ", rt_addr_n2a(r->rtm_family,
     269                    RTA_DATA(tb[RTA_PREFSRC]),
     270                    abuf, sizeof(abuf)));
    262271    }
    263272    if (tb[RTA_PRIORITY]) {
    264         fprintf(fp, " metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
     273        printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
    265274    }
    266275    if (r->rtm_family == AF_INET6) {
     
    271280        if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
    272281            if (r->rtm_flags & RTM_F_CLONED) {
    273                 fprintf(fp, "%c    cache ", _SL_);
     282                printf("%c    cache ", _SL_);
    274283            }
    275284            if (ci->rta_expires) {
    276                 fprintf(fp, " expires %dsec", ci->rta_expires / get_hz());
     285                printf(" expires %dsec", ci->rta_expires / get_hz());
    277286            }
    278287            if (ci->rta_error != 0) {
    279                 fprintf(fp, " error %d", ci->rta_error);
     288                printf(" error %d", ci->rta_error);
    280289            }
    281290        } else if (ci) {
    282291            if (ci->rta_error != 0)
    283                 fprintf(fp, " error %d", ci->rta_error);
    284         }
    285     }
    286     if (tb[RTA_IIF] && filter.iifmask != -1) {
    287         fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
    288     }
    289     fputc('\n', fp);
    290     fflush(fp);
     292                printf(" error %d", ci->rta_error);
     293        }
     294    }
     295    if (tb[RTA_IIF] && G_filter.iifmask != -1) {
     296        printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
     297    }
     298    bb_putchar('\n');
    291299    return 0;
    292300}
    293301
    294302/* Return value becomes exitcode. It's okay to not return at all */
    295 static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
     303static int iproute_modify(int cmd, unsigned flags, char **argv)
    296304{
    297305    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";
     306        "src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
     307        "dev\0""oif\0""to\0""metric\0";
    300308    enum {
    301309        ARG_src,
     
    303311        ARG_mtu, PARM_lock,
    304312        ARG_protocol,
    305 USE_FEATURE_IP_RULE(ARG_table,)
     313IF_FEATURE_IP_RULE(ARG_table,)
    306314        ARG_dev,
    307315        ARG_oif,
    308         ARG_to
     316        ARG_to,
     317        ARG_metric,
    309318    };
    310319    enum {
     
    316325    struct rtnl_handle rth;
    317326    struct {
    318         struct nlmsghdr     n;
    319         struct rtmsg        r;
    320         char            buf[1024];
     327        struct nlmsghdr n;
     328        struct rtmsg    r;
     329        char            buf[1024];
    321330    } req;
    322331    char mxbuf[256];
     
    330339
    331340    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    332     req.n.nlmsg_flags = NLM_F_REQUEST|flags;
     341    req.n.nlmsg_flags = NLM_F_REQUEST | flags;
    333342    req.n.nlmsg_type = cmd;
    334343    req.r.rtm_family = preferred_family;
    335     req.r.rtm_table = RT_TABLE_MAIN;
    336     req.r.rtm_scope = RT_SCOPE_NOWHERE;
     344    if (RT_TABLE_MAIN) /* if it is zero, memset already did it */
     345        req.r.rtm_table = RT_TABLE_MAIN;
     346    if (RT_SCOPE_NOWHERE)
     347        req.r.rtm_scope = RT_SCOPE_NOWHERE;
    337348
    338349    if (cmd != RTM_DELROUTE) {
     
    345356    mxrta->rta_len = RTA_LENGTH(0);
    346357
    347     while (argc > 0) {
     358    while (*argv) {
    348359        arg = index_in_substrings(keywords, *argv);
    349360        if (arg == ARG_src) {
     
    367378            NEXT_ARG();
    368379            if (index_in_strings(keywords, *argv) == PARM_lock) {
    369                 mxlock |= (1<<RTAX_MTU);
    370                 NEXT_ARG();
    371             }
    372             if (get_unsigned(&mtu, *argv, 0))
    373                 invarg(*argv, "mtu");
     380                mxlock |= (1 << RTAX_MTU);
     381                NEXT_ARG();
     382            }
     383            mtu = get_unsigned(*argv, "mtu");
    374384            rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
    375385        } else if (arg == ARG_protocol) {
     
    391401            NEXT_ARG();
    392402            d = *argv;
     403        } else if (arg == ARG_metric) {
     404            uint32_t metric;
     405            NEXT_ARG();
     406            metric = get_u32(*argv, "metric");
     407            addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
    393408        } else {
    394409            int type;
     
    399414            }
    400415            if ((**argv < '0' || **argv > '9')
    401                 && rtnl_rtntype_a2n(&type, *argv) == 0) {
     416             && rtnl_rtntype_a2n(&type, *argv) == 0) {
    402417                NEXT_ARG();
    403418                req.r.rtm_type = type;
     
    418433            }
    419434        }
    420         argc--; argv++;
     435        argv++;
    421436    }
    422437
     
    443458    if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
    444459        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)
     460    else
     461    if (req.r.rtm_type == RTN_BROADCAST
     462     || req.r.rtm_type == RTN_MULTICAST
     463     || req.r.rtm_type == RTN_ANYCAST
     464    ) {
    448465        req.r.rtm_scope = RT_SCOPE_LINK;
     466    }
    449467    else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
    450468        if (cmd == RTM_DELROUTE)
     
    478496
    479497    req.nlh.nlmsg_len = sizeof(req);
    480     req.nlh.nlmsg_type = RTM_GETROUTE;
    481     req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
    482     req.nlh.nlmsg_pid = 0;
     498    if (RTM_GETROUTE)
     499        req.nlh.nlmsg_type = RTM_GETROUTE;
     500    if (NLM_F_ROOT | NLM_F_REQUEST)
     501        req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
     502    /*req.nlh.nlmsg_pid = 0; - memset did it already */
    483503    req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
    484504    req.rtm.rtm_family = family;
    485     req.rtm.rtm_flags |= RTM_F_CLONED;
     505    if (RTM_F_CLONED)
     506        req.rtm.rtm_flags = RTM_F_CLONED;
    486507
    487508    return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
     
    498519
    499520    if (write(flush_fd, "-1", 2) < 2) {
    500         bb_perror_msg("cannot flush routing cache");
     521        bb_perror_msg("can't flush routing cache");
    501522        return;
    502523    }
     
    506527static void iproute_reset_filter(void)
    507528{
    508     memset(&filter, 0, sizeof(filter));
    509     filter.mdst.bitlen = -1;
    510     filter.msrc.bitlen = -1;
     529    memset(&G_filter, 0, sizeof(G_filter));
     530    G_filter.mdst.bitlen = -1;
     531    G_filter.msrc.bitlen = -1;
    511532}
    512533
    513534/* Return value becomes exitcode. It's okay to not return at all */
    514 static int iproute_list_or_flush(int argc, char **argv, int flush)
     535static int iproute_list_or_flush(char **argv, int flush)
    515536{
    516537    int do_ipv6 = preferred_family;
     
    519540    char *od = NULL;
    520541    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*/;
     542        /* "ip route list/flush" parameters: */
     543        "protocol\0" "dev\0"   "oif\0"   "iif\0"
     544        "via\0"      "table\0" "cache\0"
     545        "from\0"     "to\0"
     546        /* and possible further keywords */
     547        "all\0"
     548        "root\0"
     549        "match\0"
     550        "exact\0"
     551        "main\0"
     552        ;
    523553    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*/
     554        KW_proto, KW_dev,   KW_oif,  KW_iif,
     555        KW_via,   KW_table, KW_cache,
     556        KW_from,  KW_to,
     557        /* */
     558        KW_all,
     559        KW_root,
     560        KW_match,
     561        KW_exact,
     562        KW_main,
    532563    };
    533564    int arg, parm;
     565
    534566    iproute_reset_filter();
    535     filter.tb = RT_TABLE_MAIN;
    536 
    537     if (flush && argc <= 0)
     567    G_filter.tb = RT_TABLE_MAIN;
     568
     569    if (flush && !*argv)
    538570        bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
    539571
    540     while (argc > 0) {
     572    while (*argv) {
    541573        arg = index_in_substrings(keywords, *argv);
    542         if (arg == ARG_proto) {
     574        if (arg == KW_proto) {
    543575            uint32_t prot = 0;
    544576            NEXT_ARG();
    545             filter.protocolmask = -1;
     577            //G_filter.protocolmask = -1;
    546578            if (rtnl_rtprot_a2n(&prot, *argv)) {
    547                 if (index_in_strings(keywords, *argv) != PARM_all)
     579                if (index_in_strings(keywords, *argv) != KW_all)
    548580                    invarg(*argv, "protocol");
    549581                prot = 0;
    550                 filter.protocolmask = 0;
    551             }
    552             filter.protocol = prot;
    553         } else if (arg == ARG_dev || arg == ARG_oif) {
     582                //G_filter.protocolmask = 0;
     583            }
     584            //G_filter.protocol = prot;
     585        } else if (arg == KW_dev || arg == KW_oif) {
    554586            NEXT_ARG();
    555587            od = *argv;
    556         } else if (arg == ARG_iif) {
     588        } else if (arg == KW_iif) {
    557589            NEXT_ARG();
    558590            id = *argv;
    559         } else if (arg == ARG_via) {
    560             NEXT_ARG();
    561             get_prefix(&filter.rvia, *argv, do_ipv6);
    562         } else if (arg == ARG_table) {
     591        } else if (arg == KW_via) {
     592            NEXT_ARG();
     593            get_prefix(&G_filter.rvia, *argv, do_ipv6);
     594        } else if (arg == KW_table) { /* table all/cache/main */
    563595            NEXT_ARG();
    564596            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
     597            if (parm == KW_cache)
     598                G_filter.tb = -1;
     599            else if (parm == KW_all)
     600                G_filter.tb = 0;
     601            else if (parm != KW_main) {
     602#if ENABLE_FEATURE_IP_RULE
     603                uint32_t tid;
     604                if (rtnl_rttable_a2n(&tid, *argv))
     605                    invarg(*argv, "table");
     606                G_filter.tb = tid;
     607#else
    570608                invarg(*argv, "table");
    571         } else if (arg == ARG_from) {
     609#endif
     610            }
     611        } else if (arg == KW_cache) {
     612            /* The command 'ip route flush cache' is used by OpenSWAN.
     613             * Assuming it's a synonym for 'ip route flush table cache' */
     614            G_filter.tb = -1;
     615        } else if (arg == KW_from) {
    572616            NEXT_ARG();
    573617            parm = index_in_substrings(keywords, *argv);
    574             if (parm == PARM_root) {
    575                 NEXT_ARG();
    576                 get_prefix(&filter.rsrc, *argv, do_ipv6);
    577             } else if (parm == PARM_match) {
    578                 NEXT_ARG();
    579                 get_prefix(&filter.msrc, *argv, do_ipv6);
     618            if (parm == KW_root) {
     619                NEXT_ARG();
     620                get_prefix(&G_filter.rsrc, *argv, do_ipv6);
     621            } else if (parm == KW_match) {
     622                NEXT_ARG();
     623                get_prefix(&G_filter.msrc, *argv, do_ipv6);
    580624            } else {
    581                 if (parm == PARM_exact)
     625                if (parm == KW_exact)
    582626                    NEXT_ARG();
    583                 get_prefix(&filter.msrc, *argv, do_ipv6);
    584                 filter.rsrc = filter.msrc;
    585             }
    586         } else {
    587             /* parm = arg; // would be more plausible, we reuse arg here */
    588             if (arg == ARG_to) {
     627                get_prefix(&G_filter.msrc, *argv, do_ipv6);
     628                G_filter.rsrc = G_filter.msrc;
     629            }
     630        } else { /* "to" is the default parameter */
     631            if (arg == KW_to) {
    589632                NEXT_ARG();
    590633                arg = index_in_substrings(keywords, *argv);
    591634            }
    592             if (arg == PARM_root) {
    593                 NEXT_ARG();
    594                 get_prefix(&filter.rdst, *argv, do_ipv6);
    595             } else if (arg == PARM_match) {
    596                 NEXT_ARG();
    597                 get_prefix(&filter.mdst, *argv, do_ipv6);
    598             } else {
    599                 if (arg == PARM_exact)
     635            /* parm = arg; - would be more plausible, but we reuse 'arg' here */
     636            if (arg == KW_root) {
     637                NEXT_ARG();
     638                get_prefix(&G_filter.rdst, *argv, do_ipv6);
     639            } else if (arg == KW_match) {
     640                NEXT_ARG();
     641                get_prefix(&G_filter.mdst, *argv, do_ipv6);
     642            } else { /* "to exact" is the default */
     643                if (arg == KW_exact)
    600644                    NEXT_ARG();
    601                 get_prefix(&filter.mdst, *argv, do_ipv6);
    602                 filter.rdst = filter.mdst;
    603             }
    604         }
    605         argc--;
     645                get_prefix(&G_filter.mdst, *argv, do_ipv6);
     646                G_filter.rdst = G_filter.mdst;
     647            }
     648        }
    606649        argv++;
    607650    }
    608651
    609     if (do_ipv6 == AF_UNSPEC && filter.tb) {
     652    if (do_ipv6 == AF_UNSPEC && G_filter.tb) {
    610653        do_ipv6 = AF_INET;
    611654    }
    612655
    613656    xrtnl_open(&rth);
    614 
    615657    ll_init_map(&rth);
    616658
     
    620662        if (id) {
    621663            idx = xll_name_to_index(id);
    622             filter.iif = idx;
    623             filter.iifmask = -1;
     664            G_filter.iif = idx;
     665            G_filter.iifmask = -1;
    624666        }
    625667        if (od) {
    626668            idx = xll_name_to_index(od);
    627             filter.oif = idx;
    628             filter.oifmask = -1;
     669            G_filter.oif = idx;
     670            G_filter.oifmask = -1;
    629671        }
    630672    }
     
    633675        char flushb[4096-512];
    634676
    635         if (filter.tb == -1) {
     677        if (G_filter.tb == -1) { /* "flush table cache" */
    636678            if (do_ipv6 != AF_INET6)
    637679                iproute_flush_cache();
     
    640682        }
    641683
    642         filter.flushb = flushb;
    643         filter.flushp = 0;
    644         filter.flushe = sizeof(flushb);
    645         filter.rth = &rth;
     684        G_filter.flushb = flushb;
     685        G_filter.flushp = 0;
     686        G_filter.flushe = sizeof(flushb);
     687        G_filter.rth = &rth;
    646688
    647689        for (;;) {
    648690            xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
    649             filter.flushed = 0;
    650             xrtnl_dump_filter(&rth, print_route, stdout);
    651             if (filter.flushed == 0)
     691            G_filter.flushed = 0;
     692            xrtnl_dump_filter(&rth, print_route, NULL);
     693            if (G_filter.flushed == 0)
    652694                return 0;
    653695            if (flush_update())
     
    656698    }
    657699
    658     if (filter.tb != -1) {
     700    if (G_filter.tb != -1) {
    659701        xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
    660702    } 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);
     703        bb_perror_msg_and_die("can't send dump request");
     704    }
     705    xrtnl_dump_filter(&rth, print_route, NULL);
    664706
    665707    return 0;
     
    668710
    669711/* Return value becomes exitcode. It's okay to not return at all */
    670 static int iproute_get(int argc, char **argv)
     712static int iproute_get(char **argv)
    671713{
    672714    struct rtnl_handle rth;
     
    688730
    689731    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    690     req.n.nlmsg_flags = NLM_F_REQUEST;
    691     req.n.nlmsg_type = RTM_GETROUTE;
     732    if (NLM_F_REQUEST)
     733        req.n.nlmsg_flags = NLM_F_REQUEST;
     734    if (RTM_GETROUTE)
     735        req.n.nlmsg_type = RTM_GETROUTE;
    692736    req.r.rtm_family = preferred_family;
    693     req.r.rtm_table = 0;
    694     req.r.rtm_protocol = 0;
    695     req.r.rtm_scope = 0;
    696     req.r.rtm_type = 0;
    697     req.r.rtm_src_len = 0;
    698     req.r.rtm_dst_len = 0;
    699     req.r.rtm_tos = 0;
    700 
    701     while (argc > 0) {
     737    /*req.r.rtm_table = 0; - memset did this already */
     738    /*req.r.rtm_protocol = 0;*/
     739    /*req.r.rtm_scope = 0;*/
     740    /*req.r.rtm_type = 0;*/
     741    /*req.r.rtm_src_len = 0;*/
     742    /*req.r.rtm_dst_len = 0;*/
     743    /*req.r.rtm_tos = 0;*/
     744
     745    while (*argv) {
    702746        switch (index_in_strings(options, *argv)) {
    703747            case 0: /* from */
     
    745789                req.r.rtm_dst_len = addr.bitlen;
    746790            }
    747             argc--; argv++;
    748         }
     791        }
     792        argv++;
    749793    }
    750794
     
    783827        struct rtattr * tb[RTA_MAX+1];
    784828
    785         print_route(NULL, &req.n, (void*)stdout);
     829        print_route(NULL, &req.n, NULL);
    786830
    787831        if (req.n.nlmsg_type != RTM_NEWROUTE) {
     
    800844            r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
    801845        } else if (!tb[RTA_SRC]) {
    802             bb_error_msg_and_die("failed to connect the route");
     846            bb_error_msg_and_die("can't connect the route");
    803847        }
    804848        if (!odev && tb[RTA_OIF]) {
     
    818862        }
    819863    }
    820     print_route(NULL, &req.n, (void*)stdout);
     864    print_route(NULL, &req.n, NULL);
    821865    return 0;
    822866}
    823867
    824868/* Return value becomes exitcode. It's okay to not return at all */
    825 int do_iproute(int argc, char **argv)
     869int FAST_FUNC do_iproute(char **argv)
    826870{
    827871    static const char ip_route_commands[] ALIGN1 =
     
    829873    /*4-7*/ "delete\0""get\0""list\0""show\0"
    830874    /*8..*/ "prepend\0""replace\0""test\0""flush\0";
    831     int command_num = 6;
     875    int command_num;
    832876    unsigned flags = 0;
    833877    int cmd = RTM_NEWROUTE;
    834878
     879    if (!*argv)
     880        return iproute_list_or_flush(argv, 0);
     881
    835882    /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
    836883    /* It probably means that it is using "first match" rule */
    837     if (*argv) {
    838         command_num = index_in_substrings(ip_route_commands, *argv);
    839     }
     884    command_num = index_in_substrings(ip_route_commands, *argv);
     885
    840886    switch (command_num) {
    841887        case 0: /* add */
     
    853899            break;
    854900        case 5: /* get */
    855             return iproute_get(argc-1, argv+1);
     901            return iproute_get(argv+1);
    856902        case 6: /* list */
    857903        case 7: /* show */
    858             return iproute_list_or_flush(argc-1, argv+1, 0);
     904            return iproute_list_or_flush(argv+1, 0);
    859905        case 8: /* prepend */
    860906            flags = NLM_F_CREATE;
     907            break;
    861908        case 9: /* replace */
    862909            flags = NLM_F_CREATE|NLM_F_REPLACE;
     910            break;
    863911        case 10: /* test */
    864912            flags = NLM_F_EXCL;
     913            break;
    865914        case 11: /* flush */
    866             return iproute_list_or_flush(argc-1, argv+1, 1);
     915            return iproute_list_or_flush(argv+1, 1);
    867916        default:
    868917            bb_error_msg_and_die("unknown command %s", *argv);
    869918    }
    870919
    871     return iproute_modify(cmd, flags, argc-1, argv+1);
     920    return iproute_modify(cmd, flags, argv+1);
    872921}
  • branches/2.2.9/mindi-busybox/networking/libiproute/iprule.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * iprule.c     "ip rule".
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    11  *
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    129 *
    1310 * Changes:
    1411 *
    15  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
    16  * initially integrated into busybox by Bernhard Fischer
     12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     13 * initially integrated into busybox by Bernhard Reutner-Fischer
    1714 */
    1815
    19 #include <syslog.h>
    20 //#include <sys/socket.h>
    2116#include <netinet/in.h>
    2217#include <netinet/ip.h>
     
    4338*/
    4439
    45 static int print_rule(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
    46                     struct nlmsghdr *n, void *arg)
    47 {
    48     FILE *fp = (FILE*)arg;
     40static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
     41                    struct nlmsghdr *n, void *arg UNUSED_PARAM)
     42{
    4943    struct rtmsg *r = NLMSG_DATA(n);
    5044    int len = n->nlmsg_len;
     
    7367        host_len = 80;
    7468*/
    75     if (tb[RTA_PRIORITY])
    76         fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY]));
    77     else
    78         fprintf(fp, "0:\t");
    79 
    80     fprintf(fp, "from ");
     69    printf("%u:\t", tb[RTA_PRIORITY] ?
     70                    *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])
     71                    : 0);
     72    printf("from ");
    8173    if (tb[RTA_SRC]) {
    8274        if (r->rtm_src_len != host_len) {
    83             fprintf(fp, "%s/%u", rt_addr_n2a(r->rtm_family,
    84                              RTA_PAYLOAD(tb[RTA_SRC]),
     75            printf("%s/%u", rt_addr_n2a(r->rtm_family,
    8576                             RTA_DATA(tb[RTA_SRC]),
    8677                             abuf, sizeof(abuf)),
     
    8879                );
    8980        } else {
    90             fprintf(fp, "%s", format_host(r->rtm_family,
     81            fputs(format_host(r->rtm_family,
    9182                               RTA_PAYLOAD(tb[RTA_SRC]),
    9283                               RTA_DATA(tb[RTA_SRC]),
    93                                abuf, sizeof(abuf))
    94                 );
     84                               abuf, sizeof(abuf)), stdout);
    9585        }
    9686    } else if (r->rtm_src_len) {
    97         fprintf(fp, "0/%d", r->rtm_src_len);
     87        printf("0/%d", r->rtm_src_len);
    9888    } else {
    99         fprintf(fp, "all");
    100     }
    101     fprintf(fp, " ");
     89        printf("all");
     90    }
     91    bb_putchar(' ');
    10292
    10393    if (tb[RTA_DST]) {
    10494        if (r->rtm_dst_len != host_len) {
    105             fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family,
    106                              RTA_PAYLOAD(tb[RTA_DST]),
     95            printf("to %s/%u ", rt_addr_n2a(r->rtm_family,
    10796                             RTA_DATA(tb[RTA_DST]),
    10897                             abuf, sizeof(abuf)),
     
    11099                );
    111100        } else {
    112             fprintf(fp, "to %s ", format_host(r->rtm_family,
     101            printf("to %s ", format_host(r->rtm_family,
    113102                               RTA_PAYLOAD(tb[RTA_DST]),
    114103                               RTA_DATA(tb[RTA_DST]),
     
    116105        }
    117106    } else if (r->rtm_dst_len) {
    118         fprintf(fp, "to 0/%d ", r->rtm_dst_len);
     107        printf("to 0/%d ", r->rtm_dst_len);
    119108    }
    120109
    121110    if (r->rtm_tos) {
    122         fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
     111        printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1));
    123112    }
    124113    if (tb[RTA_PROTOINFO]) {
    125         fprintf(fp, "fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO]));
     114        printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO]));
    126115    }
    127116
    128117    if (tb[RTA_IIF]) {
    129         fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
     118        printf("iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
    130119    }
    131120
    132121    if (r->rtm_table)
    133         fprintf(fp, "lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1)));
     122        printf("lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1));
    134123
    135124    if (tb[RTA_FLOW]) {
     
    138127        to &= 0xFFFF;
    139128        if (from) {
    140             fprintf(fp, "realms %s/",
    141                 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
     129            printf("realms %s/",
     130                rtnl_rtrealm_n2a(from, b1));
    142131        }
    143         fprintf(fp, "%s ",
    144             rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
     132        printf("%s ",
     133            rtnl_rtrealm_n2a(to, b1));
    145134    }
    146135
    147136    if (r->rtm_type == RTN_NAT) {
    148137        if (tb[RTA_GATEWAY]) {
    149             fprintf(fp, "map-to %s ",
     138            printf("map-to %s ",
    150139                format_host(r->rtm_family,
    151140                        RTA_PAYLOAD(tb[RTA_GATEWAY]),
     
    153142                        abuf, sizeof(abuf)));
    154143        } else
    155             fprintf(fp, "masquerade");
     144            printf("masquerade");
    156145    } else if (r->rtm_type != RTN_UNICAST)
    157         fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
    158 
    159     fputc('\n', fp);
    160     fflush(fp);
     146        fputs(rtnl_rtntype_n2a(r->rtm_type, b1), stdout);
     147
     148    bb_putchar('\n');
     149    /*fflush_all();*/
    161150    return 0;
    162151}
    163152
    164153/* Return value becomes exitcode. It's okay to not return at all */
    165 static int iprule_list(int argc, char **argv)
     154static int iprule_list(char **argv)
    166155{
    167156    struct rtnl_handle rth;
     
    171160        af = AF_INET;
    172161
    173     if (argc > 0) {
     162    if (*argv) {
    174163        //bb_error_msg("\"rule show\" needs no arguments");
    175         bb_warn_ignoring_args(argc);
     164        bb_warn_ignoring_args(*argv);
    176165        return -1;
    177166    }
     
    180169
    181170    xrtnl_wilddump_request(&rth, af, RTM_GETRULE);
    182     xrtnl_dump_filter(&rth, print_rule, stdout);
     171    xrtnl_dump_filter(&rth, print_rule, NULL);
    183172
    184173    return 0;
     
    186175
    187176/* Return value becomes exitcode. It's okay to not return at all */
    188 static int iprule_modify(int cmd, int argc, char **argv)
     177static int iprule_modify(int cmd, char **argv)
    189178{
    190179    static const char keywords[] ALIGN1 =
     
    200189    struct rtnl_handle rth;
    201190    struct {
    202         struct nlmsghdr n;
    203         struct rtmsg    r;
    204         char        buf[1024];
     191        struct nlmsghdr n;
     192        struct rtmsg    r;
     193        char            buf[1024];
    205194    } req;
    206195    smalluint key;
     
    222211    }
    223212
    224     while (argc > 0) {
     213    while (*argv) {
    225214        key = index_in_substrings(keywords, *argv) + 1;
    226215        if (key == 0) /* no match found in keywords array, bail out. */
     
    240229        } else if (key == ARG_preference ||
    241230               key == ARG_order ||
    242                key == ARG_priority) {
     231               key == ARG_priority
     232        ) {
    243233            uint32_t pref;
    244234            NEXT_ARG();
    245             if (get_u32(&pref, *argv, 0))
    246                 invarg(*argv, "preference");
     235            pref = get_u32(*argv, "preference");
    247236            addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref);
    248237        } else if (key == ARG_tos) {
     
    255244            uint32_t fwmark;
    256245            NEXT_ARG();
    257             if (get_u32(&fwmark, *argv, 0))
    258                 invarg(*argv, "fwmark");
     246            fwmark = get_u32(*argv, "fwmark");
    259247            addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark);
    260248        } else if (key == ARG_realms) {
     
    265253            addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
    266254        } else if (key == ARG_table ||
    267                key == ARG_lookup) {
     255               key == ARG_lookup
     256        ) {
    268257            uint32_t tid;
    269258            NEXT_ARG();
     
    273262            table_ok = 1;
    274263        } else if (key == ARG_dev ||
    275                key == ARG_iif) {
     264               key == ARG_iif
     265        ) {
    276266            NEXT_ARG();
    277267            addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1);
    278268        } else if (key == ARG_nat ||
    279                key == ARG_map_to) {
     269               key == ARG_map_to
     270        ) {
    280271            NEXT_ARG();
    281272            addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
     
    293284            req.r.rtm_type = type;
    294285        }
    295         argc--;
    296286        argv++;
    297287    }
     
    312302
    313303/* Return value becomes exitcode. It's okay to not return at all */
    314 int do_iprule(int argc, char **argv)
     304int FAST_FUNC do_iprule(char **argv)
    315305{
    316306    static const char ip_rule_commands[] ALIGN1 =
    317307        "add\0""delete\0""list\0""show\0";
    318     int cmd = 2; /* list */
    319 
    320     if (argc < 1)
    321         return iprule_list(0, NULL);
    322     if (*argv)
    323         cmd = index_in_substrings(ip_rule_commands, *argv);
    324 
    325     switch (cmd) {
    326         case 0: /* add */
    327             cmd = RTM_NEWRULE;
    328             break;
    329         case 1: /* delete */
    330             cmd = RTM_DELRULE;
    331             break;
    332         case 2: /* list */
    333         case 3: /* show */
    334             return iprule_list(argc-1, argv+1);
    335             break;
    336         default:
    337             bb_error_msg_and_die("unknown command %s", *argv);
    338     }
    339     return iprule_modify(cmd, argc-1, argv+1);
    340 }
     308    if (*argv) {
     309        smalluint cmd = index_in_substrings(ip_rule_commands, *argv);
     310        if (cmd > 3)
     311            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
     312        argv++;
     313        if (cmd < 2)
     314            return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv);
     315    }
     316    return iprule_list(argv);
     317}
  • branches/2.2.9/mindi-busybox/networking/libiproute/iptunnel.c

    r1772 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * iptunnel.c          "ip tunnel"
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 *
    5  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    6  *
    7  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    8  *
     5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    96 *
    107 * Changes:
    118 *
    12  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
    13  * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
    14  * Phil Karn <karn@ka9q.ampr.org>   990408: "pmtudisc" flag
     9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     10 * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
     11 * Phil Karn <karn@ka9q.ampr.org>       990408: "pmtudisc" flag
    1512 */
    1613
     
    1916#include <net/if_arp.h>
    2017#include <asm/types.h>
     18
    2119#ifndef __constant_htons
    2220#define __constant_htons htons
    2321#endif
    24 #include <linux/if_tunnel.h>
     22
     23// FYI: #define SIOCDEVPRIVATE 0x89F0
     24
     25/* From linux/if_tunnel.h. #including it proved troublesome
     26 * (redefiniton errors due to name collisions in linux/ and net[inet]/) */
     27#define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
     28#define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
     29#define SIOCDELTUNNEL   (SIOCDEVPRIVATE + 2)
     30#define SIOCCHGTUNNEL   (SIOCDEVPRIVATE + 3)
     31//#define SIOCGETPRL      (SIOCDEVPRIVATE + 4)
     32//#define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
     33//#define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
     34//#define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
     35#define GRE_CSUM        __constant_htons(0x8000)
     36//#define GRE_ROUTING     __constant_htons(0x4000)
     37#define GRE_KEY         __constant_htons(0x2000)
     38#define GRE_SEQ         __constant_htons(0x1000)
     39//#define GRE_STRICT      __constant_htons(0x0800)
     40//#define GRE_REC         __constant_htons(0x0700)
     41//#define GRE_FLAGS       __constant_htons(0x00F8)
     42//#define GRE_VERSION     __constant_htons(0x0007)
     43struct ip_tunnel_parm {
     44    char            name[IFNAMSIZ];
     45    int             link;
     46    uint16_t        i_flags;
     47    uint16_t        o_flags;
     48    uint32_t        i_key;
     49    uint32_t        o_key;
     50    struct iphdr    iph;
     51};
     52/* SIT-mode i_flags */
     53//#define SIT_ISATAP 0x0001
     54//struct ip_tunnel_prl {
     55//  uint32_t          addr;
     56//  uint16_t          flags;
     57//  uint16_t          __reserved;
     58//  uint32_t          datalen;
     59//  uint32_t          __reserved2;
     60//  /* data follows */
     61//};
     62///* PRL flags */
     63//#define PRL_DEFAULT 0x0001
    2564
    2665#include "ip_common.h"  /* #include "libbb.h" is inside */
     
    3574    int fd;
    3675
    37     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     76    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
    3877    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    3978    xioctl(fd, SIOCGIFINDEX, &ifr);
     
    4887    int err;
    4988
    50     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
     89    strncpy_IFNAMSIZ(ifr.ifr_name, dev);
    5190    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    5291    err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr);
     
    74113    int err;
    75114
    76     strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
     115    strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
    77116    ifr.ifr_ifru.ifru_data = (void*)p;
    78117    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
     
    89128
    90129    if (cmd == SIOCCHGTUNNEL && p->name[0]) {
    91         strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
     130        strncpy_IFNAMSIZ(ifr.ifr_name, p->name);
    92131    } else {
    93         strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
     132        strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
    94133    }
    95134    ifr.ifr_ifru.ifru_data = (void*)p;
     
    115154
    116155    if (p->name[0]) {
    117         strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
     156        strncpy_IFNAMSIZ(ifr.ifr_name, p->name);
    118157    } else {
    119         strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
     158        strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
    120159    }
    121160    ifr.ifr_ifru.ifru_data = (void*)p;
     
    127166
    128167/* Dies on error */
    129 static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
     168static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p)
    130169{
    131170    static const char keywords[] ALIGN1 =
     
    149188
    150189    memset(p, 0, sizeof(*p));
    151     memset(&medium, 0, sizeof(medium));
     190    medium[0] = '\0';
    152191
    153192    p->iph.version = 4;
     
    158197    p->iph.frag_off = htons(IP_DF);
    159198
    160     while (argc > 0) {
     199    while (*argv) {
    161200        key = index_in_strings(keywords, *argv);
    162201        if (key == ARG_mode) {
     
    164203            key = index_in_strings(keywords, *argv);
    165204            if (key == ARG_ipip ||
    166                 key == ARG_ip_ip) {
     205                key == ARG_ip_ip
     206            ) {
    167207                if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
    168                     bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
     208                    bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
    169209                }
    170210                p->iph.protocol = IPPROTO_IPIP;
    171211            } else if (key == ARG_gre ||
    172                    key == ARG_gre_ip) {
     212                   key == ARG_gre_ip
     213            ) {
    173214                if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
    174                     bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
     215                    bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
    175216                }
    176217                p->iph.protocol = IPPROTO_GRE;
    177218            } else if (key == ARG_sit ||
    178                    key == ARG_ip6_ip) {
     219                   key == ARG_ip6_ip
     220            ) {
    179221                if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
    180                     bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
     222                    bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
    181223                }
    182224                p->iph.protocol = IPPROTO_IPV6;
    183225            } else {
    184                 bb_error_msg_and_die("cannot guess tunnel mode");
     226                bb_error_msg_and_die("%s tunnel mode", "can't guess");
    185227            }
    186228        } else if (key == ARG_key) {
     
    192234                p->i_key = p->o_key = get_addr32(*argv);
    193235            else {
    194                 if (get_unsigned(&uval, *argv, 0)<0) {
    195                     bb_error_msg_and_die("invalid value of \"key\"");
    196                 }
     236                uval = get_unsigned(*argv, "key");
    197237                p->i_key = p->o_key = htonl(uval);
    198238            }
     
    204244                p->o_key = get_addr32(*argv);
    205245            else {
    206                 if (get_unsigned(&uval, *argv, 0)<0) {
    207                     bb_error_msg_and_die("invalid value of \"ikey\"");
    208                 }
     246                uval = get_unsigned(*argv, "ikey");
    209247                p->i_key = htonl(uval);
    210248            }
     
    216254                p->o_key = get_addr32(*argv);
    217255            else {
    218                 if (get_unsigned(&uval, *argv, 0)<0) {
    219                     bb_error_msg_and_die("invalid value of \"okey\"");
    220                 }
     256                uval = get_unsigned(*argv, "okey");
    221257                p->o_key = htonl(uval);
    222258            }
     
    251287        } else if (key == ARG_dev) {
    252288            NEXT_ARG();
    253             strncpy(medium, *argv, IFNAMSIZ-1);
     289            strncpy_IFNAMSIZ(medium, *argv);
    254290        } else if (key == ARG_ttl) {
    255291            unsigned uval;
     
    257293            key = index_in_strings(keywords, *argv);
    258294            if (key != ARG_inherit) {
    259                 if (get_unsigned(&uval, *argv, 0))
    260                     invarg(*argv, "TTL");
     295                uval = get_unsigned(*argv, "TTL");
    261296                if (uval > 255)
    262297                    invarg(*argv, "TTL must be <=255");
     
    264299            }
    265300        } else if (key == ARG_tos ||
    266                key == ARG_dsfield) {
     301               key == ARG_dsfield
     302        ) {
    267303            uint32_t uval;
    268304            NEXT_ARG();
     
    280316            if (p->name[0])
    281317                duparg2("name", *argv);
    282             strncpy(p->name, *argv, IFNAMSIZ);
     318            strncpy_IFNAMSIZ(p->name, *argv);
    283319            if (cmd == SIOCCHGTUNNEL && count == 0) {
    284320                struct ip_tunnel_parm old_p;
    285321                memset(&old_p, 0, sizeof(old_p));
    286322                if (do_get_ioctl(*argv, &old_p))
    287                     exit(1);
     323                    exit(EXIT_FAILURE);
    288324                *p = old_p;
    289325            }
    290326        }
    291327        count++;
    292         argc--;
    293328        argv++;
    294329    }
     
    326361}
    327362
    328 
    329363/* Return value becomes exitcode. It's okay to not return at all */
    330 static int do_add(int cmd, int argc, char **argv)
     364static int do_add(int cmd, char **argv)
    331365{
    332366    struct ip_tunnel_parm p;
    333367
    334     parse_args(argc, argv, cmd, &p);
     368    parse_args(argv, cmd, &p);
    335369
    336370    if (p.iph.ttl && p.iph.frag_off == 0) {
     
    346380        return do_add_ioctl(cmd, "sit0", &p);
    347381    default:
    348         bb_error_msg_and_die("cannot determine tunnel mode (ipip, gre or sit)");
     382        bb_error_msg_and_die("can't determine tunnel mode (ipip, gre or sit)");
    349383    }
    350384}
    351385
    352386/* Return value becomes exitcode. It's okay to not return at all */
    353 static int do_del(int argc, char **argv)
     387static int do_del(char **argv)
    354388{
    355389    struct ip_tunnel_parm p;
    356390
    357     parse_args(argc, argv, SIOCDELTUNNEL, &p);
     391    parse_args(argv, SIOCDELTUNNEL, &p);
    358392
    359393    switch (p.iph.protocol) {
     
    405439        if (p->iph.tos & ~1)
    406440            printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
    407                    rtnl_dsfield_n2a(p->iph.tos & ~1, b1, sizeof(b1)));
     441                   rtnl_dsfield_n2a(p->iph.tos & ~1, b1));
    408442    }
    409443    if (!(p->iph.frag_off & htons(IP_DF)))
     
    444478        return;
    445479    }
    446 
     480    /* skip headers */
    447481    fgets(buf, sizeof(buf), fp);
    448482    fgets(buf, sizeof(buf), fp);
     
    454488        ptr = strchr(buf, ':');
    455489        if (ptr == NULL ||
    456             (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
     490            (*ptr++ = 0, sscanf(buf, "%s", name) != 1)
     491        ) {
    457492            bb_error_msg("wrong format of /proc/net/dev");
    458493            return;
     
    468503        type = do_ioctl_get_iftype(name);
    469504        if (type == -1) {
    470             bb_error_msg("cannot get type of [%s]", name);
     505            bb_error_msg("can't get type of [%s]", name);
    471506            continue;
    472507        }
     
    480515            (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
    481516            (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
    482             (p->i_key && p1.i_key != p->i_key))
     517            (p->i_key && p1.i_key != p->i_key)
     518        ) {
    483519            continue;
     520        }
    484521        print_tunnel(&p1);
    485         puts("");
     522        bb_putchar('\n');
    486523    }
    487524}
    488525
    489526/* Return value becomes exitcode. It's okay to not return at all */
    490 static int do_show(int argc, char **argv)
     527static int do_show(char **argv)
    491528{
    492529    int err;
    493530    struct ip_tunnel_parm p;
    494531
    495     parse_args(argc, argv, SIOCGETTUNNEL, &p);
     532    parse_args(argv, SIOCGETTUNNEL, &p);
    496533
    497534    switch (p.iph.protocol) {
     
    513550
    514551    print_tunnel(&p);
    515     puts("");
     552    bb_putchar('\n');
    516553    return 0;
    517554}
    518555
    519556/* Return value becomes exitcode. It's okay to not return at all */
    520 int do_iptunnel(int argc, char **argv)
     557int FAST_FUNC do_iptunnel(char **argv)
    521558{
    522559    static const char keywords[] ALIGN1 =
    523560        "add\0""change\0""delete\0""show\0""list\0""lst\0";
    524561    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)
     562
     563    if (*argv) {
     564        smalluint key = index_in_substrings(keywords, *argv);
     565        if (key > 5)
    530566            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
    531         --argc;
    532         ++argv;
     567        argv++;
    533568        if (key == ARG_add)
    534             return do_add(SIOCADDTUNNEL, argc, argv);
     569            return do_add(SIOCADDTUNNEL, argv);
    535570        if (key == ARG_change)
    536             return do_add(SIOCCHGTUNNEL, argc, argv);
     571            return do_add(SIOCCHGTUNNEL, argv);
    537572        if (key == ARG_del)
    538             return do_del(argc, argv);
    539     }
    540     return do_show(argc, argv);
    541 }
     573            return do_del(argv);
     574    }
     575    return do_show(argv);
     576}
  • branches/2.2.9/mindi-busybox/networking/libiproute/libnetlink.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * libnetlink.c RTnetlink service routines.
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    11  *
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    129 */
    1310
     
    1815#include "libnetlink.h"
    1916
    20 void rtnl_close(struct rtnl_handle *rth)
    21 {
    22     close(rth->fd);
    23 }
    24 
    25 int xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
     17void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
    2618{
    2719    socklen_t addr_len;
    2820
    29     memset(rth, 0, sizeof(rth));
    30 
     21    memset(rth, 0, sizeof(*rth));
    3122    rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    32 
    33     memset(&rth->local, 0, sizeof(rth->local));
    3423    rth->local.nl_family = AF_NETLINK;
    3524    /*rth->local.nl_groups = subscriptions;*/
     
    3726    xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
    3827    addr_len = sizeof(rth->local);
     28    getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
     29
     30/* too much paranoia
    3931    if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
    40         bb_perror_msg_and_die("cannot getsockname");
     32        bb_perror_msg_and_die("getsockname");
    4133    if (addr_len != sizeof(rth->local))
    4234        bb_error_msg_and_die("wrong address length %d", addr_len);
    4335    if (rth->local.nl_family != AF_NETLINK)
    4436        bb_error_msg_and_die("wrong address family %d", rth->local.nl_family);
     37*/
    4538    rth->seq = time(NULL);
    46     return 0;
    47 }
    48 
    49 int xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
     39}
     40
     41int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
    5042{
    5143    struct {
     
    5345        struct rtgenmsg g;
    5446    } req;
    55     struct sockaddr_nl nladdr;
    56 
    57     memset(&nladdr, 0, sizeof(nladdr));
    58     nladdr.nl_family = AF_NETLINK;
    5947
    6048    req.nlh.nlmsg_len = sizeof(req);
     
    6553    req.g.rtgen_family = family;
    6654
    67     return xsendto(rth->fd, (void*)&req, sizeof(req),
    68                  (struct sockaddr*)&nladdr, sizeof(nladdr));
    69 }
    70 
    71 int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
     55    return rtnl_send(rth, (void*)&req, sizeof(req));
     56}
     57
     58int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len)
    7259{
    7360    struct sockaddr_nl nladdr;
     
    7966}
    8067
    81 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
     68int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
    8269{
    8370    struct nlmsghdr nlh;
     
    8673    struct msghdr msg = {
    8774        (void*)&nladdr, sizeof(nladdr),
    88         iov,    2,
    89         NULL,   0,
     75        iov,  2,
     76        NULL, 0,
    9077        0
    9178    };
     
    10491
    10592static int rtnl_dump_filter(struct rtnl_handle *rth,
    106         int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
     93        int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *n, void *) FAST_FUNC,
    10794        void *arg1/*,
    10895        int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
    10996        void *arg2*/)
    11097{
    111     char buf[8192];
     98    int retval = -1;
     99    char *buf = xmalloc(8*1024); /* avoid big stack buffer */
    112100    struct sockaddr_nl nladdr;
    113     struct iovec iov = { buf, sizeof(buf) };
     101    struct iovec iov = { buf, 8*1024 };
    114102
    115103    while (1) {
     
    119107        struct msghdr msg = {
    120108            (void*)&nladdr, sizeof(nladdr),
    121             &iov,   1,
    122             NULL,   0,
     109            &iov, 1,
     110            NULL, 0,
    123111            0
    124112        };
     
    134122        if (status == 0) {
    135123            bb_error_msg("EOF on netlink");
    136             return -1;
     124            goto ret;
    137125        }
    138126        if (msg.msg_namelen != sizeof(nladdr)) {
     
    146134            if (nladdr.nl_pid != 0 ||
    147135                h->nlmsg_pid != rth->local.nl_pid ||
    148                 h->nlmsg_seq != rth->dump) {
    149 /*              if (junk) {
    150                     err = junk(&nladdr, h, arg2);
    151                     if (err < 0)
    152                         return err;
    153                 } */
     136                h->nlmsg_seq != rth->dump
     137            ) {
     138//              if (junk) {
     139//                  err = junk(&nladdr, h, arg2);
     140//                  if (err < 0) {
     141//                      retval = err;
     142//                      goto ret;
     143//                  }
     144//              }
    154145                goto skip_it;
    155146            }
    156147
    157148            if (h->nlmsg_type == NLMSG_DONE) {
    158                 return 0;
     149                goto ret_0;
    159150            }
    160151            if (h->nlmsg_type == NLMSG_ERROR) {
     
    166157                    bb_perror_msg("RTNETLINK answers");
    167158                }
    168                 return -1;
     159                goto ret;
    169160            }
    170161            err = filter(&nladdr, h, arg1);
    171             if (err < 0)
    172                 return err;
    173 
    174 skip_it:
     162            if (err < 0) {
     163                retval = err;
     164                goto ret;
     165            }
     166
     167 skip_it:
    175168            h = NLMSG_NEXT(h, status);
    176169        }
     
    182175            bb_error_msg_and_die("remnant of size %d!", status);
    183176        }
    184     }
    185 }
    186 
    187 int xrtnl_dump_filter(struct rtnl_handle *rth,
    188         int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
     177    } /* while (1) */
     178 ret_0:
     179    retval++; /* = 0 */
     180 ret:
     181    free(buf);
     182    return retval;
     183}
     184
     185int FAST_FUNC xrtnl_dump_filter(struct rtnl_handle *rth,
     186        int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *, void *) FAST_FUNC,
    189187        void *arg1)
    190188{
     
    195193}
    196194
    197 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
    198           unsigned groups, struct nlmsghdr *answer,
    199           int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
    200           void *jarg)
    201 {
     195int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
     196        pid_t peer, unsigned groups,
     197        struct nlmsghdr *answer,
     198        int (*junk)(struct sockaddr_nl *, struct nlmsghdr *, void *),
     199        void *jarg)
     200{
     201/* bbox doesn't use parameters no. 3, 4, 6, 7, they are stubbed out */
     202#define peer   0
     203#define groups 0
     204#define junk   NULL
     205#define jarg   NULL
     206    int retval = -1;
    202207    int status;
    203208    unsigned seq;
     
    205210    struct sockaddr_nl nladdr;
    206211    struct iovec iov = { (void*)n, n->nlmsg_len };
    207     char   buf[8192];
     212    char   *buf = xmalloc(8*1024); /* avoid big stack buffer */
    208213    struct msghdr msg = {
    209214        (void*)&nladdr, sizeof(nladdr),
    210         &iov,   1,
    211         NULL,   0,
     215        &iov, 1,
     216        NULL, 0,
    212217        0
    213218    };
     
    215220    memset(&nladdr, 0, sizeof(nladdr));
    216221    nladdr.nl_family = AF_NETLINK;
    217     nladdr.nl_pid = peer;
    218     nladdr.nl_groups = groups;
     222//  nladdr.nl_pid = peer;
     223//  nladdr.nl_groups = groups;
    219224
    220225    n->nlmsg_seq = seq = ++rtnl->seq;
     
    225230
    226231    if (status < 0) {
    227         bb_perror_msg("cannot talk to rtnetlink");
    228         return -1;
     232        bb_perror_msg("can't talk to rtnetlink");
     233        goto ret;
    229234    }
    230235
     
    232237
    233238    while (1) {
    234         iov.iov_len = sizeof(buf);
     239        iov.iov_len = 8*1024;
    235240        status = recvmsg(rtnl->fd, &msg, 0);
    236241
     
    244249        if (status == 0) {
    245250            bb_error_msg("EOF on netlink");
    246             return -1;
     251            goto ret;
    247252        }
    248253        if (msg.msg_namelen != sizeof(nladdr)) {
    249254            bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
    250255        }
    251         for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
    252             int l_err;
     256        for (h = (struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) {
     257//          int l_err;
    253258            int len = h->nlmsg_len;
    254259            int l = len - sizeof(*h);
    255260
    256             if (l<0 || len>status) {
     261            if (l < 0 || len > status) {
    257262                if (msg.msg_flags & MSG_TRUNC) {
    258263                    bb_error_msg("truncated message");
    259                     return -1;
     264                    goto ret;
    260265                }
    261266                bb_error_msg_and_die("malformed message: len=%d!", len);
     
    264269            if (nladdr.nl_pid != peer ||
    265270                h->nlmsg_pid != rtnl->local.nl_pid ||
    266                 h->nlmsg_seq != seq) {
    267                 if (junk) {
    268                     l_err = junk(&nladdr, h, jarg);
    269                     if (l_err < 0) {
    270                         return l_err;
    271                     }
    272                 }
     271                h->nlmsg_seq != seq
     272            ) {
     273//              if (junk) {
     274//                  l_err = junk(&nladdr, h, jarg);
     275//                  if (l_err < 0) {
     276//                      retval = l_err;
     277//                      goto ret;
     278//                  }
     279//              }
    273280                continue;
    274281            }
     
    276283            if (h->nlmsg_type == NLMSG_ERROR) {
    277284                struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    278                 if (l < sizeof(struct nlmsgerr)) {
     285                if (l < (int)sizeof(struct nlmsgerr)) {
    279286                    bb_error_msg("ERROR truncated");
    280287                } else {
    281                     errno = -err->error;
     288                    errno = - err->error;
    282289                    if (errno == 0) {
    283290                        if (answer) {
    284291                            memcpy(answer, h, h->nlmsg_len);
    285292                        }
    286                         return 0;
     293                        goto ret_0;
    287294                    }
    288295                    bb_perror_msg("RTNETLINK answers");
    289296                }
    290                 return -1;
     297                goto ret;
    291298            }
    292299            if (answer) {
    293300                memcpy(answer, h, h->nlmsg_len);
    294                 return 0;
     301                goto ret_0;
    295302            }
    296303
     
    307314            bb_error_msg_and_die("remnant of size %d!", status);
    308315        }
    309     }
    310 }
    311 
    312 int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
     316    } /* while (1) */
     317 ret_0:
     318    retval++; /* = 0 */
     319 ret:
     320    free(buf);
     321    return retval;
     322}
     323
     324int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data)
    313325{
    314326    int len = RTA_LENGTH(4);
    315327    struct rtattr *rta;
    316     if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
     328
     329    if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
    317330        return -1;
     331    }
    318332    rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
    319333    rta->rta_type = type;
    320334    rta->rta_len = len;
    321     memcpy(RTA_DATA(rta), &data, 4);
     335    move_to_unaligned32(RTA_DATA(rta), data);
    322336    n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
    323337    return 0;
    324338}
    325339
    326 int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
     340int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
    327341{
    328342    int len = RTA_LENGTH(alen);
    329343    struct rtattr *rta;
    330344
    331     if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
     345    if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
    332346        return -1;
     347    }
    333348    rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
    334349    rta->rta_type = type;
     
    339354}
    340355
    341 int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
     356int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)
    342357{
    343358    int len = RTA_LENGTH(4);
     
    350365    subrta->rta_type = type;
    351366    subrta->rta_len = len;
    352     memcpy(RTA_DATA(subrta), &data, 4);
     367    move_to_unaligned32(RTA_DATA(subrta), data);
    353368    rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
    354369    return 0;
    355370}
    356371
    357 int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
     372int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
    358373{
    359374    struct rtattr *subrta;
     
    372387
    373388
    374 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
     389void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
    375390{
    376391    while (RTA_OK(rta, len)) {
     
    383398        bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len);
    384399    }
    385     return 0;
    386 }
     400}
  • branches/2.2.9/mindi-busybox/networking/libiproute/libnetlink.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 #ifndef __LIBNETLINK_H__
    3 #define __LIBNETLINK_H__ 1
     2#ifndef LIBNETLINK_H
     3#define LIBNETLINK_H 1
    44
    55#include <linux/types.h>
     
    99#include <linux/rtnetlink.h>
    1010
    11 struct rtnl_handle
    12 {
    13     int         fd;
    14     struct sockaddr_nl  local;
    15     struct sockaddr_nl  peer;
    16     uint32_t        seq;
    17     uint32_t        dump;
     11PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
     12
     13struct rtnl_handle {
     14    int                fd;
     15    struct sockaddr_nl local;
     16    struct sockaddr_nl peer;
     17    uint32_t           seq;
     18    uint32_t           dump;
    1819};
    1920
    20 extern int xrtnl_open(struct rtnl_handle *rth);
    21 extern void rtnl_close(struct rtnl_handle *rth);
    22 extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
    23 extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
     21extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC;
     22#define rtnl_close(rth) (close((rth)->fd))
     23extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC;
     24extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC;
    2425extern int xrtnl_dump_filter(struct rtnl_handle *rth,
    25             int (*filter)(struct sockaddr_nl*, struct nlmsghdr *n, void*),
    26             void *arg1);
     26        int (*filter)(const struct sockaddr_nl*, struct nlmsghdr *n, void*) FAST_FUNC,
     27        void *arg1) FAST_FUNC;
     28
     29/* bbox doesn't use parameters no. 3, 4, 6, 7, stub them out */
     30#define rtnl_talk(rtnl, n, peer, groups, answer, junk, jarg) \
     31    rtnl_talk(rtnl, n, answer)
    2732extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
    28             unsigned groups, struct nlmsghdr *answer,
    29             int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
    30             void *jarg);
    31 extern int rtnl_send(struct rtnl_handle *rth, char *buf, int);
     33        unsigned groups, struct nlmsghdr *answer,
     34        int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
     35        void *jarg) FAST_FUNC;
     36
     37extern int rtnl_send(struct rtnl_handle *rth, char *buf, int) FAST_FUNC;
    3238
    3339
    34 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data);
    35 extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen);
    36 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data);
    37 extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen);
     40extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC;
     41extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC;
     42extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) FAST_FUNC;
     43extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) FAST_FUNC;
    3844
    39 extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
     45extern void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) FAST_FUNC;
    4046
    41 #endif /* __LIBNETLINK_H__ */
     47POP_SAVED_FUNCTION_VISIBILITY
     48
     49#endif
  • branches/2.2.9/mindi-busybox/networking/libiproute/ll_addr.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ll_addr.c
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    119 */
    1210
     
    1816
    1917
    20 const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen)
     18const char* FAST_FUNC ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen)
    2119{
    2220    int i;
    2321    int l;
    2422
    25     if (alen == 4 &&
    26         (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
     23    if (alen == 4
     24     && (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)
     25    ) {
    2726        return inet_ntop(AF_INET, addr, buf, blen);
    2827    }
    2928    l = 0;
    30     for (i=0; i<alen; i++) {
    31         if (i==0) {
    32             snprintf(buf+l, blen, ":%02x"+1, addr[i]);
     29    for (i = 0; i < alen; i++) {
     30        if (i == 0) {
     31            snprintf(buf + l, blen, ":%02x"+1, addr[i]);
    3332            blen -= 2;
    3433            l += 2;
    3534        } else {
    36             snprintf(buf+l, blen, ":%02x", addr[i]);
     35            snprintf(buf + l, blen, ":%02x", addr[i]);
    3736            blen -= 3;
    3837            l += 3;
     
    4241}
    4342
    44 int ll_addr_a2n(unsigned char *lladdr, int len, char *arg)
     43int FAST_FUNC ll_addr_a2n(unsigned char *lladdr, int len, char *arg)
    4544{
     45    int i;
     46
    4647    if (strchr(arg, '.')) {
    4748        inet_prefix pfx;
     
    5556        memcpy(lladdr, pfx.data, 4);
    5657        return 4;
    57     } else {
    58         int i;
     58    }
    5959
    60         for (i=0; i<len; i++) {
    61             int temp;
    62             char *cp = strchr(arg, ':');
    63             if (cp) {
    64                 *cp = 0;
    65                 cp++;
    66             }
    67             if (sscanf(arg, "%x", &temp) != 1) {
    68                 bb_error_msg("\"%s\" is invalid lladdr", arg);
    69                 return -1;
    70             }
    71             if (temp < 0 || temp > 255) {
    72                 bb_error_msg("\"%s\" is invalid lladdr", arg);
    73                 return -1;
    74             }
    75             lladdr[i] = temp;
    76             if (!cp) {
    77                 break;
    78             }
    79             arg = cp;
     60    for (i = 0; i < len; i++) {
     61        int temp;
     62        char *cp = strchr(arg, ':');
     63        if (cp) {
     64            *cp = 0;
     65            cp++;
    8066        }
    81         return i+1;
     67        if (sscanf(arg, "%x", &temp) != 1 || (temp < 0 || temp > 255)) {
     68            bb_error_msg("\"%s\" is invalid lladdr", arg);
     69            return -1;
     70        }
     71        lladdr[i] = temp;
     72        if (!cp) {
     73            break;
     74        }
     75        arg = cp;
    8276    }
     77    return i+1;
    8378}
  • branches/2.2.9/mindi-busybox/networking/libiproute/ll_map.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ll_map.c
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    11  *
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    129 */
    1310
    14 #include <net/if.h> /* struct ifreq and co. */
     11#include <net/if.h>  /* struct ifreq and co. */
    1512
    1613#include "libbb.h"
     
    2825};
    2926
    30 static struct idxmap *idxmap[16];
     27static struct idxmap **idxmap; /* treat as *idxmap[16] */
    3128
    3229static struct idxmap *find_by_index(int idx)
     
    3431    struct idxmap *im;
    3532
    36     for (im = idxmap[idx & 0xF]; im; im = im->next)
    37         if (im->index == idx)
    38             return im;
     33    if (idxmap)
     34        for (im = idxmap[idx & 0xF]; im; im = im->next)
     35            if (im->index == idx)
     36                return im;
    3937    return NULL;
    4038}
    4139
    42 int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
     40int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM,
     41        struct nlmsghdr *n,
     42        void *arg UNUSED_PARAM)
    4343{
    4444    int h;
     
    5858        return 0;
    5959
     60    if (!idxmap)
     61        idxmap = xzalloc(sizeof(idxmap[0]) * 16);
     62
    6063    h = ifi->ifi_index & 0xF;
    61 
    6264    for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next)
    6365        if (im->index == ifi->ifi_index)
     
    7476        int alen;
    7577        im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
    76         if (alen > sizeof(im->addr))
     78        if (alen > (int)sizeof(im->addr))
    7779            alen = sizeof(im->addr);
    7880        memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
     
    8587}
    8688
    87 const char *ll_idx_n2a(int idx, char *buf)
     89const char FAST_FUNC *ll_idx_n2a(int idx, char *buf)
    8890{
    8991    struct idxmap *im;
     
    99101
    100102
    101 const char *ll_index_to_name(int idx)
     103const char FAST_FUNC *ll_index_to_name(int idx)
    102104{
    103105    static char nbuf[16];
     
    120122#endif
    121123
    122 unsigned ll_index_to_flags(int idx)
     124unsigned FAST_FUNC ll_index_to_flags(int idx)
    123125{
    124126    struct idxmap *im;
     
    132134}
    133135
    134 int xll_name_to_index(const char *const name)
     136int FAST_FUNC xll_name_to_index(const char *name)
    135137{
    136138    int ret = 0;
     
    151153        goto out;
    152154    }
    153     for (i = 0; i < 16; i++) {
    154         for (im = idxmap[i]; im; im = im->next) {
    155             if (strcmp(im->name, name) == 0) {
    156                 icache = im->index;
    157                 strcpy(ncache, name);
    158                 ret = im->index;
    159                 goto out;
     155    if (idxmap) {
     156        for (i = 0; i < 16; i++) {
     157            for (im = idxmap[i]; im; im = im->next) {
     158                if (strcmp(im->name, name) == 0) {
     159                    icache = im->index;
     160                    strcpy(ncache, name);
     161                    ret = im->index;
     162                    goto out;
     163                }
    160164            }
    161165        }
     
    171175
    172176    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    173     if (sock_fd) {
     177    if (sock_fd >= 0) {
    174178        struct ifreq ifr;
    175179        int tmp;
    176180
    177         strncpy(ifr.ifr_name, name, IFNAMSIZ);
     181        strncpy_IFNAMSIZ(ifr.ifr_name, name);
    178182        ifr.ifr_ifindex = -1;
    179183        tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr);
     
    187191/* out:*/
    188192    if (ret <= 0)
    189         bb_error_msg_and_die("cannot find device \"%s\"", name);
     193        bb_error_msg_and_die("can't find device '%s'", name);
    190194    return ret;
    191195}
    192196
    193 int ll_init_map(struct rtnl_handle *rth)
     197int FAST_FUNC ll_init_map(struct rtnl_handle *rth)
    194198{
    195199    xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK);
    196     xrtnl_dump_filter(rth, ll_remember_index, &idxmap);
     200    xrtnl_dump_filter(rth, ll_remember_index, NULL);
    197201    return 0;
    198202}
  • branches/2.2.9/mindi-busybox/networking/libiproute/ll_map.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 #ifndef __LL_MAP_H__
    3 #define __LL_MAP_H__ 1
     2#ifndef LL_MAP_H
     3#define LL_MAP_H 1
    44
    5 int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
    6 int ll_init_map(struct rtnl_handle *rth);
    7 int xll_name_to_index(const char *const name);
    8 const char *ll_index_to_name(int idx);
    9 const char *ll_idx_n2a(int idx, char *buf);
     5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
     6
     7int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) FAST_FUNC;
     8int ll_init_map(struct rtnl_handle *rth) FAST_FUNC;
     9int xll_name_to_index(const char *name) FAST_FUNC;
     10const char *ll_index_to_name(int idx) FAST_FUNC;
     11const char *ll_idx_n2a(int idx, char *buf) FAST_FUNC;
    1012/* int ll_index_to_type(int idx); */
    11 unsigned ll_index_to_flags(int idx);
     13unsigned ll_index_to_flags(int idx) FAST_FUNC;
    1214
    13 #endif /* __LL_MAP_H__ */
     15POP_SAVED_FUNCTION_VISIBILITY
     16
     17#endif
  • branches/2.2.9/mindi-busybox/networking/libiproute/ll_proto.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ll_proto.c
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    119 */
    1210
     
    2018#include <linux/if_ether.h>
    2119#endif
     20
     21#if !ENABLE_WERROR
     22#warning de-bloat
     23#endif
     24/* Before re-enabling this, please (1) conditionalize exotic protocols
     25 * on CONFIG_something, and (2) decouple strings and numbers
     26 * (use llproto_ids[] = n,n,n..; and llproto_names[] = "loop\0" "pup\0" ...;)
     27 */
    2228
    2329#define __PF(f,n) { ETH_P_##f, #n },
     
    9197
    9298
    93 const char * ll_proto_n2a(unsigned short id, char *buf, int len)
     99const char* FAST_FUNC ll_proto_n2a(unsigned short id, char *buf, int len)
    94100{
    95     int i;
    96 
     101    unsigned i;
    97102    id = ntohs(id);
    98 
    99     for (i=0; i < ARRAY_SIZE(llproto_names); i++) {
     103    for (i = 0; i < ARRAY_SIZE(llproto_names); i++) {
    100104         if (llproto_names[i].id == id)
    101105            return llproto_names[i].name;
     
    105109}
    106110
    107 int ll_proto_a2n(unsigned short *id, char *buf)
     111int FAST_FUNC ll_proto_a2n(unsigned short *id, char *buf)
    108112{
    109     int i;
    110     for (i=0; i < ARRAY_SIZE(llproto_names); i++) {
     113    unsigned i;
     114    for (i = 0; i < ARRAY_SIZE(llproto_names); i++) {
    111115         if (strcasecmp(llproto_names[i].name, buf) == 0) {
    112              *id = htons(llproto_names[i].id);
    113              return 0;
     116             i = llproto_names[i].id;
     117             goto good;
    114118         }
    115119    }
    116     if (get_u16(id, buf, 0))
     120    i = bb_strtou(buf, NULL, 0);
     121    if (errno || i > 0xffff)
    117122        return -1;
    118     *id = htons(*id);
     123 good:
     124    *id = htons(i);
    119125    return 0;
    120126}
  • branches/2.2.9/mindi-busybox/networking/libiproute/ll_types.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * ll_types.c
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    119 */
    1210#include <arpa/inet.h>
     
    1614#include "rt_names.h"
    1715
    18 const char* ll_type_n2a(int type, char *buf, int len)
     16const char* FAST_FUNC ll_type_n2a(int type, char *buf)
    1917{
    20 #define __PF(f,n) { ARPHRD_##f, #n },
    21 static const struct {
    22     int type;
    23     const char *name;
    24 } arphrd_names[] = {
    25 { 0, "generic" },
    26 __PF(ETHER,ether)
    27 __PF(EETHER,eether)
    28 __PF(AX25,ax25)
    29 __PF(PRONET,pronet)
    30 __PF(CHAOS,chaos)
     18    static const char arphrd_name[] =
     19    /* 0,                  */ "generic" "\0"
     20    /* ARPHRD_LOOPBACK,    */ "loopback" "\0"
     21    /* ARPHRD_ETHER,       */ "ether" "\0"
     22#ifdef ARPHRD_INFINIBAND
     23    /* ARPHRD_INFINIBAND,  */ "infiniband" "\0"
     24#endif
    3125#ifdef ARPHRD_IEEE802_TR
    32 __PF(IEEE802,ieee802)
     26    /* ARPHRD_IEEE802,     */ "ieee802" "\0"
     27    /* ARPHRD_IEEE802_TR,  */ "tr" "\0"
    3328#else
    34 __PF(IEEE802,tr)
    35 #endif
    36 __PF(ARCNET,arcnet)
    37 __PF(APPLETLK,atalk)
    38 __PF(DLCI,dlci)
     29    /* ARPHRD_IEEE802,     */ "tr" "\0"
     30#endif
     31#ifdef ARPHRD_IEEE80211
     32    /* ARPHRD_IEEE80211,   */ "ieee802.11" "\0"
     33#endif
     34#ifdef ARPHRD_IEEE1394
     35    /* ARPHRD_IEEE1394,    */ "ieee1394" "\0"
     36#endif
     37    /* ARPHRD_IRDA,        */ "irda" "\0"
     38    /* ARPHRD_SLIP,        */ "slip" "\0"
     39    /* ARPHRD_CSLIP,       */ "cslip" "\0"
     40    /* ARPHRD_SLIP6,       */ "slip6" "\0"
     41    /* ARPHRD_CSLIP6,      */ "cslip6" "\0"
     42    /* ARPHRD_PPP,         */ "ppp" "\0"
     43    /* ARPHRD_TUNNEL,      */ "ipip" "\0"
     44    /* ARPHRD_TUNNEL6,     */ "tunnel6" "\0"
     45    /* ARPHRD_SIT,         */ "sit" "\0"
     46    /* ARPHRD_IPGRE,       */ "gre" "\0"
     47#ifdef ARPHRD_VOID
     48    /* ARPHRD_VOID,        */ "void" "\0"
     49#endif
     50
     51#if ENABLE_FEATURE_IP_RARE_PROTOCOLS
     52    /* ARPHRD_EETHER,      */ "eether" "\0"
     53    /* ARPHRD_AX25,        */ "ax25" "\0"
     54    /* ARPHRD_PRONET,      */ "pronet" "\0"
     55    /* ARPHRD_CHAOS,       */ "chaos" "\0"
     56    /* ARPHRD_ARCNET,      */ "arcnet" "\0"
     57    /* ARPHRD_APPLETLK,    */ "atalk" "\0"
     58    /* ARPHRD_DLCI,        */ "dlci" "\0"
    3959#ifdef ARPHRD_ATM
    40 __PF(ATM,atm)
    41 #endif
    42 __PF(METRICOM,metricom)
     60    /* ARPHRD_ATM,         */ "atm" "\0"
     61#endif
     62    /* ARPHRD_METRICOM,    */ "metricom" "\0"
     63    /* ARPHRD_RSRVD,       */ "rsrvd" "\0"
     64    /* ARPHRD_ADAPT,       */ "adapt" "\0"
     65    /* ARPHRD_ROSE,        */ "rose" "\0"
     66    /* ARPHRD_X25,         */ "x25" "\0"
     67#ifdef ARPHRD_HWX25
     68    /* ARPHRD_HWX25,       */ "hwx25" "\0"
     69#endif
     70    /* ARPHRD_HDLC,        */ "hdlc" "\0"
     71    /* ARPHRD_LAPB,        */ "lapb" "\0"
     72#ifdef ARPHRD_DDCMP
     73    /* ARPHRD_DDCMP,       */ "ddcmp" "\0"
     74    /* ARPHRD_RAWHDLC,     */ "rawhdlc" "\0"
     75#endif
     76    /* ARPHRD_FRAD,        */ "frad" "\0"
     77    /* ARPHRD_SKIP,        */ "skip" "\0"
     78    /* ARPHRD_LOCALTLK,    */ "ltalk" "\0"
     79    /* ARPHRD_FDDI,        */ "fddi" "\0"
     80    /* ARPHRD_BIF,         */ "bif" "\0"
     81    /* ARPHRD_IPDDP,       */ "ip/ddp" "\0"
     82    /* ARPHRD_PIMREG,      */ "pimreg" "\0"
     83    /* ARPHRD_HIPPI,       */ "hippi" "\0"
     84    /* ARPHRD_ASH,         */ "ash" "\0"
     85    /* ARPHRD_ECONET,      */ "econet" "\0"
     86    /* ARPHRD_FCPP,        */ "fcpp" "\0"
     87    /* ARPHRD_FCAL,        */ "fcal" "\0"
     88    /* ARPHRD_FCPL,        */ "fcpl" "\0"
     89    /* ARPHRD_FCFABRIC,    */ "fcfb0" "\0"
     90    /* ARPHRD_FCFABRIC+1,  */ "fcfb1" "\0"
     91    /* ARPHRD_FCFABRIC+2,  */ "fcfb2" "\0"
     92    /* ARPHRD_FCFABRIC+3,  */ "fcfb3" "\0"
     93    /* ARPHRD_FCFABRIC+4,  */ "fcfb4" "\0"
     94    /* ARPHRD_FCFABRIC+5,  */ "fcfb5" "\0"
     95    /* ARPHRD_FCFABRIC+6,  */ "fcfb6" "\0"
     96    /* ARPHRD_FCFABRIC+7,  */ "fcfb7" "\0"
     97    /* ARPHRD_FCFABRIC+8,  */ "fcfb8" "\0"
     98    /* ARPHRD_FCFABRIC+9,  */ "fcfb9" "\0"
     99    /* ARPHRD_FCFABRIC+10, */ "fcfb10" "\0"
     100    /* ARPHRD_FCFABRIC+11, */ "fcfb11" "\0"
     101    /* ARPHRD_FCFABRIC+12, */ "fcfb12" "\0"
     102#endif /* FEATURE_IP_RARE_PROTOCOLS */
     103    ;
     104
     105    /* Keep these arrays in sync! */
     106
     107    static const uint16_t arphrd_type[] = {
     108    0,                  /* "generic" "\0" */
     109    ARPHRD_LOOPBACK,    /* "loopback" "\0" */
     110    ARPHRD_ETHER,       /* "ether" "\0" */
     111#ifdef ARPHRD_INFINIBAND
     112    ARPHRD_INFINIBAND,  /* "infiniband" "\0" */
     113#endif
     114#ifdef ARPHRD_IEEE802_TR
     115    ARPHRD_IEEE802,     /* "ieee802" "\0" */
     116    ARPHRD_IEEE802_TR,  /* "tr" "\0" */
     117#else
     118    ARPHRD_IEEE802,     /* "tr" "\0" */
     119#endif
     120#ifdef ARPHRD_IEEE80211
     121    ARPHRD_IEEE80211,   /* "ieee802.11" "\0" */
     122#endif
    43123#ifdef ARPHRD_IEEE1394
    44 __PF(IEEE1394,ieee1394)
    45 #endif
    46 
    47 __PF(SLIP,slip)
    48 __PF(CSLIP,cslip)
    49 __PF(SLIP6,slip6)
    50 __PF(CSLIP6,cslip6)
    51 __PF(RSRVD,rsrvd)
    52 __PF(ADAPT,adapt)
    53 __PF(ROSE,rose)
    54 __PF(X25,x25)
     124    ARPHRD_IEEE1394,    /* "ieee1394" "\0" */
     125#endif
     126    ARPHRD_IRDA,        /* "irda" "\0" */
     127    ARPHRD_SLIP,        /* "slip" "\0" */
     128    ARPHRD_CSLIP,       /* "cslip" "\0" */
     129    ARPHRD_SLIP6,       /* "slip6" "\0" */
     130    ARPHRD_CSLIP6,      /* "cslip6" "\0" */
     131    ARPHRD_PPP,         /* "ppp" "\0" */
     132    ARPHRD_TUNNEL,      /* "ipip" "\0" */
     133    ARPHRD_TUNNEL6,     /* "tunnel6" "\0" */
     134    ARPHRD_SIT,         /* "sit" "\0" */
     135    ARPHRD_IPGRE,       /* "gre" "\0" */
     136#ifdef ARPHRD_VOID
     137    ARPHRD_VOID,        /* "void" "\0" */
     138#endif
     139
     140#if ENABLE_FEATURE_IP_RARE_PROTOCOLS
     141    ARPHRD_EETHER,      /* "eether" "\0" */
     142    ARPHRD_AX25,        /* "ax25" "\0" */
     143    ARPHRD_PRONET,      /* "pronet" "\0" */
     144    ARPHRD_CHAOS,       /* "chaos" "\0" */
     145    ARPHRD_ARCNET,      /* "arcnet" "\0" */
     146    ARPHRD_APPLETLK,    /* "atalk" "\0" */
     147    ARPHRD_DLCI,        /* "dlci" "\0" */
     148#ifdef ARPHRD_ATM
     149    ARPHRD_ATM,         /* "atm" "\0" */
     150#endif
     151    ARPHRD_METRICOM,    /* "metricom" "\0" */
     152    ARPHRD_RSRVD,       /* "rsrvd" "\0" */
     153    ARPHRD_ADAPT,       /* "adapt" "\0" */
     154    ARPHRD_ROSE,        /* "rose" "\0" */
     155    ARPHRD_X25,         /* "x25" "\0" */
    55156#ifdef ARPHRD_HWX25
    56 __PF(HWX25,hwx25)
    57 #endif
    58 __PF(PPP,ppp)
    59 __PF(HDLC,hdlc)
    60 __PF(LAPB,lapb)
     157    ARPHRD_HWX25,       /* "hwx25" "\0" */
     158#endif
     159    ARPHRD_HDLC,        /* "hdlc" "\0" */
     160    ARPHRD_LAPB,        /* "lapb" "\0" */
    61161#ifdef ARPHRD_DDCMP
    62 __PF(DDCMP,ddcmp)
    63 __PF(RAWHDLC,rawhdlc)
    64 #endif
    65 
    66 __PF(TUNNEL,ipip)
    67 __PF(TUNNEL6,tunnel6)
    68 __PF(FRAD,frad)
    69 __PF(SKIP,skip)
    70 __PF(LOOPBACK,loopback)
    71 __PF(LOCALTLK,ltalk)
    72 __PF(FDDI,fddi)
    73 __PF(BIF,bif)
    74 __PF(SIT,sit)
    75 __PF(IPDDP,ip/ddp)
    76 __PF(IPGRE,gre)
    77 __PF(PIMREG,pimreg)
    78 __PF(HIPPI,hippi)
    79 __PF(ASH,ash)
    80 __PF(ECONET,econet)
    81 __PF(IRDA,irda)
    82 __PF(FCPP,fcpp)
    83 __PF(FCAL,fcal)
    84 __PF(FCPL,fcpl)
    85 __PF(FCFABRIC,fcfb0)
    86 __PF(FCFABRIC+1,fcfb1)
    87 __PF(FCFABRIC+2,fcfb2)
    88 __PF(FCFABRIC+3,fcfb3)
    89 __PF(FCFABRIC+4,fcfb4)
    90 __PF(FCFABRIC+5,fcfb5)
    91 __PF(FCFABRIC+6,fcfb6)
    92 __PF(FCFABRIC+7,fcfb7)
    93 __PF(FCFABRIC+8,fcfb8)
    94 __PF(FCFABRIC+9,fcfb9)
    95 __PF(FCFABRIC+10,fcfb10)
    96 __PF(FCFABRIC+11,fcfb11)
    97 __PF(FCFABRIC+12,fcfb12)
    98 #ifdef ARPHRD_IEEE802_TR
    99 __PF(IEEE802_TR,tr)
    100 #endif
    101 #ifdef ARPHRD_IEEE80211
    102 __PF(IEEE80211,ieee802.11)
    103 #endif
    104 #ifdef ARPHRD_VOID
    105 __PF(VOID,void)
    106 #endif
    107 };
    108 #undef __PF
    109 
    110     int i;
    111     for (i = 0; i < ARRAY_SIZE(arphrd_names); i++) {
    112          if (arphrd_names[i].type == type)
    113             return arphrd_names[i].name;
     162    ARPHRD_DDCMP,       /* "ddcmp" "\0" */
     163    ARPHRD_RAWHDLC,     /* "rawhdlc" "\0" */
     164#endif
     165    ARPHRD_FRAD,        /* "frad" "\0" */
     166    ARPHRD_SKIP,        /* "skip" "\0" */
     167    ARPHRD_LOCALTLK,    /* "ltalk" "\0" */
     168    ARPHRD_FDDI,        /* "fddi" "\0" */
     169    ARPHRD_BIF,         /* "bif" "\0" */
     170    ARPHRD_IPDDP,       /* "ip/ddp" "\0" */
     171    ARPHRD_PIMREG,      /* "pimreg" "\0" */
     172    ARPHRD_HIPPI,       /* "hippi" "\0" */
     173    ARPHRD_ASH,         /* "ash" "\0" */
     174    ARPHRD_ECONET,      /* "econet" "\0" */
     175    ARPHRD_FCPP,        /* "fcpp" "\0" */
     176    ARPHRD_FCAL,        /* "fcal" "\0" */
     177    ARPHRD_FCPL,        /* "fcpl" "\0" */
     178    ARPHRD_FCFABRIC,    /* "fcfb0" "\0" */
     179    ARPHRD_FCFABRIC+1,  /* "fcfb1" "\0" */
     180    ARPHRD_FCFABRIC+2,  /* "fcfb2" "\0" */
     181    ARPHRD_FCFABRIC+3,  /* "fcfb3" "\0" */
     182    ARPHRD_FCFABRIC+4,  /* "fcfb4" "\0" */
     183    ARPHRD_FCFABRIC+5,  /* "fcfb5" "\0" */
     184    ARPHRD_FCFABRIC+6,  /* "fcfb6" "\0" */
     185    ARPHRD_FCFABRIC+7,  /* "fcfb7" "\0" */
     186    ARPHRD_FCFABRIC+8,  /* "fcfb8" "\0" */
     187    ARPHRD_FCFABRIC+9,  /* "fcfb9" "\0" */
     188    ARPHRD_FCFABRIC+10, /* "fcfb10" "\0" */
     189    ARPHRD_FCFABRIC+11, /* "fcfb11" "\0" */
     190    ARPHRD_FCFABRIC+12, /* "fcfb12" "\0" */
     191#endif /* FEATURE_IP_RARE_PROTOCOLS */
     192    };
     193
     194    unsigned i;
     195    const char *aname = arphrd_name;
     196    for (i = 0; i < ARRAY_SIZE(arphrd_type); i++) {
     197        if (arphrd_type[i] == type)
     198            return aname;
     199        aname += strlen(aname) + 1;
    114200    }
    115     snprintf(buf, len, "[%d]", type);
     201    sprintf(buf, "[%d]", type);
    116202    return buf;
    117203}
  • branches/2.2.9/mindi-busybox/networking/libiproute/rt_names.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * rt_names.c       rtnetlink names DB.
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    119 */
    12 
    1310#include "libbb.h"
    1411#include "rt_names.h"
    1512
    16 static void rtnl_tab_initialize(const char *file, const char **tab, int size)
    17 {
    18     char buf[512];
    19     FILE *fp;
    20 
    21     fp = fopen(file, "r");
    22     if (!fp)
    23         return;
    24     while (fgets(buf, sizeof(buf), fp)) {
    25         char *p = buf;
    26         int id;
    27         char namebuf[512];
    28 
    29         while (*p == ' ' || *p == '\t')
    30             p++;
    31         if (*p == '#' || *p == '\n' || *p == 0)
    32             continue;
    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
     13typedef struct rtnl_tab_t {
     14    const char *cached_str;
     15    unsigned cached_result;
     16    const char *tab[256];
     17} rtnl_tab_t;
     18
     19static void rtnl_tab_initialize(const char *file, const char **tab)
     20{
     21    char *token[2];
     22    parser_t *parser = config_open2(file, fopen_for_read);
     23
     24    while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
     25        unsigned id = bb_strtou(token[0], NULL, 0);
     26        if (id > 256) {
     27            bb_error_msg("database %s is corrupted at line %d",
     28                file, parser->lineno);
     29            break;
     30        }
     31        tab[id] = xstrdup(token[1]);
     32    }
     33    config_close(parser);
     34}
     35
     36static int rtnl_a2n(rtnl_tab_t *tab, uint32_t *id, const char *arg, int base)
     37{
     38    unsigned i;
     39
     40    if (tab->cached_str && strcmp(tab->cached_str, arg) == 0) {
     41        *id = tab->cached_result;
     42        return 0;
     43    }
     44
     45    for (i = 0; i < 256; i++) {
     46        if (tab->tab[i]
     47         && strcmp(tab->tab[i], arg) == 0
    3748        ) {
    38             bb_error_msg("database %s is corrupted at %s",
    39                 file, p);
    40             return;
     49            tab->cached_str = tab->tab[i];
     50            tab->cached_result = i;
     51            *id = i;
     52            return 0;
    4153        }
    42 
    43         if (id < 0 || id > size)
    44             continue;
    45 
    46         tab[id] = xstrdup(namebuf);
    47     }
    48     fclose(fp);
    49 }
    50 
    51 
    52 static const char **rtnl_rtprot_tab; /* [256] */
     54    }
     55
     56    i = bb_strtou(arg, NULL, base);
     57    if (i > 255)
     58        return -1;
     59    *id = i;
     60    return 0;
     61}
     62
     63
     64static rtnl_tab_t *rtnl_rtprot_tab;
    5365
    5466static void rtnl_rtprot_initialize(void)
     
    6981        "bird",
    7082    };
    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));
    74     rtnl_tab_initialize("/etc/iproute2/rt_protos",
    75                 rtnl_rtprot_tab, 256);
    76 }
    77 
    78 
    79 const char* rtnl_rtprot_n2a(int id, char *buf, int len)
    80 {
    81     if (id < 0 || id >= 256) {
    82         snprintf(buf, len, "%d", id);
     83
     84    if (rtnl_rtprot_tab)
     85        return;
     86    rtnl_rtprot_tab = xzalloc(sizeof(*rtnl_rtprot_tab));
     87    memcpy(rtnl_rtprot_tab->tab, init_tab, sizeof(init_tab));
     88    rtnl_tab_initialize("/etc/iproute2/rt_protos", rtnl_rtprot_tab->tab);
     89}
     90
     91const char* FAST_FUNC rtnl_rtprot_n2a(int id, char *buf)
     92{
     93    if (id < 0 || id >= 256) {
     94        sprintf(buf, "%d", id);
    8395        return buf;
    8496    }
     
    8698    rtnl_rtprot_initialize();
    8799
    88     if (rtnl_rtprot_tab[id])
    89         return rtnl_rtprot_tab[id];
    90     snprintf(buf, len, "%d", id);
    91     return buf;
    92 }
    93 
    94 int rtnl_rtprot_a2n(uint32_t *id, char *arg)
    95 {
    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 
     100    if (rtnl_rtprot_tab->tab[id])
     101        return rtnl_rtprot_tab->tab[id];
     102    /* buf is SPRINT_BSIZE big */
     103    sprintf(buf, "%d", id);
     104    return buf;
     105}
     106
     107int FAST_FUNC rtnl_rtprot_a2n(uint32_t *id, char *arg)
     108{
    105109    rtnl_rtprot_initialize();
    106 
    107     for (i = 0; i < 256; i++) {
    108         if (rtnl_rtprot_tab[i] &&
    109             strcmp(rtnl_rtprot_tab[i], arg) == 0) {
    110             cache = rtnl_rtprot_tab[i];
    111             res = i;
    112             *id = res;
    113             return 0;
    114         }
    115     }
    116 
    117     res = bb_strtoul(arg, NULL, 0);
    118     if (errno || res > 255)
    119         return -1;
    120     *id = res;
    121     return 0;
    122 }
    123 
    124 
    125 static const char **rtnl_rtscope_tab; /* [256] */
     110    return rtnl_a2n(rtnl_rtprot_tab, id, arg, 0);
     111}
     112
     113
     114static rtnl_tab_t *rtnl_rtscope_tab;
    126115
    127116static void rtnl_rtscope_initialize(void)
    128117{
    129     if (rtnl_rtscope_tab) return;
    130     rtnl_rtscope_tab = xzalloc(256 * sizeof(rtnl_rtscope_tab[0]));
    131     rtnl_rtscope_tab[0] = "global";
    132     rtnl_rtscope_tab[255] = "nowhere";
    133     rtnl_rtscope_tab[254] = "host";
    134     rtnl_rtscope_tab[253] = "link";
    135     rtnl_rtscope_tab[200] = "site";
    136     rtnl_tab_initialize("/etc/iproute2/rt_scopes",
    137                 rtnl_rtscope_tab, 256);
    138 }
    139 
    140 
    141 const char* rtnl_rtscope_n2a(int id, char *buf, int len)
    142 {
    143     if (id < 0 || id >= 256) {
    144         snprintf(buf, len, "%d", id);
     118    if (rtnl_rtscope_tab)
     119        return;
     120    rtnl_rtscope_tab = xzalloc(sizeof(*rtnl_rtscope_tab));
     121    rtnl_rtscope_tab->tab[0] = "global";
     122    rtnl_rtscope_tab->tab[255] = "nowhere";
     123    rtnl_rtscope_tab->tab[254] = "host";
     124    rtnl_rtscope_tab->tab[253] = "link";
     125    rtnl_rtscope_tab->tab[200] = "site";
     126    rtnl_tab_initialize("/etc/iproute2/rt_scopes", rtnl_rtscope_tab->tab);
     127}
     128
     129const char* FAST_FUNC rtnl_rtscope_n2a(int id, char *buf)
     130{
     131    if (id < 0 || id >= 256) {
     132        sprintf(buf, "%d", id);
    145133        return buf;
    146134    }
     
    148136    rtnl_rtscope_initialize();
    149137
    150     if (rtnl_rtscope_tab[id])
    151         return rtnl_rtscope_tab[id];
    152     snprintf(buf, len, "%d", id);
    153     return buf;
    154 }
    155 
    156 int rtnl_rtscope_a2n(uint32_t *id, char *arg)
    157 {
    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 
     138    if (rtnl_rtscope_tab->tab[id])
     139        return rtnl_rtscope_tab->tab[id];
     140    /* buf is SPRINT_BSIZE big */
     141    sprintf(buf, "%d", id);
     142    return buf;
     143}
     144
     145int FAST_FUNC rtnl_rtscope_a2n(uint32_t *id, char *arg)
     146{
    167147    rtnl_rtscope_initialize();
    168 
    169     for (i = 0; i < 256; i++) {
    170         if (rtnl_rtscope_tab[i] &&
    171             strcmp(rtnl_rtscope_tab[i], arg) == 0) {
    172             cache = rtnl_rtscope_tab[i];
    173             res = i;
    174             *id = res;
    175             return 0;
    176         }
    177     }
    178 
    179     res = bb_strtoul(arg, NULL, 0);
    180     if (errno || res > 255)
    181         return -1;
    182     *id = res;
    183     return 0;
    184 }
    185 
    186 
    187 static const char **rtnl_rtrealm_tab; /* [256] */
     148    return rtnl_a2n(rtnl_rtscope_tab, id, arg, 0);
     149}
     150
     151
     152static rtnl_tab_t *rtnl_rtrealm_tab;
    188153
    189154static void rtnl_rtrealm_initialize(void)
    190155{
    191156    if (rtnl_rtrealm_tab) return;
    192     rtnl_rtrealm_tab = xzalloc(256 * sizeof(rtnl_rtrealm_tab[0]));
    193     rtnl_rtrealm_tab[0] = "unknown";
    194     rtnl_tab_initialize("/etc/iproute2/rt_realms",
    195                 rtnl_rtrealm_tab, 256);
    196 }
    197 
    198 
    199 int rtnl_rtrealm_a2n(uint32_t *id, char *arg)
    200 {
    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 
     157    rtnl_rtrealm_tab = xzalloc(sizeof(*rtnl_rtrealm_tab));
     158    rtnl_rtrealm_tab->tab[0] = "unknown";
     159    rtnl_tab_initialize("/etc/iproute2/rt_realms", rtnl_rtrealm_tab->tab);
     160}
     161
     162int FAST_FUNC rtnl_rtrealm_a2n(uint32_t *id, char *arg)
     163{
    210164    rtnl_rtrealm_initialize();
    211 
    212     for (i = 0; i < 256; i++) {
    213         if (rtnl_rtrealm_tab[i] &&
    214             strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
    215             cache = rtnl_rtrealm_tab[i];
    216             res = i;
    217             *id = res;
    218             return 0;
    219         }
    220     }
    221 
    222     res = bb_strtoul(arg, NULL, 0);
    223     if (errno || res > 255)
    224         return -1;
    225     *id = res;
    226     return 0;
     165    return rtnl_a2n(rtnl_rtrealm_tab, id, arg, 0);
    227166}
    228167
    229168#if ENABLE_FEATURE_IP_RULE
    230 const char* rtnl_rtrealm_n2a(int id, char *buf, int len)
    231 {
    232     if (id < 0 || id >= 256) {
    233         snprintf(buf, len, "%d", id);
     169const char* FAST_FUNC rtnl_rtrealm_n2a(int id, char *buf)
     170{
     171    if (id < 0 || id >= 256) {
     172        sprintf(buf, "%d", id);
    234173        return buf;
    235174    }
     
    237176    rtnl_rtrealm_initialize();
    238177
    239     if (rtnl_rtrealm_tab[id])
    240         return rtnl_rtrealm_tab[id];
    241     snprintf(buf, len, "%d", id);
     178    if (rtnl_rtrealm_tab->tab[id])
     179        return rtnl_rtrealm_tab->tab[id];
     180    /* buf is SPRINT_BSIZE big */
     181    sprintf(buf, "%d", id);
    242182    return buf;
    243183}
     
    245185
    246186
    247 static const char **rtnl_rtdsfield_tab; /* [256] */
     187static rtnl_tab_t *rtnl_rtdsfield_tab;
    248188
    249189static void rtnl_rtdsfield_initialize(void)
    250190{
    251191    if (rtnl_rtdsfield_tab) return;
    252     rtnl_rtdsfield_tab = xzalloc(256 * sizeof(rtnl_rtdsfield_tab[0]));
    253     rtnl_rtdsfield_tab[0] = "0";
    254     rtnl_tab_initialize("/etc/iproute2/rt_dsfield",
    255                 rtnl_rtdsfield_tab, 256);
    256 }
    257 
    258 
    259 const char * rtnl_dsfield_n2a(int id, char *buf, int len)
    260 {
    261     if (id < 0 || id >= 256) {
    262         snprintf(buf, len, "%d", id);
     192    rtnl_rtdsfield_tab = xzalloc(sizeof(*rtnl_rtdsfield_tab));
     193    rtnl_rtdsfield_tab->tab[0] = "0";
     194    rtnl_tab_initialize("/etc/iproute2/rt_dsfield", rtnl_rtdsfield_tab->tab);
     195}
     196
     197const char* FAST_FUNC rtnl_dsfield_n2a(int id, char *buf)
     198{
     199    if (id < 0 || id >= 256) {
     200        sprintf(buf, "%d", id);
    263201        return buf;
    264202    }
     
    266204    rtnl_rtdsfield_initialize();
    267205
    268     if (rtnl_rtdsfield_tab[id])
    269         return rtnl_rtdsfield_tab[id];
    270     snprintf(buf, len, "0x%02x", id);
    271     return buf;
    272 }
    273 
    274 
    275 int rtnl_dsfield_a2n(uint32_t *id, char *arg)
    276 {
    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 
     206    if (rtnl_rtdsfield_tab->tab[id])
     207        return rtnl_rtdsfield_tab->tab[id];
     208    /* buf is SPRINT_BSIZE big */
     209    sprintf(buf, "0x%02x", id);
     210    return buf;
     211}
     212
     213int FAST_FUNC rtnl_dsfield_a2n(uint32_t *id, char *arg)
     214{
    286215    rtnl_rtdsfield_initialize();
    287 
    288     for (i = 0; i < 256; i++) {
    289         if (rtnl_rtdsfield_tab[i] &&
    290             strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
    291             cache = rtnl_rtdsfield_tab[i];
    292             res = i;
    293             *id = res;
    294             return 0;
    295         }
    296     }
    297 
    298     res = bb_strtoul(arg, NULL, 16);
    299     if (errno || res > 255)
    300         return -1;
    301     *id = res;
    302     return 0;
     216    return rtnl_a2n(rtnl_rtdsfield_tab, id, arg, 16);
    303217}
    304218
    305219
    306220#if ENABLE_FEATURE_IP_RULE
    307 static const char **rtnl_rttable_tab; /* [256] */
     221static rtnl_tab_t *rtnl_rttable_tab;
    308222
    309223static void rtnl_rttable_initialize(void)
    310224{
    311225    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 
    321 const char *rtnl_rttable_n2a(int id, char *buf, int len)
    322 {
    323     if (id < 0 || id >= 256) {
    324         snprintf(buf, len, "%d", id);
     226    rtnl_rttable_tab = xzalloc(sizeof(*rtnl_rttable_tab));
     227    rtnl_rttable_tab->tab[0] = "unspec";
     228    rtnl_rttable_tab->tab[255] = "local";
     229    rtnl_rttable_tab->tab[254] = "main";
     230    rtnl_rttable_tab->tab[253] = "default";
     231    rtnl_tab_initialize("/etc/iproute2/rt_tables", rtnl_rttable_tab->tab);
     232}
     233
     234const char* FAST_FUNC rtnl_rttable_n2a(int id, char *buf)
     235{
     236    if (id < 0 || id >= 256) {
     237        sprintf(buf, "%d", id);
    325238        return buf;
    326239    }
     
    328241    rtnl_rttable_initialize();
    329242
    330     if (rtnl_rttable_tab[id])
    331         return rtnl_rttable_tab[id];
    332     snprintf(buf, len, "%d", id);
    333     return buf;
    334 }
    335 
    336 int 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 
     243    if (rtnl_rttable_tab->tab[id])
     244        return rtnl_rttable_tab->tab[id];
     245    /* buf is SPRINT_BSIZE big */
     246    sprintf(buf, "%d", id);
     247    return buf;
     248}
     249
     250int FAST_FUNC rtnl_rttable_a2n(uint32_t *id, char *arg)
     251{
    347252    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;
     253    return rtnl_a2n(rtnl_rttable_tab, id, arg, 0);
    363254}
    364255
  • branches/2.2.9/mindi-busybox/networking/libiproute/rt_names.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 #ifndef RT_NAMES_H_
    3 #define RT_NAMES_H_ 1
     2#ifndef RT_NAMES_H
     3#define RT_NAMES_H 1
    44
    5 #include <stdint.h>
     5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    66
    7 extern const char* rtnl_rtprot_n2a(int id, char *buf, int len);
    8 extern const char* rtnl_rtscope_n2a(int id, char *buf, int len);
    9 extern const char* rtnl_rtrealm_n2a(int id, char *buf, int len);
    10 extern const char* rtnl_dsfield_n2a(int id, char *buf, int len);
    11 extern const char* rtnl_rttable_n2a(int id, char *buf, int len);
    12 extern int rtnl_rtprot_a2n(uint32_t *id, char *arg);
    13 extern int rtnl_rtscope_a2n(uint32_t *id, char *arg);
    14 extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg);
    15 extern int rtnl_dsfield_a2n(uint32_t *id, char *arg);
    16 extern int rtnl_rttable_a2n(uint32_t *id, char *arg);
     7/* buf is SPRINT_BSIZE big */
     8extern const char* rtnl_rtprot_n2a(int id, char *buf) FAST_FUNC;
     9extern const char* rtnl_rtscope_n2a(int id, char *buf) FAST_FUNC;
     10extern const char* rtnl_rtrealm_n2a(int id, char *buf) FAST_FUNC;
     11extern const char* rtnl_dsfield_n2a(int id, char *buf) FAST_FUNC;
     12extern const char* rtnl_rttable_n2a(int id, char *buf) FAST_FUNC;
     13extern int rtnl_rtprot_a2n(uint32_t *id, char *arg) FAST_FUNC;
     14extern int rtnl_rtscope_a2n(uint32_t *id, char *arg) FAST_FUNC;
     15extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg) FAST_FUNC;
     16extern int rtnl_dsfield_a2n(uint32_t *id, char *arg) FAST_FUNC;
     17extern int rtnl_rttable_a2n(uint32_t *id, char *arg) FAST_FUNC;
    1718
    18 
    19 extern const char* ll_type_n2a(int type, char *buf, int len);
     19extern const char* ll_type_n2a(int type, char *buf) FAST_FUNC;
    2020
    2121extern const char* ll_addr_n2a(unsigned char *addr, int alen, int type,
    22                 char *buf, int blen);
    23 extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg);
     22                char *buf, int blen) FAST_FUNC;
     23extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg) FAST_FUNC;
    2424
    25 extern const char* ll_proto_n2a(unsigned short id, char *buf, int len);
    26 extern int ll_proto_a2n(unsigned short *id, char *buf);
     25extern const char* ll_proto_n2a(unsigned short id, char *buf, int len) FAST_FUNC;
     26extern int ll_proto_a2n(unsigned short *id, char *buf) FAST_FUNC;
     27
     28POP_SAVED_FUNCTION_VISIBILITY
    2729
    2830#endif
  • branches/2.2.9/mindi-busybox/networking/libiproute/rtm_map.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * rtm_map.c
     3 * This program is free software; you can redistribute it and/or
     4 * modify it under the terms of the GNU General Public License
     5 * as published by the Free Software Foundation; either version
     6 * 2 of the License, or (at your option) any later version.
    47 *
    5  *      This program is free software; you can redistribute it and/or
    6  *      modify it under the terms of the GNU General Public License
    7  *      as published by the Free Software Foundation; either version
    8  *      2 of the License, or (at your option) any later version.
    9  *
    10  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    11  *
     8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    129 */
    1310
     
    1613#include "utils.h"
    1714
    18 const char *rtnl_rtntype_n2a(int id, char *buf, int len)
     15const char* FAST_FUNC rtnl_rtntype_n2a(int id, char *buf)
    1916{
    2017    switch (id) {
     
    4441        return "xresolve";
    4542    default:
    46         snprintf(buf, len, "%d", id);
     43        /* buf is SPRINT_BSIZE big */
     44        sprintf(buf, "%d", id);
    4745        return buf;
    4846    }
     
    5048
    5149
    52 int rtnl_rtntype_a2n(int *id, char *arg)
     50int FAST_FUNC rtnl_rtntype_a2n(int *id, char *arg)
    5351{
    5452    static const char keywords[] ALIGN1 =
     
    8987    else {
    9088        res = strtoul(arg, &end, 0);
    91         if (!end || end == arg || *end || res > 255)
     89        if (end == arg || *end || res > 255)
    9290            return -1;
    9391    }
     
    9694}
    9795
    98 int get_rt_realms(uint32_t *realms, char *arg)
     96int FAST_FUNC get_rt_realms(uint32_t *realms, char *arg)
    9997{
    10098    uint32_t realm = 0;
  • branches/2.2.9/mindi-busybox/networking/libiproute/rtm_map.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 #ifndef __RTM_MAP_H__
    3 #define __RTM_MAP_H__ 1
     2#ifndef RTM_MAP_H
     3#define RTM_MAP_H 1
    44
    5 const char *rtnl_rtntype_n2a(int id, char *buf, int len);
    6 int rtnl_rtntype_a2n(int *id, char *arg);
     5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    76
    8 int get_rt_realms(uint32_t *realms, char *arg);
     7const char *rtnl_rtntype_n2a(int id, char *buf) FAST_FUNC;
     8int rtnl_rtntype_a2n(int *id, char *arg) FAST_FUNC;
    99
     10int get_rt_realms(uint32_t *realms, char *arg) FAST_FUNC;
    1011
    11 #endif /* __RTM_MAP_H__ */
     12POP_SAVED_FUNCTION_VISIBILITY
     13
     14#endif
  • branches/2.2.9/mindi-busybox/networking/libiproute/utils.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * utils.c
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    6  *
    7  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
     5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
    86 *
    97 * Changes:
    108 *
    11  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
     9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
    1210 */
    1311
     
    1614#include "inet_common.h"
    1715
    18 int get_integer(int *val, char *arg, int base)
    19 {
    20     long res;
    21     char *ptr;
    22 
    23     if (!arg || !*arg)
    24         return -1;
    25     res = strtol(arg, &ptr, base);
    26     if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
    27         return -1;
    28     *val = res;
    29     return 0;
    30 }
    31 //XXX: FIXME: use some libbb function instead
    32 int get_unsigned(unsigned *val, char *arg, int base)
     16unsigned get_unsigned(char *arg, const char *errmsg)
    3317{
    3418    unsigned long res;
    3519    char *ptr;
    3620
    37     if (!arg || !*arg)
    38         return -1;
    39     res = strtoul(arg, &ptr, base);
    40     if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
    41         return -1;
    42     *val = res;
    43     return 0;
    44 }
    45 
    46 int get_u32(uint32_t * val, char *arg, int base)
     21    if (*arg) {
     22        res = strtoul(arg, &ptr, 0);
     23//FIXME: "" will be accepted too, is it correct?!
     24        if (!*ptr && res <= UINT_MAX) {
     25            return res;
     26        }
     27    }
     28    invarg(arg, errmsg); /* does not return */
     29}
     30
     31uint32_t get_u32(char *arg, const char *errmsg)
    4732{
    4833    unsigned long res;
    4934    char *ptr;
    5035
    51     if (!arg || !*arg)
    52         return -1;
    53     res = strtoul(arg, &ptr, base);
    54     if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
    55         return -1;
    56     *val = res;
    57     return 0;
    58 }
    59 
    60 int get_u16(uint16_t * val, char *arg, int base)
     36    if (*arg) {
     37        res = strtoul(arg, &ptr, 0);
     38//FIXME: "" will be accepted too, is it correct?!
     39        if (!*ptr && res <= 0xFFFFFFFFUL) {
     40            return res;
     41        }
     42    }
     43    invarg(arg, errmsg); /* does not return */
     44}
     45
     46uint16_t get_u16(char *arg, const char *errmsg)
    6147{
    6248    unsigned long res;
    6349    char *ptr;
    6450
    65     if (!arg || !*arg)
    66         return -1;
    67     res = strtoul(arg, &ptr, base);
    68     if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
    69         return -1;
    70     *val = res;
    71     return 0;
    72 }
    73 
    74 int get_u8(uint8_t * val, char *arg, int base)
    75 {
    76     unsigned long res;
    77     char *ptr;
    78 
    79     if (!arg || !*arg)
    80         return -1;
    81     res = strtoul(arg, &ptr, base);
    82     if (!ptr || ptr == arg || *ptr || res > 0xFF)
    83         return -1;
    84     *val = res;
    85     return 0;
    86 }
    87 
    88 int get_s16(int16_t * val, char *arg, int base)
    89 {
    90     long res;
    91     char *ptr;
    92 
    93     if (!arg || !*arg)
    94         return -1;
    95     res = strtol(arg, &ptr, base);
    96     if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
    97         return -1;
    98     *val = res;
    99     return 0;
    100 }
    101 
    102 int get_s8(int8_t * val, char *arg, int base)
    103 {
    104     long res;
    105     char *ptr;
    106 
    107     if (!arg || !*arg)
    108         return -1;
    109     res = strtol(arg, &ptr, base);
    110     if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
    111         return -1;
    112     *val = res;
    113     return 0;
    114 }
    115 
    116 int get_addr_1(inet_prefix * addr, char *name, int family)
    117 {
    118     char *cp;
    119     unsigned char *ap = (unsigned char *) addr->data;
    120     int i;
    121 
     51    if (*arg) {
     52        res = strtoul(arg, &ptr, 0);
     53//FIXME: "" will be accepted too, is it correct?!
     54        if (!*ptr && res <= 0xFFFF) {
     55            return res;
     56        }
     57    }
     58    invarg(arg, errmsg); /* does not return */
     59}
     60
     61int get_addr_1(inet_prefix *addr, char *name, int family)
     62{
    12263    memset(addr, 0, sizeof(*addr));
    12364
    124     if (strcmp(name, bb_str_default) == 0 ||
    125         strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
     65    if (strcmp(name, "default") == 0
     66     || strcmp(name, "all") == 0
     67     || strcmp(name, "any") == 0
     68    ) {
    12669        addr->family = family;
    12770        addr->bytelen = (family == AF_INET6 ? 16 : 4);
     
    14487    if (family != AF_UNSPEC && family != AF_INET)
    14588        return -1;
     89    if (inet_pton(AF_INET, name, addr->data) <= 0)
     90        return -1;
    14691    addr->bytelen = 4;
    14792    addr->bitlen = -1;
    148     for (cp = name, i = 0; *cp; cp++) {
    149         if (*cp <= '9' && *cp >= '0') {
    150             ap[i] = 10 * ap[i] + (*cp - '0');
    151             continue;
    152         }
    153         if (*cp == '.' && ++i <= 3)
    154             continue;
    155         return -1;
    156     }
    157     return 0;
    158 }
    159 
    160 int get_prefix_1(inet_prefix * dst, char *arg, int family)
     93    return 0;
     94}
     95
     96static int get_prefix_1(inet_prefix *dst, char *arg, int family)
    16197{
    16298    int err;
    163     int plen;
     99    unsigned plen;
    164100    char *slash;
    165101
    166102    memset(dst, 0, sizeof(*dst));
    167103
    168     if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) {
     104    if (strcmp(arg, "default") == 0
     105     || strcmp(arg, "all") == 0
     106     || strcmp(arg, "any") == 0
     107    ) {
    169108        dst->family = family;
    170         dst->bytelen = 0;
    171         dst->bitlen = 0;
     109        /*dst->bytelen = 0; - done by memset */
     110        /*dst->bitlen = 0;*/
    172111        return 0;
    173112    }
     
    178117    err = get_addr_1(dst, arg, family);
    179118    if (err == 0) {
    180         switch (dst->family) {
    181         case AF_INET6:
    182             dst->bitlen = 128;
    183             break;
    184         default:
    185         case AF_INET:
    186             dst->bitlen = 32;
    187         }
     119        dst->bitlen = (dst->family == AF_INET6) ? 128 : 32;
    188120        if (slash) {
    189             if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) {
     121            inet_prefix netmask_pfx;
     122
     123            netmask_pfx.family = AF_UNSPEC;
     124            plen = bb_strtou(slash + 1, NULL, 0);
     125            if ((errno || plen > dst->bitlen)
     126             && (get_addr_1(&netmask_pfx, slash + 1, family)))
    190127                err = -1;
    191                 goto done;
     128            else if (netmask_pfx.family == AF_INET) {
     129                /* fill in prefix length of dotted quad */
     130                uint32_t mask = ntohl(netmask_pfx.data[0]);
     131                uint32_t host = ~mask;
     132
     133                /* a valid netmask must be 2^n - 1 */
     134                if (!(host & (host + 1))) {
     135                    for (plen = 0; mask; mask <<= 1)
     136                        ++plen;
     137                    if (plen <= dst->bitlen) {
     138                        dst->bitlen = plen;
     139                        /* dst->flags |= PREFIXLEN_SPECIFIED; */
     140                    } else
     141                        err = -1;
     142                } else
     143                    err = -1;
     144            } else {
     145                /* plain prefix */
     146                dst->bitlen = plen;
    192147            }
    193             dst->bitlen = plen;
    194         }
    195     }
    196  done:
     148        }
     149    }
    197150    if (slash)
    198151        *slash = '/';
     
    200153}
    201154
    202 int get_addr(inet_prefix * dst, char *arg, int family)
     155int get_addr(inet_prefix *dst, char *arg, int family)
    203156{
    204157    if (family == AF_PACKET) {
    205         bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg);
     158        bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address");
    206159    }
    207160    if (get_addr_1(dst, arg, family)) {
    208         bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg);
    209     }
    210     return 0;
    211 }
    212 
    213 int get_prefix(inet_prefix * dst, char *arg, int family)
     161        bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg);
     162    }
     163    return 0;
     164}
     165
     166int get_prefix(inet_prefix *dst, char *arg, int family)
    214167{
    215168    if (family == AF_PACKET) {
    216         bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg);
     169        bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix");
    217170    }
    218171    if (get_prefix_1(dst, arg, family)) {
    219         bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg);
     172        bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg);
    220173    }
    221174    return 0;
     
    227180
    228181    if (get_addr_1(&addr, name, AF_INET)) {
    229         bb_error_msg_and_die("an IP address is expected rather than \"%s\"", name);
     182        bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name);
    230183    }
    231184    return addr.data[0];
     
    252205}
    253206
    254 int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
     207int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits)
    255208{
    256209    uint32_t *a1 = a->data;
    257210    uint32_t *a2 = b->data;
    258     int words = bits >> 0x05;
     211    int words = bits >> 5;
    259212
    260213    bits &= 0x1f;
     
    280233}
    281234
    282 const char *rt_addr_n2a(int af, int ATTRIBUTE_UNUSED len,
     235const char *rt_addr_n2a(int af,
    283236        void *addr, char *buf, int buflen)
    284237{
     
    292245}
    293246
    294 
     247#ifdef RESOLVE_HOSTNAMES
    295248const char *format_host(int af, int len, void *addr, char *buf, int buflen)
    296249{
    297 #ifdef RESOLVE_HOSTNAMES
    298250    if (resolve_hosts) {
    299251        struct hostent *h_ent;
     
    318270        }
    319271    }
     272    return rt_addr_n2a(af, addr, buf, buflen);
     273}
    320274#endif
    321     return rt_addr_n2a(af, len, addr, buf, buflen);
    322 }
  • branches/2.2.9/mindi-busybox/networking/libiproute/utils.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 #ifndef __UTILS_H__
    3 #define __UTILS_H__ 1
     2#ifndef UTILS_H
     3#define UTILS_H 1
    44
    55#include "libnetlink.h"
     
    77#include "rtm_map.h"
    88
    9 extern int preferred_family;
     9PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
     10
     11extern family_t preferred_family;
    1012extern smallint show_stats;    /* UNUSED */
    1113extern smallint show_details;  /* UNUSED */
     
    1618
    1719#ifndef IPPROTO_ESP
    18 #define IPPROTO_ESP 50
     20#define IPPROTO_ESP  50
    1921#endif
    2022#ifndef IPPROTO_AH
    21 #define IPPROTO_AH  51
     23#define IPPROTO_AH  51
    2224#endif
    2325
    2426#define SPRINT_BSIZE 64
    25 #define SPRINT_BUF(x)   char x[SPRINT_BSIZE]
     27#define SPRINT_BUF(x)  char x[SPRINT_BSIZE]
    2628
    27 extern void incomplete_command(void) ATTRIBUTE_NORETURN;
     29extern void incomplete_command(void) NORETURN;
    2830
    29 #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while (0)
     31#define NEXT_ARG() do { if (!*++argv) incomplete_command(); } while (0)
    3032
    31 typedef struct
    32 {
     33typedef struct {
    3334    uint8_t family;
    3435    uint8_t bytelen;
     
    3637    uint32_t data[4];
    3738} inet_prefix;
     39
     40#define PREFIXLEN_SPECIFIED 1
    3841
    3942#define DN_MAXADDL 20
     
    4346
    4447struct dn_naddr {
    45     unsigned short          a_len;
    46     unsigned char a_addr[DN_MAXADDL];
     48    unsigned short a_len;
     49    unsigned char  a_addr[DN_MAXADDL];
    4750};
    4851
     
    5659extern uint32_t get_addr32(char *name);
    5760extern int get_addr_1(inet_prefix *dst, char *arg, int family);
    58 extern int get_prefix_1(inet_prefix *dst, char *arg, int family);
     61/*extern int get_prefix_1(inet_prefix *dst, char *arg, int family);*/
    5962extern int get_addr(inet_prefix *dst, char *arg, int family);
    6063extern int get_prefix(inet_prefix *dst, char *arg, int family);
    6164
    62 extern int get_integer(int *val, char *arg, int base);
    63 extern int get_unsigned(unsigned *val, char *arg, int base);
    64 #define get_byte get_u8
    65 #define get_ushort get_u16
    66 #define get_short get_s16
    67 extern int get_u32(uint32_t *val, char *arg, int base);
    68 extern int get_u16(uint16_t *val, char *arg, int base);
    69 extern int get_s16(int16_t *val, char *arg, int base);
    70 extern int get_u8(uint8_t *val, char *arg, int base);
    71 extern int get_s8(int8_t *val, char *arg, int base);
     65extern unsigned get_unsigned(char *arg, const char *errmsg);
     66extern uint32_t get_u32(char *arg, const char *errmsg);
     67extern uint16_t get_u16(char *arg, const char *errmsg);
    7268
     69extern const char *rt_addr_n2a(int af, void *addr, char *buf, int buflen);
     70#ifdef RESOLVE_HOSTNAMES
    7371extern const char *format_host(int af, int len, void *addr, char *buf, int buflen);
    74 extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen);
     72#else
     73#define format_host(af, len, addr, buf, buflen) \
     74    rt_addr_n2a(af, addr, buf, buflen)
     75#endif
    7576
    76 void invarg(const char *, const char *) ATTRIBUTE_NORETURN;
    77 void duparg(const char *, const char *) ATTRIBUTE_NORETURN;
    78 void duparg2(const char *, const char *) ATTRIBUTE_NORETURN;
     77void invarg(const char *, const char *) NORETURN;
     78void duparg(const char *, const char *) NORETURN;
     79void duparg2(const char *, const char *) NORETURN;
    7980int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits);
    8081
     
    8586int ipx_pton(int af, const char *src, void *addr);
    8687
    87 #endif /* __UTILS_H__ */
     88POP_SAVED_FUNCTION_VISIBILITY
     89
     90#endif
  • branches/2.2.9/mindi-busybox/networking/nameif.c

    r1765 r2725  
    55 * Written 2000 by Andi Kleen.
    66 * Busybox port 2002 by Nick Fedchik <nick@fedchik.org.ua>
    7  *          Glenn McGrath <bug1@iinet.net.au>
     7 *          Glenn McGrath
     8 * Extended matching support 2008 by Nico Erfurth <masta@perlgolf.de>
    89 *
    9  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1011 */
    1112
     
    1415#include <net/if.h>
    1516#include <netinet/ether.h>
    16 
    17 
    18 /* Older versions of net/if.h do not appear to define IF_NAMESIZE. */
    19 #ifndef IF_NAMESIZE
    20 #  ifdef IFNAMSIZ
    21 #    define IF_NAMESIZE IFNAMSIZ
    22 #  else
    23 #    define IF_NAMESIZE 16
    24 #  endif
    25 #endif
    26 
    27 /* take from linux/sockios.h */
    28 #define SIOCSIFNAME 0x8923  /* set interface name */
     17#include <linux/sockios.h>
     18
     19#ifndef IFNAMSIZ
     20#define IFNAMSIZ 16
     21#endif
     22
     23/* Taken from linux/sockios.h */
     24#define SIOCSIFNAME  0x8923  /* set interface name */
    2925
    3026/* Octets in one Ethernet addr, from <linux/if_ether.h> */
    31 #define ETH_ALEN    6
     27#define ETH_ALEN     6
    3228
    3329#ifndef ifr_newname
     
    3531#endif
    3632
    37 typedef struct mactable_s {
    38     struct mactable_s *next;
    39     struct mactable_s *prev;
     33typedef struct ethtable_s {
     34    struct ethtable_s *next;
     35    struct ethtable_s *prev;
    4036    char *ifname;
    4137    struct ether_addr *mac;
    42 } mactable_t;
    43 
    44 /* Check ascii str_macaddr, convert and copy to *mac */
    45 static struct ether_addr *cc_macaddr(const char *str_macaddr)
    46 {
    47     struct ether_addr *lmac, *mac;
    48 
    49     lmac = ether_aton(str_macaddr);
    50     if (lmac == NULL)
    51         bb_error_msg_and_die("cannot parse MAC %s", str_macaddr);
    52     mac = xmalloc(ETH_ALEN);
    53     memcpy(mac, lmac, ETH_ALEN);
    54 
    55     return mac;
     38#if ENABLE_FEATURE_NAMEIF_EXTENDED
     39    char *bus_info;
     40    char *driver;
     41#endif
     42} ethtable_t;
     43
     44#if ENABLE_FEATURE_NAMEIF_EXTENDED
     45/* Cut'n'paste from ethtool.h */
     46#define ETHTOOL_BUSINFO_LEN 32
     47/* these strings are set to whatever the driver author decides... */
     48struct ethtool_drvinfo {
     49    uint32_t cmd;
     50    char  driver[32]; /* driver short name, "tulip", "eepro100" */
     51    char  version[32];  /* driver version string */
     52    char  fw_version[32]; /* firmware version string, if applicable */
     53    char  bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
     54    /* For PCI devices, use pci_dev->slot_name. */
     55    char  reserved1[32];
     56    char  reserved2[16];
     57    uint32_t n_stats;  /* number of u64's from ETHTOOL_GSTATS */
     58    uint32_t testinfo_len;
     59    uint32_t eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
     60    uint32_t regdump_len;  /* Size of data from ETHTOOL_GREGS (bytes) */
     61};
     62#define ETHTOOL_GDRVINFO  0x00000003 /* Get driver info. */
     63#endif
     64
     65
     66static void nameif_parse_selector(ethtable_t *ch, char *selector)
     67{
     68    struct ether_addr *lmac;
     69#if ENABLE_FEATURE_NAMEIF_EXTENDED
     70    int found_selector = 0;
     71
     72    while (*selector) {
     73        char *next;
     74#endif
     75        selector = skip_whitespace(selector);
     76#if ENABLE_FEATURE_NAMEIF_EXTENDED
     77        if (*selector == '\0')
     78            break;
     79        /* Search for the end .... */
     80        next = skip_non_whitespace(selector);
     81        if (*next)
     82            *next++ = '\0';
     83        /* Check for selectors, mac= is assumed */
     84        if (strncmp(selector, "bus=", 4) == 0) {
     85            ch->bus_info = xstrdup(selector + 4);
     86            found_selector++;
     87        } else if (strncmp(selector, "driver=", 7) == 0) {
     88            ch->driver = xstrdup(selector + 7);
     89            found_selector++;
     90        } else {
     91#endif
     92            lmac = xmalloc(ETH_ALEN);
     93            ch->mac = ether_aton_r(selector + (strncmp(selector, "mac=", 4) != 0 ? 0 : 4), lmac);
     94            if (ch->mac == NULL)
     95                bb_error_msg_and_die("can't parse %s", selector);
     96#if  ENABLE_FEATURE_NAMEIF_EXTENDED
     97            found_selector++;
     98        };
     99        selector = next;
     100    }
     101    if (found_selector == 0)
     102        bb_error_msg_and_die("no selectors found for %s", ch->ifname);
     103#endif
    56104}
    57105
    58 int nameif_main(int argc, char **argv);
     106static void prepend_new_eth_table(ethtable_t **clist, char *ifname, char *selector)
     107{
     108    ethtable_t *ch;
     109    if (strlen(ifname) >= IFNAMSIZ)
     110        bb_error_msg_and_die("interface name '%s' too long", ifname);
     111    ch = xzalloc(sizeof(*ch));
     112    ch->ifname = xstrdup(ifname);
     113    nameif_parse_selector(ch, selector);
     114    ch->next = *clist;
     115    if (*clist)
     116        (*clist)->prev = ch;
     117    *clist = ch;
     118}
     119
     120#if ENABLE_FEATURE_CLEAN_UP
     121static void delete_eth_table(ethtable_t *ch)
     122{
     123    free(ch->ifname);
     124#if ENABLE_FEATURE_NAMEIF_EXTENDED
     125    free(ch->bus_info);
     126    free(ch->driver);
     127#endif
     128    free(ch->mac);
     129    free(ch);
     130};
     131#else
     132void delete_eth_table(ethtable_t *ch);
     133#endif
     134
     135int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    59136int nameif_main(int argc, char **argv)
    60137{
    61     mactable_t *clist = NULL;
    62     FILE *ifh;
     138    ethtable_t *clist = NULL;
    63139    const char *fname = "/etc/mactab";
    64     char *line;
    65140    int ctl_sk;
    66     int if_index = 1;
    67     mactable_t *ch;
     141    ethtable_t *ch;
     142    parser_t *parser;
     143    char *token[2];
    68144
    69145    if (1 & getopt32(argv, "sc:", &fname)) {
    70146        openlog(applet_name, 0, LOG_LOCAL0);
    71         logmode = LOGMODE_SYSLOG;
    72     }
    73 
    74     if ((argc - optind) & 1)
     147        /* Why not just "="? I assume logging to stderr
     148         * can't hurt. 2>/dev/null if you don't like it: */
     149        logmode |= LOGMODE_SYSLOG;
     150    }
     151    argc -= optind;
     152    argv += optind;
     153
     154    if (argc & 1)
    75155        bb_show_usage();
    76156
    77     if (optind < argc) {
    78         char **a = argv + optind;
    79 
    80         while (*a) {
    81             if (strlen(*a) > IF_NAMESIZE)
    82                 bb_error_msg_and_die("interface name '%s' "
    83                         "too long", *a);
    84             ch = xzalloc(sizeof(mactable_t));
    85             ch->ifname = xstrdup(*a++);
    86             ch->mac = cc_macaddr(*a++);
    87             if (clist)
    88                 clist->prev = ch;
    89             ch->next = clist;
    90             clist = ch;
     157    if (argc) {
     158        while (*argv) {
     159            char *ifname = xstrdup(*argv++);
     160            prepend_new_eth_table(&clist, ifname, *argv++);
    91161        }
    92162    } else {
    93         ifh = xfopen(fname, "r");
    94 
    95         while ((line = xmalloc_fgets(ifh)) != NULL) {
    96             char *line_ptr;
    97             size_t name_length;
    98 
    99             line_ptr = line + strspn(line, " \t");
    100             if ((line_ptr[0] == '#') || (line_ptr[0] == '\n')) {
    101                 free(line);
     163        parser = config_open(fname);
     164        while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL))
     165            prepend_new_eth_table(&clist, token[0], token[1]);
     166        config_close(parser);
     167    }
     168
     169    ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0);
     170    parser = config_open2("/proc/net/dev", xfopen_for_read);
     171
     172    while (clist && config_read(parser, token, 2, 2, "\0: \t", PARSE_NORMAL)) {
     173        struct ifreq ifr;
     174#if  ENABLE_FEATURE_NAMEIF_EXTENDED
     175        struct ethtool_drvinfo drvinfo;
     176#endif
     177        if (parser->lineno < 2)
     178            continue; /* Skip the first two lines */
     179
     180        /* Find the current interface name and copy it to ifr.ifr_name */
     181        memset(&ifr, 0, sizeof(struct ifreq));
     182        strncpy_IFNAMSIZ(ifr.ifr_name, token[0]);
     183
     184#if ENABLE_FEATURE_NAMEIF_EXTENDED
     185        /* Check for driver etc. */
     186        memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo));
     187        drvinfo.cmd = ETHTOOL_GDRVINFO;
     188        ifr.ifr_data = (caddr_t) &drvinfo;
     189        /* Get driver and businfo first, so we have it in drvinfo */
     190        ioctl(ctl_sk, SIOCETHTOOL, &ifr);
     191#endif
     192        ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
     193
     194        /* Search the list for a matching device */
     195        for (ch = clist; ch; ch = ch->next) {
     196#if ENABLE_FEATURE_NAMEIF_EXTENDED
     197            if (ch->bus_info && strcmp(ch->bus_info, drvinfo.bus_info) != 0)
    102198                continue;
    103             }
    104             name_length = strcspn(line_ptr, " \t");
    105             ch = xzalloc(sizeof(mactable_t));
    106             ch->ifname = xstrndup(line_ptr, name_length);
    107             if (name_length > IF_NAMESIZE)
    108                 bb_error_msg_and_die("interface name '%s' "
    109                         "too long", ch->ifname);
    110             line_ptr += name_length;
    111             line_ptr += strspn(line_ptr, " \t");
    112             name_length = strspn(line_ptr, "0123456789ABCDEFabcdef:");
    113             line_ptr[name_length] = '\0';
    114             ch->mac = cc_macaddr(line_ptr);
    115             if (clist)
    116                 clist->prev = ch;
    117             ch->next = clist;
    118             clist = ch;
    119             free(line);
     199            if (ch->driver && strcmp(ch->driver, drvinfo.driver) != 0)
     200                continue;
     201#endif
     202            if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0)
     203                continue;
     204            /* if we came here, all selectors have matched */
     205            break;
    120206        }
    121         fclose(ifh);
    122     }
    123 
    124     ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0);
    125 
    126     while (clist) {
    127         struct ifreq ifr;
    128 
    129         memset(&ifr, 0, sizeof(struct ifreq));
    130         if_index++;
    131         ifr.ifr_ifindex = if_index;
    132 
    133         /* Get ifname by index or die */
    134         if (ioctl(ctl_sk, SIOCGIFNAME, &ifr))
    135             break;
    136 
    137         /* Has this device hwaddr? */
    138         if (ioctl(ctl_sk, SIOCGIFHWADDR, &ifr))
     207        /* Nothing found for current interface */
     208        if (!ch)
    139209            continue;
    140210
    141         /* Search for mac like in ifr.ifr_hwaddr.sa_data */
     211        if (strcmp(ifr.ifr_name, ch->ifname) != 0) {
     212            strcpy(ifr.ifr_newname, ch->ifname);
     213            ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr,
     214                    "can't change ifname %s to %s",
     215                    ifr.ifr_name, ch->ifname);
     216        }
     217        /* Remove list entry of renamed interface */
     218        if (ch->prev != NULL)
     219            ch->prev->next = ch->next;
     220        else
     221            clist = ch->next;
     222        if (ch->next != NULL)
     223            ch->next->prev = ch->prev;
     224        if (ENABLE_FEATURE_CLEAN_UP)
     225            delete_eth_table(ch);
     226    }
     227    if (ENABLE_FEATURE_CLEAN_UP) {
    142228        for (ch = clist; ch; ch = ch->next)
    143             if (!memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN))
    144                 break;
    145 
    146         /* Nothing found for current ifr.ifr_hwaddr.sa_data */
    147         if (ch == NULL)
    148             continue;
    149 
    150         strcpy(ifr.ifr_newname, 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);
    154 
    155         /* Remove list entry of renamed interface */
    156         if (ch->prev != NULL) {
    157             (ch->prev)->next = ch->next;
    158         } else {
    159             clist = ch->next;
    160         }
    161         if (ch->next != NULL)
    162             (ch->next)->prev = ch->prev;
    163         if (ENABLE_FEATURE_CLEAN_UP) {
    164             free(ch->ifname);
    165             free(ch->mac);
    166             free(ch);
    167         }
    168     }
     229            delete_eth_table(ch);
     230        config_close(parser);
     231    };
    169232
    170233    return 0;
  • branches/2.2.9/mindi-busybox/networking/nc.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /*  nc: mini-netcat - built from the ground up for LRP
     2/* nc: mini-netcat - built from the ground up for LRP
    33 *
    4  *  Copyright (C) 1998, 1999  Charles P. Wright
    5  *  Copyright (C) 1998  Dave Cinege
     4 * Copyright (C) 1998, 1999  Charles P. Wright
     5 * Copyright (C) 1998  Dave Cinege
    66 *
    7  *  Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    1111
    12 #if ENABLE_DESKTOP
    13 #include "nc_bloaty.c"
     12//config:config NC
     13//config:   bool "nc"
     14//config:   default y
     15//config:   help
     16//config:     A simple Unix utility which reads and writes data across network
     17//config:     connections.
     18//config:
     19//config:config NC_SERVER
     20//config:   bool "Netcat server options (-l)"
     21//config:   default y
     22//config:   depends on NC
     23//config:   help
     24//config:     Allow netcat to act as a server.
     25//config:
     26//config:config NC_EXTRA
     27//config:   bool "Netcat extensions (-eiw and filename)"
     28//config:   default y
     29//config:   depends on NC
     30//config:   help
     31//config:     Add -e (support for executing the rest of the command line after
     32//config:     making or receiving a successful connection), -i (delay interval for
     33//config:     lines sent), -w (timeout for initial connection).
     34//config:
     35//config:config NC_110_COMPAT
     36//config:   bool "Netcat 1.10 compatibility (+2.5k)"
     37//config:   default n  # off specially for Rob
     38//config:   depends on NC
     39//config:   help
     40//config:     This option makes nc closely follow original nc-1.10.
     41//config:     The code is about 2.5k bigger. It enables
     42//config:     -s ADDR, -n, -u, -v, -o FILE, -z options, but loses
     43//config:     busybox-specific extensions: -f FILE and -ll.
     44
     45#if ENABLE_NC_110_COMPAT
     46# include "nc_bloaty.c"
    1447#else
     48
     49//usage:#if !ENABLE_NC_110_COMPAT
     50//usage:
     51//usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
     52//usage:#define NC_OPTIONS_STR "\n\nOptions:"
     53//usage:#else
     54//usage:#define NC_OPTIONS_STR
     55//usage:#endif
     56//usage:
     57//usage:#define nc_trivial_usage
     58//usage:    IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ")
     59//usage:       "["IF_NC_EXTRA("-f FILE|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]")
     60//usage:#define nc_full_usage "\n\n"
     61//usage:       "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE")
     62//usage:    NC_OPTIONS_STR
     63//usage:    IF_NC_EXTRA(
     64//usage:     "\n    -e PROG Run PROG after connect"
     65//usage:    IF_NC_SERVER(
     66//usage:     "\n    -l  Listen mode, for inbound connects"
     67//usage:    IF_NC_EXTRA(
     68//usage:     "\n        (use -l twice with -e for persistent server)")
     69//usage:     "\n    -p PORT Local port"
     70//usage:    )
     71//usage:     "\n    -w SEC  Timeout for connect"
     72//usage:     "\n    -i SEC  Delay interval for lines sent"
     73//usage:     "\n    -f FILE Use file (ala /dev/ttyS0) instead of network"
     74//usage:    )
     75//usage:
     76//usage:#define nc_notes_usage ""
     77//usage:    IF_NC_EXTRA(
     78//usage:       "To use netcat as a terminal emulator on a serial port:\n\n"
     79//usage:       "$ stty 115200 -F /dev/ttyS0\n"
     80//usage:       "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n"
     81//usage:    )
     82//usage:
     83//usage:#define nc_example_usage
     84//usage:       "$ nc foobar.somedomain.com 25\n"
     85//usage:       "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n"
     86//usage:       "help\n"
     87//usage:       "214-Commands supported:\n"
     88//usage:       "214-    HELO EHLO MAIL RCPT DATA AUTH\n"
     89//usage:       "214     NOOP QUIT RSET HELP\n"
     90//usage:       "quit\n"
     91//usage:       "221 foobar closing connection\n"
     92//usage:
     93//usage:#endif
    1594
    1695/* Lots of small differences in features
     
    1897 */
    1998
    20 static void timeout(int signum)
     99static void timeout(int signum UNUSED_PARAM)
    21100{
    22101    bb_error_msg_and_die("timed out");
    23102}
    24103
    25 int nc_main(int argc, char **argv);
     104int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    26105int nc_main(int argc, char **argv)
    27106{
     
    30109    int cfd = 0;
    31110    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;
     111    IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
     112    IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
     113    IF_NOT_NC_EXTRA (const) unsigned delay = 0;
     114    IF_NOT_NC_EXTRA (const int execparam = 0;)
     115    IF_NC_EXTRA     (char **execparam = NULL;)
    38116    fd_set readfds, testfds;
    39117    int opt; /* must be signed (getopt returns -1) */
     
    41119    if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
    42120        /* getopt32 is _almost_ usable:
    43         ** it cannot handle "... -e prog -prog-opt" */
     121        ** it cannot handle "... -e PROG -prog-opt" */
    44122        while ((opt = getopt(argc, argv,
    45                 "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0
     123                "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0
    46124        ) {
    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) {
     125            if (ENABLE_NC_SERVER && opt == 'l')
     126                IF_NC_SERVER(do_listen++);
     127            else if (ENABLE_NC_SERVER && opt == 'p')
     128                IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
     129            else if (ENABLE_NC_EXTRA && opt == 'w')
     130                IF_NC_EXTRA( wsecs = xatou(optarg));
     131            else if (ENABLE_NC_EXTRA && opt == 'i')
     132                IF_NC_EXTRA( delay = xatou(optarg));
     133            else if (ENABLE_NC_EXTRA && opt == 'f')
     134                IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
     135            else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) {
    55136                /* We cannot just 'break'. We should let getopt finish.
    56137                ** Or else we won't be able to find where
    57138                ** 'host' and 'port' params are
    58                 ** (think "nc -w 60 host port -e prog"). */
    59                 USE_NC_EXTRA(
     139                ** (think "nc -w 60 host port -e PROG"). */
     140                IF_NC_EXTRA(
    60141                    char **p;
    61142                    // +2: one for progname (optarg) and one for NULL
     
    69150                /* optind points to argv[arvc] (NULL) now.
    70151                ** FIXME: we assume that getopt will not count options
    71                 ** possibly present on "-e prog args" and will not
     152                ** possibly present on "-e PROG ARGS" and will not
    72153                ** include them into final value of optind
    73154                ** which is to be used ...  */
     
    78159        // -l and -f don't mix
    79160        if (do_listen && cfd) bb_show_usage();
    80         // Listen or file modes need zero arguments, client mode needs 2
    81         if (do_listen || cfd) {
     161        // File mode needs need zero arguments, listen mode needs zero or one,
     162        // client mode needs one or two
     163        if (cfd) {
    82164            if (argc) bb_show_usage();
     165        } else if (do_listen) {
     166            if (argc > 1) bb_show_usage();
    83167        } else {
    84168            if (!argc || argc > 2) bb_show_usage();
     
    97181    if (!cfd) {
    98182        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);
     183            sfd = create_and_bind_stream_or_die(argv[0], lport);
    107184            xlisten(sfd, do_listen); /* can be > 1 */
     185#if 0  /* nc-1.10 does not do this (without -v) */
    108186            /* If we didn't specify a port number,
    109187             * query and print it after listen() */
    110188            if (!lport) {
    111                 socklen_t addrlen = lsa->len;
    112                 getsockname(sfd, &lsa->sa, &addrlen);
    113                 lport = get_nport(&lsa->sa);
     189                len_and_sockaddr lsa;
     190                lsa.len = LSA_SIZEOF_SA;
     191                getsockname(sfd, &lsa.u.sa, &lsa.len);
     192                lport = get_nport(&lsa.u.sa);
    114193                fdprintf(2, "%d\n", ntohs(lport));
    115194            }
    116             fcntl(sfd, F_SETFD, FD_CLOEXEC);
     195#endif
     196            close_on_exec_on(sfd);
    117197 accept_again:
    118198            cfd = accept(sfd, NULL, 0);
     
    129209    if (wsecs) {
    130210        alarm(0);
    131         signal(SIGALRM, SIG_DFL);
     211        /* Non-ignored signals revert to SIG_DFL on exec anyway */
     212        /*signal(SIGALRM, SIG_DFL);*/
    132213    }
    133214
    134215    /* -e given? */
    135216    if (execparam) {
    136         signal(SIGCHLD, SIG_IGN);
    137         // With more than one -l, repeatedly act as server.
    138         if (do_listen > 1 && vfork()) {
     217        pid_t pid;
     218        /* With more than one -l, repeatedly act as server */
     219        if (do_listen > 1 && (pid = xvfork()) != 0) {
    139220            /* 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);
     221            /* prevent zombies */
     222            signal(SIGCHLD, SIG_IGN);
     223            close(cfd);
    147224            goto accept_again;
    148225        }
    149         /* child (or main thread if no multiple -l) */
    150         if (cfd) {
    151             dup2(cfd, 0);
    152             close(cfd);
    153         }
    154         dup2(0, 1);
    155         dup2(0, 2);
    156         USE_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
    157         /* Don't print stuff or it will go over the wire.... */
     226        /* child, or main thread if only one -l */
     227        xmove_fd(cfd, 0);
     228        xdup2(0, 1);
     229        xdup2(0, 2);
     230        IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
     231        /* Don't print stuff or it will go over the wire... */
    158232        _exit(127);
    159233    }
    160234
    161     // Select loop copying stdin to cfd, and cfd to stdout.
     235    /* Select loop copying stdin to cfd, and cfd to stdout */
    162236
    163237    FD_ZERO(&readfds);
     
    172246        testfds = readfds;
    173247
    174         if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
     248        if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0)
    175249            bb_perror_msg_and_die("select");
    176250
    177251#define iobuf bb_common_bufsiz1
    178         for (fd = 0; fd < FD_SETSIZE; fd++) {
     252        fd = STDIN_FILENO;
     253        while (1) {
    179254            if (FD_ISSET(fd, &testfds)) {
    180255                nread = safe_read(fd, iobuf, sizeof(iobuf));
    181256                if (fd == cfd) {
    182257                    if (nread < 1)
    183                         exit(0);
     258                        exit(EXIT_SUCCESS);
    184259                    ofd = STDOUT_FILENO;
    185260                } else {
    186                     if (nread<1) {
    187                         // Close outgoing half-connection so they get EOF, but
    188                         // leave incoming alone so we can see response.
     261                    if (nread < 1) {
     262                        /* Close outgoing half-connection so they get EOF,
     263                         * but leave incoming alone so we can see response */
    189264                        shutdown(cfd, 1);
    190265                        FD_CLR(STDIN_FILENO, &readfds);
     
    193268                }
    194269                xwrite(ofd, iobuf, nread);
    195                 if (delay > 0) sleep(delay);
     270                if (delay > 0)
     271                    sleep(delay);
    196272            }
     273            if (fd == cfd)
     274                break;
     275            fd = cfd;
    197276        }
    198277    }
  • branches/2.2.9/mindi-busybox/networking/nc_bloaty.c

    r1765 r2725  
    22 * Released into public domain by the author.
    33 *
    4  * Copyright (C) 2007 Denis Vlasenko.
     4 * Copyright (C) 2007 Denys Vlasenko.
    55 *
    6  * Licensed under GPLv2, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2, see file LICENSE in this source tree.
    77 */
    88
     
    3737 * - multiple DNS checks
    3838 * Functionalty which is different from nc 1.10:
    39  * - Prog in '-e prog' can have prog's parameters and options.
     39 * - PROG in '-e PROG' can have ARGS (and options).
    4040 *   Because of this -e option must be last.
    41  * - nc doesn't redirect stderr to the network socket for the -e prog.
     41//TODO: remove -e incompatibility?
     42 * - we don't redirect stderr to the network socket for the -e PROG.
     43 *   (PROG can do it itself if needed, but sometimes it is NOT wanted!)
    4244 * - numeric addresses are printed in (), not [] (IPv6 looks better),
    4345 *   port numbers are inside (): (1.2.3.4:5678)
     
    4648 * - TCP connects from wrong ip/ports (if peer ip:port is specified
    4749 *   on the command line, but accept() says that it came from different addr)
    48  *   are closed, but nc doesn't exit - continues to listen/accept.
     50 *   are closed, but we don't exit - we continue to listen/accept.
    4951 */
    5052
    5153/* done in nc.c: #include "libbb.h" */
     54
     55//usage:#if ENABLE_NC_110_COMPAT
     56//usage:
     57//usage:#define nc_trivial_usage
     58//usage:       "[OPTIONS] HOST PORT  - connect"
     59//usage:    IF_NC_SERVER("\n"
     60//usage:       "nc [OPTIONS] -l -p PORT [HOST] [PORT]  - listen"
     61//usage:    )
     62//usage:#define nc_full_usage "\n\n"
     63//usage:       "Options:"
     64//usage:     "\n    -e PROG Run PROG after connect (must be last)"
     65//usage:    IF_NC_SERVER(
     66//usage:     "\n    -l  Listen mode, for inbound connects"
     67//usage:    )
     68//usage:     "\n    -p PORT Local port"
     69//usage:     "\n    -s ADDR Local address"
     70//usage:     "\n    -w SEC  Timeout for connects and final net reads"
     71//usage:    IF_NC_EXTRA(
     72//usage:     "\n    -i SEC  Delay interval for lines sent" /* ", ports scanned" */
     73//usage:    )
     74//usage:     "\n    -n  Don't do DNS resolution"
     75//usage:     "\n    -u  UDP mode"
     76//usage:     "\n    -v  Verbose"
     77//usage:    IF_NC_EXTRA(
     78//usage:     "\n    -o FILE Hex dump traffic"
     79//usage:     "\n    -z  Zero-I/O mode (scanning)"
     80//usage:    )
     81//usage:#endif
     82
     83/*   "\n    -r      Randomize local and remote ports" */
     84/*   "\n    -g gateway  Source-routing hop point[s], up to 8" */
     85/*   "\n    -G num      Source-routing pointer: 4, 8, 12, ..." */
     86/*   "\nport numbers can be individual or ranges: lo-hi [inclusive]" */
     87
     88/* -e PROG can take ARGS too: "nc ... -e ls -l", but we don't document it
     89 * in help text: nc 1.10 does not allow that. We don't want to entice
     90 * users to use this incompatibility */
    5291
    5392enum {
     
    78117    unsigned wrote_net;          /* total net bytes */
    79118#endif
    80     /* ouraddr is never NULL and goes thru three states as we progress:
     119    /* ouraddr is never NULL and goes through three states as we progress:
    81120     1 - local address before bind (IP/port possibly zero)
    82121     2 - local address after bind (port is nonzero)
     
    98137
    99138#define G (*ptr_to_globals)
    100 
    101139#define wrote_out  (G.wrote_out )
    102140#define wrote_net  (G.wrote_net )
     
    116154#define o_interval 0
    117155#endif
     156#define INIT_G() do { \
     157    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     158} while (0)
     159
    118160
    119161/* Must match getopt32 call! */
     
    150192/* Beware: writes to stdOUT... */
    151193#if 0
    152 #define Debug(...) do { printf(__VA_ARGS__); printf("\n"); fflush(stdout); sleep(1); } while (0)
     194#define Debug(...) do { printf(__VA_ARGS__); printf("\n"); fflush_all(); sleep(1); } while (0)
    153195#else
    154196#define Debug(...) do { } while (0)
     
    164206        fprintf(stderr, SENT_N_RECV_M, wrote_net, wrote_out);
    165207    fprintf(stderr, "punt!\n");
    166     exit(1);
     208    kill_myself_with_sig(sig);
    167209}
    168210
     
    175217
    176218/* timeout and other signal handling cruft */
    177 static void tmtravel(int sig)
     219static void tmtravel(int sig UNUSED_PARAM)
    178220{
    179221    unarm();
     
    220262 Use at your own hairy risk; if you leave shells lying around behind open
    221263 listening ports you deserve to lose!! */
    222 static int doexec(char **proggie) ATTRIBUTE_NORETURN;
     264static int doexec(char **proggie) NORETURN;
    223265static int doexec(char **proggie)
    224266{
     
    228270     * exec'ed prog can do it yourself, if needed */
    229271    execvp(proggie[0], proggie);
    230     bb_perror_msg_and_die("exec");
     272    bb_perror_msg_and_die("can't execute '%s'", proggie[0]);
    231273}
    232274
     
    244286    arm(o_wait);
    245287    if (setjmp(jbuf) == 0) {
    246         rr = connect(fd, &themaddr->sa, themaddr->len);
     288        rr = connect(fd, &themaddr->u.sa, themaddr->len);
    247289        unarm();
    248290    } else { /* setjmp: connect failed... */
     
    276318    if (o_verbose) {
    277319        char *addr;
    278         rr = getsockname(netfd, &ouraddr->sa, &ouraddr->len);
    279         if (rr < 0)
    280             bb_perror_msg_and_die("getsockname after bind");
    281         addr = xmalloc_sockaddr2dotted(&ouraddr->sa);
     320        getsockname(netfd, &ouraddr->u.sa, &ouraddr->len);
     321        //if (rr < 0)
     322        //  bb_perror_msg_and_die("getsockname after bind");
     323        addr = xmalloc_sockaddr2dotted(&ouraddr->u.sa);
    282324        fprintf(stderr, "listening on %s ...\n", addr);
    283325        free(addr);
     
    307349        if (themaddr) {
    308350            remend = *themaddr;
    309             xconnect(netfd, &themaddr->sa, themaddr->len);
     351            xconnect(netfd, &themaddr->u.sa, themaddr->len);
    310352        }
    311353        /* peek first packet and remember peer addr */
     
    315357            /* and here we block... */
    316358            rr = recv_from_to(netfd, NULL, 0, MSG_PEEK, /*was bigbuf_net, BIGSIZ*/
    317                 &remend.sa, &ouraddr->sa, ouraddr->len);
     359                &remend.u.sa, &ouraddr->u.sa, ouraddr->len);
    318360            if (rr < 0)
    319361                bb_perror_msg_and_die("recvfrom");
     
    324366our socket on it, so that our outbound packets will have correct local IP.
    325367Unfortunately, bind() on already bound socket will fail now (EINVAL):
    326     xbind(netfd, &ouraddr->sa, ouraddr->len);
     368    xbind(netfd, &ouraddr->u.sa, ouraddr->len);
    327369Need to read the packet, save data, close this socket and
    328370create new one, and bind() it. TODO */
    329371        if (!themaddr)
    330             xconnect(netfd, &remend.sa, ouraddr->len);
     372            xconnect(netfd, &remend.u.sa, ouraddr->len);
    331373    } else {
    332374        /* TCP */
     
    335377 again:
    336378            remend.len = LSA_SIZEOF_SA;
    337             rr = accept(netfd, &remend.sa, &remend.len);
     379            rr = accept(netfd, &remend.u.sa, &remend.len);
    338380            if (rr < 0)
    339381                bb_perror_msg_and_die("accept");
    340             if (themaddr && memcmp(&remend.sa, &themaddr->sa, remend.len) != 0) {
    341                 /* nc 1.10 bails out instead, and its error message
    342                  * is not suppressed by o_verbose */
    343                 if (o_verbose) {
    344                     char *remaddr = xmalloc_sockaddr2dotted(&remend.sa);
    345                     bb_error_msg("connect from wrong ip/port %s ignored", remaddr);
    346                     free(remaddr);
     382            if (themaddr) {
     383                int sv_port, port, r;
     384
     385                sv_port = get_nport(&remend.u.sa); /* save */
     386                port = get_nport(&themaddr->u.sa);
     387                if (port == 0) {
     388                    /* "nc -nl -p LPORT RHOST" (w/o RPORT!):
     389                     * we should accept any remote port */
     390                    set_nport(&remend, 0); /* blot out remote port# */
    347391                }
    348                 close(rr);
    349                 goto again;
     392                r = memcmp(&remend.u.sa, &themaddr->u.sa, remend.len);
     393                set_nport(&remend, sv_port); /* restore */
     394                if (r != 0) {
     395                    /* nc 1.10 bails out instead, and its error message
     396                     * is not suppressed by o_verbose */
     397                    if (o_verbose) {
     398                        char *remaddr = xmalloc_sockaddr2dotted(&remend.u.sa);
     399                        bb_error_msg("connect from wrong ip/port %s ignored", remaddr);
     400                        free(remaddr);
     401                    }
     402                    close(rr);
     403                    goto again;
     404                }
    350405            }
    351406            unarm();
     
    357412         offer different services via different alias addresses, such as the
    358413         "virtual web site" hack. */
    359         rr = getsockname(netfd, &ouraddr->sa, &ouraddr->len);
    360         if (rr < 0)
    361             bb_perror_msg_and_die("getsockname after accept");
     414        getsockname(netfd, &ouraddr->u.sa, &ouraddr->len);
     415        //if (rr < 0)
     416        //  bb_perror_msg_and_die("getsockname after accept");
    362417    }
    363418
     
    372427     any machines I've tested, but feel free to surprise me. */
    373428        char optbuf[40];
    374         int x = sizeof(optbuf);
     429        socklen_t x = sizeof(optbuf);
    375430
    376431        rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x);
    377         if (rr < 0)
    378             bb_perror_msg("getsockopt failed");
    379         else if (x) {    /* we've got options, lessee em... */
     432        if (rr >= 0 && x) {    /* we've got options, lessee em... */
    380433            bin2hex(bigbuf_net, optbuf, x);
    381434            bigbuf_net[2*x] = '\0';
     
    394447     In other words, we need a TCP MSG_PEEK. */
    395448    /* bbox: removed most of it */
    396         lcladdr = xmalloc_sockaddr2dotted(&ouraddr->sa);
    397         remaddr = xmalloc_sockaddr2dotted(&remend.sa);
    398         remhostname = o_nflag ? remaddr : xmalloc_sockaddr2host(&remend.sa);
     449        lcladdr = xmalloc_sockaddr2dotted(&ouraddr->u.sa);
     450        remaddr = xmalloc_sockaddr2dotted(&remend.u.sa);
     451        remhostname = o_nflag ? remaddr : xmalloc_sockaddr2host(&remend.u.sa);
    399452        fprintf(stderr, "connect to %s from %s (%s)\n",
    400453                lcladdr, remhostname, remaddr);
     
    434487     us to hang forever, and hit it */
    435488        o_wait = 5;                     /* enough that we'll notice?? */
    436         rr = xsocket(ouraddr->sa.sa_family, SOCK_STREAM, 0);
     489        rr = xsocket(ouraddr->u.sa.sa_family, SOCK_STREAM, 0);
    437490        set_nport(themaddr, htons(SLEAZE_PORT));
    438491        connect_w_timeout(rr);
     
    485538            x = bc;
    486539        }
    487         sprintf(&stage[1], " %8.8x ", obc);  /* xxx: still slow? */
     540        sprintf((char *)&stage[1], " %8.8x ", obc);  /* xxx: still slow? */
    488541        bc -= x;          /* fix current count */
    489542        obc += x;         /* fix current offset */
     
    560613     from the net during that time, assume it's dead and close it too. */
    561614        if (rr == 0) {
    562             if (!FD_ISSET(0, &ding1))
     615            if (!FD_ISSET(STDIN_FILENO, &ding1))
    563616                netretry--;                        /* we actually try a coupla times. */
    564617            if (!netretry) {
     
    595648
    596649    /* okay, suck more stdin */
    597         if (FD_ISSET(0, &ding2)) {                /* stdin: ding! */
    598             rr = read(0, bigbuf_in, BIGSIZ);
     650        if (FD_ISSET(STDIN_FILENO, &ding2)) {                /* stdin: ding! */
     651            rr = read(STDIN_FILENO, bigbuf_in, BIGSIZ);
    599652    /* Considered making reads here smaller for UDP mode, but 8192-byte
    600653     mobygrams are kinda fun and exercise the reassembler. */
    601654            if (rr <= 0) {                        /* at end, or fukt, or ... */
    602                 FD_CLR(0, &ding1);                /* disable and close stdin */
    603                 close(0);
     655                FD_CLR(STDIN_FILENO, &ding1);                /* disable and close stdin */
     656                close(STDIN_FILENO);
     657// Does it make sense to shutdown(net_fd, SHUT_WR)
     658// to let other side know that we won't write anything anymore?
     659// (and what about keeping compat if we do that?)
    604660            } else {
    605661                rzleft = rr;
     
    623679        }
    624680        if (rnleft) {
    625             rr = write(1, np, rnleft);
     681            rr = write(STDOUT_FILENO, np, rnleft);
    626682            if (rr > 0) {
    627                 if (o_ofile)
    628                     oprint('<', np, rr);                /* log the stdout */
     683                if (o_ofile) /* log the stdout */
     684                    oprint('<', (unsigned char *)np, rr);
    629685                np += rr;                        /* fix up ptrs and whatnot */
    630686                rnleft -= rr;                        /* will get sanity-checked above */
     
    640696            rr = write(netfd, zp, rr);        /* one line, or the whole buffer */
    641697            if (rr > 0) {
    642                 if (o_ofile)
    643                     oprint('>', zp, rr);                /* log what got sent */
     698                if (o_ofile) /* log what got sent */
     699                    oprint('>', (unsigned char *)zp, rr);
    644700                zp += rr;
    645701                rzleft -= rr;
     
    669725
    670726/* main: now we pull it all together... */
    671 int nc_main(int argc, char **argv);
    672 int nc_main(int argc, char **argv)
    673 {
    674     char *str_p, *str_s, *str_w;
    675     USE_NC_EXTRA(char *str_i, *str_o;)
     727int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     728int nc_main(int argc UNUSED_PARAM, char **argv)
     729{
     730    char *str_p, *str_s;
     731    IF_NC_EXTRA(char *str_i, *str_o;)
    676732    char *themdotted = themdotted; /* gcc */
    677733    char **proggie;
     
    679735    unsigned o_lport = 0;
    680736
    681     /* I was in this barbershop quartet in Skokie IL ... */
    682     /* round up the usual suspects, i.e. malloc up all the stuff we need */
    683     PTR_TO_GLOBALS = xzalloc(sizeof(G));
     737    INIT_G();
    684738
    685739    /* catch a signal or two for cleanup */
    686     signal(SIGINT, catch);
    687     signal(SIGQUIT, catch);
    688     signal(SIGTERM, catch);
     740    bb_signals(0
     741        + (1 << SIGINT)
     742        + (1 << SIGQUIT)
     743        + (1 << SIGTERM)
     744        , catch);
    689745    /* and suppress others... */
     746    bb_signals(0
    690747#ifdef SIGURG
    691     signal(SIGURG, SIG_IGN);
    692 #endif
    693     signal(SIGPIPE, SIG_IGN); /* important! */
     748        + (1 << SIGURG)
     749#endif
     750        + (1 << SIGPIPE) /* important! */
     751        , SIG_IGN);
    694752
    695753    proggie = argv;
     
    697755        if (strcmp(*proggie, "-e") == 0) {
    698756            *proggie = NULL;
    699             argc = proggie - argv;
    700757            proggie++;
    701758            goto e_found;
     
    706763
    707764    // -g -G -t -r deleted, unimplemented -a deleted too
    708     opt_complementary = "?2:vv"; /* max 2 params, -v is a counter */
    709     getopt32(argv, "hnp:s:uvw:" USE_NC_SERVER("l")
    710             USE_NC_EXTRA("i:o:z"),
    711             &str_p, &str_s, &str_w
    712             USE_NC_EXTRA(, &str_i, &str_o, &o_verbose));
     765    opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */
     766    getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l")
     767            IF_NC_EXTRA("i:o:z"),
     768            &str_p, &str_s, &o_wait
     769            IF_NC_EXTRA(, &str_i, &str_o), &o_verbose);
    713770    argv += optind;
    714771#if ENABLE_NC_EXTRA
     
    727784    //if (option_mask32 & OPT_u) /* use UDP */
    728785    //if (option_mask32 & OPT_v) /* verbose */
    729     if (option_mask32 & OPT_w) { /* wait time */
    730         o_wait = xatoi_u(str_w);
    731     }
     786    //if (option_mask32 & OPT_w) /* wait time */
    732787    //if (option_mask32 & OPT_z) /* little or no data xfer */
    733788
     
    747802        /* if o_lport is still 0, then we will use random port */
    748803        ouraddr = xhost2sockaddr(str_s, o_lport);
    749         x = xsocket(ouraddr->sa.sa_family, x, 0);
     804#ifdef BLOAT
     805        /* prevent spurious "UDP listen needs !0 port" */
     806        o_lport = get_nport(ouraddr);
     807        o_lport = ntohs(o_lport);
     808#endif
     809        x = xsocket(ouraddr->u.sa.sa_family, x, 0);
    750810    } else {
    751811        /* We try IPv6, then IPv4, unless addr family is
    752812         * implicitly set by way of remote addr/port spec */
    753813        x = xsocket_type(&ouraddr,
    754                 USE_FEATURE_IPV6((themaddr ? themaddr->sa.sa_family : AF_UNSPEC),)
     814                (themaddr ? themaddr->u.sa.sa_family : AF_UNSPEC),
    755815                x);
    756816        if (o_lport)
     
    761821    if (o_udpmode)
    762822        socket_want_pktinfo(netfd);
    763     xbind(netfd, &ouraddr->sa, ouraddr->len);
     823    if (!ENABLE_FEATURE_UNIX_LOCAL
     824     || o_listen
     825     || ouraddr->u.sa.sa_family != AF_UNIX
     826    ) {
     827        xbind(netfd, &ouraddr->u.sa, ouraddr->len);
     828    }
    764829#if 0
    765830    setsockopt(netfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf);
     
    767832#endif
    768833
     834#ifdef BLOAT
    769835    if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) {
    770836        /* apparently UDP can listen ON "port 0",
     
    773839            bb_error_msg_and_die("UDP listen needs nonzero -p port");
    774840    }
    775 
    776     FD_SET(0, &ding1);                        /* stdin *is* initially open */
     841#endif
     842
     843    FD_SET(STDIN_FILENO, &ding1);                        /* stdin *is* initially open */
    777844    if (proggie) {
    778845        close(0); /* won't need stdin */
     
    793860        /* Outbound connects.  Now we're more picky about args... */
    794861        if (!themaddr)
    795             bb_error_msg_and_die("no destination");
     862            bb_show_usage();
    796863
    797864        remend = *themaddr;
    798865        if (o_verbose)
    799             themdotted = xmalloc_sockaddr2dotted(&themaddr->sa);
     866            themdotted = xmalloc_sockaddr2dotted(&themaddr->u.sa);
    800867
    801868        x = connect_w_timeout(netfd);
  • branches/2.2.9/mindi-busybox/networking/netstat.c

    r1765 r2725  
    99 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
    1010 *
    11  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     11 * 2008-07-10
     12 * optional '-p' flag support ported from net-tools by G. Somlo <somlo@cmu.edu>
     13 *
     14 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1215 */
    1316
     
    1518#include "inet_common.h"
    1619
     20//usage:#define netstat_trivial_usage
     21//usage:       "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]"
     22//usage:#define netstat_full_usage "\n\n"
     23//usage:       "Display networking information\n"
     24//usage:     "\nOptions:"
     25//usage:    IF_ROUTE(
     26//usage:     "\n    -r  Routing table"
     27//usage:    )
     28//usage:     "\n    -a  All sockets"
     29//usage:     "\n    -l  Listening sockets"
     30//usage:     "\n        Else: connected sockets"
     31//usage:     "\n    -t  TCP sockets"
     32//usage:     "\n    -u  UDP sockets"
     33//usage:     "\n    -w  Raw sockets"
     34//usage:     "\n    -x  Unix sockets"
     35//usage:     "\n        Else: all socket types"
     36//usage:     "\n    -e  Other/more information"
     37//usage:     "\n    -n  Don't resolve names"
     38//usage:    IF_FEATURE_NETSTAT_WIDE(
     39//usage:     "\n    -W  Wide display"
     40//usage:    )
     41//usage:    IF_FEATURE_NETSTAT_PRG(
     42//usage:     "\n    -p  Show PID/program name for sockets"
     43//usage:    )
     44
     45#define NETSTAT_OPTS "laentuwx" \
     46    IF_ROUTE(               "r") \
     47    IF_FEATURE_NETSTAT_WIDE("W") \
     48    IF_FEATURE_NETSTAT_PRG( "p")
     49
    1750enum {
    18     OPT_extended = 0x4,
    19     OPT_showroute = 0x100,
    20     OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE,
     51    OPT_sock_listen = 1 << 0, // l
     52    OPT_sock_all    = 1 << 1, // a
     53    OPT_extended    = 1 << 2, // e
     54    OPT_noresolve   = 1 << 3, // n
     55    OPT_sock_tcp    = 1 << 4, // t
     56    OPT_sock_udp    = 1 << 5, // u
     57    OPT_sock_raw    = 1 << 6, // w
     58    OPT_sock_unix   = 1 << 7, // x
     59    OPTBIT_x        = 7,
     60    IF_ROUTE(               OPTBIT_ROUTE,)
     61    IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,)
     62    IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG  ,)
     63    OPT_route       = IF_ROUTE(               (1 << OPTBIT_ROUTE)) + 0, // r
     64    OPT_wide        = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W
     65    OPT_prg         = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG  )) + 0, // p
    2166};
    22 # define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")
    2367
    2468#define NETSTAT_CONNECTED 0x01
     
    3276#define NETSTAT_ALLPROTO  (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX)
    3377
    34 static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;
    3578
    3679enum {
     
    4588    TCP_LAST_ACK,
    4689    TCP_LISTEN,
    47     TCP_CLOSING /* now a valid state */
     90    TCP_CLOSING, /* now a valid state */
    4891};
    4992
     
    71114} socket_state;
    72115
    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 
     116#define SO_ACCEPTCON (1<<16)  /* performed a listen           */
     117#define SO_WAITDATA  (1<<17)  /* wait data to read            */
     118#define SO_NOSPACE   (1<<18)  /* no space to write            */
     119
     120#define ADDR_NORMAL_WIDTH        23
    82121/* When there are IPv6 connections the IPv6 addresses will be
    83122 * truncated to none-recognition. The '-W' option makes the
     
    86125 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd
    87126 */
    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 
    92 static const char *net_conn_line = PRINT_NET_CONN;
     127#define ADDR_WIDE                51  /* INET6_ADDRSTRLEN + 5 for the port number */
     128#if ENABLE_FEATURE_NETSTAT_WIDE
     129# define FMT_NET_CONN_DATA       "%s   %6ld %6ld %-*s %-*s %-12s"
     130# define FMT_NET_CONN_HEADER     "\nProto Recv-Q Send-Q %-*s %-*s State       %s\n"
     131#else
     132# define FMT_NET_CONN_DATA       "%s   %6ld %6ld %-23s %-23s %-12s"
     133# define FMT_NET_CONN_HEADER     "\nProto Recv-Q Send-Q %-23s %-23s State       %s\n"
     134#endif
     135
     136#define PROGNAME_WIDTH     20
     137#define PROGNAME_WIDTH_STR "20"
     138/* PROGNAME_WIDTH chars: 12345678901234567890 */
     139#define PROGNAME_BANNER "PID/Program name    "
     140
     141struct prg_node {
     142    struct prg_node *next;
     143    long inode;
     144    char name[PROGNAME_WIDTH];
     145};
     146
     147#define PRG_HASH_SIZE 211
     148
     149struct globals {
     150    smallint flags;
     151#if ENABLE_FEATURE_NETSTAT_PRG
     152    smallint prg_cache_loaded;
     153    struct prg_node *prg_hash[PRG_HASH_SIZE];
     154#endif
     155#if ENABLE_FEATURE_NETSTAT_PRG
     156    const char *progname_banner;
     157#endif
     158#if ENABLE_FEATURE_NETSTAT_WIDE
     159    unsigned addr_width;
     160#endif
     161};
     162#define G (*ptr_to_globals)
     163#define flags            (G.flags           )
     164#define prg_cache_loaded (G.prg_cache_loaded)
     165#define prg_hash         (G.prg_hash        )
     166#if ENABLE_FEATURE_NETSTAT_PRG
     167# define progname_banner (G.progname_banner )
     168#else
     169# define progname_banner ""
     170#endif
     171#define INIT_G() do { \
     172    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     173    flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \
     174} while (0)
     175
     176
     177#if ENABLE_FEATURE_NETSTAT_PRG
     178
     179/* Deliberately truncating long to unsigned *int* */
     180#define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE)
     181
     182static void prg_cache_add(long inode, char *name)
     183{
     184    unsigned hi = PRG_HASHIT(inode);
     185    struct prg_node **pnp, *pn;
     186
     187    prg_cache_loaded = 2;
     188    for (pnp = prg_hash + hi; (pn = *pnp) != NULL; pnp = &pn->next) {
     189        if (pn->inode == inode) {
     190            /* Some warning should be appropriate here
     191               as we got multiple processes for one i-node */
     192            return;
     193        }
     194    }
     195    *pnp = xzalloc(sizeof(struct prg_node));
     196    pn = *pnp;
     197    pn->inode = inode;
     198    safe_strncpy(pn->name, name, PROGNAME_WIDTH);
     199}
     200
     201static const char *prg_cache_get(long inode)
     202{
     203    unsigned hi = PRG_HASHIT(inode);
     204    struct prg_node *pn;
     205
     206    for (pn = prg_hash[hi]; pn; pn = pn->next)
     207        if (pn->inode == inode)
     208            return pn->name;
     209    return "-";
     210}
     211
     212#if ENABLE_FEATURE_CLEAN_UP
     213static void prg_cache_clear(void)
     214{
     215    struct prg_node **pnp, *pn;
     216
     217    for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++) {
     218        while ((pn = *pnp) != NULL) {
     219            *pnp = pn->next;
     220            free(pn);
     221        }
     222    }
     223}
     224#else
     225#define prg_cache_clear() ((void)0)
     226#endif
     227
     228static long extract_socket_inode(const char *lname)
     229{
     230    long inode = -1;
     231
     232    if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) {
     233        /* "socket:[12345]", extract the "12345" as inode */
     234        inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0);
     235        if (*lname != ']')
     236            inode = -1;
     237    } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) {
     238        /* "[0000]:12345", extract the "12345" as inode */
     239        inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0);
     240        if (errno) /* not NUL terminated? */
     241            inode = -1;
     242    }
     243
     244#if 0 /* bb_strtol returns all-ones bit pattern on ERANGE anyway */
     245    if (errno == ERANGE)
     246        inode = -1;
     247#endif
     248    return inode;
     249}
     250
     251static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName,
     252        struct stat *statbuf UNUSED_PARAM,
     253        void *pid_slash_progname,
     254        int depth UNUSED_PARAM)
     255{
     256    char *linkname;
     257    long inode;
     258
     259    linkname = xmalloc_readlink(fileName);
     260    if (linkname != NULL) {
     261        inode = extract_socket_inode(linkname);
     262        free(linkname);
     263        if (inode >= 0)
     264            prg_cache_add(inode, (char *)pid_slash_progname);
     265    }
     266    return TRUE;
     267}
     268
     269static int FAST_FUNC dir_act(const char *fileName,
     270        struct stat *statbuf UNUSED_PARAM,
     271        void *userData UNUSED_PARAM,
     272        int depth)
     273{
     274    const char *pid;
     275    char *pid_slash_progname;
     276    char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3];
     277    char cmdline_buf[512];
     278    int n, len;
     279
     280    if (depth == 0) /* "/proc" itself */
     281        return TRUE; /* continue looking one level below /proc */
     282
     283    pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */
     284    if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */
     285        return SKIP;
     286
     287    len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName);
     288    n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1);
     289    if (n < 0)
     290        return FALSE;
     291    cmdline_buf[n] = '\0';
     292
     293    /* go through all files in /proc/PID/fd and check whether they are sockets */
     294    strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd");
     295    pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */
     296    n = recursive_action(proc_pid_fname,
     297            ACTION_RECURSE | ACTION_QUIET,
     298            add_to_prg_cache_if_socket,
     299            NULL,
     300            (void *)pid_slash_progname,
     301            0);
     302    free(pid_slash_progname);
     303
     304    if (!n)
     305        return FALSE; /* signal permissions error to caller */
     306
     307    return SKIP; /* caller should not recurse further into this dir */
     308}
     309
     310static void prg_cache_load(void)
     311{
     312    int load_ok;
     313
     314    prg_cache_loaded = 1;
     315    load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET,
     316                NULL, dir_act, NULL, 0);
     317    if (load_ok)
     318        return;
     319
     320    if (prg_cache_loaded == 1)
     321        bb_error_msg("can't scan /proc - are you root?");
     322    else
     323        bb_error_msg("showing only processes with your user ID");
     324}
     325
     326#else
     327
     328#define prg_cache_clear()       ((void)0)
     329
     330#endif //ENABLE_FEATURE_NETSTAT_PRG
    93331
    94332
     
    103341           &in6.s6_addr32[2], &in6.s6_addr32[3]);
    104342    inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
    105     inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr->sin6_addr);
     343    inet_pton(AF_INET6, addr6, &localaddr->sin6_addr);
    106344
    107345    localaddr->sin6_family = AF_INET6;
     
    109347#endif
    110348
    111 #if ENABLE_FEATURE_IPV6
    112 static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr)
    113 #else
    114349static 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;
     350{
     351    sscanf(local_addr, "%X", &localaddr->sin_addr.s_addr);
     352    localaddr->sin_family = AF_INET;
    120353}
    121354
     
    135368static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric)
    136369{
    137     enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) };
    138370    char *host, *host_port;
    139371
    140     /* Code which used "*" for INADDR_ANY is removed: it's ambiguous in IPv6,
    141      * while "0.0.0.0" is not. */
     372    /* Code which used "*" for INADDR_ANY is removed: it's ambiguous
     373     * in IPv6, while "0.0.0.0" is not. */
    142374
    143375    host = numeric ? xmalloc_sockaddr2dotted_noport(addr)
     
    149381}
    150382
    151 static 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;
     383struct inet_params {
     384    int local_port, rem_port, state, uid;
     385    union {
     386        struct sockaddr     sa;
     387        struct sockaddr_in  sin;
    156388#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';
     389        struct sockaddr_in6 sin6;
     390#endif
     391    } localaddr, remaddr;
     392    unsigned long rxq, txq, inode;
     393};
     394
     395static int scan_inet_proc_line(struct inet_params *param, char *line)
     396{
     397    int num;
     398    /* IPv6 /proc files use 32-char hex representation
     399     * of IPv6 address, followed by :PORT_IN_HEX
     400     */
     401    char local_addr[33], rem_addr[33]; /* 32 + 1 for NUL */
     402
    167403    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);
     404            "%*d: %32[0-9A-Fa-f]:%X "
     405            "%32[0-9A-Fa-f]:%X %X "
     406            "%lX:%lX %*X:%*X "
     407            "%*X %d %*d %ld ",
     408            local_addr, &param->local_port,
     409            rem_addr, &param->rem_port, &param->state,
     410            &param->txq, &param->rxq,
     411            &param->uid, &param->inode);
     412    if (num < 9) {
     413        return 1; /* error */
     414    }
    172415
    173416    if (strlen(local_addr) > 8) {
    174417#if ENABLE_FEATURE_IPV6
    175         build_ipv6_addr(local_addr, &localaddr);
    176         build_ipv6_addr(rem_addr, &remaddr);
     418        build_ipv6_addr(local_addr, &param->localaddr.sin6);
     419        build_ipv6_addr(rem_addr, &param->remaddr.sin6);
    177420#endif
    178421    } else {
    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))
     422        build_ipv4_addr(local_addr, &param->localaddr.sin);
     423        build_ipv4_addr(rem_addr, &param->remaddr.sin);
     424    }
     425    return 0;
     426}
     427
     428static void print_inet_line(struct inet_params *param,
     429        const char *state_str, const char *proto, int is_connected)
     430{
     431    if ((is_connected && (flags & NETSTAT_CONNECTED))
     432     || (!is_connected && (flags & NETSTAT_LISTENING))
    190433    ) {
    191434        char *l = ip_port_str(
    192                 (struct sockaddr *) &localaddr, local_port,
    193                 "tcp", flags & NETSTAT_NUMERIC);
     435                &param->localaddr.sa, param->local_port,
     436                proto, flags & NETSTAT_NUMERIC);
    194437        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]);
     438                &param->remaddr.sa, param->rem_port,
     439                proto, flags & NETSTAT_NUMERIC);
     440        printf(FMT_NET_CONN_DATA,
     441            proto, param->rxq, param->txq,
     442            IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l,
     443            IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r,
     444            state_str);
     445#if ENABLE_FEATURE_NETSTAT_PRG
     446        if (option_mask32 & OPT_prg)
     447            printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode));
     448#endif
     449        bb_putchar('\n');
    199450        free(l);
    200451        free(r);
     
    202453}
    203454
    204 static void udp_do_one(int lnr, const char *line)
    205 {
    206     char local_addr[64], rem_addr[64];
    207     const char *state_str;
    208     char more[512];
    209     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
     455static int FAST_FUNC tcp_do_one(char *line)
     456{
     457    struct inet_params param;
     458
     459    memset(&param, 0, sizeof(param));
     460    if (scan_inet_proc_line(&param, line))
     461        return 1;
     462
     463    print_inet_line(&param, tcp_state[param.state], "tcp", param.rem_port);
     464    return 0;
     465}
     466
    210467#if ENABLE_FEATURE_IPV6
    211     struct sockaddr_in6 localaddr, remaddr;
    212 #else
    213     struct sockaddr_in localaddr, remaddr;
    214 #endif
    215     unsigned long rxq, txq, time_len, retr, inode;
    216 
    217     if (lnr == 0)
    218         return;
    219 
    220     more[0] = '\0';
    221     num = sscanf(line,
    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);
    226 
    227     if (strlen(local_addr) > 8) {
    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);
    232 #endif
    233     } else {
    234         build_ipv4_addr(local_addr, &localaddr);
    235         build_ipv4_addr(rem_addr, &remaddr);
    236     }
    237 
    238     if (num < 10) {
    239         bb_error_msg("warning, got bogus udp line");
    240         return;
    241     }
    242     switch (state) {
    243         case TCP_ESTABLISHED:
    244             state_str = "ESTABLISHED";
    245             break;
    246         case TCP_CLOSE:
    247             state_str = "";
    248             break;
    249         default:
    250             state_str = "UNKNOWN";
    251             break;
    252     }
    253 
    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     )                                                           \
     468# define NOT_NULL_ADDR(A) ( \
     469    ( (A.sa.sa_family == AF_INET6) \
     470      && (A.sin6.sin6_addr.s6_addr32[0] | A.sin6.sin6_addr.s6_addr32[1] | \
     471          A.sin6.sin6_addr.s6_addr32[2] | A.sin6.sin6_addr.s6_addr32[3])  \
     472    ) || ( \
     473      (A.sa.sa_family == AF_INET) \
     474      && A.sin.sin_addr.s_addr != 0 \
     475    ) \
    263476)
    264477#else
    265 # define notnull(A) (A.sin_addr.s_addr)
    266 #endif
    267     {
    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         }
    283     }
    284 }
    285 
    286 static void raw_do_one(int lnr, const char *line)
    287 {
    288     char local_addr[64], rem_addr[64];
    289     char more[512];
    290     int num, local_port, rem_port, d, state, timer_run, uid, timeout;
    291 #if ENABLE_FEATURE_IPV6
    292     struct sockaddr_in6 localaddr, remaddr;
    293 #else
    294     struct sockaddr_in localaddr, remaddr;
    295 #endif
    296     unsigned long rxq, txq, time_len, retr, inode;
    297 
    298     if (lnr == 0)
    299         return;
    300 
    301     more[0] = '\0';
    302     num = sscanf(line,
    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);
    307 
    308     if (strlen(local_addr) > 8) {
    309 #if ENABLE_FEATURE_IPV6
    310         build_ipv6_addr(local_addr, &localaddr);
    311         build_ipv6_addr(rem_addr, &remaddr);
    312 #endif
    313     } else {
    314         build_ipv4_addr(local_addr, &localaddr);
    315         build_ipv4_addr(rem_addr, &remaddr);
    316     }
    317 
    318     if (num < 10) {
    319         bb_error_msg("warning, got bogus raw line");
    320         return;
    321     }
    322 
    323     {
    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 }
    341 
    342 static void unix_do_one(int nr, const char *line)
    343 {
    344     static smallint has_inode = 0;
    345 
    346     char path[PATH_MAX], ss_flags[32];
     478# define NOT_NULL_ADDR(A) (A.sin.sin_addr.s_addr)
     479#endif
     480
     481static int FAST_FUNC udp_do_one(char *line)
     482{
     483    int have_remaddr;
     484    const char *state_str;
     485    struct inet_params param;
     486
     487    memset(&param, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */
     488    if (scan_inet_proc_line(&param, line))
     489        return 1;
     490
     491    state_str = "UNKNOWN";
     492    switch (param.state) {
     493    case TCP_ESTABLISHED:
     494        state_str = "ESTABLISHED";
     495        break;
     496    case TCP_CLOSE:
     497        state_str = "";
     498        break;
     499    }
     500
     501    have_remaddr = NOT_NULL_ADDR(param.remaddr);
     502    print_inet_line(&param, state_str, "udp", have_remaddr);
     503    return 0;
     504}
     505
     506static int FAST_FUNC raw_do_one(char *line)
     507{
     508    int have_remaddr;
     509    struct inet_params param;
     510
     511    if (scan_inet_proc_line(&param, line))
     512        return 1;
     513
     514    have_remaddr = NOT_NULL_ADDR(param.remaddr);
     515    print_inet_line(&param, itoa(param.state), "raw", have_remaddr);
     516    return 0;
     517}
     518
     519static int FAST_FUNC unix_do_one(char *line)
     520{
     521    unsigned long refcnt, proto, unix_flags;
     522    unsigned long inode;
     523    int type, state;
     524    int num, path_ofs;
    347525    const char *ss_proto, *ss_state, *ss_type;
    348     int num, state, type, inode;
    349     void *d;
    350     unsigned long refcnt, proto, unix_flags;
    351 
    352     if (nr == 0) {
    353         if (strstr(line, "Inode"))
    354             has_inode = 1;
    355         return;
    356     }
    357     path[0] = '\0';
    358     num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
    359             &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
     526    char ss_flags[32];
     527
     528    /* 2.6.15 may report lines like "... @/tmp/fam-user-^@^@^@^@^@^@^@..."
     529     * Other users report long lines filled by NUL bytes.
     530     * (those ^@ are NUL bytes too). We see them as empty lines. */
     531    if (!line[0])
     532        return 0;
     533
     534    path_ofs = 0; /* paranoia */
     535    num = sscanf(line, "%*p: %lX %lX %lX %X %X %lu %n",
     536            &refcnt, &proto, &unix_flags, &type, &state, &inode, &path_ofs);
    360537    if (num < 6) {
    361         bb_error_msg("warning, got bogus unix line");
    362         return;
    363     }
    364     if (!has_inode)
    365         sprintf(path, "%d", inode);
    366 
     538        return 1; /* error */
     539    }
    367540    if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
    368541        if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
    369542            if (!(flags & NETSTAT_LISTENING))
    370                 return;
     543                return 0;
    371544        } else {
    372545            if (!(flags & NETSTAT_CONNECTED))
    373                 return;
     546                return 0;
    374547        }
    375548    }
     
    440613    strcat(ss_flags, "]");
    441614
    442     printf("%-5s %-6ld %-11s %-10s %-13s ",
    443            ss_proto, refcnt, ss_flags, ss_type, ss_state);
    444     if (has_inode)
    445         printf("%-6d ", inode);
    446     else
    447         printf("-      ");
    448     puts(path);
    449 }
    450 
    451 #define _PATH_PROCNET_UDP "/proc/net/udp"
    452 #define _PATH_PROCNET_UDP6 "/proc/net/udp6"
    453 #define _PATH_PROCNET_TCP "/proc/net/tcp"
    454 #define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
    455 #define _PATH_PROCNET_RAW "/proc/net/raw"
    456 #define _PATH_PROCNET_RAW6 "/proc/net/raw6"
    457 #define _PATH_PROCNET_UNIX "/proc/net/unix"
    458 
    459 static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
    460 {
    461     int lnr = 0;
     615    printf("%-5s %-6ld %-11s %-10s %-13s %6lu ",
     616        ss_proto, refcnt, ss_flags, ss_type, ss_state, inode
     617        );
     618
     619#if ENABLE_FEATURE_NETSTAT_PRG
     620    if (option_mask32 & OPT_prg)
     621        printf("%-"PROGNAME_WIDTH_STR"s", prg_cache_get(inode));
     622#endif
     623
     624    /* TODO: currently we stop at first NUL byte. Is it a problem? */
     625    line += path_ofs;
     626    *strchrnul(line, '\n') = '\0';
     627    while (*line)
     628        fputc_printable(*line++, stdout);
     629    bb_putchar('\n');
     630    return 0;
     631}
     632
     633static void do_info(const char *file, int FAST_FUNC (*proc)(char *))
     634{
     635    int lnr;
    462636    FILE *procinfo;
    463 
    464     procinfo = fopen(file, "r");
     637    char *buffer;
     638
     639    /* _stdin is just to save "r" param */
     640    procinfo = fopen_or_warn_stdin(file);
    465641    if (procinfo == NULL) {
    466         if (errno != ENOENT) {
    467             bb_perror_msg("%s", file);
    468         } else {
    469             bb_error_msg("no support for '%s' on this system", name);
    470         }
    471642        return;
    472643    }
    473     do {
    474         char *buffer = xmalloc_fgets(procinfo);
    475         if (buffer) {
    476             (proc)(lnr++, buffer);
    477             free(buffer);
    478         }
    479     } while (!feof(procinfo));
     644    lnr = 0;
     645    /* Why xmalloc_fgets_str? because it doesn't stop on NULs */
     646    while ((buffer = xmalloc_fgets_str(procinfo, "\n")) != NULL) {
     647        /* line 0 is skipped */
     648        if (lnr && proc(buffer))
     649            bb_error_msg("%s: bogus data on line %d", file, lnr + 1);
     650        lnr++;
     651        free(buffer);
     652    }
    480653    fclose(procinfo);
    481654}
    482655
    483 /*
    484  * Our main function.
    485  */
    486 
    487 int netstat_main(int argc, char **argv);
    488 int netstat_main(int argc, char **argv)
    489 {
    490     const char *net_conn_line_header = PRINT_NET_CONN_HEADER;
     656int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     657int netstat_main(int argc UNUSED_PARAM, char **argv)
     658{
    491659    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
     660
     661    INIT_G();
    498662
    499663    /* Option string must match NETSTAT_xxx constants */
    500664    opt = getopt32(argv, NETSTAT_OPTS);
    501     if (opt & 0x1) { // -l
     665    if (opt & OPT_sock_listen) { // -l
    502666        flags &= ~NETSTAT_CONNECTED;
    503667        flags |= NETSTAT_LISTENING;
    504668    }
    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
     669    if (opt & OPT_sock_all) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a
     670    //if (opt & OPT_extended) // -e
     671    if (opt & OPT_noresolve) flags |= NETSTAT_NUMERIC; // -n
     672    //if (opt & OPT_sock_tcp) // -t: NETSTAT_TCP
     673    //if (opt & OPT_sock_udp) // -u: NETSTAT_UDP
     674    //if (opt & OPT_sock_raw) // -w: NETSTAT_RAW
     675    //if (opt & OPT_sock_unix) // -x: NETSTAT_UNIX
    513676#if ENABLE_ROUTE
     677    if (opt & OPT_route) { // -r
    514678        bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended));
    515679        return 0;
    516 #else
    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     }
     680    }
     681#endif
     682#if ENABLE_FEATURE_NETSTAT_WIDE
     683    G.addr_width = ADDR_NORMAL_WIDTH;
     684    if (opt & OPT_wide) { // -W
     685        G.addr_width = ADDR_WIDE;
     686    }
     687#endif
     688#if ENABLE_FEATURE_NETSTAT_PRG
     689    progname_banner = "";
     690    if (opt & OPT_prg) { // -p
     691        progname_banner = PROGNAME_BANNER;
     692        prg_cache_load();
     693    }
     694#endif
    525695
    526696    opt &= NETSTAT_ALLPROTO;
     
    530700    }
    531701    if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
    532         printf("Active Internet connections "); /* xxx */
     702        printf("Active Internet connections "); /* xxx */
    533703
    534704        if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED))
     
    538708        else
    539709            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);
     710        printf(FMT_NET_CONN_HEADER,
     711                IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address",
     712                IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address",
     713                progname_banner
     714        );
     715    }
     716    if (flags & NETSTAT_TCP) {
     717        do_info("/proc/net/tcp", tcp_do_one);
    544718#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);
     719        do_info("/proc/net/tcp6", tcp_do_one);
     720#endif
     721    }
     722    if (flags & NETSTAT_UDP) {
     723        do_info("/proc/net/udp", udp_do_one);
    550724#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);
     725        do_info("/proc/net/udp6", udp_do_one);
     726#endif
     727    }
     728    if (flags & NETSTAT_RAW) {
     729        do_info("/proc/net/raw", raw_do_one);
    556730#if ENABLE_FEATURE_IPV6
    557     if (inet6 && flags & NETSTAT_RAW)
    558         do_info(_PATH_PROCNET_RAW6, "AF INET6 (raw)", raw_do_one);
    559 #endif
     731        do_info("/proc/net/raw6", raw_do_one);
     732#endif
     733    }
    560734    if (flags & NETSTAT_UNIX) {
    561735        printf("Active UNIX domain sockets ");
     
    566740        else
    567741            printf("(w/o servers)");
    568         printf("\nProto RefCnt Flags       Type       State         I-Node Path\n");
    569         do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one);
    570     }
     742        printf("\nProto RefCnt Flags       Type       State         I-Node %sPath\n", progname_banner);
     743        do_info("/proc/net/unix", unix_do_one);
     744    }
     745    prg_cache_clear();
    571746    return 0;
    572747}
  • branches/2.2.9/mindi-busybox/networking/nslookup.c

    r1765 r2725  
    99 * added by Ben Zeckel <bzeckel@hmc.edu> June 2001
    1010 *
    11  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1212 */
    1313
     
    1616
    1717/*
    18  *  I'm only implementing non-interactive mode;
    19  *  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.
     20 *
     21 * This applet is the only user of res_init(). Without it,
     22 * you may avoid pulling in _res global from libc.
    2023 */
    2124
     
    5255    /* We can't use xhost2sockaddr() - we want to get ALL addresses,
    5356     * not just one */
    54 
    5557    struct addrinfo *result = NULL;
    5658    int rc;
     
    7072
    7173        printf("%-10s %s\n", header, hostname);
    72         // printf("%s\n", cur->ai_canonname); ?
     74        // puts(cur->ai_canonname); ?
    7375        while (cur) {
    7476            char *dotted, *revhost;
     
    102104{
    103105    char *server;
     106    struct sockaddr *sa;
    104107
    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. */
     108#if ENABLE_FEATURE_IPV6
     109    sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
     110    if (!sa)
     111#endif
     112        sa = (struct sockaddr*)&_res.nsaddr_list[0];
     113    server = xmalloc_sockaddr2dotted_noport(sa);
     114
    112115    print_host(server, "Server:");
    113116    if (ENABLE_FEATURE_CLEAN_UP)
    114117        free(server);
    115     puts("");
     118    bb_putchar('\n');
    116119}
    117120
    118121/* alter the global _res nameserver structure to use
    119    an explicit dns server instead of what is in /etc/resolv.h */
    120 static void set_default_dns(char *server)
     122   an explicit dns server instead of what is in /etc/resolv.conf */
     123static void set_default_dns(const char *server)
    121124{
    122     struct in_addr server_in_addr;
     125    len_and_sockaddr *lsa;
    123126
    124     if (inet_pton(AF_INET, server, &server_in_addr) > 0) {
     127    /* NB: this works even with, say, "[::1]:5353"! :) */
     128    lsa = xhost2sockaddr(server, 53);
     129
     130    if (lsa->u.sa.sa_family == AF_INET) {
    125131        _res.nscount = 1;
    126         _res.nsaddr_list[0].sin_addr = server_in_addr;
     132        /* struct copy */
     133        _res.nsaddr_list[0] = lsa->u.sin;
    127134    }
     135#if ENABLE_FEATURE_IPV6
     136    /* Hoped libc can cope with IPv4 address there too.
     137     * No such luck, glibc 2.4 segfaults even with IPv6,
     138     * maybe I misunderstand how to make glibc use IPv6 addr?
     139     * (uclibc 0.9.31+ should work) */
     140    if (lsa->u.sa.sa_family == AF_INET6) {
     141        // glibc neither SEGVs nor sends any dgrams with this
     142        // (strace shows no socket ops):
     143        //_res.nscount = 0;
     144        _res._u._ext.nscount = 1;
     145        /* store a pointer to part of malloc'ed lsa */
     146        _res._u._ext.nsaddrs[0] = &lsa->u.sin6;
     147        /* must not free(lsa)! */
     148    }
     149#endif
    128150}
    129151
    130 int nslookup_main(int argc, char **argv);
     152int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    131153int nslookup_main(int argc, char **argv)
    132154{
     
    136158     * More than 3 arguments is an error to follow the pattern of the
    137159     * standard nslookup */
    138 
    139     if (argc < 2 || *argv[1] == '-' || argc > 3)
     160    if (!argv[1] || argv[1][0] == '-' || argc > 3)
    140161        bb_show_usage();
    141162
     
    144165    res_init();
    145166    /* rfc2133 says this enables IPv6 lookups */
    146     /* (but it also says "may be enabled in /etc/resolv.conf|) */
     167    /* (but it also says "may be enabled in /etc/resolv.conf") */
    147168    /*_res.options |= RES_USE_INET6;*/
    148169
    149     if (argc == 3)
     170    if (argv[2])
    150171        set_default_dns(argv[2]);
    151172
  • branches/2.2.9/mindi-busybox/networking/ping.c

    r1765 r2725  
    1212 * Mike Muuss.
    1313 *
    14  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     14 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1515 */
    1616/* from ping6.c:
     
    3131
    3232#if ENABLE_PING6
    33 #include <netinet/icmp6.h>
     33# include <netinet/icmp6.h>
    3434/* I see RENUMBERED constants in bits/in.h - !!?
    3535 * 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
     36# ifdef IPV6_2292HOPLIMIT
     37#  undef IPV6_HOPLIMIT
     38#  define IPV6_HOPLIMIT IPV6_2292HOPLIMIT
     39# endif
    4040#endif
    4141
     
    4444    MAXIPLEN = 60,
    4545    MAXICMPLEN = 76,
    46     MAXPACKET = 65468,
    4746    MAX_DUP_CHK = (8 * 128),
    4847    MAXWAIT = 10,
     
    5049};
    5150
    52 /* common routines */
     51/* Common routines */
    5352
    5453static int in_cksum(unsigned short *buf, int sz)
     
    7776#if !ENABLE_FEATURE_FANCY_PING
    7877
    79 /* simple version */
    80 
    81 static char *hostname;
    82 
    83 static void noresp(int ign ATTRIBUTE_UNUSED)
    84 {
    85     printf("No response from %s\n", hostname);
     78/* Simple version */
     79
     80struct globals {
     81    char *hostname;
     82    char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
     83} FIX_ALIASING;
     84#define G (*(struct globals*)&bb_common_bufsiz1)
     85#define INIT_G() do { } while (0)
     86
     87static void noresp(int ign UNUSED_PARAM)
     88{
     89    printf("No response from %s\n", G.hostname);
    8690    exit(EXIT_FAILURE);
    8791}
     
    8993static void ping4(len_and_sockaddr *lsa)
    9094{
    91     struct sockaddr_in pingaddr;
    9295    struct icmp *pkt;
    9396    int pingsock, c;
    94     char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
    9597
    9698    pingsock = create_icmp_socket();
    97     pingaddr = lsa->sin;
    98 
    99     pkt = (struct icmp *) packet;
    100     memset(pkt, 0, sizeof(packet));
     99
     100    pkt = (struct icmp *) G.packet;
     101    memset(pkt, 0, sizeof(G.packet));
    101102    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));
     103    pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(G.packet));
     104
     105    xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len);
    106106
    107107    /* listen for replies */
     
    110110        socklen_t fromlen = sizeof(from);
    111111
    112         c = recvfrom(pingsock, packet, sizeof(packet), 0,
     112        c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
    113113                (struct sockaddr *) &from, &fromlen);
    114114        if (c < 0) {
     
    118118        }
    119119        if (c >= 76) {          /* ip + icmp */
    120             struct iphdr *iphdr = (struct iphdr *) packet;
    121 
    122             pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */
     120            struct iphdr *iphdr = (struct iphdr *) G.packet;
     121
     122            pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2));   /* skip ip hdr */
    123123            if (pkt->icmp_type == ICMP_ECHOREPLY)
    124124                break;
     
    132132static void ping6(len_and_sockaddr *lsa)
    133133{
    134     struct sockaddr_in6 pingaddr;
    135134    struct icmp6_hdr *pkt;
    136135    int pingsock, c;
    137136    int sockopt;
    138     char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
    139137
    140138    pingsock = create_icmp6_socket();
    141     pingaddr = lsa->sin6;
    142 
    143     pkt = (struct icmp6_hdr *) packet;
    144     memset(pkt, 0, sizeof(packet));
     139
     140    pkt = (struct icmp6_hdr *) G.packet;
     141    memset(pkt, 0, sizeof(G.packet));
    145142    pkt->icmp6_type = ICMP6_ECHO_REQUEST;
    146143
     
    148145    setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
    149146
    150     c = xsendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr),
    151                (struct sockaddr *) &pingaddr, sizeof(pingaddr));
     147    xsendto(pingsock, G.packet, DEFDATALEN + sizeof(struct icmp6_hdr), &lsa->u.sa, lsa->len);
    152148
    153149    /* listen for replies */
     
    156152        socklen_t fromlen = sizeof(from);
    157153
    158         c = recvfrom(pingsock, packet, sizeof(packet), 0,
     154        c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
    159155                (struct sockaddr *) &from, &fromlen);
    160156        if (c < 0) {
     
    163159            continue;
    164160        }
    165         if (c >= 8) {           /* icmp6_hdr */
    166             pkt = (struct icmp6_hdr *) packet;
     161        if (c >= ICMP_MINLEN) {         /* icmp6_hdr */
     162            pkt = (struct icmp6_hdr *) G.packet;
    167163            if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
    168164                break;
     
    174170#endif
    175171
    176 int ping_main(int argc, char **argv);
    177 int ping_main(int argc, char **argv)
     172#if !ENABLE_PING6
     173# define common_ping_main(af, argv) common_ping_main(argv)
     174#endif
     175static int common_ping_main(sa_family_t af, char **argv)
    178176{
    179177    len_and_sockaddr *lsa;
    180 #if ENABLE_PING6
    181     sa_family_t af = AF_UNSPEC;
    182 
     178
     179    INIT_G();
     180
     181#if ENABLE_PING6
    183182    while ((++argv)[0] && argv[0][0] == '-') {
    184183        if (argv[0][1] == '4') {
     
    196195#endif
    197196
    198     hostname = *argv;
    199     if (!hostname)
     197    G.hostname = *argv;
     198    if (!G.hostname)
    200199        bb_show_usage();
    201200
    202201#if ENABLE_PING6
    203     lsa = xhost_and_af2sockaddr(hostname, 0, af);
     202    lsa = xhost_and_af2sockaddr(G.hostname, 0, af);
    204203#else
    205     lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET);
     204    lsa = xhost_and_af2sockaddr(G.hostname, 0, AF_INET);
    206205#endif
    207206    /* Set timer _after_ DNS resolution */
     
    210209
    211210#if ENABLE_PING6
    212     if (lsa->sa.sa_family == AF_INET6)
     211    if (lsa->u.sa.sa_family == AF_INET6)
    213212        ping6(lsa);
    214213    else
    215214#endif
    216215        ping4(lsa);
    217     printf("%s is alive!\n", hostname);
     216    printf("%s is alive!\n", G.hostname);
    218217    return EXIT_SUCCESS;
    219218}
     
    223222
    224223
    225 /* full(er) version */
    226 
    227 #define OPT_STRING ("qvc:s:I:4" USE_PING6("6"))
     224/* Full(er) version */
     225
     226#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6"))
    228227enum {
    229228    OPT_QUIET = 1 << 0,
     
    231230    OPT_c = 1 << 2,
    232231    OPT_s = 1 << 3,
    233     OPT_I = 1 << 4,
    234     OPT_IPV4 = 1 << 5,
    235     OPT_IPV6 = (1 << 6) * ENABLE_PING6,
     232    OPT_w = 1 << 4,
     233    OPT_W = 1 << 5,
     234    OPT_I = 1 << 6,
     235    OPT_IPV4 = 1 << 7,
     236    OPT_IPV6 = (1 << 8) * ENABLE_PING6,
    236237};
    237238
     
    239240struct globals {
    240241    int pingsock;
     242    int if_index;
     243    char *str_I;
    241244    len_and_sockaddr *source_lsa;
    242245    unsigned datalen;
    243     int if_index;
    244     unsigned long ntransmitted, nreceived, nrepeats, pingcount;
     246    unsigned pingcount; /* must be int-sized */
     247    unsigned long ntransmitted, nreceived, nrepeats;
    245248    uint16_t myid;
    246249    unsigned tmin, tmax; /* in us */
    247250    unsigned long long tsum; /* in us, sum of all times */
     251    unsigned deadline;
     252    unsigned timeout;
     253    unsigned total_secs;
     254    unsigned sizeof_rcv_packet;
     255    char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */
     256    void *snd_packet; /* [datalen + ipv4/ipv6_const] */
    248257    const char *hostname;
    249258    const char *dotted;
     
    256265    } pingaddr;
    257266    char rcvd_tbl[MAX_DUP_CHK / 8];
    258 };
     267} FIX_ALIASING;
    259268#define G (*(struct globals*)&bb_common_bufsiz1)
    260269#define pingsock     (G.pingsock    )
     270#define if_index     (G.if_index    )
    261271#define source_lsa   (G.source_lsa  )
     272#define str_I        (G.str_I       )
    262273#define datalen      (G.datalen     )
    263 #define if_index     (G.if_index    )
    264274#define ntransmitted (G.ntransmitted)
    265275#define nreceived    (G.nreceived   )
     
    270280#define tmax         (G.tmax        )
    271281#define tsum         (G.tsum        )
     282#define deadline     (G.deadline    )
     283#define timeout      (G.timeout     )
     284#define total_secs   (G.total_secs  )
    272285#define hostname     (G.hostname    )
    273286#define dotted       (G.dotted      )
     
    276289void BUG_ping_globals_too_big(void);
    277290#define INIT_G() do { \
    278         if (sizeof(G) > COMMON_BUFSIZE) \
    279                 BUG_ping_globals_too_big(); \
     291    if (sizeof(G) > COMMON_BUFSIZE) \
     292        BUG_ping_globals_too_big(); \
    280293    pingsock = -1; \
     294    datalen = DEFDATALEN; \
     295    timeout = MAXWAIT; \
    281296    tmin = UINT_MAX; \
    282297} while (0)
    283298
    284299
    285 #define A(bit)      rcvd_tbl[(bit)>>3]  /* identify byte in array */
    286 #define B(bit)      (1 << ((bit) & 0x07))   /* identify bit in byte */
    287 #define SET(bit)    (A(bit) |= B(bit))
    288 #define CLR(bit)    (A(bit) &= (~B(bit)))
    289 #define TST(bit)    (A(bit) & B(bit))
     300#define A(bit)      rcvd_tbl[(bit)>>3]  /* identify byte in array */
     301#define B(bit)      (1 << ((bit) & 0x07))   /* identify bit in byte */
     302#define SET(bit)    (A(bit) |= B(bit))
     303#define CLR(bit)    (A(bit) &= (~B(bit)))
     304#define TST(bit)    (A(bit) & B(bit))
    290305
    291306/**************************************************************************/
    292307
    293 static void pingstats(int junk ATTRIBUTE_UNUSED)
     308static void print_stats_and_exit(int junk) NORETURN;
     309static void print_stats_and_exit(int junk UNUSED_PARAM)
    294310{
    295311    signal(SIGINT, SIG_IGN);
     
    310326            tmax / 1000, tmax % 1000);
    311327    }
    312     exit(nreceived == 0); /* (nreceived == 0) is true (1) -- 'failure' */
     328    /* if condition is true, exit with 1 -- 'failure' */
     329    exit(nreceived == 0 || (deadline && nreceived < pingcount));
    313330}
    314331
     
    326343        bb_error_msg_and_die(bb_msg_write_error);
    327344
    328     signal(SIGALRM, sp);
    329     if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
     345    if (pingcount == 0 || deadline || ntransmitted < pingcount) {
     346        /* Didn't send all pings yet - schedule next in 1s */
     347        signal(SIGALRM, sp);
     348        if (deadline) {
     349            total_secs += PINGINTERVAL;
     350            if (total_secs >= deadline)
     351                signal(SIGALRM, print_stats_and_exit);
     352        }
    330353        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 
    338 static 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);
    343 
     354    } else { /* -c NN, and all NN are sent (and no deadline) */
     355        /* Wait for the last ping to come back.
     356         * -W timeout: wait for a response in seconds.
     357         * Affects only timeout in absense of any responses,
     358         * otherwise ping waits for two RTTs. */
     359        unsigned expire = timeout;
     360
     361        if (nreceived) {
     362            /* approx. 2*tmax, in seconds (2 RTT) */
     363            expire = tmax / (512*1024);
     364            if (expire == 0)
     365                expire = 1;
     366        }
     367        signal(SIGALRM, print_stats_and_exit);
     368        alarm(expire);
     369    }
     370}
     371
     372static void sendping4(int junk UNUSED_PARAM)
     373{
     374    struct icmp *pkt = G.snd_packet;
     375
     376    //memset(pkt, 0, datalen + ICMP_MINLEN + 4); - G.snd_packet was xzalloced
    344377    pkt->icmp_type = ICMP_ECHO;
    345     pkt->icmp_code = 0;
    346     pkt->icmp_cksum = 0;
     378    /*pkt->icmp_code = 0;*/
     379    pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */
    347380    pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
    348381    pkt->icmp_id = myid;
    349382
    350     /* We don't do hton, because we will read it back on the same machine */
     383    /* If datalen < 4, we store timestamp _past_ the packet,
     384     * but it's ok - we allocated 4 extra bytes in xzalloc() just in case.
     385     */
    351386    /*if (datalen >= 4)*/
     387        /* No hton: we'll read it back on the same machine */
    352388        *(uint32_t*)&pkt->icmp_dun = monotonic_us();
    353389
     
    357393}
    358394#if ENABLE_PING6
    359 static void sendping6(int junk ATTRIBUTE_UNUSED)
    360 {
    361     struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4);
    362 
     395static void sendping6(int junk UNUSED_PARAM)
     396{
     397    struct icmp6_hdr *pkt = G.snd_packet;
     398
     399    //memset(pkt, 0, datalen + sizeof(struct icmp6_hdr) + 4);
    363400    pkt->icmp6_type = ICMP6_ECHO_REQUEST;
    364     pkt->icmp6_code = 0;
    365     pkt->icmp6_cksum = 0;
     401    /*pkt->icmp6_code = 0;*/
     402    /*pkt->icmp6_cksum = 0;*/
    366403    pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
    367404    pkt->icmp6_id = myid;
     
    369406    /*if (datalen >= 4)*/
    370407        *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us();
     408
     409    //TODO? pkt->icmp_cksum = in_cksum(...);
    371410
    372411    sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr));
     
    458497        printf(" time=%u.%03u ms", triptime / 1000, triptime % 1000);
    459498    puts(dupmsg);
    460     fflush(stdout);
     499    fflush_all();
    461500}
    462501static void unpack4(char *buf, int sz, struct sockaddr_in *from)
     
    494533}
    495534#if ENABLE_PING6
    496 static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
     535static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hoplimit)
    497536{
    498537    struct icmp6_hdr *icmppkt;
     
    527566static void ping4(len_and_sockaddr *lsa)
    528567{
    529     char packet[datalen + MAXIPLEN + MAXICMPLEN];
    530568    int sockopt;
    531569
    532570    pingsock = create_icmp_socket();
    533     pingaddr.sin = lsa->sin;
     571    pingaddr.sin = lsa->u.sin;
    534572    if (source_lsa) {
    535573        if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF,
    536                 &source_lsa->sa, source_lsa->len))
     574                &source_lsa->u.sa, source_lsa->len))
    537575            bb_error_msg_and_die("can't set multicast source interface");
    538         xbind(pingsock, &source_lsa->sa, source_lsa->len);
    539     }
     576        xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
     577    }
     578    if (str_I)
     579        setsockopt_bindtodevice(pingsock, str_I);
    540580
    541581    /* enable broadcast pings */
    542582    setsockopt_broadcast(pingsock);
    543583
    544     /* set recv buf for broadcast pings */
    545     sockopt = 48 * 1024; /* explain why 48k? */
     584    /* set recv buf (needed if we can get lots of responses: flood ping,
     585     * broadcast ping etc) */
     586    sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */
    546587    setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
    547588
    548     signal(SIGINT, pingstats);
     589    signal(SIGINT, print_stats_and_exit);
    549590
    550591    /* start the ping's going ... */
     
    557598        int c;
    558599
    559         c = recvfrom(pingsock, packet, sizeof(packet), 0,
     600        c = recvfrom(pingsock, G.rcv_packet, G.sizeof_rcv_packet, 0,
    560601                (struct sockaddr *) &from, &fromlen);
    561602        if (c < 0) {
     
    564605            continue;
    565606        }
    566         unpack4(packet, c, &from);
    567         if (pingcount > 0 && nreceived >= pingcount)
     607        unpack4(G.rcv_packet, c, &from);
     608        if (pingcount && nreceived >= pingcount)
    568609            break;
    569610    }
     
    573614static void ping6(len_and_sockaddr *lsa)
    574615{
    575     char packet[datalen + MAXIPLEN + MAXICMPLEN];
    576616    int sockopt;
    577617    struct msghdr msg;
     
    581621
    582622    pingsock = create_icmp6_socket();
    583     pingaddr.sin6 = lsa->sin6;
     623    pingaddr.sin6 = lsa->u.sin6;
    584624    /* untested whether "-I addr" really works for IPv6: */
    585625    if (source_lsa)
    586         xbind(pingsock, &source_lsa->sa, source_lsa->len);
     626        xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
     627    if (str_I)
     628        setsockopt_bindtodevice(pingsock, str_I);
    587629
    588630#ifdef ICMP6_FILTER
     
    604646    setsockopt_broadcast(pingsock);
    605647
    606     /* set recv buf for broadcast pings */
    607     sockopt = 48 * 1024; /* explain why 48k? */
     648    /* set recv buf (needed if we can get lots of responses: flood ping,
     649     * broadcast ping etc) */
     650    sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */
    608651    setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
    609652
     
    619662        pingaddr.sin6.sin6_scope_id = if_index;
    620663
    621     signal(SIGINT, pingstats);
     664    signal(SIGINT, print_stats_and_exit);
    622665
    623666    /* start the ping's going ... */
     
    630673    msg.msg_iovlen = 1;
    631674    msg.msg_control = control_buf;
    632     iov.iov_base = packet;
    633     iov.iov_len = sizeof(packet);
     675    iov.iov_base = G.rcv_packet;
     676    iov.iov_len = G.sizeof_rcv_packet;
    634677    while (1) {
    635678        int c;
     
    650693             /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */
    651694            ) {
    652                 hoplimit = *(int*)CMSG_DATA(mp);
     695                /*hoplimit = *(int*)CMSG_DATA(mp); - unaligned access */
     696                move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
    653697            }
    654698        }
    655         unpack6(packet, c, &from, hoplimit);
    656         if (pingcount > 0 && nreceived >= pingcount)
     699        unpack6(G.rcv_packet, c, /*&from,*/ hoplimit);
     700        if (pingcount && nreceived >= pingcount)
    657701            break;
    658702    }
     
    665709    if (source_lsa) {
    666710        printf(" from %s",
    667             xmalloc_sockaddr2dotted_noport(&source_lsa->sa));
     711            xmalloc_sockaddr2dotted_noport(&source_lsa->u.sa));
    668712    }
    669713    printf(": %d data bytes\n", datalen);
    670714
    671 #if ENABLE_PING6
    672     if (lsa->sa.sa_family == AF_INET6)
     715    G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN;
     716    G.rcv_packet = xzalloc(G.sizeof_rcv_packet);
     717#if ENABLE_PING6
     718    if (lsa->u.sa.sa_family == AF_INET6) {
     719        /* +4 reserves a place for timestamp, which may end up sitting
     720         * _after_ packet. Saves one if() - see sendping4/6() */
     721        G.snd_packet = xzalloc(datalen + sizeof(struct icmp6_hdr) + 4);
    673722        ping6(lsa);
    674     else
    675 #endif
     723    } else
     724#endif
     725    {
     726        G.snd_packet = xzalloc(datalen + ICMP_MINLEN + 4);
    676727        ping4(lsa);
    677 }
    678 
    679 int ping_main(int argc, char **argv);
    680 int ping_main(int argc, char **argv)
     728    }
     729}
     730
     731static int common_ping_main(int opt, char **argv)
    681732{
    682733    len_and_sockaddr *lsa;
    683     char *opt_c, *opt_s, *opt_I;
    684     USE_PING6(sa_family_t af = AF_UNSPEC;)
     734    char *str_s;
    685735
    686736    INIT_G();
    687737
    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);
     738    /* exactly one argument needed; -v and -q don't mix; -c NUM, -w NUM, -W NUM */
     739    opt_complementary = "=1:q--v:v--q:c+:w+:W+";
     740    opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &deadline, &timeout, &str_I);
     741    if (opt & OPT_s)
     742        datalen = xatou16(str_s); // -s
     743    if (opt & OPT_I) { // -I
     744        if_index = if_nametoindex(str_I);
    697745        if (!if_index) {
    698746            /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */
    699             source_lsa = xdotted2sockaddr(opt_I, 0);
     747            source_lsa = xdotted2sockaddr(str_I, 0);
     748            str_I = NULL; /* don't try to bind to device later */
    700749        }
    701750    }
     
    703752    hostname = argv[optind];
    704753#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);
     754    {
     755        sa_family_t af = AF_UNSPEC;
     756        if (opt & OPT_IPV4)
     757            af = AF_INET;
     758        if (opt & OPT_IPV6)
     759            af = AF_INET6;
     760        lsa = xhost_and_af2sockaddr(hostname, 0, af);
     761    }
    710762#else
    711763    lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET);
    712764#endif
    713765
    714     if (source_lsa && source_lsa->sa.sa_family != lsa->sa.sa_family)
     766    if (source_lsa && source_lsa->u.sa.sa_family != lsa->u.sa.sa_family)
    715767        /* leaking it here... */
    716768        source_lsa = NULL;
    717769
    718     dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa);
     770    dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
    719771    ping(lsa);
    720     pingstats(0);
    721     return EXIT_SUCCESS;
     772    print_stats_and_exit(EXIT_SUCCESS);
     773    /*return EXIT_SUCCESS;*/
    722774}
    723775#endif /* FEATURE_FANCY_PING */
    724776
    725777
    726 #if ENABLE_PING6
    727 int ping6_main(int argc, char **argv);
    728 int ping6_main(int argc, char **argv)
    729 {
    730     argv[0] = (char*)"-6";
    731     return ping_main(argc + 1, argv - 1);
     778int ping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     779int ping_main(int argc UNUSED_PARAM, char **argv)
     780{
     781#if !ENABLE_FEATURE_FANCY_PING
     782    return common_ping_main(AF_UNSPEC, argv);
     783#else
     784    return common_ping_main(0, argv);
     785#endif
     786}
     787
     788#if ENABLE_PING6
     789int ping6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     790int ping6_main(int argc UNUSED_PARAM, char **argv)
     791{
     792# if !ENABLE_FEATURE_FANCY_PING
     793    return common_ping_main(AF_INET6, argv);
     794# else
     795    return common_ping_main(OPT_IPV6, argv);
     796# endif
    732797}
    733798#endif
  • branches/2.2.9/mindi-busybox/networking/pscan.c

    r1765 r2725  
    44 * Copyright 2007 Tito Ragusa <farmatito@tiscali.it>
    55 *
    6  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    77 */
    88
     
    3131#define MONOTONIC_US() ((unsigned)monotonic_us())
    3232
    33 int pscan_main(int argc, char **argv);
    34 int pscan_main(int argc, char **argv)
     33int pscan_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     34int pscan_main(int argc UNUSED_PARAM, char **argv)
    3535{
    3636    const char *opt_max_port = "1024";      /* -P: default max port */
     
    4343     * will take N seconds at absolute minimum */
    4444    const char *opt_min_rtt = "5";          /* -T: default min rtt in msec */
     45    const char *result_str;
    4546    len_and_sockaddr *lsap;
    4647    int s;
     48    unsigned opt;
    4749    unsigned port, max_port, nports;
    4850    unsigned closed_ports = 0;
     
    5254    unsigned min_rtt;
    5355    unsigned rtt_4;
    54     unsigned start;
     56    unsigned start, diff;
    5557
    5658    opt_complementary = "=1"; /* exactly one non-option */
    57     getopt32(argv, "p:P:t:T:", &opt_min_port, &opt_max_port, &opt_timeout, &opt_min_rtt);
     59    opt = getopt32(argv, "cbp:P:t:T:", &opt_min_port, &opt_max_port, &opt_timeout, &opt_min_rtt);
    5860    argv += optind;
    5961    max_port = xatou_range(opt_max_port, 1, 65535);
    6062    port = xatou_range(opt_min_port, 1, max_port);
    6163    nports = max_port - port + 1;
    62     rtt_4 = timeout = xatou_range(opt_timeout, 1, INT_MAX/1000 / 4) * 1000;
    6364    min_rtt = xatou_range(opt_min_rtt, 1, INT_MAX/1000 / 4) * 1000;
     65    timeout = xatou_range(opt_timeout, 1, INT_MAX/1000 / 4) * 1000;
     66    /* Initial rtt is BIG: */
     67    rtt_4 = timeout;
    6468
    6569    DMSG("min_rtt %u timeout %u", min_rtt, timeout);
     
    7478        /* The SOCK_STREAM socket type is implemented on the TCP/IP protocol. */
    7579        set_nport(lsap, htons(port));
    76         s = xsocket(lsap->sa.sa_family, SOCK_STREAM, 0);
    77 
     80        s = xsocket(lsap->u.sa.sa_family, SOCK_STREAM, 0);
    7881        /* We need unblocking socket so we don't need to wait for ETIMEOUT. */
    7982        /* Nonblocking connect typically "fails" with errno == EINPROGRESS */
    8083        ndelay_on(s);
     84
    8185        DMSG("connect to port %u", port);
     86        result_str = NULL;
    8287        start = MONOTONIC_US();
    83         if (connect(s, &lsap->sa, lsap->len) == 0) {
     88        if (connect(s, &lsap->u.sa, lsap->len) == 0) {
    8489            /* Unlikely, for me even localhost fails :) */
    8590            DMSG("connect succeeded");
     
    9398        }
    9499
     100        diff = 0;
    95101        while (1) {
    96102            if (errno == ECONNREFUSED) {
    97                 DMSG("port %u: ECONNREFUSED", port);
     103                if (opt & 1) /* -c: show closed too */
     104                    result_str = "closed";
    98105                closed_ports++;
    99106                break;
    100107            }
    101             DERR("port %u errno %d @%u", port, errno, MONOTONIC_US() - start);
    102             if ((MONOTONIC_US() - start) > rtt_4)
     108            DERR("port %u errno %d @%u", port, errno, diff);
     109
     110            if (diff > rtt_4) {
     111                if (opt & 2) /* -b: show blocked too */
     112                    result_str = "blocked";
    103113                break;
     114            }
    104115            /* Can sleep (much) longer than specified delay.
    105116             * We check rtt BEFORE we usleep, otherwise
    106              * on localhost we'll do zero writes done (!)
     117             * on localhost we'll have no writes done (!)
    107118             * before we exceed (rather small) rtt */
    108119            usleep(rtt_4/8);
    109             DMSG("write to port %u @%u", port, MONOTONIC_US() - start);
     120 open:
     121            diff = MONOTONIC_US() - start;
     122            DMSG("write to port %u @%u", port, diff - start);
    110123            if (write(s, " ", 1) >= 0) { /* We were able to write to the socket */
    111  open:
    112124                open_ports++;
    113                 printf("%5u\ttcp\topen\t%s\n", port, port_name(port));
     125                result_str = "open";
    114126                break;
    115127            }
    116128        }
    117         DMSG("out of loop @%u", MONOTONIC_US() - start);
     129        DMSG("out of loop @%u", diff);
     130        if (result_str)
     131            printf("%5u" "\t" "tcp" "\t" "%s" "\t" "%s" "\n",
     132                    port, result_str, port_name(port));
    118133
    119134        /* Estimate new rtt - we don't want to wait entire timeout
    120135         * for each port. *4 allows for rise in net delay.
    121          * We increase rtt quickly (*4), decrease slowly (4/8 == 1/2)
     136         * We increase rtt quickly (rtt_4*4), decrease slowly
     137         * (diff is at least rtt_4/8, *4 == rtt_4/2)
    122138         * because we don't want to accidentally miss ports. */
    123         rtt_4 = (MONOTONIC_US() - start) * 4;
     139        rtt_4 = diff * 4;
    124140        if (rtt_4 < min_rtt)
    125141            rtt_4 = min_rtt;
     
    131147    if (ENABLE_FEATURE_CLEAN_UP) free(lsap);
    132148
    133     printf("%d closed, %d open, %d timed out ports\n",
     149    printf("%d closed, %d open, %d timed out (or blocked) ports\n",
    134150                    closed_ports,
    135151                    open_ports,
  • branches/2.2.9/mindi-busybox/networking/route.c

    r1765 r2725  
    1111 *              (derived from FvK's 'route.c     1.70    01/04/94')
    1212 *
    13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1414 *
    1515 *
     
    2626 */
    2727
    28 #include <getopt.h>
    2928#include <net/route.h>
    3029#include <net/if.h>
     
    153152/* Add or delete a route, depending on action. */
    154153
    155 static void INET_setroute(int action, char **args)
     154static NOINLINE void INET_setroute(int action, char **args)
    156155{
    157156    struct rtentry rt;
     
    180179
    181180            prefix_len = xatoul_range(prefix+1, 0, 32);
    182             mask_in_addr(rt) = htonl( ~ (0xffffffffUL >> prefix_len));
     181            mask_in_addr(rt) = htonl( ~(0xffffffffUL >> prefix_len));
    183182            *prefix = '\0';
    184183#if HAVE_NEW_ADDRT
     
    187186        } else {
    188187            /* Default netmask. */
    189             netmask = bb_str_default;
     188            netmask = "default";
    190189        }
    191190        /* Prefer hostname lookup is -host flag (xflag==1) was given. */
     
    304303    /* sanity checks.. */
    305304    if (mask_in_addr(rt)) {
    306         unsigned long mask = mask_in_addr(rt);
     305        uint32_t mask = mask_in_addr(rt);
    307306
    308307        mask = ~ntohl(mask);
     
    315314        }
    316315        mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
    317         if (mask & ~mask_in_addr(rt)) {
     316        if (mask & ~(uint32_t)mask_in_addr(rt)) {
    318317            bb_error_msg_and_die("netmask and route address conflict");
    319318        }
     
    338337#if ENABLE_FEATURE_IPV6
    339338
    340 static void INET6_setroute(int action, char **args)
     339static NOINLINE void INET6_setroute(int action, char **args)
    341340{
    342341    struct sockaddr_in6 sa6;
     
    348347        const char *target = *args++;
    349348
    350         if (strcmp(target, bb_str_default) == 0) {
     349        if (strcmp(target, "default") == 0) {
    351350            prefix_len = 0;
    352351            memset(&sa6, 0, sizeof(sa6));
    353352        } else {
    354353            char *cp;
    355             if ((cp = strchr(target, '/'))) { /* Yes... const to non is ok. */
    356                 *cp = 0;
    357                 prefix_len = xatoul_range(cp+1, 0, 128);
     354            cp = strchr(target, '/'); /* Yes... const to non is ok. */
     355            if (cp) {
     356                *cp = '\0';
     357                prefix_len = xatoul_range(cp + 1, 0, 128);
    358358            } else {
    359359                prefix_len = 128;
     
    424424        struct ifreq ifr;
    425425        memset(&ifr, 0, sizeof(ifr));
    426         strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
     426        strncpy_IFNAMSIZ(ifr.ifr_name, devname);
    427427        xioctl(skfd, SIOGIFINDEX, &ifr);
    428428        rt.rtmsg_ifindex = ifr.ifr_ifindex;
     
    477477
    478478/* also used in netstat */
    479 void bb_displayroutes(int noresolve, int netstatfmt)
     479void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt)
    480480{
    481481    char devname[64], flags[16], *sdest, *sgw;
     
    485485    struct in_addr mask;
    486486
    487     FILE *fp = xfopen("/proc/net/route", "r");
     487    FILE *fp = xfopen_for_read("/proc/net/route");
    488488
    489489    printf("Kernel IP routing table\n"
     
    539539#if ENABLE_FEATURE_IPV6
    540540
    541 static void INET6_displayroutes(int noresolve)
     541static void INET6_displayroutes(void)
    542542{
    543543    char addr6[128], *naddr6;
     
    553553    struct sockaddr_in6 snaddr6;
    554554
    555     FILE *fp = xfopen("/proc/net/ipv6_route", "r");
     555    FILE *fp = xfopen_for_read("/proc/net/ipv6_route");
    556556
    557557    printf("Kernel IPv6 routing table\n%-44s%-40s"
     
    562562        int r;
    563563        r = fscanf(fp, "%32s%x%*s%x%32s%x%x%x%x%s\n",
    564                    addr6x+14, &prefix_len, &slen, addr6x+40+7,
    565                    &metric, &use, &refcnt, &iflags, iface);
     564                addr6x+14, &prefix_len, &slen, addr6x+40+7,
     565                &metric, &use, &refcnt, &iflags, iface);
    566566        if (r != 9) {
    567567            if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
     
    641641;
    642642
    643 int route_main(int argc, char **argv);
    644 int route_main(int argc, char **argv)
     643int route_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     644int route_main(int argc UNUSED_PARAM, char **argv)
    645645{
    646646    unsigned opt;
     
    675675#if ENABLE_FEATURE_IPV6
    676676        if (opt & ROUTE_OPT_INET6)
    677             INET6_displayroutes(noresolve);
     677            INET6_displayroutes();
    678678        else
    679679#endif
  • branches/2.2.9/mindi-busybox/networking/slattach.c

    r1765 r2725  
    55 * Author: Ignacio Garcia Perez (iggarpe at gmail dot com)
    66 *
    7  * License: GPLv2 or later, see LICENSE file in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 *
    99 * There are some differences from the standard net-tools slattach:
     
    2121    int saved_disc;
    2222    struct termios saved_state;
    23 };
     23} FIX_ALIASING;
    2424#define G (*(struct globals*)&bb_common_bufsiz1)
    2525#define handle       (G.handle      )
    2626#define saved_disc   (G.saved_disc  )
    2727#define saved_state  (G.saved_state )
    28 #define INIT_G() do {} while (0)
     28#define INIT_G() do { } while (0)
    2929
    3030
     
    4444}
    4545
    46 static int set_termios_state_and_warn(struct termios *state)
     46static int set_termios_state_or_warn(struct termios *state)
    4747{
    4848    int ret;
     
    6565 * as possible.
    6666 */
    67 static void restore_state_and_exit(int exitcode) ATTRIBUTE_NORETURN;
     67static void restore_state_and_exit(int exitcode) NORETURN;
    6868static void restore_state_and_exit(int exitcode)
    6969{
     
    7979    cfsetispeed(&state, B0);
    8080    cfsetospeed(&state, B0);
    81     if (set_termios_state_and_warn(&state))
     81    if (set_termios_state_or_warn(&state))
    8282        exitcode = 1;
    8383    sleep(1);
    8484
    8585    /* Restore line status */
    86     if (set_termios_state_and_warn(&saved_state))
     86    if (set_termios_state_or_warn(&saved_state))
    8787        exit(EXIT_FAILURE);
    8888    if (ENABLE_FEATURE_CLEAN_UP)
     
    100100
    101101    /* Set line status */
    102     if (set_termios_state_and_warn(state))
     102    if (set_termios_state_or_warn(state))
    103103        goto bad;
    104104    /* Set line discliple (N_SLIP always) */
     
    111111    if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) {
    112112 bad:
    113         restore_state_and_exit(1);
    114     }
    115 }
    116 
    117 static void sig_handler(int signo)
    118 {
    119     restore_state_and_exit(0);
    120 }
    121 
    122 int slattach_main(int argc, char **argv);
    123 int slattach_main(int argc, char **argv)
     113        restore_state_and_exit(EXIT_FAILURE);
     114    }
     115}
     116
     117static void sig_handler(int signo UNUSED_PARAM)
     118{
     119    restore_state_and_exit(EXIT_SUCCESS);
     120}
     121
     122int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     123int slattach_main(int argc UNUSED_PARAM, char **argv)
    124124{
    125125    /* Line discipline code table */
     
    135135    struct termios state;
    136136    const char *proto = "cslip";
    137     const char *extcmd;             /* Command to execute after hangup */
     137    const char *extcmd;   /* Command to execute after hangup */
    138138    const char *baud_str;
    139     int baud_code = -1;             /* Line baud rate (system code) */
     139    int baud_code = -1;   /* Line baud rate (system code) */
    140140
    141141    enum {
     
    176176    /* Trap signals in order to restore tty states upon exit */
    177177    if (!(opt & OPT_e_quit)) {
    178         signal(SIGHUP, sig_handler);
    179         signal(SIGINT, sig_handler);
    180         signal(SIGQUIT, sig_handler);
    181         signal(SIGTERM, sig_handler);
     178        bb_signals(0
     179            + (1 << SIGHUP)
     180            + (1 << SIGINT)
     181            + (1 << SIGQUIT)
     182            + (1 << SIGTERM)
     183            , sig_handler);
    182184    }
    183185
     
    205207                      | ((opt & OPT_L_local) ? CLOCAL : 0)
    206208                      | ((opt & OPT_F_noflow) ? 0 : CRTSCTS);
     209        cfsetispeed(&state, cfgetispeed(&saved_state));
     210        cfsetospeed(&state, cfgetospeed(&saved_state));
    207211    }
    208212
     
    238242
    239243    /* Restore states and exit */
    240     restore_state_and_exit(0);
    241 }
     244    restore_state_and_exit(EXIT_SUCCESS);
     245}
  • branches/2.2.9/mindi-busybox/networking/telnet.c

    r1765 r2725  
    99 * Last modified: Fri Jun  9 14:34:24 2000 too
    1010 *
    11  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1212 *
    1313 * HISTORY
     
    2222 */
    2323
    24 #include <termios.h>
    2524#include <arpa/telnet.h>
    2625#include <netinet/in.h>
     
    4443    UF_SGA = 0x02,
    4544
    46     TS_0 = 1,
     45    TS_NORMAL = 0,
     46    TS_COPY = 1,
    4747    TS_IAC = 2,
    4848    TS_OPT = 3,
    4949    TS_SUB1 = 4,
    5050    TS_SUB2 = 5,
     51    TS_CR = 6,
    5152};
    5253
    5354typedef unsigned char byte;
    5455
     56enum { netfd = 3 };
     57
    5558struct globals {
    56     int netfd; /* console fd:s are 0 and 1 (and 2) */
    57     short   iaclen; /* could even use byte */
     59    int iaclen; /* could even use byte, but it's a loss on x86 */
    5860    byte    telstate; /* telnet negotiation state from network input */
    5961    byte    telwish;  /* DO, DONT, WILL, WONT */
    6062    byte    charmode;
    6163    byte    telflags;
    62     byte    gotsig;
    6364    byte    do_termios;
    6465#if ENABLE_FEATURE_TELNET_TTYPE
     
    6970#endif
    7071#if ENABLE_FEATURE_AUTOWIDTH
    71     int win_width, win_height;
     72    unsigned win_width, win_height;
    7273#endif
    7374    /* same buffer used both for network and console read/write */
     
    7778    struct termios termios_def;
    7879    struct termios termios_raw;
    79 };
     80} FIX_ALIASING;
    8081#define G (*(struct globals*)&bb_common_bufsiz1)
    81 void BUG_telnet_globals_too_big(void);
    8282#define INIT_G() do { \
    83     if (sizeof(G) > COMMON_BUFSIZE) \
    84         BUG_telnet_globals_too_big(); \
    85     /* memset(&G, 0, sizeof G); - already is */ \
     83    struct G_sizecheck { \
     84        char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
     85    }; \
    8686} while (0)
    8787
    88 /* Function prototypes */
     88
    8989static void rawmode(void);
    9090static void cookmode(void);
     
    9292static void will_charmode(void);
    9393static void telopt(byte c);
    94 static int subneg(byte c);
    95 
    96 static void iacflush(void)
    97 {
    98     write(G.netfd, G.iacbuf, G.iaclen);
     94static void subneg(byte c);
     95
     96static void iac_flush(void)
     97{
     98    write(netfd, G.iacbuf, G.iaclen);
    9999    G.iaclen = 0;
    100100}
     
    102102#define write_str(fd, str) write(fd, str, sizeof(str) - 1)
    103103
     104static void doexit(int ev) NORETURN;
    104105static void doexit(int ev)
    105106{
     
    108109}
    109110
    110 static void conescape(void)
     111static void con_escape(void)
    111112{
    112113    char b;
    113114
    114     if (G.gotsig)   /* came from line mode... go raw */
     115    if (bb_got_signal) /* came from line mode... go raw */
    115116        rawmode();
    116117
     
    121122            " e exit telnet\r\n");
    122123
    123     if (read(0, &b, 1) <= 0)
    124         doexit(1);
     124    if (read(STDIN_FILENO, &b, 1) <= 0)
     125        doexit(EXIT_FAILURE);
    125126
    126127    switch (b) {
    127128    case 'l':
    128         if (!G.gotsig) {
     129        if (!bb_got_signal) {
    129130            do_linemode();
    130             goto rrturn;
     131            goto ret;
    131132        }
    132133        break;
    133134    case 'c':
    134         if (G.gotsig) {
     135        if (bb_got_signal) {
    135136            will_charmode();
    136             goto rrturn;
     137            goto ret;
    137138        }
    138139        break;
     
    143144        break;
    144145    case 'e':
    145         doexit(0);
     146        doexit(EXIT_SUCCESS);
    146147    }
    147148
    148149    write_str(1, "continuing...\r\n");
    149150
    150     if (G.gotsig)
     151    if (bb_got_signal)
    151152        cookmode();
    152 
    153  rrturn:
    154     G.gotsig = 0;
    155 
    156 }
    157 
    158 static void handlenetoutput(int len)
    159 {
    160     /*  here we could do smart tricks how to handle 0xFF:s in output
    161      *  stream  like writing twice every sequence of FF:s (thus doing
    162      *  many write()s. But I think interactive telnet application does
    163      *  not need to be 100% 8-bit clean, so changing every 0xff:s to
    164      *  0x7f:s
     153 ret:
     154    bb_got_signal = 0;
     155}
     156
     157static void handle_net_output(int len)
     158{
     159    /* here we could do smart tricks how to handle 0xFF:s in output
     160     * stream like writing twice every sequence of FF:s (thus doing
     161     * many write()s. But I think interactive telnet application does
     162     * not need to be 100% 8-bit clean, so changing every 0xff:s to
     163     * 0x7f:s
    165164     *
    166      *  2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
    167      *  I don't agree.
    168      *  first - I cannot use programs like sz/rz
    169      *  second - the 0x0D is sent as one character and if the next
    170      *       char is 0x0A then it's eaten by a server side.
    171      *  third - whay doy you have to make 'many write()s'?
    172      *      I don't understand.
    173      *  So I implemented it. It's realy useful for me. I hope that
    174      *  others people will find it interesting to.
     165     * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
     166     * I don't agree.
     167     * first - I cannot use programs like sz/rz
     168     * second - the 0x0D is sent as one character and if the next
     169     *  char is 0x0A then it's eaten by a server side.
     170     * third - why do you have to make 'many write()s'?
     171     *  I don't understand.
     172     * So I implemented it. It's really useful for me. I hope that
     173     * other people will find it interesting too.
    175174     */
    176 
    177     int i, j;
    178     byte * p = (byte*)G.buf;
    179     byte outbuf[4*DATABUFSIZE];
    180 
    181     for (i = len, j = 0; i > 0; i--, p++)
    182     {
    183         if (*p == 0x1d)
    184         {
    185             conescape();
     175    byte outbuf[2 * DATABUFSIZE];
     176    byte *p = (byte*)G.buf;
     177    int j = 0;
     178
     179    for (; len > 0; len--, p++) {
     180        byte c = *p;
     181        if (c == 0x1d) {
     182            con_escape();
    186183            return;
    187184        }
    188         outbuf[j++] = *p;
    189         if (*p == 0xff)
    190             outbuf[j++] = 0xff;
    191         else if (*p == 0x0d)
    192             outbuf[j++] = 0x00;
     185        outbuf[j++] = c;
     186        if (c == IAC)
     187            outbuf[j++] = c; /* IAC -> IAC IAC */
     188        else if (c == '\r')
     189            outbuf[j++] = '\0'; /* CR -> CR NUL */
    193190    }
    194191    if (j > 0)
    195         write(G.netfd, outbuf, j);
    196 }
    197 
    198 static void handlenetinput(int len)
     192        full_write(netfd, outbuf, j);
     193}
     194
     195static void handle_net_input(int len)
    199196{
    200197    int i;
    201198    int cstart = 0;
    202199
    203     for (i = 0; i < len; i++)
    204     {
     200    for (i = 0; i < len; i++) {
    205201        byte c = G.buf[i];
    206202
    207         if (G.telstate == 0) /* most of the time state == 0 */
    208         {
    209             if (c == IAC)
    210             {
     203        if (G.telstate == TS_NORMAL) { /* most typical state */
     204            if (c == IAC) {
    211205                cstart = i;
    212206                G.telstate = TS_IAC;
    213207            }
    214         }
    215         else
    216             switch (G.telstate)
    217              {
    218              case TS_0:
    219                  if (c == IAC)
    220                      G.telstate = TS_IAC;
    221                  else
    222                      G.buf[cstart++] = c;
    223                  break;
    224 
    225              case TS_IAC:
    226                  if (c == IAC) /* IAC IAC -> 0xFF */
    227                  {
    228                      G.buf[cstart++] = c;
    229                      G.telstate = TS_0;
    230                      break;
    231                  }
    232                  /* else */
    233                  switch (c)
    234                  {
    235                  case SB:
    236                      G.telstate = TS_SUB1;
    237                      break;
    238                  case DO:
    239                  case DONT:
    240                  case WILL:
    241                  case WONT:
    242                      G.telwish =  c;
    243                      G.telstate = TS_OPT;
    244                      break;
    245                  default:
    246                      G.telstate = TS_0; /* DATA MARK must be added later */
    247                  }
    248                  break;
    249              case TS_OPT: /* WILL, WONT, DO, DONT */
    250                  telopt(c);
    251                  G.telstate = TS_0;
    252                  break;
    253              case TS_SUB1: /* Subnegotiation */
    254              case TS_SUB2: /* Subnegotiation */
    255                  if (subneg(c))
    256                      G.telstate = TS_0;
    257                  break;
    258              }
    259     }
    260     if (G.telstate)
    261     {
    262         if (G.iaclen)           iacflush();
    263         if (G.telstate == TS_0) G.telstate = 0;
    264 
     208            else if (c == '\r') {
     209                cstart = i + 1;
     210                G.telstate = TS_CR;
     211            }
     212            /* No IACs were seen so far, no need to copy
     213             * bytes within G.buf: */
     214            continue;
     215        }
     216
     217        switch (G.telstate) {
     218        case TS_CR:
     219            /* Prev char was CR. If cur one is NUL, ignore it.
     220             * See RFC 1123 section 3.3.1 for discussion of telnet EOL handling.
     221             */
     222            G.telstate = TS_COPY;
     223            if (c == '\0')
     224                break;
     225            /* else: fall through - need to handle CR IAC ... properly */
     226
     227        case TS_COPY: /* Prev char was ordinary */
     228            /* Similar to NORMAL, but in TS_COPY we need to copy bytes */
     229            if (c == IAC)
     230                G.telstate = TS_IAC;
     231            else
     232                G.buf[cstart++] = c;
     233            if (c == '\r')
     234                G.telstate = TS_CR;
     235            break;
     236
     237        case TS_IAC: /* Prev char was IAC */
     238            if (c == IAC) { /* IAC IAC -> one IAC */
     239                G.buf[cstart++] = c;
     240                G.telstate = TS_COPY;
     241                break;
     242            }
     243            /* else */
     244            switch (c) {
     245            case SB:
     246                G.telstate = TS_SUB1;
     247                break;
     248            case DO:
     249            case DONT:
     250            case WILL:
     251            case WONT:
     252                G.telwish = c;
     253                G.telstate = TS_OPT;
     254                break;
     255            /* DATA MARK must be added later */
     256            default:
     257                G.telstate = TS_COPY;
     258            }
     259            break;
     260
     261        case TS_OPT: /* Prev chars were IAC WILL/WONT/DO/DONT */
     262            telopt(c);
     263            G.telstate = TS_COPY;
     264            break;
     265
     266        case TS_SUB1: /* Subnegotiation */
     267        case TS_SUB2: /* Subnegotiation */
     268            subneg(c); /* can change G.telstate */
     269            break;
     270        }
     271    }
     272
     273    if (G.telstate != TS_NORMAL) {
     274        /* We had some IACs, or CR */
     275        if (G.iaclen)
     276            iac_flush();
     277        if (G.telstate == TS_COPY) /* we aren't in the middle of IAC */
     278            G.telstate = TS_NORMAL;
    265279        len = cstart;
    266280    }
    267281
    268282    if (len)
    269         write(1, G.buf, len);
    270 }
    271 
    272 static void putiac(int c)
     283        full_write(STDOUT_FILENO, G.buf, len);
     284}
     285
     286static void put_iac(int c)
    273287{
    274288    G.iacbuf[G.iaclen++] = c;
    275289}
    276290
    277 static void putiac2(byte wwdd, byte c)
     291static void put_iac2(byte wwdd, byte c)
    278292{
    279293    if (G.iaclen + 3 > IACBUFSIZE)
    280         iacflush();
    281 
    282     putiac(IAC);
    283     putiac(wwdd);
    284     putiac(c);
     294        iac_flush();
     295
     296    put_iac(IAC);
     297    put_iac(wwdd);
     298    put_iac(c);
    285299}
    286300
    287301#if ENABLE_FEATURE_TELNET_TTYPE
    288 static void putiac_subopt(byte c, char *str)
    289 {
    290     int len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )
     302static void put_iac_subopt(byte c, char *str)
     303{
     304    int len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )
    291305
    292306    if (G.iaclen + len > IACBUFSIZE)
    293         iacflush();
    294 
    295     putiac(IAC);
    296     putiac(SB);
    297     putiac(c);
    298     putiac(0);
     307        iac_flush();
     308
     309    put_iac(IAC);
     310    put_iac(SB);
     311    put_iac(c);
     312    put_iac(0);
    299313
    300314    while (*str)
    301         putiac(*str++);
    302 
    303     putiac(IAC);
    304     putiac(SE);
     315        put_iac(*str++);
     316
     317    put_iac(IAC);
     318    put_iac(SE);
    305319}
    306320#endif
    307321
    308322#if ENABLE_FEATURE_TELNET_AUTOLOGIN
    309 static void putiac_subopt_autologin(void)
     323static void put_iac_subopt_autologin(void)
    310324{
    311325    int len = strlen(G.autologin) + 6;  // (2 + 1 + 1 + strlen + 2)
    312     const char *user = "USER";
     326    const char *p = "USER";
    313327
    314328    if (G.iaclen + len > IACBUFSIZE)
    315         iacflush();
    316 
    317     putiac(IAC);
    318     putiac(SB);
    319     putiac(TELOPT_NEW_ENVIRON);
    320     putiac(TELQUAL_IS);
    321     putiac(NEW_ENV_VAR);
    322 
    323     while (*user)
    324         putiac(*user++);
    325 
    326     putiac(NEW_ENV_VALUE);
    327 
    328     while (*G.autologin)
    329         putiac(*G.autologin++);
    330 
    331     putiac(IAC);
    332     putiac(SE);
     329        iac_flush();
     330
     331    put_iac(IAC);
     332    put_iac(SB);
     333    put_iac(TELOPT_NEW_ENVIRON);
     334    put_iac(TELQUAL_IS);
     335    put_iac(NEW_ENV_VAR);
     336
     337    while (*p)
     338        put_iac(*p++);
     339
     340    put_iac(NEW_ENV_VALUE);
     341
     342    p = G.autologin;
     343    while (*p)
     344        put_iac(*p++);
     345
     346    put_iac(IAC);
     347    put_iac(SE);
    333348}
    334349#endif
    335350
    336351#if ENABLE_FEATURE_AUTOWIDTH
    337 static void putiac_naws(byte c, int x, int y)
     352static void put_iac_naws(byte c, int x, int y)
    338353{
    339354    if (G.iaclen + 9 > IACBUFSIZE)
    340         iacflush();
    341 
    342     putiac(IAC);
    343     putiac(SB);
    344     putiac(c);
    345 
    346     putiac((x >> 8) & 0xff);
    347     putiac(x & 0xff);
    348     putiac((y >> 8) & 0xff);
    349     putiac(y & 0xff);
    350 
    351     putiac(IAC);
    352     putiac(SE);
     355        iac_flush();
     356
     357    put_iac(IAC);
     358    put_iac(SB);
     359    put_iac(c);
     360
     361    put_iac((x >> 8) & 0xff);
     362    put_iac(x & 0xff);
     363    put_iac((y >> 8) & 0xff);
     364    put_iac(y & 0xff);
     365
     366    put_iac(IAC);
     367    put_iac(SE);
    353368}
    354369#endif
     
    379394    setConMode();
    380395
    381     putiac2(DO, TELOPT_ECHO);
    382     putiac2(DO, TELOPT_SGA);
    383     iacflush();
     396    put_iac2(DO, TELOPT_ECHO);
     397    put_iac2(DO, TELOPT_SGA);
     398    iac_flush();
    384399}
    385400
     
    390405    setConMode();
    391406
    392     putiac2(DONT, TELOPT_ECHO);
    393     putiac2(DONT, TELOPT_SGA);
    394     iacflush();
     407    put_iac2(DONT, TELOPT_ECHO);
     408    put_iac2(DONT, TELOPT_SGA);
     409    iac_flush();
    395410}
    396411
     
    398413{
    399414    if (G.telwish == WILL)
    400         putiac2(DONT, c);
     415        put_iac2(DONT, c);
    401416    else if (G.telwish == DO)
    402         putiac2(WONT, c);
     417        put_iac2(WONT, c);
    403418}
    404419
     
    407422    /* if server requests ECHO, don't agree */
    408423    if (G.telwish == DO) {
    409         putiac2(WONT, TELOPT_ECHO);
     424        put_iac2(WONT, TELOPT_ECHO);
    410425        return;
    411426    }
     
    423438
    424439    if (G.telflags & UF_ECHO)
    425         putiac2(DO, TELOPT_ECHO);
     440        put_iac2(DO, TELOPT_ECHO);
    426441    else
    427         putiac2(DONT, TELOPT_ECHO);
     442        put_iac2(DONT, TELOPT_ECHO);
    428443
    429444    setConMode();
    430     write_str(1, "\r\n");  /* sudden modec */
     445    full_write1_str("\r\n");  /* sudden modec */
    431446}
    432447
     
    441456        return;
    442457
    443     if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
    444         putiac2(DO, TELOPT_SGA);
     458    G.telflags ^= UF_SGA; /* toggle */
     459    if (G.telflags & UF_SGA)
     460        put_iac2(DO, TELOPT_SGA);
    445461    else
    446         putiac2(DONT, TELOPT_SGA);
     462        put_iac2(DONT, TELOPT_SGA);
    447463}
    448464
     
    451467{
    452468    /* Tell server we will (or won't) do TTYPE */
    453 
    454469    if (G.ttype)
    455         putiac2(WILL, TELOPT_TTYPE);
     470        put_iac2(WILL, TELOPT_TTYPE);
    456471    else
    457         putiac2(WONT, TELOPT_TTYPE);
     472        put_iac2(WONT, TELOPT_TTYPE);
    458473}
    459474#endif
     
    463478{
    464479    /* Tell server we will (or will not) do AUTOLOGIN */
    465 
    466480    if (G.autologin)
    467         putiac2(WILL, TELOPT_NEW_ENVIRON);
     481        put_iac2(WILL, TELOPT_NEW_ENVIRON);
    468482    else
    469         putiac2(WONT, TELOPT_NEW_ENVIRON);
     483        put_iac2(WONT, TELOPT_NEW_ENVIRON);
    470484}
    471485#endif
     
    475489{
    476490    /* Tell server we will do NAWS */
    477     putiac2(WILL, TELOPT_NAWS);
     491    put_iac2(WILL, TELOPT_NAWS);
    478492}
    479493#endif
     
    497511    case TELOPT_NAWS:
    498512        to_naws();
    499         putiac_naws(c, G.win_width, G.win_height);
     513        put_iac_naws(c, G.win_width, G.win_height);
    500514        break;
    501515#endif
     
    507521
    508522/* subnegotiation -- ignore all (except TTYPE,NAWS) */
    509 static int subneg(byte c)
     523static void subneg(byte c)
    510524{
    511525    switch (G.telstate) {
     
    515529#if ENABLE_FEATURE_TELNET_TTYPE
    516530        else
    517         if (c == TELOPT_TTYPE)
    518             putiac_subopt(TELOPT_TTYPE, G.ttype);
     531        if (c == TELOPT_TTYPE && G.ttype)
     532            put_iac_subopt(TELOPT_TTYPE, G.ttype);
    519533#endif
    520534#if ENABLE_FEATURE_TELNET_AUTOLOGIN
    521535        else
    522         if (c == TELOPT_NEW_ENVIRON)
    523             putiac_subopt_autologin();
     536        if (c == TELOPT_NEW_ENVIRON && G.autologin)
     537            put_iac_subopt_autologin();
    524538#endif
    525539        break;
    526540    case TS_SUB2:
    527         if (c == SE)
    528             return TRUE;
     541        if (c == SE) {
     542            G.telstate = TS_COPY;
     543            return;
     544        }
    529545        G.telstate = TS_SUB1;
    530         /* break; */
    531     }
    532     return FALSE;
    533 }
    534 
    535 static void fgotsig(int sig)
    536 {
    537     G.gotsig = sig;
    538 }
    539 
     546        break;
     547    }
     548}
    540549
    541550static void rawmode(void)
     
    551560}
    552561
    553 int telnet_main(int argc, char** argv);
    554 int telnet_main(int argc, char** argv)
     562int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     563int telnet_main(int argc UNUSED_PARAM, char **argv)
    555564{
    556565    char *host;
    557566    int port;
    558567    int len;
    559 #ifdef USE_POLL
    560568    struct pollfd ufds[2];
    561 #else
    562     fd_set readfds;
    563     int maxfd;
    564 #endif
    565569
    566570    INIT_G();
     
    579583        cfmakeraw(&G.termios_raw);
    580584    }
    581 
    582     if (argc < 2)
    583         bb_show_usage();
    584585
    585586#if ENABLE_FEATURE_TELNET_AUTOLOGIN
     
    597598        bb_show_usage();
    598599
    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));
    602 
    603     signal(SIGINT, fgotsig);
    604 
    605 #ifdef USE_POLL
    606     ufds[0].fd = 0; ufds[1].fd = G.netfd;
    607     ufds[0].events = ufds[1].events = POLLIN;
    608 #else
    609     FD_ZERO(&readfds);
    610     FD_SET(0, &readfds);
    611     FD_SET(G.netfd, &readfds);
    612     maxfd = G.netfd + 1;
    613 #endif
     600    xmove_fd(create_and_connect_stream_or_die(host, port), netfd);
     601
     602    setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     603
     604    signal(SIGINT, record_signo);
     605
     606    ufds[0].fd = STDIN_FILENO;
     607    ufds[0].events = POLLIN;
     608    ufds[1].fd = netfd;
     609    ufds[1].events = POLLIN;
    614610
    615611    while (1) {
    616 #ifndef USE_POLL
    617         fd_set rfds = readfds;
    618 
    619         switch (select(maxfd, &rfds, NULL, NULL, NULL))
    620 #else
    621         switch (poll(ufds, 2, -1))
    622 #endif
    623         {
    624         case 0:
    625             /* timeout */
    626         case -1:
     612        if (poll(ufds, 2, -1) < 0) {
    627613            /* error, ignore and/or log something, bay go to loop */
    628             if (G.gotsig)
    629                 conescape();
     614            if (bb_got_signal)
     615                con_escape();
    630616            else
    631617                sleep(1);
    632             break;
    633         default:
    634 
    635 #ifdef USE_POLL
    636             if (ufds[0].revents) /* well, should check POLLIN, but ... */
    637 #else
    638             if (FD_ISSET(0, &rfds))
    639 #endif
    640             {
    641                 len = read(0, G.buf, DATABUFSIZE);
    642                 if (len <= 0)
    643                     doexit(0);
    644                 TRACE(0, ("Read con: %d\n", len));
    645                 handlenetoutput(len);
     618            continue;
     619        }
     620
     621// FIXME: reads can block. Need full bidirectional buffering.
     622
     623        if (ufds[0].revents) {
     624            len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE);
     625            if (len <= 0)
     626                doexit(EXIT_SUCCESS);
     627            TRACE(0, ("Read con: %d\n", len));
     628            handle_net_output(len);
     629        }
     630
     631        if (ufds[1].revents) {
     632            len = safe_read(netfd, G.buf, DATABUFSIZE);
     633            if (len <= 0) {
     634                full_write1_str("Connection closed by foreign host\r\n");
     635                doexit(EXIT_FAILURE);
    646636            }
    647 
    648 #ifdef USE_POLL
    649             if (ufds[1].revents) /* well, should check POLLIN, but ... */
    650 #else
    651             if (FD_ISSET(G.netfd, &rfds))
    652 #endif
    653             {
    654                 len = read(G.netfd, G.buf, DATABUFSIZE);
    655                 if (len <= 0) {
    656                     write_str(1, "Connection closed by foreign host\r\n");
    657                     doexit(1);
    658                 }
    659                 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
    660                 handlenetinput(len);
    661             }
    662         }
    663     }
    664 }
     637            TRACE(0, ("Read netfd (%d): %d\n", netfd, len));
     638            handle_net_input(len);
     639        }
     640    } /* while (1) */
     641}
  • branches/2.2.9/mindi-busybox/networking/telnetd.c

    r1765 r2725  
    44 * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
    55 *
    6  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    77 *
    88 * ---------------------------------------------------------------------------
     
    1212 * The telnetd manpage says it all:
    1313 *
    14  *   Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for
    15  *   a client, then creating a login process which has the slave side of the
    16  *   pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
    17  *   master side of the pseudo-terminal, implementing the telnet protocol and
    18  *   passing characters between the remote client and the login process.
     14 * Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for
     15 * a client, then creating a login process which has the slave side of the
     16 * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
     17 * master side of the pseudo-terminal, implementing the telnet protocol and
     18 * passing characters between the remote client and the login process.
    1919 *
    2020 * Vladimir Oleynik <dzo@simtreas.ru> 2001
    21  *     Set process group corrections, initial busybox port
     21 * Set process group corrections, initial busybox port
    2222 */
    23 
    2423#define DEBUG 0
    2524
    2625#include "libbb.h"
     26#include <syslog.h>
    2727
    2828#if DEBUG
    29 #define TELCMDS
    30 #define TELOPTS
     29# define TELCMDS
     30# define TELOPTS
    3131#endif
    3232#include <arpa/telnet.h>
    33 #include <sys/syslog.h>
    34 
    35 
    36 #if ENABLE_LOGIN
    37 static const char *loginpath = "/bin/login";
    38 #else
    39 static const char *loginpath = DEFAULT_SHELL;
    40 #endif
    41 
    42 static const char *issuefile = "/etc/issue.net";
    43 
    44 /* structure that describes a session */
     33
     34#if ENABLE_FEATURE_UTMP
     35# include <utmp.h> /* LOGIN_PROCESS */
     36#endif
     37
    4538
    4639struct tsession {
    4740    struct tsession *next;
    48     int sockfd_read, sockfd_write, ptyfd;
    49     int shell_pid;
     41    pid_t shell_pid;
     42    int sockfd_read;
     43    int sockfd_write;
     44    int ptyfd;
     45
    5046    /* two circular buffers */
    51     char *buf1, *buf2;
     47    /*char *buf1, *buf2;*/
     48/*#define TS_BUF1(ts) ts->buf1*/
     49/*#define TS_BUF2(ts) TS_BUF2(ts)*/
     50#define TS_BUF1(ts) ((unsigned char*)(ts + 1))
     51#define TS_BUF2(ts) (((unsigned char*)(ts + 1)) + BUFSIZE)
    5252    int rdidx1, wridx1, size1;
    5353    int rdidx2, wridx2, size2;
     
    5656/* Two buffers are directly after tsession in malloced memory.
    5757 * Make whole thing fit in 4k */
    58 enum { BUFSIZE = (4*1024 - sizeof(struct tsession)) / 2 };
     58enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
     59
     60
     61/* Globals */
     62struct globals {
     63    struct tsession *sessions;
     64    const char *loginpath;
     65    const char *issuefile;
     66    int maxfd;
     67} FIX_ALIASING;
     68#define G (*(struct globals*)&bb_common_bufsiz1)
     69#define INIT_G() do { \
     70    G.loginpath = "/bin/login"; \
     71    G.issuefile = "/etc/issue.net"; \
     72} while (0)
     73
    5974
    6075/*
    61    This is how the buffers are used. The arrows indicate the movement
    62    of data.
     76   Remove all IAC's from buf1 (received IACs are ignored and must be removed
     77   so as to not be interpreted by the terminal).  Make an uninterrupted
     78   string of characters fit for the terminal.  Do this by packing
     79   all characters meant for the terminal sequentially towards the end of buf.
     80
     81   Return a pointer to the beginning of the characters meant for the terminal
     82   and make *num_totty the number of characters that should be sent to
     83   the terminal.
     84
     85   Note - if an IAC (3 byte quantity) starts before (bf + len) but extends
     86   past (bf + len) then that IAC will be left unprocessed and *processed
     87   will be less than len.
     88
     89   CR-LF ->'s CR mapping is also done here, for convenience.
     90
     91   NB: may fail to remove iacs which wrap around buffer!
     92 */
     93static unsigned char *
     94remove_iacs(struct tsession *ts, int *pnum_totty)
     95{
     96    unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
     97    unsigned char *ptr = ptr0;
     98    unsigned char *totty = ptr;
     99    unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
     100    int num_totty;
     101
     102    while (ptr < end) {
     103        if (*ptr != IAC) {
     104            char c = *ptr;
     105
     106            *totty++ = c;
     107            ptr++;
     108            /* We map \r\n ==> \r for pragmatic reasons.
     109             * Many client implementations send \r\n when
     110             * the user hits the CarriageReturn key.
     111             */
     112            if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0'))
     113                ptr++;
     114            continue;
     115        }
     116
     117        if ((ptr+1) >= end)
     118            break;
     119        if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */
     120            ptr += 2;
     121            continue;
     122        }
     123        if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */
     124            *totty++ = ptr[1];
     125            ptr += 2;
     126            continue;
     127        }
     128
     129        /*
     130         * TELOPT_NAWS support!
     131         */
     132        if ((ptr+2) >= end) {
     133            /* Only the beginning of the IAC is in the
     134            buffer we were asked to process, we can't
     135            process this char */
     136            break;
     137        }
     138        /*
     139         * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
     140         */
     141        if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
     142            struct winsize ws;
     143            if ((ptr+8) >= end)
     144                break;  /* incomplete, can't process */
     145            ws.ws_col = (ptr[3] << 8) | ptr[4];
     146            ws.ws_row = (ptr[5] << 8) | ptr[6];
     147            ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
     148            ptr += 9;
     149            continue;
     150        }
     151        /* skip 3-byte IAC non-SB cmd */
     152#if DEBUG
     153        fprintf(stderr, "Ignoring IAC %s,%s\n",
     154                TELCMD(ptr[1]), TELOPT(ptr[2]));
     155#endif
     156        ptr += 3;
     157    }
     158
     159    num_totty = totty - ptr0;
     160    *pnum_totty = num_totty;
     161    /* The difference between ptr and totty is number of iacs
     162       we removed from the stream. Adjust buf1 accordingly */
     163    if ((ptr - totty) == 0) /* 99.999% of cases */
     164        return ptr0;
     165    ts->wridx1 += ptr - totty;
     166    ts->size1 -= ptr - totty;
     167    /* Move chars meant for the terminal towards the end of the buffer */
     168    return memmove(ptr - num_totty, ptr0, num_totty);
     169}
     170
     171/*
     172 * Converting single IAC into double on output
     173 */
     174static size_t iac_safe_write(int fd, const char *buf, size_t count)
     175{
     176    const char *IACptr;
     177    size_t wr, rc, total;
     178
     179    total = 0;
     180    while (1) {
     181        if (count == 0)
     182            return total;
     183        if (*buf == (char)IAC) {
     184            static const char IACIAC[] ALIGN1 = { IAC, IAC };
     185            rc = safe_write(fd, IACIAC, 2);
     186            if (rc != 2)
     187                break;
     188            buf++;
     189            total++;
     190            count--;
     191            continue;
     192        }
     193        /* count != 0, *buf != IAC */
     194        IACptr = memchr(buf, IAC, count);
     195        wr = count;
     196        if (IACptr)
     197            wr = IACptr - buf;
     198        rc = safe_write(fd, buf, wr);
     199        if (rc != wr)
     200            break;
     201        buf += rc;
     202        total += rc;
     203        count -= rc;
     204    }
     205    /* here: rc - result of last short write */
     206    if ((ssize_t)rc < 0) { /* error? */
     207        if (total == 0)
     208            return rc;
     209        rc = 0;
     210    }
     211    return total + rc;
     212}
     213
     214/* Must match getopt32 string */
     215enum {
     216    OPT_WATCHCHILD = (1 << 2), /* -K */
     217    OPT_INETD      = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
     218    OPT_PORT       = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
     219    OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
     220    OPT_SYSLOG     = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
     221    OPT_WAIT       = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
     222};
     223
     224static struct tsession *
     225make_new_session(
     226        IF_FEATURE_TELNETD_STANDALONE(int sock)
     227        IF_NOT_FEATURE_TELNETD_STANDALONE(void)
     228) {
     229#if !ENABLE_FEATURE_TELNETD_STANDALONE
     230    enum { sock = 0 };
     231#endif
     232    const char *login_argv[2];
     233    struct termios termbuf;
     234    int fd, pid;
     235    char tty_name[GETPTY_BUFSIZE];
     236    struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
     237
     238    /*ts->buf1 = (char *)(ts + 1);*/
     239    /*ts->buf2 = ts->buf1 + BUFSIZE;*/
     240
     241    /* Got a new connection, set up a tty */
     242    fd = xgetpty(tty_name);
     243    if (fd > G.maxfd)
     244        G.maxfd = fd;
     245    ts->ptyfd = fd;
     246    ndelay_on(fd);
     247    close_on_exec_on(fd);
     248
     249    /* SO_KEEPALIVE by popular demand */
     250    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1));
     251#if ENABLE_FEATURE_TELNETD_STANDALONE
     252    ts->sockfd_read = sock;
     253    ndelay_on(sock);
     254    if (sock == 0) { /* We are called with fd 0 - we are in inetd mode */
     255        sock++; /* so use fd 1 for output */
     256        ndelay_on(sock);
     257    }
     258    ts->sockfd_write = sock;
     259    if (sock > G.maxfd)
     260        G.maxfd = sock;
     261#else
     262    /* ts->sockfd_read = 0; - done by xzalloc */
     263    ts->sockfd_write = 1;
     264    ndelay_on(0);
     265    ndelay_on(1);
     266#endif
     267
     268    /* Make the telnet client understand we will echo characters so it
     269     * should not do it locally. We don't tell the client to run linemode,
     270     * because we want to handle line editing and tab completion and other
     271     * stuff that requires char-by-char support. */
     272    {
     273        static const char iacs_to_send[] ALIGN1 = {
     274            IAC, DO, TELOPT_ECHO,
     275            IAC, DO, TELOPT_NAWS,
     276            /* This requires telnetd.ctrlSQ.patch (incomplete) */
     277            /*IAC, DO, TELOPT_LFLOW,*/
     278            IAC, WILL, TELOPT_ECHO,
     279            IAC, WILL, TELOPT_SGA
     280        };
     281        /* This confuses iac_safe_write(), it will try to duplicate
     282         * each IAC... */
     283        //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send));
     284        //ts->rdidx2 = sizeof(iacs_to_send);
     285        //ts->size2 = sizeof(iacs_to_send);
     286        /* So just stuff it into TCP stream! (no error check...) */
     287#if ENABLE_FEATURE_TELNETD_STANDALONE
     288        safe_write(sock, iacs_to_send, sizeof(iacs_to_send));
     289#else
     290        safe_write(1, iacs_to_send, sizeof(iacs_to_send));
     291#endif
     292        /*ts->rdidx2 = 0; - xzalloc did it */
     293        /*ts->size2 = 0;*/
     294    }
     295
     296    fflush_all();
     297    pid = vfork(); /* NOMMU-friendly */
     298    if (pid < 0) {
     299        free(ts);
     300        close(fd);
     301        /* sock will be closed by caller */
     302        bb_perror_msg("vfork");
     303        return NULL;
     304    }
     305    if (pid > 0) {
     306        /* Parent */
     307        ts->shell_pid = pid;
     308        return ts;
     309    }
     310
     311    /* Child */
     312    /* Careful - we are after vfork! */
     313
     314    /* Restore default signal handling ASAP */
     315    bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
     316
     317    if (ENABLE_FEATURE_UTMP) {
     318        len_and_sockaddr *lsa = get_peer_lsa(sock);
     319        char *hostname = NULL;
     320        if (lsa) {
     321            hostname = xmalloc_sockaddr2dotted(&lsa->u.sa);
     322            free(lsa);
     323        }
     324        write_new_utmp(pid, LOGIN_PROCESS, tty_name, /*username:*/ "LOGIN", hostname);
     325        free(hostname);
     326    }
     327
     328    /* Make new session and process group */
     329    setsid();
     330
     331    /* Open the child's side of the tty */
     332    /* NB: setsid() disconnects from any previous ctty's. Therefore
     333     * we must open child's side of the tty AFTER setsid! */
     334    close(0);
     335    xopen(tty_name, O_RDWR); /* becomes our ctty */
     336    xdup2(0, 1);
     337    xdup2(0, 2);
     338    pid = getpid();
     339    tcsetpgrp(0, pid); /* switch this tty's process group to us */
     340
     341    /* The pseudo-terminal allocated to the client is configured to operate
     342     * in cooked mode, and with XTABS CRMOD enabled (see tty(4)) */
     343    tcgetattr(0, &termbuf);
     344    termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
     345    termbuf.c_oflag |= ONLCR | XTABS;
     346    termbuf.c_iflag |= ICRNL;
     347    termbuf.c_iflag &= ~IXOFF;
     348    /*termbuf.c_lflag &= ~ICANON;*/
     349    tcsetattr_stdin_TCSANOW(&termbuf);
     350
     351    /* Uses FILE-based I/O to stdout, but does fflush_all(),
     352     * so should be safe with vfork.
     353     * I fear, though, that some users will have ridiculously big
     354     * issue files, and they may block writing to fd 1,
     355     * (parent is supposed to read it, but parent waits
     356     * for vforked child to exec!) */
     357    print_login_issue(G.issuefile, tty_name);
     358
     359    /* Exec shell / login / whatever */
     360    login_argv[0] = G.loginpath;
     361    login_argv[1] = NULL;
     362    /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
     363     * exec external program.
     364     * NB: sock is either 0 or has CLOEXEC set on it.
     365     * fd has CLOEXEC set on it too. These two fds will be closed here.
     366     */
     367    BB_EXECVP(G.loginpath, (char **)login_argv);
     368    /* _exit is safer with vfork, and we shouldn't send message
     369     * to remote clients anyway */
     370    _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", G.loginpath);*/
     371}
     372
     373#if ENABLE_FEATURE_TELNETD_STANDALONE
     374
     375static void
     376free_session(struct tsession *ts)
     377{
     378    struct tsession *t;
     379
     380    if (option_mask32 & OPT_INETD)
     381        exit(EXIT_SUCCESS);
     382
     383    /* Unlink this telnet session from the session list */
     384    t = G.sessions;
     385    if (t == ts)
     386        G.sessions = ts->next;
     387    else {
     388        while (t->next != ts)
     389            t = t->next;
     390        t->next = ts->next;
     391    }
     392
     393#if 0
     394    /* It was said that "normal" telnetd just closes ptyfd,
     395     * doesn't send SIGKILL. When we close ptyfd,
     396     * kernel sends SIGHUP to processes having slave side opened. */
     397    kill(ts->shell_pid, SIGKILL);
     398    waitpid(ts->shell_pid, NULL, 0);
     399#endif
     400    close(ts->ptyfd);
     401    close(ts->sockfd_read);
     402    /* We do not need to close(ts->sockfd_write), it's the same
     403     * as sockfd_read unless we are in inetd mode. But in inetd mode
     404     * we do not reach this */
     405    free(ts);
     406
     407    /* Scan all sessions and find new maxfd */
     408    G.maxfd = 0;
     409    ts = G.sessions;
     410    while (ts) {
     411        if (G.maxfd < ts->ptyfd)
     412            G.maxfd = ts->ptyfd;
     413        if (G.maxfd < ts->sockfd_read)
     414            G.maxfd = ts->sockfd_read;
     415#if 0
     416        /* Again, sockfd_write == sockfd_read here */
     417        if (G.maxfd < ts->sockfd_write)
     418            G.maxfd = ts->sockfd_write;
     419#endif
     420        ts = ts->next;
     421    }
     422}
     423
     424#else /* !FEATURE_TELNETD_STANDALONE */
     425
     426/* Used in main() only, thus "return 0" actually is exit(EXIT_SUCCESS). */
     427#define free_session(ts) return 0
     428
     429#endif
     430
     431static void handle_sigchld(int sig UNUSED_PARAM)
     432{
     433    pid_t pid;
     434    struct tsession *ts;
     435    int save_errno = errno;
     436
     437    /* Looping: more than one child may have exited */
     438    while (1) {
     439        pid = wait_any_nohang(NULL);
     440        if (pid <= 0)
     441            break;
     442        ts = G.sessions;
     443        while (ts) {
     444            if (ts->shell_pid == pid) {
     445                ts->shell_pid = -1;
     446// man utmp:
     447// When init(8) finds that a process has exited, it locates its utmp entry
     448// by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
     449// and ut_time with null bytes.
     450// [same applies to other processes which maintain utmp entries, like telnetd]
     451//
     452// We do not bother actually clearing fields:
     453// it might be interesting to know who was logged in and from where
     454                update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
     455                break;
     456            }
     457            ts = ts->next;
     458        }
     459    }
     460
     461    errno = save_errno;
     462}
     463
     464int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     465int telnetd_main(int argc UNUSED_PARAM, char **argv)
     466{
     467    fd_set rdfdset, wrfdset;
     468    unsigned opt;
     469    int count;
     470    struct tsession *ts;
     471#if ENABLE_FEATURE_TELNETD_STANDALONE
     472#define IS_INETD (opt & OPT_INETD)
     473    int master_fd = master_fd; /* for compiler */
     474    int sec_linger = sec_linger;
     475    char *opt_bindaddr = NULL;
     476    char *opt_portnbr;
     477#else
     478    enum {
     479        IS_INETD = 1,
     480        master_fd = -1,
     481    };
     482#endif
     483    INIT_G();
     484
     485    /* -w NUM, and implies -F. -w and -i don't mix */
     486    IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";)
     487    /* Even if !STANDALONE, we accept (and ignore) -i, thus people
     488     * don't need to guess whether it's ok to pass -i to us */
     489    opt = getopt32(argv, "f:l:Ki"
     490            IF_FEATURE_TELNETD_STANDALONE("p:b:F")
     491            IF_FEATURE_TELNETD_INETD_WAIT("Sw:"),
     492            &G.issuefile, &G.loginpath
     493            IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
     494            IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
     495    );
     496    if (!IS_INETD /*&& !re_execed*/) {
     497        /* inform that we start in standalone mode?
     498         * May be useful when people forget to give -i */
     499        /*bb_error_msg("listening for connections");*/
     500        if (!(opt & OPT_FOREGROUND)) {
     501            /* DAEMON_CHDIR_ROOT was giving inconsistent
     502             * behavior with/without -F, -i */
     503            bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
     504        }
     505    }
     506    /* Redirect log to syslog early, if needed */
     507    if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
     508        openlog(applet_name, LOG_PID, LOG_DAEMON);
     509        logmode = LOGMODE_SYSLOG;
     510    }
     511#if ENABLE_FEATURE_TELNETD_STANDALONE
     512    if (IS_INETD) {
     513        G.sessions = make_new_session(0);
     514        if (!G.sessions) /* pty opening or vfork problem, exit */
     515            return 1; /* make_new_session printed error message */
     516    } else {
     517        master_fd = 0;
     518        if (!(opt & OPT_WAIT)) {
     519            unsigned portnbr = 23;
     520            if (opt & OPT_PORT)
     521                portnbr = xatou16(opt_portnbr);
     522            master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
     523            xlisten(master_fd, 1);
     524        }
     525        close_on_exec_on(master_fd);
     526    }
     527#else
     528    G.sessions = make_new_session();
     529    if (!G.sessions) /* pty opening or vfork problem, exit */
     530        return 1; /* make_new_session printed error message */
     531#endif
     532
     533    /* We don't want to die if just one session is broken */
     534    signal(SIGPIPE, SIG_IGN);
     535
     536    if (opt & OPT_WATCHCHILD)
     537        signal(SIGCHLD, handle_sigchld);
     538    else /* prevent dead children from becoming zombies */
     539        signal(SIGCHLD, SIG_IGN);
     540
     541/*
     542   This is how the buffers are used. The arrows indicate data flow.
    63543
    64544   +-------+     wridx1++     +------+     rdidx1++     +----------+
     
    70550   +-------+     size2++      +------+     size2--      +----------+
    71551
    72    Each session has got two buffers.
     552   size1: "how many bytes are buffered for pty between rdidx1 and wridx1?"
     553   size2: "how many bytes are buffered for socket between rdidx2 and wridx2?"
     554
     555   Each session has got two buffers. Buffers are circular. If sizeN == 0,
     556   buffer is empty. If sizeN == BUFSIZE, buffer is full. In both these cases
     557   rdidxN == wridxN.
    73558*/
    74 
    75 static int maxfd;
    76 
    77 static struct tsession *sessions;
    78 
    79 
    80 /*
    81    Remove all IAC's from the buffer pointed to by bf (received IACs are ignored
    82    and must be removed so as to not be interpreted by the terminal).  Make an
    83    uninterrupted string of characters fit for the terminal.  Do this by packing
    84    all characters meant for the terminal sequentially towards the end of bf.
    85 
    86    Return a pointer to the beginning of the characters meant for the terminal.
    87    and make *num_totty the number of characters that should be sent to
    88    the terminal.
    89 
    90    Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
    91    past (bf + len) then that IAC will be left unprocessed and *processed will be
    92    less than len.
    93 
    94    FIXME - if we mean to send 0xFF to the terminal then it will be escaped,
    95    what is the escape character?  We aren't handling that situation here.
    96 
    97    CR-LF ->'s CR mapping is also done here, for convenience
    98  */
    99 static char *
    100 remove_iacs(struct tsession *ts, int *pnum_totty)
    101 {
    102     unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1;
    103     unsigned char *ptr = ptr0;
    104     unsigned char *totty = ptr;
    105     unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
    106     int processed;
    107     int num_totty;
    108 
    109     while (ptr < end) {
    110         if (*ptr != IAC) {
    111             int c = *ptr;
    112             *totty++ = *ptr++;
    113             /* We now map \r\n ==> \r for pragmatic reasons.
    114              * Many client implementations send \r\n when
    115              * the user hits the CarriageReturn key.
    116              */
    117             if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end)
    118                 ptr++;
    119         } else {
    120             /*
    121              * TELOPT_NAWS support!
    122              */
    123             if ((ptr+2) >= end) {
    124                 /* only the beginning of the IAC is in the
    125                 buffer we were asked to process, we can't
    126                 process this char. */
    127                 break;
    128             }
    129 
    130             /*
    131              * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
    132              */
    133             else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
    134                 struct winsize ws;
    135                 if ((ptr+8) >= end)
    136                     break;  /* incomplete, can't process */
    137                 ws.ws_col = (ptr[3] << 8) | ptr[4];
    138                 ws.ws_row = (ptr[5] << 8) | ptr[6];
    139                 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
    140                 ptr += 9;
    141             } else {
    142                 /* skip 3-byte IAC non-SB cmd */
    143 #if DEBUG
    144                 fprintf(stderr, "Ignoring IAC %s,%s\n",
    145                     TELCMD(ptr[1]), TELOPT(ptr[2]));
    146 #endif
    147                 ptr += 3;
    148             }
    149         }
    150     }
    151 
    152     processed = ptr - ptr0;
    153     num_totty = totty - ptr0;
    154     /* the difference between processed and num_to tty
    155        is all the iacs we removed from the stream.
    156        Adjust buf1 accordingly. */
    157     ts->wridx1 += processed - num_totty;
    158     ts->size1 -= processed - num_totty;
    159     *pnum_totty = num_totty;
    160     /* move the chars meant for the terminal towards the end of the
    161     buffer. */
    162     return memmove(ptr - num_totty, ptr0, num_totty);
    163 }
    164 
    165 
    166 static int
    167 getpty(char *line, int size)
    168 {
    169     int p;
    170 #if ENABLE_FEATURE_DEVPTS
    171     p = open("/dev/ptmx", O_RDWR);
    172     if (p > 0) {
    173         const char *name;
    174         grantpt(p);
    175         unlockpt(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;
    183     }
    184 #else
    185     struct stat stb;
    186     int i;
    187     int j;
    188 
    189     strcpy(line, "/dev/ptyXX");
    190 
    191     for (i = 0; i < 16; i++) {
    192         line[8] = "pqrstuvwxyzabcde"[i];
    193         line[9] = '0';
    194         if (stat(line, &stb) < 0) {
    195             continue;
    196         }
    197         for (j = 0; j < 16; j++) {
    198             line[9] = j < 10 ? j + '0' : j - 10 + 'a';
    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) {
    203                 line[5] = 't';
    204                 return p;
    205             }
    206         }
    207     }
    208 #endif /* FEATURE_DEVPTS */
    209     return -1;
    210 }
    211 
    212 
    213 static void
    214 send_iac(struct tsession *ts, unsigned char command, int option)
    215 {
    216     /* We rely on that there is space in the buffer for now. */
    217     char *b = ts->buf2 + ts->rdidx2;
    218     *b++ = IAC;
    219     *b++ = command;
    220     *b++ = option;
    221     ts->rdidx2 += 3;
    222     ts->size2 += 3;
    223 }
    224 
    225 
    226 static struct tsession *
    227 make_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];
    232     struct termios termbuf;
    233     int fd, pid;
    234     char tty_name[32];
    235     struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
    236 
    237     ts->buf1 = (char *)(&ts[1]);
    238     ts->buf2 = ts->buf1 + BUFSIZE;
    239 
    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
    254     ts->sockfd_write = 1;
    255     /* xzalloc: ts->sockfd_read = 0; */
    256     ndelay_on(0);
    257     ndelay_on(1);
    258 #endif
    259     /* Make the telnet client understand we will echo characters so it
    260      * should not do it locally. We don't tell the client to run linemode,
    261      * because we want to handle line editing and tab completion and other
    262      * stuff that requires char-by-char support. */
    263     send_iac(ts, DO, TELOPT_ECHO);
    264     send_iac(ts, DO, TELOPT_NAWS);
    265     send_iac(ts, DO, TELOPT_LFLOW);
    266     send_iac(ts, WILL, TELOPT_ECHO);
    267     send_iac(ts, WILL, TELOPT_SGA);
    268 
    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);
    315 }
    316 
    317 #if ENABLE_FEATURE_TELNETD_STANDALONE
    318 
    319 static void
    320 free_session(struct tsession *ts)
    321 {
    322     struct tsession *t = sessions;
    323 
    324     /* unlink this telnet session from the session list */
    325     if (t == ts)
    326         sessions = ts->next;
    327     else {
    328         while (t->next != ts)
    329             t = t->next;
    330         t->next = ts->next;
    331     }
    332 
    333     kill(ts->shell_pid, SIGKILL);
    334     wait4(ts->shell_pid, NULL, 0, NULL);
    335     close(ts->ptyfd);
    336     close(ts->sockfd_read);
    337     /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */
    338     close(ts->sockfd_write);
    339     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     }
    353 }
    354 
    355 #else /* !FEATURE_TELNETD_STANDALONE */
    356 
    357 /* Never actually called */
    358 void free_session(struct tsession *ts);
    359 
    360 #endif
    361 
    362 
    363 int telnetd_main(int argc, char **argv);
    364 int telnetd_main(int argc, char **argv)
    365 {
    366     fd_set rdfdset, wrfdset;
    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
    420     sessions = make_new_session();
    421 #endif
    422 
    423     /* We don't want to die if just one session is broken */
    424     signal(SIGPIPE, SIG_IGN);
    425 
    426559 again:
    427560    FD_ZERO(&rdfdset);
    428561    FD_ZERO(&wrfdset);
     562
     563    /* Select on the master socket, all telnet sockets and their
     564     * ptys if there is room in their session buffers.
     565     * NB: scalability problem: we recalculate entire bitmap
     566     * before each select. Can be a problem with 500+ connections. */
     567    ts = G.sessions;
     568    while (ts) {
     569        struct tsession *next = ts->next; /* in case we free ts */
     570        if (ts->shell_pid == -1) {
     571            /* Child died and we detected that */
     572            free_session(ts);
     573        } else {
     574            if (ts->size1 > 0)       /* can write to pty */
     575                FD_SET(ts->ptyfd, &wrfdset);
     576            if (ts->size1 < BUFSIZE) /* can read from socket */
     577                FD_SET(ts->sockfd_read, &rdfdset);
     578            if (ts->size2 > 0)       /* can write to socket */
     579                FD_SET(ts->sockfd_write, &wrfdset);
     580            if (ts->size2 < BUFSIZE) /* can read from pty */
     581                FD_SET(ts->ptyfd, &rdfdset);
     582        }
     583        ts = next;
     584    }
    429585    if (!IS_INETD) {
    430586        FD_SET(master_fd, &rdfdset);
    431587        /* 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)
     588         * take master_fd into account when it finds new
     589         * maxfd among remaining fd's */
     590        if (master_fd > G.maxfd)
     591            G.maxfd = master_fd;
     592    }
     593
     594    {
     595        struct timeval *tv_ptr = NULL;
     596#if ENABLE_FEATURE_TELNETD_INETD_WAIT
     597        struct timeval tv;
     598        if ((opt & OPT_WAIT) && !G.sessions) {
     599            tv.tv_sec = sec_linger;
     600            tv.tv_usec = 0;
     601            tv_ptr = &tv;
     602        }
     603#endif
     604        count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
     605    }
     606    if (count == 0) /* "telnetd -w SEC" timed out */
    457607        return 0;
     608    if (count < 0)
     609        goto again; /* EINTR or ENOMEM */
    458610
    459611#if ENABLE_FEATURE_TELNETD_STANDALONE
    460     /* First check for and accept new sessions. */
     612    /* Check for and accept new sessions */
    461613    if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
    462614        int fd;
    463615        struct tsession *new_ts;
    464616
    465         fd = accept(master_fd, NULL, 0);
     617        fd = accept(master_fd, NULL, NULL);
    466618        if (fd < 0)
    467619            goto again;
    468         /* Create a new session and link it into our active list */
    469         new_ts = make_new_session(fd, fd);
     620        close_on_exec_on(fd);
     621
     622        /* Create a new session and link it into active list */
     623        new_ts = make_new_session(fd);
    470624        if (new_ts) {
    471             new_ts->next = sessions;
    472             sessions = new_ts;
     625            new_ts->next = G.sessions;
     626            G.sessions = new_ts;
    473627        } else {
    474628            close(fd);
     
    477631#endif
    478632
    479     /* Then check for data tunneling. */
    480     ts = sessions;
     633    /* Then check for data tunneling */
     634    ts = G.sessions;
    481635    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)) {
     636        struct tsession *next = ts->next; /* in case we free ts */
     637
     638        if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
    485639            int num_totty;
    486             char *ptr;
    487             /* Write to pty from buffer 1. */
     640            unsigned char *ptr;
     641            /* Write to pty from buffer 1 */
    488642            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;
    496                 continue;
     643            count = safe_write(ts->ptyfd, ptr, num_totty);
     644            if (count < 0) {
     645                if (errno == EAGAIN)
     646                    goto skip1;
     647                goto kill_session;
    497648            }
    498             ts->wridx1 += w;
    499             ts->size1 -= w;
    500             if (ts->wridx1 == BUFSIZE)
     649            ts->size1 -= count;
     650            ts->wridx1 += count;
     651            if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */
    501652                ts->wridx1 = 0;
    502653        }
    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;
     654 skip1:
     655        if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) {
     656            /* Write to socket from buffer 2 */
     657            count = MIN(BUFSIZE - ts->wridx2, ts->size2);
     658            count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
     659            if (count < 0) {
     660                if (errno == EAGAIN)
     661                    goto skip2;
     662                goto kill_session;
    515663            }
    516             ts->wridx2 += w;
    517             ts->size2 -= w;
    518             if (ts->wridx2 == BUFSIZE)
     664            ts->size2 -= count;
     665            ts->wridx2 += count;
     666            if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */
    519667                ts->wridx2 = 0;
    520668        }
    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)
    536                     continue;
    537             ts->rdidx1 += r;
    538             ts->size1 += r;
    539             if (ts->rdidx1 == BUFSIZE)
    540                 ts->rdidx1 = 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)
    558                 ts->rdidx2 = 0;
    559         }
    560 
     669 skip2:
     670        /* Should not be needed, but... remove_iacs is actually buggy
     671         * (it cannot process iacs which wrap around buffer's end)!
     672         * Since properly fixing it requires writing bigger code,
     673         * we rely instead on this code making it virtually impossible
     674         * to have wrapped iac (people don't type at 2k/second).
     675         * It also allows for bigger reads in common case. */
    561676        if (ts->size1 == 0) {
    562677            ts->rdidx1 = 0;
     
    567682            ts->wridx2 = 0;
    568683        }
     684
     685        if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
     686            /* Read from socket to buffer 1 */
     687            count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
     688            count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
     689            if (count <= 0) {
     690                if (count < 0 && errno == EAGAIN)
     691                    goto skip3;
     692                goto kill_session;
     693            }
     694            /* Ignore trailing NUL if it is there */
     695            if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
     696                --count;
     697            }
     698            ts->size1 += count;
     699            ts->rdidx1 += count;
     700            if (ts->rdidx1 >= BUFSIZE) /* actually == BUFSIZE */
     701                ts->rdidx1 = 0;
     702        }
     703 skip3:
     704        if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
     705            /* Read from pty to buffer 2 */
     706            count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
     707            count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
     708            if (count <= 0) {
     709                if (count < 0 && errno == EAGAIN)
     710                    goto skip4;
     711                goto kill_session;
     712            }
     713            ts->size2 += count;
     714            ts->rdidx2 += count;
     715            if (ts->rdidx2 >= BUFSIZE) /* actually == BUFSIZE */
     716                ts->rdidx2 = 0;
     717        }
     718 skip4:
    569719        ts = next;
    570     }
     720        continue;
     721 kill_session:
     722        if (ts->shell_pid > 0)
     723            update_utmp(ts->shell_pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL);
     724        free_session(ts);
     725        ts = next;
     726    }
     727
    571728    goto again;
    572729}
  • branches/2.2.9/mindi-busybox/networking/tftp.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* -------------------------------------------------------------------------
    3  * tftp.c
    4  *
    5  * A simple tftp client for busybox.
     2/*
     3 * A simple tftp client/server for busybox.
    64 * Tries to follow RFC1350.
    75 * Only "octet" mode supported.
     
    1715 * utftp:  Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
    1816 *
    19  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    20  * ------------------------------------------------------------------------- */
    21 
     17 * tftpd added by Denys Vlasenko & Vladimir Dronnikov
     18 *
     19 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     20 */
    2221#include "libbb.h"
    2322
    24 
    2523#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
    2624
    27 #define TFTP_BLOCKSIZE_DEFAULT 512  /* according to RFC 1350, don't change */
    28 #define TFTP_TIMEOUT 5  /* seconds */
    29 #define TFTP_NUM_RETRIES 5 /* number of retries */
     25#define TFTP_BLKSIZE_DEFAULT       512  /* according to RFC 1350, don't change */
     26#define TFTP_BLKSIZE_DEFAULT_STR "512"
     27/* Was 50 ms but users asked to bump it up a bit */
     28#define TFTP_TIMEOUT_MS            100
     29#define TFTP_MAXTIMEOUT_MS        2000
     30#define TFTP_NUM_RETRIES            12  /* number of backed-off retries */
    3031
    3132/* opcodes we support */
     
    3738#define TFTP_OACK  6
    3839
     40/* error codes sent over network (we use only 0, 1, 3 and 8) */
     41/* generic (error message is included in the packet) */
     42#define ERR_UNSPEC   0
     43#define ERR_NOFILE   1
     44#define ERR_ACCESS   2
     45/* disk full or allocation exceeded */
     46#define ERR_WRITE    3
     47#define ERR_OP       4
     48#define ERR_BAD_ID   5
     49#define ERR_EXIST    6
     50#define ERR_BAD_USER 7
     51#define ERR_BAD_OPT  8
     52
     53/* masks coming from getopt32 */
     54enum {
     55    TFTP_OPT_GET = (1 << 0),
     56    TFTP_OPT_PUT = (1 << 1),
     57    /* pseudo option: if set, it's tftpd */
     58    TFTPD_OPT = (1 << 7) * ENABLE_TFTPD,
     59    TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD,
     60    TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD,
     61    TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD,
     62};
     63
    3964#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
    40 #define USE_GETPUT(...)
     65#define IF_GETPUT(...)
    4166#define CMD_GET(cmd) 1
    4267#define CMD_PUT(cmd) 0
    4368#elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
    44 #define USE_GETPUT(...)
     69#define IF_GETPUT(...)
    4570#define CMD_GET(cmd) 0
    4671#define CMD_PUT(cmd) 1
    4772#else
    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)
     73#define IF_GETPUT(...) __VA_ARGS__
     74#define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET)
     75#define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT)
    5276#endif
    5377/* NB: in the code below
     
    5680
    5781
     82struct globals {
     83    /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
     84    uint8_t error_pkt[4 + 32];
     85    char *user_opt;
     86    /* used in tftpd_main(), a bit big for stack: */
     87    char block_buf[TFTP_BLKSIZE_DEFAULT];
     88#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
     89    off_t pos;
     90    off_t size;
     91    const char *file;
     92    bb_progress_t pmt;
     93#endif
     94} FIX_ALIASING;
     95#define G (*(struct globals*)&bb_common_bufsiz1)
     96struct BUG_G_too_big {
     97    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     98};
     99#define block_buf        (G.block_buf   )
     100#define user_opt         (G.user_opt    )
     101#define error_pkt        (G.error_pkt   )
     102#define INIT_G() do { } while (0)
     103
     104#define error_pkt_reason (error_pkt[3])
     105#define error_pkt_str    (error_pkt + 4)
     106
     107#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
     108static void tftp_progress_update(void)
     109{
     110    bb_progress_update(&G.pmt, G.file, 0, G.pos, G.size);
     111}
     112static void tftp_progress_init(void)
     113{
     114    bb_progress_init(&G.pmt);
     115    tftp_progress_update();
     116}
     117static void tftp_progress_done(void)
     118{
     119    if (G.pmt.inited) {
     120        tftp_progress_update();
     121        bb_putchar_stderr('\n');
     122        G.pmt.inited = 0;
     123    }
     124}
     125#else
     126# define tftp_progress_init() ((void)0)
     127# define tftp_progress_done() ((void)0)
     128#endif
     129
    58130#if ENABLE_FEATURE_TFTP_BLOCKSIZE
    59131
    60 static int tftp_blocksize_check(int blocksize, int bufsize)
     132static int tftp_blksize_check(const char *blksize_str, int maxsize)
    61133{
    62     /* Check if the blocksize is valid:
     134    /* Check if the blksize is valid:
    63135     * RFC2348 says between 8 and 65464,
    64136     * but our implementation makes it impossible
    65      * to use blocksizes smaller than 22 octets.
    66      */
    67 
    68     if ((bufsize && (blocksize > bufsize))
    69      || (blocksize < 8) || (blocksize > 65564)
     137     * to use blksizes smaller than 22 octets. */
     138    unsigned blksize = bb_strtou(blksize_str, NULL, 10);
     139    if (errno
     140     || (blksize < 24) || (blksize > maxsize)
    70141    ) {
    71         bb_error_msg("bad blocksize");
    72         return 0;
    73     }
    74 
    75     return blocksize;
     142        bb_error_msg("bad blocksize '%s'", blksize_str);
     143        return -1;
     144    }
     145# if ENABLE_TFTP_DEBUG
     146    bb_error_msg("using blksize %u", blksize);
     147# endif
     148    return blksize;
    76149}
    77150
    78 static char *tftp_option_get(char *buf, int len, const char *option)
     151static char *tftp_get_option(const char *option, char *buf, int len)
    79152{
    80153    int opt_val = 0;
     
    82155    int k;
    83156
     157    /* buf points to:
     158     * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */
     159
    84160    while (len > 0) {
    85         /* Make sure the options are terminated correctly */
     161        /* Make sure options are terminated correctly */
    86162        for (k = 0; k < len; k++) {
    87163            if (buf[k] == '\0') {
     
    91167        return NULL;
    92168 nul_found:
    93         if (opt_val == 0) {
     169        if (opt_val == 0) { /* it's "name" part */
    94170            if (strcasecmp(buf, option) == 0) {
    95171                opt_found = 1;
     
    110186#endif
    111187
    112 static int tftp( USE_GETPUT(const int cmd,)
     188static int tftp_protocol(
     189        /* NULL if tftp, !NULL if tftpd: */
     190        len_and_sockaddr *our_lsa,
    113191        len_and_sockaddr *peer_lsa,
    114         const char *remotefile, const int localfd,
    115         unsigned port, int tftp_bufsize)
     192        const char *local_file
     193        IF_TFTP(, const char *remote_file)
     194#if !ENABLE_TFTP
     195# define remote_file NULL
     196#endif
     197        /* 1 for tftp; 1/0 for tftpd depending whether client asked about it: */
     198        IF_FEATURE_TFTP_BLOCKSIZE(, int want_transfer_size)
     199        IF_FEATURE_TFTP_BLOCKSIZE(, int blksize))
    116200{
    117     struct timeval tv;
    118     fd_set rfds;
    119     int socketfd;
     201#if !ENABLE_FEATURE_TFTP_BLOCKSIZE
     202    enum { blksize = TFTP_BLKSIZE_DEFAULT };
     203#endif
     204
     205    struct pollfd pfd[1];
     206#define socket_fd (pfd[0].fd)
    120207    int len;
    121208    int send_len;
    122     USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
     209    IF_FEATURE_TFTP_BLOCKSIZE(smallint expect_OACK = 0;)
    123210    smallint finished = 0;
    124211    uint16_t opcode;
    125     uint16_t block_nr = 1;
     212    uint16_t block_nr;
    126213    uint16_t recv_blk;
    127     int timeout = TFTP_NUM_RETRIES;
     214    int open_mode, local_fd;
     215    int retries, waittime_ms;
     216    int io_bufsize = blksize + 4;
    128217    char *cp;
    129 
    130     unsigned org_port;
    131     len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len);
    132 
    133218    /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
    134      * size varies meaning BUFFERS_GO_ON_STACK would fail */
    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);
    143 
    144     /* build opcode */
    145     opcode = TFTP_WRQ;
    146     if (CMD_GET(cmd)) {
    147         opcode = TFTP_RRQ;
    148     }
     219     * size varies meaning BUFFERS_GO_ON_STACK would fail.
     220     *
     221     * We must keep the transmit and receive buffers separate
     222     * in case we rcv a garbage pkt - we need to rexmit the last pkt.
     223     */
     224    char *xbuf = xmalloc(io_bufsize);
     225    char *rbuf = xmalloc(io_bufsize);
     226
     227    socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
     228    setsockopt_reuseaddr(socket_fd);
     229
     230    if (!ENABLE_TFTP || our_lsa) { /* tftpd */
     231        /* Create a socket which is:
     232         * 1. bound to IP:port peer sent 1st datagram to,
     233         * 2. connected to peer's IP:port
     234         * This way we will answer from the IP:port peer
     235         * expects, will not get any other packets on
     236         * the socket, and also plain read/write will work. */
     237        xbind(socket_fd, &our_lsa->u.sa, our_lsa->len);
     238        xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
     239
     240        /* Is there an error already? Send pkt and bail out */
     241        if (error_pkt_reason || error_pkt_str[0])
     242            goto send_err_pkt;
     243
     244        if (user_opt) {
     245            struct passwd *pw = xgetpwnam(user_opt);
     246            change_identity(pw); /* initgroups, setgid, setuid */
     247        }
     248    }
     249
     250    /* Prepare open mode */
     251    if (CMD_PUT(option_mask32)) {
     252        open_mode = O_RDONLY;
     253    } else {
     254        open_mode = O_WRONLY | O_TRUNC | O_CREAT;
     255#if ENABLE_TFTPD
     256        if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) {
     257            /* tftpd without -c */
     258            open_mode = O_WRONLY | O_TRUNC;
     259        }
     260#endif
     261    }
     262
     263    /* Examples of network traffic.
     264     * Note two cases when ACKs with block# of 0 are sent.
     265     *
     266     * Download without options:
     267     * tftp -> "\0\1FILENAME\0octet\0"
     268     *         "\0\3\0\1FILEDATA..." <- tftpd
     269     * tftp -> "\0\4\0\1"
     270     * ...
     271     * Download with option of blksize 16384:
     272     * tftp -> "\0\1FILENAME\0octet\0blksize\00016384\0"
     273     *         "\0\6blksize\00016384\0" <- tftpd
     274     * tftp -> "\0\4\0\0"
     275     *         "\0\3\0\1FILEDATA..." <- tftpd
     276     * tftp -> "\0\4\0\1"
     277     * ...
     278     * Upload without options:
     279     * tftp -> "\0\2FILENAME\0octet\0"
     280     *         "\0\4\0\0" <- tftpd
     281     * tftp -> "\0\3\0\1FILEDATA..."
     282     *         "\0\4\0\1" <- tftpd
     283     * ...
     284     * Upload with option of blksize 16384:
     285     * tftp -> "\0\2FILENAME\0octet\0blksize\00016384\0"
     286     *         "\0\6blksize\00016384\0" <- tftpd
     287     * tftp -> "\0\3\0\1FILEDATA..."
     288     *         "\0\4\0\1" <- tftpd
     289     * ...
     290     */
     291    block_nr = 1;
    149292    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 
     293
     294    if (!ENABLE_TFTP || our_lsa) { /* tftpd */
     295        /* Open file (must be after changing user) */
     296        local_fd = open(local_file, open_mode, 0666);
     297        if (local_fd < 0) {
     298            error_pkt_reason = ERR_NOFILE;
     299            strcpy((char*)error_pkt_str, "can't open file");
     300            goto send_err_pkt;
     301        }
     302/* gcc 4.3.1 would NOT optimize it out as it should! */
    163303#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")) {
     304        if (blksize != TFTP_BLKSIZE_DEFAULT || want_transfer_size) {
     305            /* Create and send OACK packet. */
     306            /* For the download case, block_nr is still 1 -
     307             * we expect 1st ACK from peer to be for (block_nr-1),
     308             * that is, for "block 0" which is our OACK pkt */
     309            opcode = TFTP_OACK;
     310            goto add_blksize_opt;
     311        }
     312#endif
     313        if (CMD_GET(option_mask32)) {
     314            /* It's upload and we don't send OACK.
     315             * We must ACK 1st packet (with filename)
     316             * as if it is "block 0" */
     317            block_nr = 0;
     318        }
     319
     320    } else { /* tftp */
     321        /* Open file (must be after changing user) */
     322        local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO;
     323        if (NOT_LONE_DASH(local_file))
     324            local_fd = xopen(local_file, open_mode);
     325/* Removing #if, or using if() statement instead of #if may lead to
     326 * "warning: null argument where non-null required": */
     327#if ENABLE_TFTP
     328        /* tftp */
     329
     330        /* We can't (and don't really need to) bind the socket:
     331         * we don't know from which local IP datagrams will be sent,
     332         * but kernel will pick the same IP every time (unless routing
     333         * table is changed), thus peer will see dgrams consistently
     334         * coming from the same IP.
     335         * We would like to connect the socket, but since peer's
     336         * UDP code can be less perfect than ours, _peer's_ IP:port
     337         * in replies may differ from IP:port we used to send
     338         * our first packet. We can connect() only when we get
     339         * first reply. */
     340
     341        /* build opcode */
     342        opcode = TFTP_WRQ;
     343        if (CMD_GET(option_mask32)) {
     344            opcode = TFTP_RRQ;
     345        }
     346        /* add filename and mode */
     347        /* fill in packet if the filename fits into xbuf */
     348        len = strlen(remote_file) + 1;
     349        if (2 + len + sizeof("octet") >= io_bufsize) {
    168350            bb_error_msg("remote filename is too long");
    169351            goto ret;
    170352        }
    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;
     353        strcpy(cp, remote_file);
     354        cp += len;
     355        /* add "mode" part of the packet */
     356        strcpy(cp, "octet");
     357        cp += sizeof("octet");
     358
     359# if ENABLE_FEATURE_TFTP_BLOCKSIZE
     360        if (blksize == TFTP_BLKSIZE_DEFAULT && !want_transfer_size)
     361            goto send_pkt;
     362
     363        /* Need to add option to pkt */
     364        if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN tsize ") + sizeof(off_t)*3) {
     365            bb_error_msg("remote filename is too long");
     366            goto ret;
     367        }
     368        expect_OACK = 1;
     369# endif
     370#endif /* ENABLE_TFTP */
     371
     372#if ENABLE_FEATURE_TFTP_BLOCKSIZE
     373 add_blksize_opt:
     374        if (blksize != TFTP_BLKSIZE_DEFAULT) {
     375            /* add "blksize", <nul>, blksize, <nul> */
     376            strcpy(cp, "blksize");
     377            cp += sizeof("blksize");
     378            cp += snprintf(cp, 6, "%d", blksize) + 1;
     379        }
     380        if (want_transfer_size) {
     381            /* add "tsize", <nul>, size, <nul> (see RFC2349) */
     382            /* if tftp and downloading, we send "0" (since we opened local_fd with O_TRUNC)
     383             * and this makes server to send "tsize" option with the size */
     384            /* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */
     385            /* if tftpd and downloading, we are answering to client's request */
     386            /* if tftpd and uploading: !want_transfer_size, this code is not executed */
     387            struct stat st;
     388            strcpy(cp, "tsize");
     389            cp += sizeof("tsize");
     390            st.st_size = 0;
     391            fstat(local_fd, &st);
     392            cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1;
     393# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
     394            /* Save for progress bar. If 0 (tftp downloading),
     395             * we look at server's reply later */
     396            G.size = st.st_size;
     397            if (remote_file && st.st_size)
     398                tftp_progress_init();
     399# endif
     400        }
     401#endif
     402        /* First packet is built, so skip packet generation */
     403        goto send_pkt;
     404    }
    180405
    181406    /* Using mostly goto's - continue/break will be less clear
    182407     * in where we actually jump to */
    183 
    184408    while (1) {
    185409        /* Build ACK or DATA */
     
    189413        block_nr++;
    190414        opcode = TFTP_ACK;
    191         if (CMD_PUT(cmd)) {
     415        if (CMD_PUT(option_mask32)) {
    192416            opcode = TFTP_DATA;
    193             len = full_read(localfd, cp, tftp_bufsize - 4);
     417            len = full_read(local_fd, cp, blksize);
    194418            if (len < 0) {
    195                 bb_perror_msg(bb_msg_read_error);
    196                 goto ret;
    197             }
    198             if (len != (tftp_bufsize - 4)) {
     419                goto send_read_err_pkt;
     420            }
     421            if (len != blksize) {
    199422                finished = 1;
    200423            }
     
    207430        /* NB: send_len value is preserved in code below
    208431         * for potential resend */
     432
     433        retries = TFTP_NUM_RETRIES;  /* re-initialize */
     434        waittime_ms = TFTP_TIMEOUT_MS;
     435
    209436 send_again:
    210 #if ENABLE_DEBUG_TFTP
     437#if ENABLE_TFTP_DEBUG
    211438        fprintf(stderr, "sending %u bytes\n", send_len);
    212439        for (cp = xbuf; cp < &xbuf[send_len]; cp++)
     
    214441        fprintf(stderr, "\n");
    215442#endif
    216         xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len);
     443        xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
     444
     445#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
     446        if (ENABLE_TFTP && remote_file) /* tftp */
     447            G.pos = (block_nr - 1) * (uoff_t)blksize;
     448        if (G.pmt.inited)
     449            tftp_progress_update();
     450#endif
    217451        /* Was it final ACK? then exit */
    218452        if (finished && (opcode == TFTP_ACK))
    219453            goto ret;
    220454
    221         timeout = TFTP_NUM_RETRIES; /* re-initialize */
    222455 recv_again:
    223456        /* 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;
     457        /*pfd[0].fd = socket_fd;*/
     458        pfd[0].events = POLLIN;
     459        switch (safe_poll(pfd, 1, waittime_ms)) {
     460        default:
     461            /*bb_perror_msg("poll"); - done in safe_poll */
     462            goto ret;
     463        case 0:
     464            retries--;
     465            if (retries == 0) {
     466                tftp_progress_done();
     467                bb_error_msg("timeout");
     468                goto ret; /* no err packet sent */
     469            }
     470
     471            /* exponential backoff with limit */
     472            waittime_ms += waittime_ms/2;
     473            if (waittime_ms > TFTP_MAXTIMEOUT_MS) {
     474                waittime_ms = TFTP_MAXTIMEOUT_MS;
     475            }
     476
     477            goto send_again; /* resend last sent pkt */
    230478        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);
     479            if (!our_lsa) {
     480                /* tftp (not tftpd!) receiving 1st packet */
     481                our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
     482                len = recvfrom(socket_fd, rbuf, io_bufsize, 0,
     483                        &peer_lsa->u.sa, &peer_lsa->len);
     484                /* Our first dgram went to port 69
     485                 * but reply may come from different one.
     486                 * Remember and use this new port (and IP) */
     487                if (len >= 0)
     488                    xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
     489            } else {
     490                /* tftpd, or not the very first packet:
     491                 * socket is connect()ed, can just read from it. */
     492                /* Don't full_read()!
     493                 * This is not TCP, one read == one pkt! */
     494                len = safe_read(socket_fd, rbuf, io_bufsize);
     495            }
    235496            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)
     497                goto send_read_err_pkt;
     498            }
     499            if (len < 4) { /* too small? */
    248500                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:
     501            }
     502        }
     503
    263504        /* Process recv'ed packet */
    264505        opcode = ntohs( ((uint16_t*)rbuf)[0] );
    265506        recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
    266 
    267 #if ENABLE_DEBUG_TFTP
     507#if ENABLE_TFTP_DEBUG
    268508        fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
    269509#endif
    270 
    271510        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             };
     511            static const char errcode_str[] ALIGN1 =
     512                "\0"
     513                "file not found\0"
     514                "access violation\0"
     515                "disk full\0"
     516                "bad operation\0"
     517                "unknown transfer id\0"
     518                "file already exists\0"
     519                "no such user\0"
     520                "bad option";
    283521
    284522            const char *msg = "";
    285523
    286             if (rbuf[4] != '\0') {
     524            if (len > 4 && rbuf[4] != '\0') {
    287525                msg = &rbuf[4];
    288                 rbuf[tftp_bufsize - 1] = '\0';
    289             } else if (recv_blk < ARRAY_SIZE(errcode_str)) {
    290                 msg = errcode_str[recv_blk];
     526                rbuf[io_bufsize - 1] = '\0'; /* paranoia */
     527            } else if (recv_blk <= 8) {
     528                msg = nth_string(errcode_str, recv_blk);
    291529            }
    292530            bb_error_msg("server error: (%u) %s", recv_blk, msg);
     
    295533
    296534#if ENABLE_FEATURE_TFTP_BLOCKSIZE
    297         if (want_option_ack) {
    298             want_option_ack = 0;
    299 
     535        if (expect_OACK) {
     536            expect_OACK = 0;
    300537            if (opcode == TFTP_OACK) {
    301538                /* server seems to support options */
    302539                char *res;
    303540
    304                 res = tftp_option_get(&rbuf[2], len - 2, "blksize");
     541                res = tftp_get_option("blksize", &rbuf[2], len - 2);
    305542                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;
     543                    blksize = tftp_blksize_check(res, blksize);
     544                    if (blksize < 0) {
     545                        error_pkt_reason = ERR_BAD_OPT;
     546                        goto send_err_pkt;
    316547                    }
    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) */
     548                    io_bufsize = blksize + 4;
     549                }
     550# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
     551                if (remote_file && G.size == 0) { /* if we don't know it yet */
     552                    res = tftp_get_option("tsize", &rbuf[2], len - 2);
     553                    if (res) {
     554                        G.size = bb_strtoull(res, NULL, 10);
     555                        if (G.size)
     556                            tftp_progress_init();
     557                    }
     558                }
     559# endif
     560                if (CMD_GET(option_mask32)) {
     561                    /* We'll send ACK for OACK,
     562                     * such ACK has "block no" of 0 */
    323563                    block_nr = 0;
    324                     continue;
    325564                }
    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");
    334             tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
     565                continue;
     566            }
     567            /* rfc2347:
     568             * "An option not acknowledged by the server
     569             * must be ignored by the client and server
     570             * as if it were never requested." */
     571            if (blksize != TFTP_BLKSIZE_DEFAULT)
     572                bb_error_msg("falling back to blocksize "TFTP_BLKSIZE_DEFAULT_STR);
     573            blksize = TFTP_BLKSIZE_DEFAULT;
     574            io_bufsize = TFTP_BLKSIZE_DEFAULT + 4;
    335575        }
    336576#endif
     
    338578         * to get / block# we are about to send next time */
    339579
    340         if (CMD_GET(cmd) && (opcode == TFTP_DATA)) {
     580        if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) {
    341581            if (recv_blk == block_nr) {
    342                 len = full_write(localfd, &rbuf[4], len - 4);
    343                 if (len < 0) {
    344                     bb_perror_msg(bb_msg_write_error);
    345                     goto ret;
     582                int sz = full_write(local_fd, &rbuf[4], len - 4);
     583                if (sz != len - 4) {
     584                    strcpy((char*)error_pkt_str, bb_msg_write_error);
     585                    error_pkt_reason = ERR_WRITE;
     586                    goto send_err_pkt;
    346587                }
    347                 if (len != (tftp_bufsize - 4)) {
     588                if (sz != blksize) {
    348589                    finished = 1;
    349590                }
    350591                continue; /* send ACK */
    351592            }
     593/* Disabled to cope with servers with Sorcerer's Apprentice Syndrome */
     594#if 0
    352595            if (recv_blk == (block_nr - 1)) {
    353596                /* Server lost our TFTP_ACK.  Resend it */
     
    355598                continue;
    356599            }
    357         }
    358 
    359         if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) {
    360             /* did server ACK our last DATA pkt? */
     600#endif
     601        }
     602
     603        if (CMD_PUT(option_mask32) && (opcode == TFTP_ACK)) {
     604            /* did peer ACK our last DATA pkt? */
    361605            if (recv_blk == (uint16_t) (block_nr - 1)) {
    362606                if (finished)
     
    376620         * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
    377621         */
    378     }
     622    } /* end of "while (1)" */
    379623 ret:
    380624    if (ENABLE_FEATURE_CLEAN_UP) {
    381         close(socketfd);
     625        close(local_fd);
     626        close(socket_fd);
    382627        free(xbuf);
    383628        free(rbuf);
    384629    }
    385630    return finished == 0; /* returns 1 on failure */
     631
     632 send_read_err_pkt:
     633    strcpy((char*)error_pkt_str, bb_msg_read_error);
     634 send_err_pkt:
     635    if (error_pkt_str[0])
     636        bb_error_msg("%s", (char*)error_pkt_str);
     637    error_pkt[1] = TFTP_ERROR;
     638    xsendto(socket_fd, error_pkt, 4 + 1 + strlen((char*)error_pkt_str),
     639            &peer_lsa->u.sa, peer_lsa->len);
     640    return EXIT_FAILURE;
     641#undef remote_file
    386642}
    387643
    388 int tftp_main(int argc, char **argv);
    389 int tftp_main(int argc, char **argv)
     644#if ENABLE_TFTP
     645
     646int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     647int tftp_main(int argc UNUSED_PARAM, char **argv)
    390648{
    391649    len_and_sockaddr *peer_lsa;
    392     const char *localfile = NULL;
    393     const char *remotefile = NULL;
    394 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
    395     const char *sblocksize = NULL;
    396 #endif
     650    const char *local_file = NULL;
     651    const char *remote_file = NULL;
     652# if ENABLE_FEATURE_TFTP_BLOCKSIZE
     653    const char *blksize_str = TFTP_BLKSIZE_DEFAULT_STR;
     654    int blksize;
     655# endif
     656    int result;
    397657    int port;
    398     USE_GETPUT(int cmd;)
    399     int fd = -1;
    400     int flags = 0;
    401     int result;
    402     int blocksize = TFTP_BLOCKSIZE_DEFAULT;
     658    IF_GETPUT(int opt;)
     659
     660    INIT_G();
    403661
    404662    /* -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));
     663    opt_complementary = "" IF_FEATURE_TFTP_GET("g:") IF_FEATURE_TFTP_PUT("p:")
     664            IF_GETPUT("g--p:p--g:");
     665
     666    IF_GETPUT(opt =) getopt32(argv,
     667            IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p")
     668                "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:"),
     669            &local_file, &remote_file
     670            IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
    413671    argv += optind;
    414672
    415     flags = O_RDONLY;
    416     if (CMD_GET(cmd))
    417         flags = O_WRONLY | O_CREAT | O_TRUNC;
    418 
    419 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
    420     if (sblocksize) {
    421         blocksize = xatoi_u(sblocksize);
    422         if (!tftp_blocksize_check(blocksize, 0)) {
    423             return EXIT_FAILURE;
    424         }
    425     }
    426 #endif
    427 
    428     if (!localfile)
    429         localfile = remotefile;
    430     if (!remotefile)
    431         remotefile = localfile;
     673# if ENABLE_FEATURE_TFTP_BLOCKSIZE
     674    /* Check if the blksize is valid:
     675     * RFC2348 says between 8 and 65464 */
     676    blksize = tftp_blksize_check(blksize_str, 65564);
     677    if (blksize < 0) {
     678        //bb_error_msg("bad block size");
     679        return EXIT_FAILURE;
     680    }
     681# endif
     682
     683    if (remote_file) {
     684        if (!local_file) {
     685            const char *slash = strrchr(remote_file, '/');
     686            local_file = slash ? slash + 1 : remote_file;
     687        }
     688    } else {
     689        remote_file = local_file;
     690    }
     691
    432692    /* Error if filename or host is not known */
    433     if (!remotefile || !argv[0])
     693    if (!remote_file || !argv[0])
    434694        bb_show_usage();
    435 
    436     fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
    437     if (!LONE_DASH(localfile)) {
    438         fd = xopen(localfile, flags);
    439     }
    440695
    441696    port = bb_lookup_port(argv[1], "udp", 69);
    442697    peer_lsa = xhost2sockaddr(argv[0], port);
    443698
    444 #if ENABLE_DEBUG_TFTP
    445     fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n",
    446             xmalloc_sockaddr2dotted(&peer_lsa->sa),
    447             remotefile, localfile);
    448 #endif
    449 
    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);
     699# if ENABLE_TFTP_DEBUG
     700    fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
     701            xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
     702            remote_file, local_file);
     703# endif
     704
     705# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
     706    G.file = remote_file;
     707# endif
     708    result = tftp_protocol(
     709        NULL /*our_lsa*/, peer_lsa,
     710        local_file, remote_file
     711        IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* want_transfer_size */)
     712        IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
     713    );
     714    tftp_progress_done();
     715
     716    if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) {
     717        unlink(local_file);
    456718    }
    457719    return result;
    458720}
    459721
     722#endif /* ENABLE_TFTP */
     723
     724#if ENABLE_TFTPD
     725int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     726int tftpd_main(int argc UNUSED_PARAM, char **argv)
     727{
     728    len_and_sockaddr *our_lsa;
     729    len_and_sockaddr *peer_lsa;
     730    char *local_file, *mode;
     731    const char *error_msg;
     732    int opt, result, opcode;
     733    IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
     734    IF_FEATURE_TFTP_BLOCKSIZE(int want_transfer_size = 0;)
     735
     736    INIT_G();
     737
     738    our_lsa = get_sock_lsa(STDIN_FILENO);
     739    if (!our_lsa) {
     740        /* This is confusing:
     741         *bb_error_msg_and_die("stdin is not a socket");
     742         * Better: */
     743        bb_show_usage();
     744        /* Help text says that tftpd must be used as inetd service,
     745         * which is by far the most usual cause of get_sock_lsa
     746         * failure */
     747    }
     748    peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
     749    peer_lsa->len = our_lsa->len;
     750
     751    /* Shifting to not collide with TFTP_OPTs */
     752    opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:", &user_opt) << 8);
     753    argv += optind;
     754    if (argv[0])
     755        xchdir(argv[0]);
     756
     757    result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
     758            0 /* flags */,
     759            &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
     760
     761    error_msg = "malformed packet";
     762    opcode = ntohs(*(uint16_t*)block_buf);
     763    if (result < 4 || result >= sizeof(block_buf)
     764     || block_buf[result-1] != '\0'
     765     || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
     766         IF_GETPUT(&&)
     767         IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
     768        )
     769    ) {
     770        goto err;
     771    }
     772    local_file = block_buf + 2;
     773    if (local_file[0] == '.' || strstr(local_file, "/.")) {
     774        error_msg = "dot in file name";
     775        goto err;
     776    }
     777    mode = local_file + strlen(local_file) + 1;
     778    if (mode >= block_buf + result || strcmp(mode, "octet") != 0) {
     779        goto err;
     780    }
     781# if ENABLE_FEATURE_TFTP_BLOCKSIZE
     782    {
     783        char *res;
     784        char *opt_str = mode + sizeof("octet");
     785        int opt_len = block_buf + result - opt_str;
     786        if (opt_len > 0) {
     787            res = tftp_get_option("blksize", opt_str, opt_len);
     788            if (res) {
     789                blksize = tftp_blksize_check(res, 65564);
     790                if (blksize < 0) {
     791                    error_pkt_reason = ERR_BAD_OPT;
     792                    /* will just send error pkt */
     793                    goto do_proto;
     794                }
     795            }
     796            if (opcode != TFTP_WRQ /* download? */
     797            /* did client ask us about file size? */
     798             && tftp_get_option("tsize", opt_str, opt_len)
     799            ) {
     800                want_transfer_size = 1;
     801            }
     802        }
     803    }
     804# endif
     805
     806    if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
     807        if (opt & TFTPD_OPT_r) {
     808            /* This would mean "disk full" - not true */
     809            /*error_pkt_reason = ERR_WRITE;*/
     810            error_msg = bb_msg_write_error;
     811            goto err;
     812        }
     813        IF_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
     814    } else {
     815        IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
     816    }
     817
     818    /* NB: if error_pkt_str or error_pkt_reason is set up,
     819     * tftp_protocol() just sends one error pkt and returns */
     820
     821 do_proto:
     822    close(STDIN_FILENO); /* close old, possibly wildcard socket */
     823    /* tftp_protocol() will create new one, bound to particular local IP */
     824    result = tftp_protocol(
     825        our_lsa, peer_lsa,
     826        local_file IF_TFTP(, NULL /*remote_file*/)
     827        IF_FEATURE_TFTP_BLOCKSIZE(, want_transfer_size)
     828        IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
     829    );
     830
     831    return result;
     832 err:
     833    strcpy((char*)error_pkt_str, error_msg);
     834    goto do_proto;
     835}
     836
     837#endif /* ENABLE_TFTPD */
     838
    460839#endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */
  • branches/2.2.9/mindi-busybox/networking/traceroute.c

    r1765 r2725  
    2323 */
    2424
    25 //#define version "1.4a12"
    26 
     25/*
     26 *  traceroute6
     27 *
     28 *      Modified for NRL 4.4BSD IPv6 release.
     29 *      07/31/96 bgp
     30 *
     31 *  Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt>
     32 *  31/07/1996
     33 *
     34 *  As ICMP error messages for IPv6 now include more than 8 bytes
     35 *  UDP datagrams are now sent via an UDP socket instead of magic
     36 *  RAW socket tricks.
     37 *
     38 *  Converted to busybox applet by Leonid Lisovskiy <lly@sf.net>
     39 *  2009-11-16
     40 */
    2741
    2842/*
     
    215229#include <netinet/ip.h>
    216230#include <netinet/ip_icmp.h>
     231#if ENABLE_FEATURE_IPV6
     232# include <netinet/ip6.h>
     233# include <netinet/icmp6.h>
     234# ifndef SOL_IPV6
     235#  define SOL_IPV6 IPPROTO_IPV6
     236# endif
     237#endif
    217238
    218239#include "libbb.h"
    219240#include "inet_common.h"
    220241
    221 
    222 /*
    223  * Definitions for internet protocol version 4.
    224  * Per RFC 791, September 1981.
    225  */
    226 #define IPVERSION 4
    227 
    228242#ifndef IPPROTO_ICMP
    229 /* Grrrr.... */
    230 #define IPPROTO_ICMP 1
     243# define IPPROTO_ICMP 1
    231244#endif
    232245#ifndef IPPROTO_IP
    233 #define IPPROTO_IP 0
    234 #endif
    235 
    236 /*
    237  * Overlay for ip header used by other protocols (tcp, udp).
    238  */
    239 struct ipovly {
    240     unsigned char  ih_x1[9];               /* (unused) */
    241     unsigned char  ih_pr;                  /* protocol */
    242     short   ih_len;                 /* protocol length */
    243     struct  in_addr ih_src;         /* source internet address */
    244     struct  in_addr ih_dst;         /* destination internet address */
     246# define IPPROTO_IP 0
     247#endif
     248
     249
     250#define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
     251            IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \
     252            "4" IF_TRACEROUTE6("6")
     253enum {
     254    OPT_DONT_FRAGMNT = (1 << 0),    /* F */
     255    OPT_USE_ICMP     = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */
     256    OPT_TTL_FLAG     = (1 << 2),    /* l */
     257    OPT_ADDR_NUM     = (1 << 3),    /* n */
     258    OPT_BYPASS_ROUTE = (1 << 4),    /* r */
     259    OPT_DEBUG        = (1 << 5),    /* d */
     260    OPT_VERBOSE      = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */
     261    OPT_IP_CHKSUM    = (1 << 7),    /* x */
     262    OPT_TOS          = (1 << 8),    /* t */
     263    OPT_DEVICE       = (1 << 9),    /* i */
     264    OPT_MAX_TTL      = (1 << 10),   /* m */
     265    OPT_PORT         = (1 << 11),   /* p */
     266    OPT_NPROBES      = (1 << 12),   /* q */
     267    OPT_SOURCE       = (1 << 13),   /* s */
     268    OPT_WAITTIME     = (1 << 14),   /* w */
     269    OPT_PAUSE_MS     = (1 << 15),   /* z */
     270    OPT_FIRST_TTL    = (1 << 16),   /* f */
     271    OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */
     272    OPT_IPV4         = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)),   /* 4 */
     273    OPT_IPV6         = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */
    245274};
    246 
    247 /*
    248  * UDP kernel structures and variables.
    249  */
    250 struct udpiphdr {
    251     struct  ipovly ui_i;            /* overlaid ip structure */
    252     struct  udphdr ui_u;            /* udp header */
     275#define verbose (option_mask32 & OPT_VERBOSE)
     276
     277enum {
     278    SIZEOF_ICMP_HDR = 8,
     279    rcvsock = 3, /* receive (icmp) socket file descriptor */
     280    sndsock = 4, /* send (udp/icmp) socket file descriptor */
    253281};
    254 #define ui_next         ui_i.ih_next
    255 #define ui_prev         ui_i.ih_prev
    256 #define ui_x1           ui_i.ih_x1
    257 #define ui_pr           ui_i.ih_pr
    258 #define ui_len          ui_i.ih_len
    259 #define ui_src          ui_i.ih_src
    260 #define ui_dst          ui_i.ih_dst
    261 #define ui_sport        ui_u.uh_sport
    262 #define ui_dport        ui_u.uh_dport
    263 #define ui_ulen         ui_u.uh_ulen
    264 #define ui_sum          ui_u.uh_sum
    265 
    266 
    267 /* Host name and address list */
    268 struct hostinfo {
    269     char *name;
    270     int n;
    271     uint32_t *addrs;
    272 };
    273282
    274283/* Data section of the probe packet */
    275 struct outdata {
     284struct outdata_t {
    276285    unsigned char seq;             /* sequence number of this packet */
    277286    unsigned char ttl;             /* ttl packet left with */
    278287// UNUSED. Retaining to have the same packet size.
    279     struct timeval tv_UNUSED ATTRIBUTE_PACKED; /* time packet left */
     288    struct timeval tv_UNUSED PACKED; /* time packet left */
    280289};
    281290
    282 struct IFADDRLIST {
    283     uint32_t addr;
    284     char device[sizeof(struct ifreq)];
     291#if ENABLE_TRACEROUTE6
     292struct outdata6_t {
     293    uint32_t ident6;
     294    uint32_t seq6;
     295    struct timeval tv_UNUSED PACKED; /* time packet left */
    285296};
    286 
    287 
    288 static struct ip *outip;               /* last output (udp) packet */
    289 static struct udphdr *outudp;          /* last output (udp) packet */
    290 static struct outdata *outdata;        /* last output (udp) packet */
    291 
    292 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    293 static struct icmp *outicmp;           /* last output (icmp) packet */
    294 #endif
    295 
    296 static int s;                          /* receive (icmp) socket file descriptor */
    297 static int sndsock;                    /* send (udp/icmp) socket file descriptor */
    298 
    299 static int packlen;                    /* total length of packet */
    300 static int minpacket;                  /* min ip packet size */
    301 static int maxpacket = 32 * 1024;      /* max ip packet size */
    302 static int pmtu;                       /* Path MTU Discovery (RFC1191) */
    303 
    304 static char *hostname;
    305 
    306 static uint16_t ident;
    307 static uint16_t port = 32768 + 666;     /* start udp dest port # for probe packets */
    308 
    309 static int waittime = 5;               /* time to wait for response (in seconds) */
    310 static int doipcksum = 1;              /* calculate ip checksums by default */
    311 
     297#endif
     298
     299struct globals {
     300    struct ip *outip;
     301    struct outdata_t *outdata;
     302    len_and_sockaddr *dest_lsa;
     303    int packlen;                    /* total length of packet */
     304    int pmtu;                       /* Path MTU Discovery (RFC1191) */
     305    uint32_t ident;
     306    uint16_t port; // 32768 + 666;  /* start udp dest port # for probe packets */
     307    int waittime; // 5;             /* time to wait for response (in seconds) */
    312308#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    313 static int optlen;                     /* length of ip options */
     309    int optlen;                     /* length of ip options */
    314310#else
    315311#define optlen 0
    316312#endif
    317 
    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 
    348 struct 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 */
     313    unsigned char recv_pkt[512];    /* last inbound (icmp) packet */
    353314#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    354315    /* Maximum number of gateways (include room for one noop) */
     
    360321
    361322#define G (*ptr_to_globals)
    362 
    363 #define packet    (G.packet   )
    364 #define whereto   (G.whereto  )
    365 #define wherefrom (G.wherefrom)
     323#define outip     (G.outip    )
     324#define outdata   (G.outdata  )
     325#define dest_lsa  (G.dest_lsa )
     326#define packlen   (G.packlen  )
     327#define pmtu      (G.pmtu     )
     328#define ident     (G.ident    )
     329#define port      (G.port     )
     330#define waittime  (G.waittime )
     331#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
     332# define optlen   (G.optlen   )
     333#endif
     334#define recv_pkt  (G.recv_pkt )
    366335#define gwlist    (G.gwlist   )
    367 
    368 
    369 /*
    370  * Return the interface list
    371  */
     336#define INIT_G() do { \
     337    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     338    port = 32768 + 666; \
     339    waittime = 5; \
     340} while (0)
     341
     342#define outicmp ((struct icmp *)(outip + 1))
     343#define outudp  ((struct udphdr *)(outip + 1))
     344
     345
     346/* libbb candidate? tftp uses this idiom too */
     347static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
     348{
     349    len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len);
     350    memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len);
     351    return new_lsa;
     352}
     353
     354
    372355static int
    373 ifaddrlist(struct IFADDRLIST **ipaddrp)
    374 {
    375     enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) };
    376 
    377     int fd, nipaddr;
    378 #ifdef HAVE_SOCKADDR_SA_LEN
    379     int n;
    380 #endif
    381     struct ifreq *ifrp, *ifend, *ifnext;
    382     struct sockaddr_in *addr_sin;
    383     struct IFADDRLIST *al;
    384     struct ifconf ifc;
    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]));
    388     struct IFADDRLIST *st_ifaddrlist;
    389 
    390     fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    391 
    392     ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]);
    393     ifc.ifc_buf = (caddr_t)ibuf;
    394 
    395     if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
    396      || ifc.ifc_len < sizeof(struct ifreq)
    397     ) {
    398         if (errno == EINVAL)
    399             bb_error_msg_and_die(
    400                 "SIOCGIFCONF: ifreq struct too small (%u bytes)",
    401                 (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0])));
    402         bb_perror_msg_and_die("SIOCGIFCONF");
    403     }
    404     ifrp = ibuf;
    405     ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
    406 
    407     nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
    408     st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST));
    409     al = st_ifaddrlist;
    410     nipaddr = 0;
    411 
    412     for (; ifrp < ifend; ifrp = ifnext) {
    413 #ifdef HAVE_SOCKADDR_SA_LEN
    414         n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
    415         if (n < sizeof(*ifrp))
    416             ifnext = ifrp + 1;
    417         else
    418             ifnext = (struct ifreq *)((char *)ifrp + n);
    419         if (ifrp->ifr_addr.sa_family != AF_INET)
    420             continue;
    421 #else
    422         ifnext = ifrp + 1;
    423 #endif
    424         /*
    425          * Need a template to preserve address info that is
    426          * used below to locate the next entry.  (Otherwise,
    427          * SIOCGIFFLAGS stomps over it because the requests
    428          * are returned in a union.)
    429          */
    430         strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
    431         if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
    432             if (errno == ENXIO)
    433                 continue;
    434             bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
    435                 (int)sizeof(ifr.ifr_name), ifr.ifr_name);
    436         }
    437 
    438         /* Must be up */
    439         if ((ifr.ifr_flags & IFF_UP) == 0)
    440             continue;
    441 
    442         safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
    443 #ifdef sun
    444         /* Ignore sun virtual interfaces */
    445         if (strchr(al->device, ':') != NULL)
    446             continue;
    447 #endif
    448         ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr,
    449                 "SIOCGIFADDR: %s", al->device);
    450 
    451         addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
    452         al->addr = addr_sin->sin_addr.s_addr;
    453         ++al;
    454         ++nipaddr;
    455     }
    456     if (nipaddr == 0)
    457         bb_error_msg_and_die("can't find any network interfaces");
    458 
    459     free(ibuf);
    460     close(fd);
    461     *ipaddrp = st_ifaddrlist;
    462     return nipaddr;
    463 }
    464 
    465 
    466 static void
    467 setsin(struct sockaddr_in *addr_sin, uint32_t addr)
    468 {
    469     memset(addr_sin, 0, sizeof(*addr_sin));
    470 #ifdef HAVE_SOCKADDR_SA_LEN
    471     addr_sin->sin_len = sizeof(*addr_sin);
    472 #endif
    473     addr_sin->sin_family = AF_INET;
    474     addr_sin->sin_addr.s_addr = addr;
    475 }
    476 
    477 
    478 /*
    479  * Return the source address for the given destination address
    480  */
    481 static void
    482 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
    483 {
    484     int i, n;
    485     FILE *f;
    486     uint32_t mask;
    487     uint32_t dest, tmask;
    488     struct IFADDRLIST *al;
    489     char buf[256], tdevice[256], device[256];
    490 
    491     f = xfopen("/proc/net/route", "r");
    492 
    493     /* Find the appropriate interface */
    494     n = 0;
    495     mask = 0;
    496     device[0] = '\0';
    497     while (fgets(buf, sizeof(buf), f) != NULL) {
    498         ++n;
    499         if (n == 1 && strncmp(buf, "Iface", 5) == 0)
    500             continue;
    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         ) {
    508             mask = tmask;
    509             strcpy(device, tdevice);
    510         }
    511     }
    512     fclose(f);
    513 
    514     if (device[0] == '\0')
    515         bb_error_msg_and_die("can't find interface");
    516 
    517     /* Get the interface address list */
    518     n = ifaddrlist(&al);
    519 
    520     /* Find our appropriate source address */
    521     for (i = n; i > 0; --i, ++al)
    522         if (strcmp(device, al->device) == 0)
    523             break;
    524     if (i <= 0)
    525         bb_error_msg_and_die("can't find interface %s", device);
    526 
    527     setsin(from, al->addr);
    528 }
    529 
    530 /*
    531 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
    532 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
    533 "\t[-w waittime] [-z pausemsecs] host [packetlen]"
    534 
    535 */
    536 
    537 static int
    538 wait_for_reply(int sock, struct sockaddr_in *fromp)
    539 {
    540     fd_set fds;
    541     struct timeval tvwait;
    542     int cc = 0;
    543     socklen_t fromlen = sizeof(*fromp);
    544 
    545     FD_ZERO(&fds);
    546     FD_SET(sock, &fds);
    547 
    548     tvwait.tv_sec = waittime;
    549     tvwait.tv_usec = 0;
    550 
    551     if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0)
    552         cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
    553                 (struct sockaddr *)fromp, &fromlen);
    554 
    555     return cc;
     356wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to)
     357{
     358    struct pollfd pfd[1];
     359    int read_len = 0;
     360
     361    pfd[0].fd = rcvsock;
     362    pfd[0].events = POLLIN;
     363    if (safe_poll(pfd, 1, waittime * 1000) > 0) {
     364        read_len = recv_from_to(rcvsock,
     365                recv_pkt, sizeof(recv_pkt),
     366                /*flags:*/ 0,
     367                &from_lsa->u.sa, to, from_lsa->len);
     368    }
     369
     370    return read_len;
    556371}
    557372
     
    568383
    569384    /*
    570      *  Our algorithm is simple, using a 32 bit accumulator (sum),
    571      *  we add sequential 16 bit words to it, and at the end, fold
    572      *  back all the carry bits from the top 16 bits into the lower
    573      *  16 bits.
     385     * Our algorithm is simple, using a 32 bit accumulator (sum),
     386     * we add sequential 16 bit words to it, and at the end, fold
     387     * back all the carry bits from the top 16 bits into the lower
     388     * 16 bits.
    574389     */
    575     while (nleft > 1)  {
     390    while (nleft > 1) {
    576391        sum += *w++;
    577392        nleft -= 2;
     
    582397        sum += *(unsigned char *)w;
    583398
    584     /*
    585      * add back carry outs from top 16 bits to low 16 bits
    586      */
     399    /* add back carry outs from top 16 bits to low 16 bits */
    587400    sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
    588401    sum += (sum >> 16);                     /* add carry */
     
    591404}
    592405
    593 
    594406static void
    595407send_probe(int seq, int ttl)
    596408{
    597     int cc;
    598     struct udpiphdr *ui, *oui;
    599     struct ip tip;
    600 
    601     outip->ip_ttl = ttl;
    602     outip->ip_id = htons(ident + seq);
    603 
    604     /*
    605      * In most cases, the kernel will recalculate the ip checksum.
    606      * But we must do it anyway so that the udp checksum comes out
    607      * right.
    608      */
    609     if (doipcksum) {
    610         outip->ip_sum =
    611             in_cksum((uint16_t *)outip, sizeof(*outip) + optlen);
    612         if (outip->ip_sum == 0)
    613             outip->ip_sum = 0xffff;
    614     }
     409    int len, res;
     410    void *out;
    615411
    616412    /* Payload */
    617     outdata->seq = seq;
    618     outdata->ttl = ttl;
     413#if ENABLE_TRACEROUTE6
     414    if (dest_lsa->u.sa.sa_family == AF_INET6) {
     415        struct outdata6_t *pkt = (struct outdata6_t *) outip;
     416        pkt->ident6 = htonl(ident);
     417        pkt->seq6   = htonl(seq);
     418        /*gettimeofday(&pkt->tv, &tz);*/
     419    } else
     420#endif
     421    {
     422        outdata->seq = seq;
     423        outdata->ttl = ttl;
    619424// 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
    623     if (useicmp)
    624         outicmp->icmp_seq = htons(seq);
    625     else
    626 #endif
    627         outudp->dest = htons(port + seq);
    628 
    629 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    630     if (useicmp) {
    631         /* Always calculate checksum for icmp packets */
    632         outicmp->icmp_cksum = 0;
    633         outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
    634             packlen - (sizeof(*outip) + optlen));
    635         if (outicmp->icmp_cksum == 0)
    636             outicmp->icmp_cksum = 0xffff;
    637     } else
    638 #endif
    639     if (doipcksum) {
    640         /* Checksum (we must save and restore ip header) */
    641         tip = *outip;
    642         ui = (struct udpiphdr *)outip;
    643         oui = (struct udpiphdr *)&tip;
    644         /* Easier to zero and put back things that are ok */
    645         memset((char *)ui, 0, sizeof(ui->ui_i));
    646         ui->ui_src = oui->ui_src;
    647         ui->ui_dst = oui->ui_dst;
    648         ui->ui_pr = oui->ui_pr;
    649         ui->ui_len = outudp->len;
    650         outudp->check = 0;
    651         outudp->check = in_cksum((uint16_t *)ui, packlen);
    652         if (outudp->check == 0)
    653             outudp->check = 0xffff;
    654         *outip = tip;
    655     }
    656 
    657 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
     425        /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
     426
     427        if (option_mask32 & OPT_USE_ICMP) {
     428            outicmp->icmp_seq = htons(seq);
     429
     430            /* Always calculate checksum for icmp packets */
     431            outicmp->icmp_cksum = 0;
     432            outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
     433                        packlen - (sizeof(*outip) + optlen));
     434            if (outicmp->icmp_cksum == 0)
     435                outicmp->icmp_cksum = 0xffff;
     436        }
     437    }
     438
     439//BUG! verbose is (x & OPT_VERBOSE), not a counter!
     440#if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE
    658441    /* XXX undocumented debugging hack */
    659442    if (verbose > 1) {
     
    680463#endif
    681464
    682 #if !defined(IP_HDRINCL) && defined(IP_TTL)
    683     if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
    684         (char *)&ttl, sizeof(ttl)) < 0) {
    685         bb_perror_msg_and_die("setsockopt ttl %d", ttl);
    686     }
    687 #endif
    688 
    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     }
     465#if ENABLE_TRACEROUTE6
     466    if (dest_lsa->u.sa.sa_family == AF_INET6) {
     467        res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
     468        if (res < 0)
     469            bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
     470        out = outip;
     471        len = packlen;
     472    } else
     473#endif
     474    {
     475#if defined IP_TTL
     476        res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
     477        if (res < 0)
     478            bb_perror_msg_and_die("setsockopt ttl %d", ttl);
     479#endif
     480        out = outicmp;
     481        len = packlen - sizeof(*outip);
     482        if (!(option_mask32 & OPT_USE_ICMP)) {
     483            out = outdata;
     484            len -= sizeof(*outudp);
     485            set_nport(dest_lsa, htons(port + seq));
     486        }
     487    }
     488
     489    res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
     490    if (res != len)
     491        bb_info_msg("sent %d octets, ret=%d", len, res);
    694492}
    695493
     
    698496 * Convert an ICMP "type" field to a printable string.
    699497 */
    700 static inline const char *
     498static const char *
    701499pr_type(unsigned char t)
    702500{
     
    708506    "Info Reply",   "Mask Request", "Mask Reply"
    709507    };
    710 
    711     if (t > 18)
     508# if ENABLE_TRACEROUTE6
     509    static const char *const ttab6[] = {
     510[0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
     511[4] "Param Problem",
     512[8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
     513[12]    "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
     514[16]    "Neighbor Advert", "Redirect",
     515    };
     516
     517    if (dest_lsa->u.sa.sa_family == AF_INET6) {
     518        if (t < 5)
     519            return ttab6[t];
     520        if (t < 128 || t > ND_REDIRECT)
     521            return "OUT-OF-RANGE";
     522        return ttab6[(t & 63) + 8];
     523    }
     524# endif
     525    if (t >= ARRAY_SIZE(ttab))
    712526        return "OUT-OF-RANGE";
    713527
     
    716530#endif
    717531
     532#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
     533#define packet4_ok(read_len, from, seq) \
     534    packet4_ok(read_len, seq)
     535#endif
    718536static int
    719 packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq)
    720 {
    721     struct icmp *icp;
     537packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
     538{
     539    const struct icmp *icp;
    722540    unsigned char type, code;
    723541    int hlen;
    724     struct ip *ip;
    725 
    726     ip = (struct ip *) buf;
     542    const struct ip *ip;
     543
     544    ip = (struct ip *) recv_pkt;
    727545    hlen = ip->ip_hl << 2;
    728     if (cc < hlen + ICMP_MINLEN) {
     546    if (read_len < hlen + ICMP_MINLEN) {
    729547#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    730548        if (verbose)
    731             printf("packet too short (%d bytes) from %s\n", cc,
     549            printf("packet too short (%d bytes) from %s\n", read_len,
    732550                inet_ntoa(from->sin_addr));
    733551#endif
    734552        return 0;
    735553    }
    736     cc -= hlen;
    737     icp = (struct icmp *)(buf + hlen);
     554    read_len -= hlen;
     555    icp = (struct icmp *)(recv_pkt + hlen);
    738556    type = icp->icmp_type;
    739557    code = icp->icmp_code;
    740558    /* Path MTU Discovery (RFC1191) */
    741     if (code != ICMP_UNREACH_NEEDFRAG)
    742         pmtu = 0;
    743     else {
     559    pmtu = 0;
     560    if (code == ICMP_UNREACH_NEEDFRAG)
    744561        pmtu = ntohs(icp->icmp_nextmtu);
    745     }
    746     if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
    747         type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
    748         struct ip *hip;
    749         struct udphdr *up;
     562
     563    if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
     564     || type == ICMP_UNREACH
     565     || type == ICMP_ECHOREPLY
     566    ) {
     567        const struct ip *hip;
     568        const struct udphdr *up;
    750569
    751570        hip = &icp->icmp_ip;
    752571        hlen = hip->ip_hl << 2;
    753 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    754         if (useicmp) {
     572        if (option_mask32 & OPT_USE_ICMP) {
    755573            struct icmp *hicmp;
    756574
    757575            /* XXX */
    758             if (type == ICMP_ECHOREPLY &&
    759                 icp->icmp_id == htons(ident) &&
    760                 icp->icmp_seq == htons(seq))
    761                 return -2;
     576            if (type == ICMP_ECHOREPLY
     577             && icp->icmp_id == htons(ident)
     578             && icp->icmp_seq == htons(seq)
     579            ) {
     580                return ICMP_UNREACH_PORT+1;
     581            }
    762582
    763583            hicmp = (struct icmp *)((unsigned char *)hip + hlen);
    764             /* XXX 8 is a magic number */
    765             if (hlen + 8 <= cc &&
    766                 hip->ip_p == IPPROTO_ICMP &&
    767                 hicmp->icmp_id == htons(ident) &&
    768                 hicmp->icmp_seq == htons(seq))
     584            if (hlen + SIZEOF_ICMP_HDR <= read_len
     585             && hip->ip_p == IPPROTO_ICMP
     586             && hicmp->icmp_id == htons(ident)
     587             && hicmp->icmp_seq == htons(seq)
     588            ) {
    769589                return (type == ICMP_TIMXCEED ? -1 : code + 1);
    770         } else
    771 #endif
    772         {
    773             up = (struct udphdr *)((unsigned char *)hip + hlen);
    774             /* XXX 8 is a magic number */
    775             if (hlen + 12 <= cc &&
    776                 hip->ip_p == IPPROTO_UDP &&
    777                 up->source == htons(ident) &&
    778                 up->dest == htons(port + seq))
     590            }
     591        } else {
     592            up = (struct udphdr *)((char *)hip + hlen);
     593            if (hlen + 12 <= read_len
     594             && hip->ip_p == IPPROTO_UDP
     595// Off: since we do not form the entire IP packet,
     596// but defer it to kernel, we can't set source port,
     597// and thus can't check it here in the reply
     598            /* && up->source == htons(ident) */
     599             && up->dest == htons(port + seq)
     600            ) {
    779601                return (type == ICMP_TIMXCEED ? -1 : code + 1);
     602            }
    780603        }
    781604    }
     
    787610        printf("\n%d bytes from %s to "
    788611               "%s: icmp type %d (%s) code %d\n",
    789             cc, inet_ntoa(from->sin_addr),
    790             inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
    791         for (i = 4; i < cc; i += sizeof(*lp))
     612            read_len, inet_ntoa(from->sin_addr),
     613            inet_ntoa(ip->ip_dst),
     614            type, pr_type(type), icp->icmp_code);
     615        for (i = 4; i < read_len; i += sizeof(*lp))
    792616            printf("%2d: x%8.8x\n", i, *lp++);
    793617    }
     
    796620}
    797621
     622#if ENABLE_TRACEROUTE6
     623# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
     624#define packet_ok(read_len, from_lsa, to, seq) \
     625    packet_ok(read_len, from_lsa, seq)
     626# endif
     627static int
     628packet_ok(int read_len, len_and_sockaddr *from_lsa,
     629            struct sockaddr *to,
     630            int seq)
     631{
     632    const struct icmp6_hdr *icp;
     633    unsigned char type, code;
     634
     635    if (from_lsa->u.sa.sa_family == AF_INET)
     636        return packet4_ok(read_len, &from_lsa->u.sin, seq);
     637
     638    icp = (struct icmp6_hdr *) recv_pkt;
     639
     640    type = icp->icmp6_type;
     641    code = icp->icmp6_code;
     642
     643    if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
     644     || type == ICMP6_DST_UNREACH
     645    ) {
     646        struct ip6_hdr *hip;
     647        struct udphdr *up;
     648        int nexthdr;
     649
     650        hip = (struct ip6_hdr *)(icp + 1);
     651        up  = (struct udphdr *) (hip + 1);
     652        nexthdr = hip->ip6_nxt;
     653
     654        if (nexthdr == IPPROTO_FRAGMENT) {
     655            nexthdr = *(unsigned char*)up;
     656            up++;
     657        }
     658        if (nexthdr == IPPROTO_UDP) {
     659            struct outdata6_t *pkt;
     660
     661            pkt = (struct outdata6_t *) (up + 1);
     662
     663            if (ntohl(pkt->ident6) == ident
     664             && ntohl(pkt->seq6) == seq
     665            ) {
     666                return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
     667            }
     668        }
     669    }
     670
     671# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
     672    if (verbose) {
     673        unsigned char *p;
     674        char pa1[MAXHOSTNAMELEN];
     675        char pa2[MAXHOSTNAMELEN];
     676        int i;
     677
     678        p = (unsigned char *) (icp + 1);
     679
     680        printf("\n%d bytes from %s to "
     681               "%s: icmp type %d (%s) code %d\n",
     682            read_len,
     683            inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
     684            inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
     685            type, pr_type(type), icp->icmp6_code);
     686
     687        read_len -= sizeof(struct icmp6_hdr);
     688        for (i = 0; i < read_len ; i++) {
     689            if (i % 16 == 0)
     690                printf("%04x:", i);
     691            if (i % 4 == 0)
     692                bb_putchar(' ');
     693            printf("%02x", p[i]);
     694            if ((i % 16 == 15) && (i + 1 < read_len))
     695                bb_putchar('\n');
     696        }
     697        bb_putchar('\n');
     698    }
     699# endif
     700
     701    return 0;
     702}
     703#else /* !ENABLE_TRACEROUTE6 */
     704static ALWAYS_INLINE int
     705packet_ok(int read_len,
     706        len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
     707        struct sockaddr *to UNUSED_PARAM,
     708        int seq)
     709{
     710    return packet4_ok(read_len, &from_lsa->u.sin, seq);
     711}
     712#endif
    798713
    799714/*
    800715 * Construct an Internet address representation.
    801  * If the nflag has been supplied, give
     716 * If the -n flag has been supplied, give
    802717 * numeric value, otherwise try for symbolic name.
    803718 */
    804 static inline void
    805 print_inetname(struct sockaddr_in *from)
    806 {
    807     const char *ina;
    808 
    809     ina = inet_ntoa(from->sin_addr);
    810     if (nflag)
    811         printf(" %s", ina);
    812     else {
     719static void
     720print_inetname(const struct sockaddr *from)
     721{
     722    char *ina = xmalloc_sockaddr2dotted_noport(from);
     723
     724    if (option_mask32 & OPT_ADDR_NUM) {
     725        printf("  %s", ina);
     726    } else {
    813727        char *n = NULL;
    814         if (from->sin_addr.s_addr != INADDR_ANY)
     728
     729        if (from->sa_family != AF_INET
     730         || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
     731        ) {
     732            /* Try to reverse resolve if it is not 0.0.0.0 */
    815733            n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
    816         printf(" %s (%s)", (n ? n : ina), ina);
     734        }
     735        printf("  %s (%s)", (n ? n : ina), ina);
    817736        free(n);
    818737    }
    819 }
    820 
    821 static inline void
    822 print(unsigned char *buf, int cc, struct sockaddr_in *from)
    823 {
    824     struct ip *ip;
    825     int hlen;
    826 
    827     ip = (struct ip *) buf;
    828     hlen = ip->ip_hl << 2;
    829     cc -= hlen;
    830 
     738    free(ina);
     739}
     740
     741static void
     742print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
     743{
    831744    print_inetname(from);
    832 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    833     if (verbose)
    834         printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst));
    835 #endif
    836 }
    837 
    838 
    839 static struct hostinfo *
    840 gethostinfo(const char *host)
    841 {
    842     int n;
    843     struct hostent *hp;
    844     struct hostinfo *hi;
    845     char **p;
    846     uint32_t addr, *ap;
    847 
    848     hi = xzalloc(sizeof(*hi));
    849     addr = inet_addr(host);
    850     if (addr != 0xffffffff) {
    851         hi->name = xstrdup(host);
    852         hi->n = 1;
    853         hi->addrs = xzalloc(sizeof(hi->addrs[0]));
    854         hi->addrs[0] = addr;
    855         return hi;
    856     }
    857 
    858     hp = xgethostbyname(host);
    859     if (hp->h_addrtype != AF_INET || hp->h_length != 4)
    860         bb_perror_msg_and_die("bad host %s", host);
    861     hi->name = xstrdup(hp->h_name);
    862     for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
    863         continue;
    864     hi->n = n;
    865     hi->addrs = xzalloc(n * sizeof(hi->addrs[0]));
    866     for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
    867         memcpy(ap, *p, sizeof(*ap));
    868     return hi;
    869 }
    870 
    871 static void
    872 freehostinfo(struct hostinfo *hi)
    873 {
    874     free(hi->name);
    875     free(hi->addrs);
    876     free(hi);
    877 }
    878 
    879 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    880 static void
    881 getaddr(uint32_t *ap, const char *host)
    882 {
    883     struct hostinfo *hi;
    884 
    885     hi = gethostinfo(host);
    886     *ap = hi->addrs[0];
    887     freehostinfo(hi);
    888 }
    889 #endif
     745
     746    if (verbose) {
     747        char *ina = xmalloc_sockaddr2dotted_noport(to);
     748#if ENABLE_TRACEROUTE6
     749        if (to->sa_family == AF_INET6) {
     750            read_len -= sizeof(struct ip6_hdr);
     751        } else
     752#endif
     753        {
     754            read_len -= ((struct ip*)recv_pkt)->ip_hl << 2;
     755        }
     756        printf(" %d bytes to %s", read_len, ina);
     757        free(ina);
     758    }
     759}
    890760
    891761static void
     
    893763{
    894764    unsigned tt = t2p - t1p;
    895     printf("  %u.%03u ms", tt/1000, tt%1000);
    896 }
    897 
    898 int traceroute_main(int argc, char **argv);
    899 int traceroute_main(int argc, char **argv)
    900 {
    901     int code, n;
    902     unsigned char *outp;
    903     uint32_t *ap;
    904     struct sockaddr_in *from;
    905     struct sockaddr_in *to;
    906     struct hostinfo *hi;
    907     int ttl, probe, i;
    908     int seq = 0;
     765    printf("  %u.%03u ms", tt / 1000, tt % 1000);
     766}
     767
     768/*
     769 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]
     770 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
     771 * [-w waittime] [-z pausemsecs] host [packetlen]"
     772 */
     773static int
     774common_traceroute_main(int op, char **argv)
     775{
     776    int i;
     777    int minpacket;
    909778    int tos = 0;
     779    int max_ttl = 30;
     780    int nprobes = 3;
     781    int first_ttl = 1;
     782    unsigned pausemsecs = 0;
     783    char *source;
     784    char *device;
    910785    char *tos_str;
    911     char *source;
    912     unsigned op;
    913 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    914     int lsrr = 0;
    915 #endif
    916     uint16_t off = 0;
    917     struct IFADDRLIST *al;
    918     char *device;
    919     int max_ttl = 30;
    920786    char *max_ttl_str;
    921787    char *port_str;
    922     int nprobes = 3;
    923788    char *nprobes_str;
    924789    char *waittime_str;
    925     unsigned pausemsecs = 0;
    926790    char *pausemsecs_str;
    927     int first_ttl = 1;
    928791    char *first_ttl_str;
    929792#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    930793    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::";
     794    int lsrr = 0;
     795#endif
     796#if ENABLE_TRACEROUTE6
     797    sa_family_t af;
    940798#else
    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
    946                     "g:"
    947 #endif
     799    enum { af = AF_INET };
     800#endif
     801    int ttl;
     802    int seq;
     803    len_and_sockaddr *from_lsa;
     804    struct sockaddr *lastaddr;
     805    struct sockaddr *to;
     806
     807    INIT_G();
     808
     809    /* minimum 1 arg */
     810    opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
     811    op |= getopt32(argv, OPT_STRING
    948812        , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
    949813        , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
     
    952816#endif
    953817    );
    954 
    955     if (op & OPT_DONT_FRAGMNT)
    956         off = IP_DF;
    957     if (op & OPT_IP_CHKSUM) {
    958         doipcksum = 0;
     818    argv += optind;
     819
     820#if 0 /* IGNORED */
     821    if (op & OPT_IP_CHKSUM)
    959822        bb_error_msg("warning: ip checksums disabled");
    960     }
     823#endif
    961824    if (op & OPT_TOS)
    962825        tos = xatou_range(tos_str, 0, 255);
     
    972835         * probe (e.g., on a multi-homed host).
    973836         */
    974         if (getuid())
    975             bb_error_msg_and_die("-s %s: permission denied", source);
     837        if (getuid() != 0)
     838            bb_error_msg_and_die(bb_msg_you_must_be_root);
    976839    }
    977840    if (op & OPT_WAITTIME)
    978         waittime = xatou_range(waittime_str, 2, 24 * 60 * 60);
     841        waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
    979842    if (op & OPT_PAUSE_MS)
    980843        pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
    981844    if (op & OPT_FIRST_TTL)
    982         first_ttl = xatou_range(first_ttl_str, 1, 255);
     845        first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
    983846
    984847#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    985848    if (source_route_list) {
    986         llist_t *l_sr;
    987 
    988         l_sr = source_route_list;
    989         while (l_sr) {
     849        while (source_route_list) {
     850            len_and_sockaddr *lsa;
     851
    990852            if (lsrr >= NGATEWAYS)
    991853                bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
    992             getaddr(gwlist + lsrr, l_sr->data);
     854            lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
     855            gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
     856            free(lsa);
    993857            ++lsrr;
    994             l_sr = l_sr->link;
    995             free(source_route_list);
    996             source_route_list = l_sr;
    997858        }
    998859        optlen = (lsrr + 1) * sizeof(gwlist[0]);
     
    1000861#endif
    1001862
    1002     if (first_ttl > max_ttl) {
    1003         bb_error_msg_and_die(
    1004             "first ttl (%d) may not be greater than max ttl (%d)",
    1005             first_ttl, max_ttl);
    1006     }
    1007 
    1008     minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
    1009 
    1010 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    1011     if (useicmp)
    1012         minpacket += 8;                 /* XXX magic number */
    1013     else
    1014 #endif
    1015         minpacket += sizeof(*outudp);
    1016     packlen = minpacket;                    /* minimum sized packet */
    1017 
    1018863    /* Process destination and optional packet size */
    1019     switch (argc - optind) {
    1020 
    1021     case 2:
    1022         packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket);
    1023         /* Fall through */
    1024 
    1025     case 1:
    1026         hostname = argv[optind];
    1027         hi = gethostinfo(hostname);
    1028         setsin(to, hi->addrs[0]);
    1029         if (hi->n > 1)
    1030             bb_error_msg("warning: %s has multiple addresses; using %s",
    1031                 hostname, inet_ntoa(to->sin_addr));
    1032         hostname = hi->name;
    1033         hi->name = NULL;
    1034         freehostinfo(hi);
    1035         break;
    1036 
    1037     default:
    1038         bb_show_usage();
    1039     }
     864    minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
     865    if (!(op & OPT_USE_ICMP))
     866        minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
     867#if ENABLE_TRACEROUTE6
     868    af = AF_UNSPEC;
     869    if (op & OPT_IPV4)
     870        af = AF_INET;
     871    if (op & OPT_IPV6)
     872        af = AF_INET6;
     873    dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
     874    af = dest_lsa->u.sa.sa_family;
     875    if (af == AF_INET6)
     876        minpacket = sizeof(struct outdata6_t);
     877#else
     878    dest_lsa = xhost2sockaddr(argv[0], port);
     879#endif
     880    packlen = minpacket;
     881    if (argv[1])
     882        packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
    1040883
    1041884    /* Ensure the socket fds won't be 0, 1 or 2 */
    1042885    bb_sanitize_stdio();
    1043886
    1044     s = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     887#if ENABLE_TRACEROUTE6
     888    if (af == AF_INET6) {
     889        xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
     890# ifdef IPV6_RECVPKTINFO
     891        setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
     892                &const_int_1, sizeof(const_int_1));
     893        setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
     894                &const_int_1, sizeof(const_int_1));
     895# else
     896        setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
     897                &const_int_1, sizeof(const_int_1));
     898# endif
     899    } else
     900#endif
     901    {
     902        xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
     903    }
    1045904
    1046905#if TRACEROUTE_SO_DEBUG
    1047906    if (op & OPT_DEBUG)
    1048         setsockopt(s, SOL_SOCKET, SO_DEBUG,
     907        setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
    1049908                &const_int_1, sizeof(const_int_1));
    1050909#endif
    1051910    if (op & OPT_BYPASS_ROUTE)
    1052         setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
     911        setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
    1053912                &const_int_1, sizeof(const_int_1));
    1054913
    1055     sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    1056 
    1057 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    1058 #if defined(IP_OPTIONS)
    1059     if (lsrr > 0) {
    1060         unsigned char optlist[MAX_IPOPTLEN];
    1061 
    1062         /* final hop */
    1063         gwlist[lsrr] = to->sin_addr.s_addr;
    1064         ++lsrr;
    1065 
    1066         /* force 4 byte alignment */
    1067         optlist[0] = IPOPT_NOP;
    1068         /* loose source route option */
    1069         optlist[1] = IPOPT_LSRR;
    1070         i = lsrr * sizeof(gwlist[0]);
    1071         optlist[2] = i + 3;
    1072         /* Pointer to LSRR addresses */
    1073         optlist[3] = IPOPT_MINOFF;
    1074         memcpy(optlist + 4, gwlist, i);
    1075 
    1076         if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
    1077             (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
    1078             bb_perror_msg_and_die("IP_OPTIONS");
    1079         }
    1080     }
    1081 #endif /* IP_OPTIONS */
    1082 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
     914#if ENABLE_TRACEROUTE6
     915    if (af == AF_INET6) {
     916        static const int two = 2;
     917        if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
     918            bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
     919        xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
     920    } else
     921#endif
     922    {
     923        if (op & OPT_USE_ICMP)
     924            xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
     925        else
     926            xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
     927#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
     928        if (lsrr > 0) {
     929            unsigned char optlist[MAX_IPOPTLEN];
     930
     931            /* final hop */
     932            gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
     933            ++lsrr;
     934
     935            /* force 4 byte alignment */
     936            optlist[0] = IPOPT_NOP;
     937            /* loose source route option */
     938            optlist[1] = IPOPT_LSRR;
     939            i = lsrr * sizeof(gwlist[0]);
     940            optlist[2] = i + 3;
     941            /* pointer to LSRR addresses */
     942            optlist[3] = IPOPT_MINOFF;
     943            memcpy(optlist + 4, gwlist, i);
     944
     945            if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
     946                    (char *)optlist, i + sizeof(gwlist[0])) < 0) {
     947                bb_perror_msg_and_die("IP_OPTIONS");
     948            }
     949        }
     950#endif
     951    }
    1083952
    1084953#ifdef SO_SNDBUF
     
    1087956    }
    1088957#endif
    1089 #ifdef IP_HDRINCL
    1090     if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 0
    1091      && errno != ENOPROTOOPT
    1092     ) {
    1093         bb_perror_msg_and_die("IP_HDRINCL");
    1094     }
    1095 #else
    1096958#ifdef IP_TOS
    1097     if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
     959    if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
    1098960        bb_perror_msg_and_die("setsockopt tos %d", tos);
    1099961    }
    1100962#endif
     963#ifdef IP_DONTFRAG
     964    if (op & OPT_DONT_FRAGMNT)
     965        setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
     966                &const_int_1, sizeof(const_int_1));
    1101967#endif
    1102968#if TRACEROUTE_SO_DEBUG
     
    1109975                &const_int_1, sizeof(const_int_1));
    1110976
     977    outip = xzalloc(packlen);
     978
     979    ident = getpid();
     980
     981    if (af == AF_INET) {
     982        if (op & OPT_USE_ICMP) {
     983            ident |= 0x8000;
     984            outicmp->icmp_type = ICMP_ECHO;
     985            outicmp->icmp_id = htons(ident);
     986            outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
     987        } else {
     988            outdata = (struct outdata_t *)(outudp + 1);
     989        }
     990    }
     991
     992    if (op & OPT_DEVICE) /* hmm, do we need error check? */
     993        setsockopt_bindtodevice(sndsock, device);
     994
     995    if (op & OPT_SOURCE) {
     996#if ENABLE_TRACEROUTE6
     997// TODO: need xdotted_and_af2sockaddr?
     998        len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
     999#else
     1000        len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
     1001#endif
     1002        /* Ping4 does this (why?) */
     1003        if (af == AF_INET)
     1004            if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
     1005                    &source_lsa->u.sa, source_lsa->len))
     1006                bb_error_msg_and_die("can't set multicast source interface");
     1007//TODO: we can query source port we bound to,
     1008// and check it in replies... if we care enough
     1009        xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
     1010        free(source_lsa);
     1011    }
     1012#if ENABLE_TRACEROUTE6
     1013    else if (af == AF_INET6) {
     1014//TODO: why we don't do it for IPv4?
     1015        len_and_sockaddr *source_lsa;
     1016
     1017        int probe_fd = xsocket(af, SOCK_DGRAM, 0);
     1018        if (op & OPT_DEVICE)
     1019            setsockopt_bindtodevice(probe_fd, device);
     1020        set_nport(dest_lsa, htons(1025));
     1021        /* dummy connect. makes kernel pick source IP (and port) */
     1022        xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
     1023        set_nport(dest_lsa, htons(port));
     1024
     1025        /* read IP and port */
     1026        source_lsa = get_sock_lsa(probe_fd);
     1027        if (source_lsa == NULL)
     1028            bb_error_msg_and_die("can't get probe addr");
     1029
     1030        close(probe_fd);
     1031
     1032        /* bind our sockets to this IP (but not port) */
     1033        set_nport(source_lsa, 0);
     1034        xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
     1035        xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
     1036
     1037        free(source_lsa);
     1038    }
     1039#endif
     1040
    11111041    /* Revert to non-privileged user after opening sockets */
    11121042    xsetgid(getgid());
    11131043    xsetuid(getuid());
    11141044
    1115     outip = xzalloc(packlen);
    1116 
    1117     outip->ip_v = IPVERSION;
    1118     if (tos_str)
    1119         outip->ip_tos = tos;
    1120     outip->ip_len = htons(packlen);
    1121     outip->ip_off = htons(off);
    1122     outp = (unsigned char *)(outip + 1);
    1123     outip->ip_dst = to->sin_addr;
    1124 
    1125     outip->ip_hl = (outp - (unsigned char *)outip) >> 2;
    1126     ident = (getpid() & 0xffff) | 0x8000;
    1127 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    1128     if (useicmp) {
    1129         outip->ip_p = IPPROTO_ICMP;
    1130         outicmp = (struct icmp *)outp;
    1131         outicmp->icmp_type = ICMP_ECHO;
    1132         outicmp->icmp_id = htons(ident);
    1133         outdata = (struct outdata *)(outp + 8); /* XXX magic number */
    1134     } else
    1135 #endif
    1136     {
    1137         outip->ip_p = IPPROTO_UDP;
    1138         outudp = (struct udphdr *)outp;
    1139         outudp->source = htons(ident);
    1140         outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen)));
    1141         outdata = (struct outdata *)(outudp + 1);
    1142     }
    1143 
    1144     /* Get the interface address list */
    1145     n = ifaddrlist(&al);
    1146 
    1147     /* Look for a specific device */
    1148     if (op & OPT_DEVICE) {
    1149         for (i = n; i > 0; --i, ++al)
    1150             if (strcmp(device, al->device) == 0)
    1151                 goto found_dev;
    1152         bb_error_msg_and_die("can't find interface %s", device);
    1153     }
    1154  found_dev:
    1155 
    1156     /* Determine our source address */
    1157     if (!(op & OPT_SOURCE)) {
    1158         /*
    1159          * If a device was specified, use the interface address.
    1160          * Otherwise, try to determine our source address.
    1161          */
    1162         if (op & OPT_DEVICE)
    1163             setsin(from, al->addr);
    1164         findsaddr(to, from);
    1165     } else {
    1166         hi = gethostinfo(source);
    1167         source = hi->name;
    1168         hi->name = NULL;
    1169         /*
    1170          * If the device was specified make sure it
    1171          * corresponds to the source address specified.
    1172          * Otherwise, use the first address (and warn if
    1173          * there are more than one).
    1174          */
    1175         if (op & OPT_DEVICE) {
    1176             for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
    1177                 if (*ap == al->addr)
    1178                     goto found_dev2;
    1179             bb_error_msg_and_die("%s is not on interface %s",
    1180                     source, device);
    1181  found_dev2:
    1182             setsin(from, *ap);
    1183         } else {
    1184             setsin(from, hi->addrs[0]);
    1185             if (hi->n > 1)
    1186                 bb_error_msg(
    1187             "warning: %s has multiple addresses; using %s",
    1188                     source, inet_ntoa(from->sin_addr));
    1189         }
    1190         freehostinfo(hi);
    1191     }
    1192 
    1193     outip->ip_src = from->sin_addr;
    1194 #ifndef IP_HDRINCL
    1195     xbind(sndsock, (struct sockaddr *)from, sizeof(*from));
    1196 #endif
    1197 
    1198     printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
     1045    printf("traceroute to %s (%s)", argv[0],
     1046            xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa));
    11991047    if (op & OPT_SOURCE)
    12001048        printf(" from %s", source);
    12011049    printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
    1202     fflush(stdout);
    1203 
     1050
     1051    from_lsa = dup_sockaddr(dest_lsa);
     1052    lastaddr = xzalloc(dest_lsa->len);
     1053    to = xzalloc(dest_lsa->len);
     1054    seq = 0;
    12041055    for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
    1205         uint32_t lastaddr = 0;
    1206         int gotlastaddr = 0;
     1056        int probe;
     1057        int unreachable = 0; /* counter */
     1058        int gotlastaddr = 0; /* flags */
    12071059        int got_there = 0;
    1208         int unreachable = 0;
    1209         int sentfirst = 0;
    1210 
    1211         printf("%2d ", ttl);
     1060        int first = 1;
     1061
     1062        printf("%2d", ttl);
    12121063        for (probe = 0; probe < nprobes; ++probe) {
    1213             int cc;
     1064            int read_len;
    12141065            unsigned t1;
    12151066            unsigned t2;
    12161067            struct ip *ip;
    12171068
    1218             if (sentfirst && pausemsecs > 0)
     1069            if (!first && pausemsecs > 0)
    12191070                usleep(pausemsecs * 1000);
     1071            fflush_all();
     1072
    12201073            t1 = monotonic_us();
    12211074            send_probe(++seq, ttl);
    1222             ++sentfirst;
    1223             while ((cc = wait_for_reply(s, from)) != 0) {
     1075
     1076            first = 0;
     1077            while ((read_len = wait_for_reply(from_lsa, to)) != 0) {
    12241078                t2 = monotonic_us();
    1225                 i = packet_ok(packet, cc, from, seq);
     1079                i = packet_ok(read_len, from_lsa, to, seq);
    12261080                /* Skip short packet */
    12271081                if (i == 0)
    12281082                    continue;
    1229                 if (!gotlastaddr ||
    1230                     from->sin_addr.s_addr != lastaddr) {
    1231                     print(packet, cc, from);
    1232                     lastaddr = from->sin_addr.s_addr;
    1233                     ++gotlastaddr;
     1083
     1084                if (!gotlastaddr
     1085                 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
     1086                ) {
     1087                    print(read_len, &from_lsa->u.sa, to);
     1088                    memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
     1089                    gotlastaddr = 1;
    12341090                }
     1091
    12351092                print_delta_ms(t1, t2);
    1236                 ip = (struct ip *)packet;
    1237                 if (op & OPT_TTL_FLAG)
    1238                     printf(" (%d)", ip->ip_ttl);
    1239                 if (i == -2) {
    1240                     if (ip->ip_ttl <= 1)
    1241                         printf(" !");
    1242                     ++got_there;
    1243                     break;
    1244                 }
     1093                ip = (struct ip *)recv_pkt;
     1094
     1095                if (from_lsa->u.sa.sa_family == AF_INET)
     1096                    if (op & OPT_TTL_FLAG)
     1097                        printf(" (%d)", ip->ip_ttl);
     1098
    12451099                /* time exceeded in transit */
    12461100                if (i == -1)
    12471101                    break;
    1248                 code = i - 1;
    1249                 switch (code) {
    1250 
     1102                i--;
     1103                switch (i) {
     1104#if ENABLE_TRACEROUTE6
     1105                case ICMP6_DST_UNREACH_NOPORT << 8:
     1106                    got_there = 1;
     1107                    break;
     1108#endif
    12511109                case ICMP_UNREACH_PORT:
    12521110                    if (ip->ip_ttl <= 1)
    12531111                        printf(" !");
    1254                     ++got_there;
     1112                    got_there = 1;
    12551113                    break;
    12561114
    12571115                case ICMP_UNREACH_NET:
     1116#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
     1117                case ICMP6_DST_UNREACH_NOROUTE << 8:
     1118#endif
     1119                    printf(" !N");
    12581120                    ++unreachable;
    1259                     printf(" !N");
    1260                     break;
    1261 
     1121                    break;
    12621122                case ICMP_UNREACH_HOST:
     1123#if ENABLE_TRACEROUTE6
     1124                case ICMP6_DST_UNREACH_ADDR << 8:
     1125#endif
     1126                    printf(" !H");
    12631127                    ++unreachable;
    1264                     printf(" !H");
    1265                     break;
    1266 
     1128                    break;
    12671129                case ICMP_UNREACH_PROTOCOL:
    1268                     ++got_there;
    12691130                    printf(" !P");
    1270                     break;
    1271 
     1131                    got_there = 1;
     1132                    break;
    12721133                case ICMP_UNREACH_NEEDFRAG:
     1134                    printf(" !F-%d", pmtu);
    12731135                    ++unreachable;
    1274                     printf(" !F-%d", pmtu);
    1275                     break;
    1276 
     1136                    break;
    12771137                case ICMP_UNREACH_SRCFAIL:
     1138#if ENABLE_TRACEROUTE6
     1139                case ICMP6_DST_UNREACH_ADMIN << 8:
     1140#endif
     1141                    printf(" !S");
    12781142                    ++unreachable;
    1279                     printf(" !S");
    1280                     break;
    1281 
     1143                    break;
    12821144                case ICMP_UNREACH_FILTER_PROHIB:
    12831145                case ICMP_UNREACH_NET_PROHIB:   /* misuse */
     1146                    printf(" !A");
    12841147                    ++unreachable;
    1285                     printf(" !A");
    1286                     break;
    1287 
     1148                    break;
    12881149                case ICMP_UNREACH_HOST_PROHIB:
     1150                    printf(" !C");
    12891151                    ++unreachable;
     1152                    break;
     1153                case ICMP_UNREACH_HOST_PRECEDENCE:
     1154                    printf(" !V");
     1155                    ++unreachable;
     1156                    break;
     1157                case ICMP_UNREACH_PRECEDENCE_CUTOFF:
    12901158                    printf(" !C");
    1291                     break;
    1292 
    1293                 case ICMP_UNREACH_HOST_PRECEDENCE:
    12941159                    ++unreachable;
    1295                     printf(" !V");
    1296                     break;
    1297 
    1298                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
    1299                     ++unreachable;
    1300                     printf(" !C");
    1301                     break;
    1302 
     1160                    break;
    13031161                case ICMP_UNREACH_NET_UNKNOWN:
    13041162                case ICMP_UNREACH_HOST_UNKNOWN:
     1163                    printf(" !U");
    13051164                    ++unreachable;
    1306                     printf(" !U");
    1307                     break;
    1308 
     1165                    break;
    13091166                case ICMP_UNREACH_ISOLATED:
     1167                    printf(" !I");
    13101168                    ++unreachable;
    1311                     printf(" !I");
    1312                     break;
    1313 
     1169                    break;
    13141170                case ICMP_UNREACH_TOSNET:
    13151171                case ICMP_UNREACH_TOSHOST:
     1172                    printf(" !T");
    13161173                    ++unreachable;
    1317                     printf(" !T");
    1318                     break;
    1319 
     1174                    break;
    13201175                default:
     1176                    printf(" !<%d>", i);
    13211177                    ++unreachable;
    1322                     printf(" !<%d>", code);
    13231178                    break;
    13241179                }
    13251180                break;
    13261181            }
    1327             if (cc == 0)
    1328                 printf(" *");
    1329             (void)fflush(stdout);
    1330         }
    1331         putchar('\n');
    1332         if (got_there ||
    1333             (unreachable > 0 && unreachable >= nprobes - 1))
     1182            /* there was no packet at all? */
     1183            if (read_len == 0)
     1184                printf("  *");
     1185        }
     1186        bb_putchar('\n');
     1187        if (got_there
     1188         || (unreachable > 0 && unreachable >= nprobes - 1)
     1189        ) {
    13341190            break;
    1335     }
     1191        }
     1192    }
     1193
    13361194    return 0;
    13371195}
     1196
     1197int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1198int traceroute_main(int argc UNUSED_PARAM, char **argv)
     1199{
     1200    return common_traceroute_main(0, argv);
     1201}
     1202
     1203#if ENABLE_TRACEROUTE6
     1204int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1205int traceroute6_main(int argc UNUSED_PARAM, char **argv)
     1206{
     1207    return common_traceroute_main(OPT_IPV6, argv);
     1208}
     1209#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/Config.in

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    45#
    56
    6 config APP_UDHCPD
    7     bool "udhcp Server (udhcpd)"
    8     default n
     7
     8
     9config UDHCPD
     10    bool "udhcp server (udhcpd)"
     11    default y
     12    depends on PLATFORM_LINUX
    913    help
    10       uDHCPd is a DHCP server geared primarily toward embedded systems,
     14      udhcpd is a DHCP server geared primarily toward embedded systems,
    1115      while striving to be fully functional and RFC compliant.
    1216
    13       See http://udhcp.busybox.net for further details.
    14 
    15 config APP_DHCPRELAY
     17config DHCPRELAY
    1618    bool "dhcprelay"
    17     default n
    18     depends on APP_UDHCPD
     19    default y
     20    depends on UDHCPD
    1921    help
    2022      dhcprelay listens for dhcp requests on one or more interfaces
     
    2224      server.
    2325
    24 config APP_DUMPLEASES
     26config DUMPLEASES
    2527    bool "Lease display utility (dumpleases)"
    26     default n
    27     depends on APP_UDHCPD
     28    default y
     29    depends on UDHCPD
    2830    help
    2931      dumpleases displays the leases written out by the udhcpd server.
     
    3133      by the absolute time that it expires in seconds from epoch.
    3234
    33       See http://udhcp.busybox.net for further details.
    34 
    3535config FEATURE_UDHCPD_WRITE_LEASES_EARLY
    3636    bool "Rewrite the lease file at every new acknowledge"
    37     default n
    38     depends on APP_UDHCPD
     37    default y
     38    depends on UDHCPD
    3939    help
    4040      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
     41      time a new lease has been accepted, thus eliminating the need
     42      to send SIGUSR1 for the initial writing or updating. Any timed
    4343      rewriting remains undisturbed
    4444
    45 config APP_UDHCPC
    46     bool "udhcp Client (udhcpc)"
    47     default n
     45config DHCPD_LEASES_FILE
     46    string "Absolute path to lease file"
     47    default "/var/lib/misc/udhcpd.leases"
     48    depends on UDHCPD
    4849    help
    49       uDHCPc is a DHCP client geared primarily toward embedded systems,
     50      udhcpd stores addresses in a lease file. This is the absolute path
     51      of the file. Normally it is safe to leave it untouched.
     52
     53config UDHCPC
     54    bool "udhcp client (udhcpc)"
     55    default y
     56    depends on PLATFORM_LINUX
     57    help
     58      udhcpc is a DHCP client geared primarily toward embedded systems,
    5059      while striving to be fully functional and RFC compliant.
    5160
    5261      The udhcp client negotiates a lease with the DHCP server and
    53       notifies a set of scripts when a lease is obtained or lost.
     62      runs a script when a lease is obtained or lost.
    5463
    55       See http://udhcp.busybox.net for further details.
     64config FEATURE_UDHCPC_ARPING
     65    bool "Verify that the offered address is free, using ARP ping"
     66    default y
     67    depends on UDHCPC
     68    help
     69      If selected, udhcpc will send ARP probes and make sure
     70      the offered address is really not in use by anyone. The client
     71      will DHCPDECLINE the offer if the address is in use,
     72      and restart the discover process.
    5673
    57 config FEATURE_UDHCP_DEBUG
    58     bool "Compile udhcp with noisy debugging messages"
    59     default n
    60     depends on APP_UDHCPD || APP_UDHCPC
     74config FEATURE_UDHCP_PORT
     75    bool "Enable '-P port' option for udhcpd and udhcpc"
     76    default y
     77    depends on UDHCPD || UDHCPC
    6178    help
    62       If selected, udhcpd will output extra debugging output.  If using
    63       this option, compile uDHCP with "-g", and do not fork the daemon to
    64       the background.
     79      At the cost of ~300 bytes, enables -P port option.
     80      This feature is typically not needed.
    6581
    66       See http://udhcp.busybox.net for further details.
     82config UDHCP_DEBUG
     83    int "Maximum verbosity level for udhcp applets (0..9)"
     84    default 9
     85    range 0 9
     86    depends on UDHCPD || UDHCPC || DHCPRELAY
     87    help
     88      Verbosity can be increased with multiple -v options.
     89      This option controls how high it can be cranked up.
    6790
    68 config FEATURE_RFC3397
     91      Bigger values result in bigger code. Levels above 1
     92      are very verbose and useful for debugging only.
     93
     94config FEATURE_UDHCP_RFC3397
    6995    bool "Support for RFC3397 domain search (experimental)"
    70     default n
    71     depends on APP_UDHCPD || APP_UDHCPC
     96    default y
     97    depends on UDHCPD || UDHCPC
    7298    help
    7399      If selected, both client and server will support passing of domain
    74       search lists via option 119, specified in RFC3397.
     100      search lists via option 119, specified in RFC 3397,
     101      and SIP servers option 120, specified in RFC 3361.
     102
     103config UDHCPC_DEFAULT_SCRIPT
     104    string "Absolute path to config script"
     105    default "/usr/share/udhcpc/default.script"
     106    depends on UDHCPC
     107    help
     108      This script is called after udhcpc receives an answer. See
     109      examples/udhcp for a working example. Normally it is safe
     110      to leave this untouched.
     111
     112config UDHCPC_SLACK_FOR_BUGGY_SERVERS
     113    int "DHCP options slack buffer size"
     114    default 80
     115    range 0 924
     116    depends on UDHCPD || UDHCPC
     117    help
     118      Some buggy DHCP servers send DHCP offer packets with option
     119      field larger than we expect (which might also be considered a
     120      buffer overflow attempt). These packets are normally discarded.
     121      If circumstances beyond your control force you to support such
     122      servers, this may help. The upper limit (924) makes dhcpc accept
     123      even 1500 byte packets (maximum-sized ethernet packets).
     124
     125      This option does not make dhcp[cd] emit non-standard
     126      sized packets.
     127
     128      Known buggy DHCP servers:
     129      3Com OfficeConnect Remote 812 ADSL Router:
     130        seems to confuse maximum allowed UDP packet size with
     131        maximum size of entire IP packet, and sends packets which are
     132        28 bytes too large.
     133      Seednet (ISP) VDSL: sends packets 2 bytes too large.
  • branches/2.2.9/mindi-busybox/networking/udhcp/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     6# Licensed under GPLv2 or later, see file LICENSE in this source tree.
    67#
    78
    89lib-y:=
    9 lib-$(CONFIG_APP_UDHCPC)        += common.o options.o packet.o \
    10                                    signalpipe.o socket.o
    11 lib-$(CONFIG_APP_UDHCPD)        += common.o options.o packet.o \
    12                                    signalpipe.o socket.o
    13 lib-$(CONFIG_APP_UDHCPC)        += dhcpc.o clientpacket.o clientsocket.o \
    14                                    script.o
    15 lib-$(CONFIG_APP_UDHCPD)        += dhcpd.o arpping.o files.o leases.o \
    16                                    serverpacket.o static_leases.o
    17 lib-$(CONFIG_APP_DUMPLEASES)    += dumpleases.o
    18 lib-$(CONFIG_APP_DHCPRELAY)     += dhcprelay.o
    19 lib-$(CONFIG_FEATURE_RFC3397)   += domain_codec.o
     10
     11
     12
     13lib-$(CONFIG_UDHCPC)     += common.o packet.o signalpipe.o socket.o
     14lib-$(CONFIG_UDHCPD)     += common.o packet.o signalpipe.o socket.o
     15
     16lib-$(CONFIG_UDHCPC)     += dhcpc.o
     17lib-$(CONFIG_UDHCPD)     += dhcpd.o arpping.o files.o leases.o static_leases.o
     18lib-$(CONFIG_DUMPLEASES) += dumpleases.o
     19lib-$(CONFIG_DHCPRELAY)  += dhcprelay.o
     20
     21lib-$(CONFIG_FEATURE_UDHCPC_ARPING) += arpping.o
     22lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o
  • branches/2.2.9/mindi-busybox/networking/udhcp/arpping.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * arpping.c
    4  *
    53 * Mostly stolen from: dhcpcd - DHCP client daemon
    64 * by Yoichi Hariguchi <yoichi@fore.com>
     5 *
     6 * Licensed under GPLv2, see file LICENSE in this source tree.
    77 */
    8 
    98#include <netinet/if_ether.h>
    109#include <net/if_arp.h>
     
    1211#include "common.h"
    1312#include "dhcpd.h"
    14 
    1513
    1614struct arpMsg {
     
    3129    uint8_t  tInaddr[4];    /* 26 target's IP address */
    3230    uint8_t  pad[18];       /* 2a pad for min. ethernet payload (60 bytes) */
    33 } ATTRIBUTE_PACKED;
     31} PACKED;
    3432
     33enum {
     34    ARP_MSG_SIZE = 0x2a
     35};
    3536
    3637/* Returns 1 if no reply received */
    37 
    38 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface)
     38int FAST_FUNC arpping(uint32_t test_nip,
     39        const uint8_t *safe_mac,
     40        uint32_t from_ip,
     41        uint8_t *from_mac,
     42        const char *interface)
    3943{
    40     int timeout = 2;
    41     int s;                  /* socket */
     44    int timeout_ms;
     45    struct pollfd pfd[1];
     46#define s (pfd[0].fd)           /* socket */
    4247    int rv = 1;             /* "no reply received" yet */
    4348    struct sockaddr addr;   /* for interface name */
    4449    struct arpMsg arp;
    45     fd_set fdset;
    46     struct timeval tm;
    47     unsigned prevTime;
    4850
    4951    s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
     
    5456
    5557    if (setsockopt_broadcast(s) == -1) {
    56         bb_perror_msg("cannot setsocketopt on raw socket");
     58        bb_perror_msg("can't enable bcast on raw socket");
    5759        goto ret;
    5860    }
     
    7072    memcpy(arp.sHaddr, from_mac, 6);                /* source hardware address */
    7173    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 */
     74    /* tHaddr is zero-filled */                     /* target hardware address */
     75    memcpy(arp.tInaddr, &test_nip, sizeof(test_nip));/* target IP address */
    7476
    7577    memset(&addr, 0, sizeof(addr));
    7678    safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data));
    77     if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
     79    if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) {
     80        // TODO: error message? caller didn't expect us to fail,
     81        // just returning 1 "no reply received" misleads it.
    7882        goto ret;
     83    }
    7984
    8085    /* wait for arp reply, and check it */
     86    timeout_ms = 2000;
    8187    do {
     88        typedef uint32_t aliased_uint32_t FIX_ALIASING;
    8289        int r;
    83         prevTime = monotonic_sec();
    84         FD_ZERO(&fdset);
    85         FD_SET(s, &fdset);
    86         tm.tv_sec = timeout;
    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)
     90        unsigned prevTime = monotonic_ms();
     91
     92        pfd[0].events = POLLIN;
     93        r = safe_poll(pfd, 1, timeout_ms);
     94        if (r < 0)
     95            break;
     96        if (r) {
     97            r = safe_read(s, &arp, sizeof(arp));
     98            if (r < 0)
    9299                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
     100
     101            //log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
     102            //  arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
     103            //  arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
     104
     105            if (r >= ARP_MSG_SIZE
     106             && arp.operation == htons(ARPOP_REPLY)
     107             /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */
     108             /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */
     109             && *(aliased_uint32_t*)arp.sInaddr == test_nip
    99110            ) {
    100                 rv = 0;
     111                /* if ARP source MAC matches safe_mac
     112                 * (which is client's MAC), then it's not a conflict
     113                 * (client simply already has this IP and replies to ARPs!)
     114                 */
     115                if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0)
     116                    rv = 0;
     117                //else log2("sHaddr == safe_mac");
    101118                break;
    102119            }
    103120        }
    104         timeout -= monotonic_sec() - prevTime;
    105     } while (timeout > 0);
     121        timeout_ms -= (unsigned)monotonic_ms() - prevTime;
     122    } while (timeout_ms > 0);
    106123
    107124 ret:
    108125    close(s);
    109     DEBUG("%srp reply received for this address", rv ? "No a" : "A");
     126    log1("%srp reply received for this address", rv ? "No a" : "A");
    110127    return rv;
    111128}
  • branches/2.2.9/mindi-busybox/networking/udhcp/common.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* common.c
     2/*
     3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
    34 *
    4  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2, see file LICENSE in this source tree.
    56 */
    6 
    77#include "common.h"
     8
     9#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     10unsigned dhcp_verbose;
     11#endif
    812
    913const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
    1014    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    1115};
     16
     17/* Supported options are easily added here.
     18 * See RFC2132 for more options.
     19 * OPTION_REQ: these options are requested by udhcpc (unless -o).
     20 */
     21const struct dhcp_optflag dhcp_optflags[] = {
     22    /* flags                                    code */
     23    { OPTION_IP                   | OPTION_REQ, 0x01 }, /* DHCP_SUBNET        */
     24    { OPTION_S32                              , 0x02 }, /* DHCP_TIME_OFFSET   */
     25    { OPTION_IP | OPTION_LIST     | OPTION_REQ, 0x03 }, /* DHCP_ROUTER        */
     26//  { OPTION_IP | OPTION_LIST                 , 0x04 }, /* DHCP_TIME_SERVER   */
     27//  { OPTION_IP | OPTION_LIST                 , 0x05 }, /* DHCP_NAME_SERVER   */
     28    { OPTION_IP | OPTION_LIST     | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER    */
     29//  { OPTION_IP | OPTION_LIST                 , 0x07 }, /* DHCP_LOG_SERVER    */
     30//  { OPTION_IP | OPTION_LIST                 , 0x08 }, /* DHCP_COOKIE_SERVER */
     31    { OPTION_IP | OPTION_LIST                 , 0x09 }, /* DHCP_LPR_SERVER    */
     32    { OPTION_STRING               | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME     */
     33    { OPTION_U16                              , 0x0d }, /* DHCP_BOOT_SIZE     */
     34    { OPTION_STRING               | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME   */
     35    { OPTION_IP                               , 0x10 }, /* DHCP_SWAP_SERVER   */
     36    { OPTION_STRING                           , 0x11 }, /* DHCP_ROOT_PATH     */
     37    { OPTION_U8                               , 0x17 }, /* DHCP_IP_TTL        */
     38    { OPTION_U16                              , 0x1a }, /* DHCP_MTU           */
     39    { OPTION_IP                   | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST     */
     40    { OPTION_IP_PAIR | OPTION_LIST            , 0x21 }, /* DHCP_ROUTES        */
     41    { OPTION_STRING                           , 0x28 }, /* DHCP_NIS_DOMAIN    */
     42    { OPTION_IP | OPTION_LIST                 , 0x29 }, /* DHCP_NIS_SERVER    */
     43    { OPTION_IP | OPTION_LIST     | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER    */
     44    { OPTION_IP | OPTION_LIST                 , 0x2c }, /* DHCP_WINS_SERVER   */
     45    { OPTION_U32                              , 0x33 }, /* DHCP_LEASE_TIME    */
     46    { OPTION_IP                               , 0x36 }, /* DHCP_SERVER_ID     */
     47    { OPTION_STRING                           , 0x38 }, /* DHCP_ERR_MESSAGE   */
     48//TODO: must be combined with 'sname' and 'file' handling:
     49    { OPTION_STRING                           , 0x42 }, /* DHCP_TFTP_SERVER_NAME */
     50    { OPTION_STRING                           , 0x43 }, /* DHCP_BOOT_FILE     */
     51//TODO: not a string, but a set of LASCII strings:
     52//  { OPTION_STRING                           , 0x4D }, /* DHCP_USER_CLASS    */
     53#if ENABLE_FEATURE_UDHCP_RFC3397
     54    { OPTION_DNS_STRING | OPTION_LIST         , 0x77 }, /* DHCP_DOMAIN_SEARCH */
     55    { OPTION_SIP_SERVERS                      , 0x78 }, /* DHCP_SIP_SERVERS   */
     56#endif
     57    { OPTION_STATIC_ROUTES                    , 0x79 }, /* DHCP_STATIC_ROUTES */
     58    { OPTION_STATIC_ROUTES                    , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
     59    { OPTION_STRING                           , 0xfc }, /* DHCP_WPAD          */
     60
     61    /* Options below have no match in dhcp_option_strings[],
     62     * are not passed to dhcpc scripts, and cannot be specified
     63     * with "option XXX YYY" syntax in dhcpd config file.
     64     * These entries are only used internally by udhcp[cd]
     65     * to correctly encode options into packets.
     66     */
     67
     68    { OPTION_IP                               , 0x32 }, /* DHCP_REQUESTED_IP  */
     69    { OPTION_U8                               , 0x35 }, /* DHCP_MESSAGE_TYPE  */
     70    { OPTION_U16                              , 0x39 }, /* DHCP_MAX_SIZE      */
     71//looks like these opts will work just fine even without these defs:
     72//  { OPTION_STRING                           , 0x3c }, /* DHCP_VENDOR        */
     73//  /* not really a string: */
     74//  { OPTION_STRING                           , 0x3d }, /* DHCP_CLIENT_ID     */
     75    { 0, 0 } /* zeroed terminating entry */
     76};
     77
     78/* Used for converting options from incoming packets to env variables
     79 * for udhcpc stript, and for setting options for udhcpd via
     80 * "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file.
     81 */
     82/* Must match dhcp_optflags[] order */
     83const char dhcp_option_strings[] ALIGN1 =
     84    "subnet" "\0"      /* DHCP_SUBNET         */
     85    "timezone" "\0"    /* DHCP_TIME_OFFSET    */
     86    "router" "\0"      /* DHCP_ROUTER         */
     87//  "timesrv" "\0"     /* DHCP_TIME_SERVER    */
     88//  "namesrv" "\0"     /* DHCP_NAME_SERVER    */
     89    "dns" "\0"         /* DHCP_DNS_SERVER     */
     90//  "logsrv" "\0"      /* DHCP_LOG_SERVER     */
     91//  "cookiesrv" "\0"   /* DHCP_COOKIE_SERVER  */
     92    "lprsrv" "\0"      /* DHCP_LPR_SERVER     */
     93    "hostname" "\0"    /* DHCP_HOST_NAME      */
     94    "bootsize" "\0"    /* DHCP_BOOT_SIZE      */
     95    "domain" "\0"      /* DHCP_DOMAIN_NAME    */
     96    "swapsrv" "\0"     /* DHCP_SWAP_SERVER    */
     97    "rootpath" "\0"    /* DHCP_ROOT_PATH      */
     98    "ipttl" "\0"       /* DHCP_IP_TTL         */
     99    "mtu" "\0"         /* DHCP_MTU            */
     100    "broadcast" "\0"   /* DHCP_BROADCAST      */
     101    "routes" "\0"      /* DHCP_ROUTES         */
     102    "nisdomain" "\0"   /* DHCP_NIS_DOMAIN     */
     103    "nissrv" "\0"      /* DHCP_NIS_SERVER     */
     104    "ntpsrv" "\0"      /* DHCP_NTP_SERVER     */
     105    "wins" "\0"        /* DHCP_WINS_SERVER    */
     106    "lease" "\0"       /* DHCP_LEASE_TIME     */
     107    "serverid" "\0"    /* DHCP_SERVER_ID      */
     108    "message" "\0"     /* DHCP_ERR_MESSAGE    */
     109    "tftp" "\0"        /* DHCP_TFTP_SERVER_NAME */
     110    "bootfile" "\0"    /* DHCP_BOOT_FILE      */
     111//  "userclass" "\0"   /* DHCP_USER_CLASS     */
     112#if ENABLE_FEATURE_UDHCP_RFC3397
     113    "search" "\0"      /* DHCP_DOMAIN_SEARCH  */
     114// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
     115// is not handled yet by "string->option" conversion code:
     116    "sipsrv" "\0"      /* DHCP_SIP_SERVERS    */
     117#endif
     118// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES
     119// is not handled yet by "string->option" conversion code:
     120    "staticroutes" "\0"/* DHCP_STATIC_ROUTES  */
     121    "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
     122    "wpad" "\0"        /* DHCP_WPAD           */
     123    ;
     124
     125/* Lengths of the option types in binary form.
     126 * Used by:
     127 * udhcp_str2optset: to determine how many bytes to allocate.
     128 * xmalloc_optname_optval: to estimate string length
     129 * from binary option length: (option[LEN] / dhcp_option_lengths[opt_type])
     130 * is the number of elements, multiply in by one element's string width
     131 * (len_of_option_as_string[opt_type]) and you know how wide string you need.
     132 */
     133const uint8_t dhcp_option_lengths[] ALIGN1 = {
     134    [OPTION_IP] =      4,
     135    [OPTION_IP_PAIR] = 8,
     136//  [OPTION_BOOLEAN] = 1,
     137    [OPTION_STRING] =  1,  /* ignored by udhcp_str2optset */
     138#if ENABLE_FEATURE_UDHCP_RFC3397
     139    [OPTION_DNS_STRING] = 1,  /* ignored by both udhcp_str2optset and xmalloc_optname_optval */
     140    [OPTION_SIP_SERVERS] = 1,
     141#endif
     142    [OPTION_U8] =      1,
     143    [OPTION_U16] =     2,
     144//  [OPTION_S16] =     2,
     145    [OPTION_U32] =     4,
     146    [OPTION_S32] =     4,
     147    /* Just like OPTION_STRING, we use minimum length here */
     148    [OPTION_STATIC_ROUTES] = 5,
     149};
     150
     151
     152#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     153static void log_option(const char *pfx, const uint8_t *opt)
     154{
     155    if (dhcp_verbose >= 2) {
     156        char buf[256 * 2 + 2];
     157        *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0';
     158        bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf);
     159    }
     160}
     161#else
     162# define log_option(pfx, opt) ((void)0)
     163#endif
     164
     165unsigned FAST_FUNC udhcp_option_idx(const char *name)
     166{
     167    int n = index_in_strings(dhcp_option_strings, name);
     168    if (n >= 0)
     169        return n;
     170
     171    {
     172        char buf[sizeof(dhcp_option_strings)];
     173        char *d = buf;
     174        const char *s = dhcp_option_strings;
     175        while (s < dhcp_option_strings + sizeof(dhcp_option_strings) - 2) {
     176            *d++ = (*s == '\0' ? ' ' : *s);
     177            s++;
     178        }
     179        *d = '\0';
     180        bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf);
     181    }
     182}
     183
     184/* Get an option with bounds checking (warning, result is not aligned) */
     185uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
     186{
     187    uint8_t *optionptr;
     188    int len;
     189    int rem;
     190    int overload = 0;
     191    enum {
     192        FILE_FIELD101  = FILE_FIELD  * 0x101,
     193        SNAME_FIELD101 = SNAME_FIELD * 0x101,
     194    };
     195
     196    /* option bytes: [code][len][data1][data2]..[dataLEN] */
     197    optionptr = packet->options;
     198    rem = sizeof(packet->options);
     199    while (1) {
     200        if (rem <= 0) {
     201            bb_error_msg("bad packet, malformed option field");
     202            return NULL;
     203        }
     204        if (optionptr[OPT_CODE] == DHCP_PADDING) {
     205            rem--;
     206            optionptr++;
     207            continue;
     208        }
     209        if (optionptr[OPT_CODE] == DHCP_END) {
     210            if ((overload & FILE_FIELD101) == FILE_FIELD) {
     211                /* can use packet->file, and didn't look at it yet */
     212                overload |= FILE_FIELD101; /* "we looked at it" */
     213                optionptr = packet->file;
     214                rem = sizeof(packet->file);
     215                continue;
     216            }
     217            if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
     218                /* can use packet->sname, and didn't look at it yet */
     219                overload |= SNAME_FIELD101; /* "we looked at it" */
     220                optionptr = packet->sname;
     221                rem = sizeof(packet->sname);
     222                continue;
     223            }
     224            break;
     225        }
     226        len = 2 + optionptr[OPT_LEN];
     227        rem -= len;
     228        if (rem < 0)
     229            continue; /* complain and return NULL */
     230
     231        if (optionptr[OPT_CODE] == code) {
     232            log_option("Option found", optionptr);
     233            return optionptr + OPT_DATA;
     234        }
     235
     236        if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
     237            overload |= optionptr[OPT_DATA];
     238            /* fall through */
     239        }
     240        optionptr += len;
     241    }
     242
     243    /* log3 because udhcpc uses it a lot - very noisy */
     244    log3("Option 0x%02x not found", code);
     245    return NULL;
     246}
     247
     248/* Return the position of the 'end' option (no bounds checking) */
     249int FAST_FUNC udhcp_end_option(uint8_t *optionptr)
     250{
     251    int i = 0;
     252
     253    while (optionptr[i] != DHCP_END) {
     254        if (optionptr[i] != DHCP_PADDING)
     255            i += optionptr[i + OPT_LEN] + OPT_DATA-1;
     256        i++;
     257    }
     258    return i;
     259}
     260
     261/* Add an option (supplied in binary form) to the options.
     262 * Option format: [code][len][data1][data2]..[dataLEN]
     263 */
     264void FAST_FUNC udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
     265{
     266    unsigned len;
     267    uint8_t *optionptr = packet->options;
     268    unsigned end = udhcp_end_option(optionptr);
     269
     270    len = OPT_DATA + addopt[OPT_LEN];
     271    /* end position + (option code/length + addopt length) + end option */
     272    if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) {
     273//TODO: learn how to use overflow option if we exhaust packet->options[]
     274        bb_error_msg("option 0x%02x did not fit into the packet",
     275                addopt[OPT_CODE]);
     276        return;
     277    }
     278    log_option("Adding option", addopt);
     279    memcpy(optionptr + end, addopt, len);
     280    optionptr[end + len] = DHCP_END;
     281}
     282
     283/* Add an one to four byte option to a packet */
     284void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data)
     285{
     286    const struct dhcp_optflag *dh;
     287
     288    for (dh = dhcp_optflags; dh->code; dh++) {
     289        if (dh->code == code) {
     290            uint8_t option[6], len;
     291
     292            option[OPT_CODE] = code;
     293            len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK];
     294            option[OPT_LEN] = len;
     295            if (BB_BIG_ENDIAN)
     296                data <<= 8 * (4 - len);
     297            /* Assignment is unaligned! */
     298            move_to_unaligned32(&option[OPT_DATA], data);
     299            udhcp_add_binary_option(packet, option);
     300            return;
     301        }
     302    }
     303
     304    bb_error_msg("can't add option 0x%02x", code);
     305}
     306
     307/* Find option 'code' in opt_list */
     308struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code)
     309{
     310    while (opt_list && opt_list->data[OPT_CODE] < code)
     311        opt_list = opt_list->next;
     312
     313    if (opt_list && opt_list->data[OPT_CODE] == code)
     314        return opt_list;
     315    return NULL;
     316}
     317
     318/* Parse string to IP in network order */
     319int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
     320{
     321    len_and_sockaddr *lsa;
     322
     323    lsa = host_and_af2sockaddr(str, 0, AF_INET);
     324    if (!lsa)
     325        return 0;
     326    *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr;
     327    free(lsa);
     328    return 1;
     329}
     330
     331/* udhcp_str2optset:
     332 * Parse string option representation to binary form and add it to opt_list.
     333 * Called to parse "udhcpc -x OPTNAME:OPTVAL"
     334 * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
     335 */
     336/* helper for the helper */
     337static char *allocate_tempopt_if_needed(
     338        const struct dhcp_optflag *optflag,
     339        char *buffer,
     340        int *length_p)
     341{
     342    char *allocated = NULL;
     343    if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
     344        const char *end;
     345        allocated = xstrdup(buffer); /* more than enough */
     346        end = hex2bin(allocated, buffer, 255);
     347        if (errno)
     348            bb_error_msg_and_die("malformed hex string '%s'", buffer);
     349        *length_p = end - allocated;
     350    }
     351    return allocated;
     352}
     353/* helper: add an option to the opt_list */
     354static NOINLINE void attach_option(
     355        struct option_set **opt_list,
     356        const struct dhcp_optflag *optflag,
     357        char *buffer,
     358        int length)
     359{
     360    struct option_set *existing, *new, **curr;
     361    char *allocated = NULL;
     362
     363    existing = udhcp_find_option(*opt_list, optflag->code);
     364    if (!existing) {
     365        log2("Attaching option %02x to list", optflag->code);
     366        allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
     367#if ENABLE_FEATURE_UDHCP_RFC3397
     368        if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
     369            /* reuse buffer and length for RFC1035-formatted string */
     370            allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length);
     371        }
     372#endif
     373        /* make a new option */
     374        new = xmalloc(sizeof(*new));
     375        new->data = xmalloc(length + OPT_DATA);
     376        new->data[OPT_CODE] = optflag->code;
     377        new->data[OPT_LEN] = length;
     378        memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length);
     379
     380        curr = opt_list;
     381        while (*curr && (*curr)->data[OPT_CODE] < optflag->code)
     382            curr = &(*curr)->next;
     383
     384        new->next = *curr;
     385        *curr = new;
     386        goto ret;
     387    }
     388
     389    if (optflag->flags & OPTION_LIST) {
     390        unsigned old_len;
     391
     392        /* add it to an existing option */
     393        log2("Attaching option %02x to existing member of list", optflag->code);
     394        allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
     395        old_len = existing->data[OPT_LEN];
     396#if ENABLE_FEATURE_UDHCP_RFC3397
     397        if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
     398            /* reuse buffer and length for RFC1035-formatted string */
     399            allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length);
     400        }
     401#endif
     402        if (old_len + length < 255) {
     403            /* actually 255 is ok too, but adding a space can overlow it */
     404
     405            existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length);
     406            if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) {
     407                /* add space separator between STRING options in a list */
     408                existing->data[OPT_DATA + old_len] = ' ';
     409                old_len++;
     410            }
     411            memcpy(existing->data + OPT_DATA + old_len, buffer, length);
     412            existing->data[OPT_LEN] = old_len + length;
     413        } /* else, ignore the data, we could put this in a second option in the future */
     414    } /* else, ignore the new data */
     415
     416 ret:
     417    free(allocated);
     418}
     419
     420int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
     421{
     422    struct option_set **opt_list = arg;
     423    char *opt, *val, *endptr;
     424    char *str;
     425    const struct dhcp_optflag *optflag;
     426    struct dhcp_optflag bin_optflag;
     427    unsigned optcode;
     428    int retval, length;
     429    char buffer[8] ALIGNED(4);
     430    uint16_t *result_u16 = (uint16_t *) buffer;
     431    uint32_t *result_u32 = (uint32_t *) buffer;
     432
     433    /* Cheat, the only *const* str possible is "" */
     434    str = (char *) const_str;
     435    opt = strtok(str, " \t=");
     436    if (!opt)
     437        return 0;
     438
     439    optcode = bb_strtou(opt, NULL, 0);
     440    if (!errno && optcode < 255) {
     441        /* Raw (numeric) option code */
     442        bin_optflag.flags = OPTION_BIN;
     443        bin_optflag.code = optcode;
     444        optflag = &bin_optflag;
     445    } else {
     446        optflag = &dhcp_optflags[udhcp_option_idx(opt)];
     447    }
     448
     449    retval = 0;
     450    do {
     451        val = strtok(NULL, ", \t");
     452        if (!val)
     453            break;
     454        length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK];
     455        retval = 0;
     456        opt = buffer; /* new meaning for variable opt */
     457        switch (optflag->flags & OPTION_TYPE_MASK) {
     458        case OPTION_IP:
     459            retval = udhcp_str2nip(val, buffer);
     460            break;
     461        case OPTION_IP_PAIR:
     462            retval = udhcp_str2nip(val, buffer);
     463            val = strtok(NULL, ", \t/-");
     464            if (!val)
     465                retval = 0;
     466            if (retval)
     467                retval = udhcp_str2nip(val, buffer + 4);
     468            break;
     469        case OPTION_STRING:
     470#if ENABLE_FEATURE_UDHCP_RFC3397
     471        case OPTION_DNS_STRING:
     472#endif
     473            length = strnlen(val, 254);
     474            if (length > 0) {
     475                opt = val;
     476                retval = 1;
     477            }
     478            break;
     479//      case OPTION_BOOLEAN: {
     480//          static const char no_yes[] ALIGN1 = "no\0yes\0";
     481//          buffer[0] = retval = index_in_strings(no_yes, val);
     482//          retval++; /* 0 - bad; 1: "no" 2: "yes" */
     483//          break;
     484//      }
     485        case OPTION_U8:
     486            buffer[0] = strtoul(val, &endptr, 0);
     487            retval = (endptr[0] == '\0');
     488            break;
     489        /* htonX are macros in older libc's, using temp var
     490         * in code below for safety */
     491        /* TODO: use bb_strtoX? */
     492        case OPTION_U16: {
     493            unsigned long tmp = strtoul(val, &endptr, 0);
     494            *result_u16 = htons(tmp);
     495            retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/);
     496            break;
     497        }
     498//      case OPTION_S16: {
     499//          long tmp = strtol(val, &endptr, 0);
     500//          *result_u16 = htons(tmp);
     501//          retval = (endptr[0] == '\0');
     502//          break;
     503//      }
     504        case OPTION_U32: {
     505            unsigned long tmp = strtoul(val, &endptr, 0);
     506            *result_u32 = htonl(tmp);
     507            retval = (endptr[0] == '\0');
     508            break;
     509        }
     510        case OPTION_S32: {
     511            long tmp = strtol(val, &endptr, 0);
     512            *result_u32 = htonl(tmp);
     513            retval = (endptr[0] == '\0');
     514            break;
     515        }
     516        case OPTION_BIN: /* handled in attach_option() */
     517            opt = val;
     518            retval = 1;
     519        default:
     520            break;
     521        }
     522        if (retval)
     523            attach_option(opt_list, optflag, opt, length);
     524    } while (retval && optflag->flags & OPTION_LIST);
     525
     526    return retval;
     527}
  • branches/2.2.9/mindi-busybox/networking/udhcp/common.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* common.h
    3  *
     2/*
    43 * Russ Dill <Russ.Dill@asu.edu> September 2001
    54 * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
    65 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    87 */
    9 
    10 #ifndef _COMMON_H
    11 #define _COMMON_H
     8#ifndef UDHCP_COMMON_H
     9#define UDHCP_COMMON_H 1
    1210
    1311#include "libbb.h"
    14 
    15 #define DEFAULT_SCRIPT  "/usr/share/udhcpc/default.script"
    16 
    17 extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
    18 
    19 /*** packet.h ***/
    20 
    2112#include <netinet/udp.h>
    2213#include <netinet/ip.h>
    2314
    24 struct 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 
    43 struct udp_dhcp_packet {
     15PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
     16
     17extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
     18
     19
     20/*** DHCP packet ***/
     21
     22/* DHCP protocol. See RFC 2131 */
     23#define DHCP_MAGIC              0x63825363
     24#define DHCP_OPTIONS_BUFSIZE    308
     25#define BOOTREQUEST             1
     26#define BOOTREPLY               2
     27
     28//TODO: rename ciaddr/yiaddr/chaddr
     29struct dhcp_packet {
     30    uint8_t op;      /* BOOTREQUEST or BOOTREPLY */
     31    uint8_t htype;   /* hardware address type. 1 = 10mb ethernet */
     32    uint8_t hlen;    /* hardware address length */
     33    uint8_t hops;    /* used by relay agents only */
     34    uint32_t xid;    /* unique id */
     35    uint16_t secs;   /* elapsed since client began acquisition/renewal */
     36    uint16_t flags;  /* only one flag so far: */
     37#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
     38    uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
     39    uint32_t yiaddr; /* 'your' (client) IP address */
     40    /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
     41    uint32_t siaddr_nip;
     42    uint32_t gateway_nip; /* relay agent IP address */
     43    uint8_t chaddr[16];   /* link-layer client hardware address (MAC) */
     44    uint8_t sname[64];    /* server host name (ASCIZ) */
     45    uint8_t file[128];    /* boot file name (ASCIZ) */
     46    uint32_t cookie;      /* fixed first four option bytes (99,130,83,99 dec) */
     47    uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
     48} PACKED;
     49#define DHCP_PKT_SNAME_LEN      64
     50#define DHCP_PKT_FILE_LEN      128
     51#define DHCP_PKT_SNAME_LEN_STR "64"
     52#define DHCP_PKT_FILE_LEN_STR "128"
     53
     54struct ip_udp_dhcp_packet {
    4455    struct iphdr ip;
    4556    struct udphdr udp;
    46     struct dhcpMessage data;
    47 };
    48 
    49 void udhcp_init_header(struct dhcpMessage *packet, char type);
    50 int udhcp_get_packet(struct dhcpMessage *packet, int fd);
    51 uint16_t udhcp_checksum(void *addr, int count);
    52 int 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);
    56 int udhcp_kernel_packet(struct dhcpMessage *payload,
    57         uint32_t source_ip, int source_port,
    58         uint32_t dest_ip, int dest_port);
    59 
    60 
    61 /**/
    62 
    63 void udhcp_run_script(struct dhcpMessage *packet, const char *name);
    64 
    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 
    81 void udhcp_sp_setup(void);
    82 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd);
    83 int udhcp_sp_read(fd_set *rfds);
    84 int raw_socket(int ifindex);
    85 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp);
    86 int listen_socket(/*uint32_t ip,*/ int port, const char *inf);
     57    struct dhcp_packet data;
     58} PACKED;
     59
     60struct udp_dhcp_packet {
     61    struct udphdr udp;
     62    struct dhcp_packet data;
     63} PACKED;
     64
     65enum {
     66    IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
     67    UDP_DHCP_SIZE    = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
     68    DHCP_SIZE        = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
     69};
     70
     71/* Let's see whether compiler understood us right */
     72struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet {
     73    char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1];
     74};
     75
     76
     77/*** Options ***/
     78
     79enum {
     80    OPTION_IP = 1,
     81    OPTION_IP_PAIR,
     82    OPTION_STRING,
     83//  OPTION_BOOLEAN,
     84    OPTION_U8,
     85    OPTION_U16,
     86//  OPTION_S16,
     87    OPTION_U32,
     88    OPTION_S32,
     89    OPTION_BIN,
     90    OPTION_STATIC_ROUTES,
     91#if ENABLE_FEATURE_UDHCP_RFC3397
     92    OPTION_DNS_STRING,  /* RFC1035 compressed domain name list */
     93    OPTION_SIP_SERVERS,
     94#endif
     95
     96    OPTION_TYPE_MASK = 0x0f,
     97    /* Client requests this option by default */
     98    OPTION_REQ  = 0x10,
     99    /* There can be a list of 1 or more of these */
     100    OPTION_LIST = 0x20,
     101};
     102
     103/* DHCP option codes (partial list). See RFC 2132 and
     104 * http://www.iana.org/assignments/bootp-dhcp-parameters/
     105 * Commented out options are handled by common option machinery,
     106 * uncommented ones have spacial cases (grep for them to see).
     107 */
     108#define DHCP_PADDING            0x00
     109#define DHCP_SUBNET             0x01
     110//#define DHCP_TIME_OFFSET      0x02 /* (localtime - UTC_time) in seconds. signed */
     111//#define DHCP_ROUTER           0x03
     112//#define DHCP_TIME_SERVER      0x04 /* RFC 868 time server (32-bit, 0 = 1.1.1900) */
     113//#define DHCP_NAME_SERVER      0x05 /* IEN 116 _really_ ancient kind of NS */
     114//#define DHCP_DNS_SERVER       0x06
     115//#define DHCP_LOG_SERVER       0x07 /* port 704 UDP log (not syslog)
     116//#define DHCP_COOKIE_SERVER    0x08 /* "quote of the day" server */
     117//#define DHCP_LPR_SERVER       0x09
     118#define DHCP_HOST_NAME          0x0c /* either client informs server or server gives name to client */
     119//#define DHCP_BOOT_SIZE        0x0d
     120//#define DHCP_DOMAIN_NAME      0x0f /* server gives domain suffix */
     121//#define DHCP_SWAP_SERVER      0x10
     122//#define DHCP_ROOT_PATH        0x11
     123//#define DHCP_IP_TTL           0x17
     124//#define DHCP_MTU              0x1a
     125//#define DHCP_BROADCAST        0x1c
     126//#define DHCP_ROUTES           0x21
     127//#define DHCP_NIS_DOMAIN       0x28
     128//#define DHCP_NIS_SERVER       0x29
     129//#define DHCP_NTP_SERVER       0x2a
     130//#define DHCP_WINS_SERVER      0x2c
     131#define DHCP_REQUESTED_IP       0x32 /* sent by client if specific IP is wanted */
     132#define DHCP_LEASE_TIME         0x33
     133#define DHCP_OPTION_OVERLOAD    0x34
     134#define DHCP_MESSAGE_TYPE       0x35
     135#define DHCP_SERVER_ID          0x36 /* by default server's IP */
     136#define DHCP_PARAM_REQ          0x37 /* list of options client wants */
     137//#define DHCP_ERR_MESSAGE      0x38 /* error message when sending NAK etc */
     138#define DHCP_MAX_SIZE           0x39
     139#define DHCP_VENDOR             0x3c /* client's vendor (a string) */
     140#define DHCP_CLIENT_ID          0x3d /* by default client's MAC addr, but may be arbitrarily long */
     141//#define DHCP_TFTP_SERVER_NAME 0x42 /* same as 'sname' field */
     142//#define DHCP_BOOT_FILE        0x43 /* same as 'file' field */
     143//#define DHCP_USER_CLASS       0x4d /* RFC 3004. set of LASCII strings. "I am a printer" etc */
     144#define DHCP_FQDN               0x51 /* client asks to update DNS to map its FQDN to its new IP */
     145//#define DHCP_DOMAIN_SEARCH    0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
     146//#define DHCP_SIP_SERVERS      0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
     147//#define DHCP_STATIC_ROUTES    0x79 /* RFC 3442. (mask,ip,router) tuples */
     148//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
     149//#define DHCP_WPAD             0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
     150#define DHCP_END                0xff
     151
     152/* Offsets in option byte sequence */
     153#define OPT_CODE                0
     154#define OPT_LEN                 1
     155#define OPT_DATA                2
     156/* Bits in "overload" option */
     157#define OPTION_FIELD            0
     158#define FILE_FIELD              1
     159#define SNAME_FIELD             2
     160
     161/* DHCP_MESSAGE_TYPE values */
     162#define DHCPDISCOVER            1 /* client -> server */
     163#define DHCPOFFER               2 /* client <- server */
     164#define DHCPREQUEST             3 /* client -> server */
     165#define DHCPDECLINE             4 /* client -> server */
     166#define DHCPACK                 5 /* client <- server */
     167#define DHCPNAK                 6 /* client <- server */
     168#define DHCPRELEASE             7 /* client -> server */
     169#define DHCPINFORM              8 /* client -> server */
     170#define DHCP_MINTYPE DHCPDISCOVER
     171#define DHCP_MAXTYPE DHCPINFORM
     172
     173struct dhcp_optflag {
     174    uint8_t flags;
     175    uint8_t code;
     176};
     177
     178struct option_set {
     179    uint8_t *data;
     180    struct option_set *next;
     181};
     182
     183extern const struct dhcp_optflag dhcp_optflags[];
     184extern const char dhcp_option_strings[];
     185extern const uint8_t dhcp_option_lengths[];
     186
     187unsigned FAST_FUNC udhcp_option_idx(const char *name);
     188
     189uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
     190int udhcp_end_option(uint8_t *optionptr) FAST_FUNC;
     191void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC;
     192void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) FAST_FUNC;
     193#if ENABLE_FEATURE_UDHCP_RFC3397
     194char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC;
     195uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC;
     196#endif
     197struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC;
     198
     199
     200// RFC 2131  Table 5: Fields and options used by DHCP clients
     201//
     202// Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero
     203//
     204// Field      DHCPDISCOVER          DHCPINFORM            DHCPREQUEST           DHCPDECLINE         DHCPRELEASE
     205// -----      ------------          ------------          -----------           -----------         -----------
     206// 'xid'      selected by client    selected by client    'xid' from server     selected by client  selected by client
     207//                                                        DHCPOFFER message
     208// 'secs'     0 or seconds since    0 or seconds since    0 or seconds since    0                   0
     209//            DHCP process started  DHCP process started  DHCP process started
     210// 'flags'    Set 'BROADCAST'       Set 'BROADCAST'       Set 'BROADCAST'       0                   0
     211//            flag if client        flag if client        flag if client
     212//            requires broadcast    requires broadcast    requires broadcast
     213//            reply                 reply                 reply
     214// 'ciaddr'   0                     client's IP           0 or client's IP      0                   client's IP
     215//                                                        (BOUND/RENEW/REBIND)
     216// 'chaddr'   client's MAC          client's MAC          client's MAC          client's MAC        client's MAC
     217// 'sname'    options or sname      options or sname      options or sname      (unused)            (unused)
     218// 'file'     options or file       options or file       options or file       (unused)            (unused)
     219// 'options'  options               options               options               message type opt    message type opt
     220//
     221// Option                     DHCPDISCOVER  DHCPINFORM  DHCPREQUEST      DHCPDECLINE  DHCPRELEASE
     222// ------                     ------------  ----------  -----------      -----------  -----------
     223// Requested IP address       MAY           MUST NOT    MUST (in         MUST         MUST NOT
     224//                                                      SELECTING or
     225//                                                      INIT-REBOOT)
     226//                                                      MUST NOT (in
     227//                                                      BOUND or
     228//                                                      RENEWING)
     229// IP address lease time      MAY           MUST NOT    MAY              MUST NOT     MUST NOT
     230// Use 'file'/'sname' fields  MAY           MAY         MAY              MAY          MAY
     231// Client identifier          MAY           MAY         MAY              MAY          MAY
     232// Vendor class identifier    MAY           MAY         MAY              MUST NOT     MUST NOT
     233// Server identifier          MUST NOT      MUST NOT    MUST (after      MUST         MUST
     234//                                                      SELECTING)
     235//                                                      MUST NOT (after
     236//                                                      INIT-REBOOT,
     237//                                                      BOUND, RENEWING
     238//                                                      or REBINDING)
     239// Parameter request list     MAY           MAY         MAY              MUST NOT     MUST NOT
     240// Maximum message size       MAY           MAY         MAY              MUST NOT     MUST NOT
     241// Message                    SHOULD NOT    SHOULD NOT  SHOULD NOT       SHOULD       SHOULD
     242// Site-specific              MAY           MAY         MAY              MUST NOT     MUST NOT
     243// All others                 MAY           MAY         MAY              MUST NOT     MUST NOT
     244
     245
     246/*** Logging ***/
     247
     248#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     249extern unsigned dhcp_verbose;
     250# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0)
     251# if CONFIG_UDHCP_DEBUG >= 2
     252void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC;
     253#  define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0)
     254# else
     255#  define udhcp_dump_packet(...) ((void)0)
     256#  define log2(...) ((void)0)
     257# endif
     258# if CONFIG_UDHCP_DEBUG >= 3
     259#  define log3(...) do { if (dhcp_verbose >= 3) bb_info_msg(__VA_ARGS__); } while (0)
     260# else
     261#  define log3(...) ((void)0)
     262# endif
     263#else
     264# define udhcp_dump_packet(...) ((void)0)
     265# define log1(...) ((void)0)
     266# define log2(...) ((void)0)
     267# define log3(...) ((void)0)
     268#endif
     269
     270
     271/*** Other shared functions ***/
     272
     273/* 2nd param is "uint32_t*" */
     274int FAST_FUNC udhcp_str2nip(const char *str, void *arg);
     275/* 2nd param is "struct option_set**" */
     276int FAST_FUNC udhcp_str2optset(const char *str, void *arg);
     277
     278uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC;
     279
     280void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC;
     281
     282int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC;
     283
     284int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
     285        uint32_t source_nip, int source_port,
     286        uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
     287        int ifindex) FAST_FUNC;
     288
     289int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
     290        uint32_t source_nip, int source_port,
     291        uint32_t dest_nip, int dest_port) FAST_FUNC;
     292
     293void udhcp_sp_setup(void) FAST_FUNC;
     294int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC;
     295int udhcp_sp_read(const fd_set *rfds) FAST_FUNC;
     296
     297int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC;
     298
     299int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC;
     300
    87301/* Returns 1 if no reply received */
    88 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface);
    89 
    90 #if ENABLE_FEATURE_UDHCP_DEBUG
    91 # define DEBUG(str, args...) bb_info_msg(str, ## args)
    92 #else
    93 # define DEBUG(str, args...) do {;} while (0)
     302int arpping(uint32_t test_nip,
     303        const uint8_t *safe_mac,
     304        uint32_t from_ip,
     305        uint8_t *from_mac,
     306        const char *interface) FAST_FUNC;
     307
     308POP_SAVED_FUNCTION_VISIBILITY
     309
    94310#endif
    95 
    96 #endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpc.c
    3  *
    4  * udhcp DHCP client
     2/*
     3 * udhcp client
    54 *
    65 * Russ Dill <Russ.Dill@asu.edu> July 2001
    76 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * This program is free software; you can redistribute it and/or modify
     8 * it under the terms of the GNU General Public License as published by
     9 * the Free Software Foundation; either version 2 of the License, or
     10 * (at your option) any later version.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    920 */
    10 
    11 #include <getopt.h>
    1221#include <syslog.h>
    13 
    1422/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
    1523#define WANT_PIDFILE 1
     
    1725#include "dhcpd.h"
    1826#include "dhcpc.h"
    19 #include "options.h"
    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 (!!)
     27
     28#include <asm/types.h>
     29#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
     30# include <netpacket/packet.h>
     31# include <net/ethernet.h>
     32#else
     33# include <linux/if_packet.h>
     34# include <linux/if_ether.h>
     35#endif
     36#include <linux/filter.h>
     37
     38/* struct client_config_t client_config is in bb_common_bufsiz1 */
     39
     40
     41/*** Script execution code ***/
     42
     43/* get a rough idea of how long an option will be (rounding up...) */
     44static const uint8_t len_of_option_as_string[] = {
     45    [OPTION_IP              ] = sizeof("255.255.255.255 "),
     46    [OPTION_IP_PAIR         ] = sizeof("255.255.255.255 ") * 2,
     47    [OPTION_STATIC_ROUTES   ] = sizeof("255.255.255.255/32 255.255.255.255 "),
     48    [OPTION_STRING          ] = 1,
     49#if ENABLE_FEATURE_UDHCP_RFC3397
     50    [OPTION_DNS_STRING      ] = 1, /* unused */
     51    /* Hmmm, this severely overestimates size if SIP_SERVERS option
     52     * is in domain name form: N-byte option in binary form
     53     * mallocs ~16*N bytes. But it is freed almost at once.
     54     */
     55    [OPTION_SIP_SERVERS     ] = sizeof("255.255.255.255 "),
     56#endif
     57//  [OPTION_BOOLEAN         ] = sizeof("yes "),
     58    [OPTION_U8              ] = sizeof("255 "),
     59    [OPTION_U16             ] = sizeof("65535 "),
     60//  [OPTION_S16             ] = sizeof("-32768 "),
     61    [OPTION_U32             ] = sizeof("4294967295 "),
     62    [OPTION_S32             ] = sizeof("-2147483684 "),
     63};
     64
     65/* note: ip is a pointer to an IP in network order, possibly misaliged */
     66static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
     67{
     68    return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
     69}
     70
     71/* really simple implementation, just count the bits */
     72static int mton(uint32_t mask)
     73{
     74    int i = 0;
     75    mask = ntohl(mask); /* 111110000-like bit pattern */
     76    while (mask) {
     77        i++;
     78        mask <<= 1;
     79    }
     80    return i;
     81}
     82
     83/* Create "opt_name=opt_value" string */
     84static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name)
     85{
     86    unsigned upper_length;
     87    int len, type, optlen;
     88    char *dest, *ret;
     89
     90    /* option points to OPT_DATA, need to go back and get OPT_LEN */
     91    len = option[OPT_LEN - OPT_DATA];
     92
     93    type = optflag->flags & OPTION_TYPE_MASK;
     94    optlen = dhcp_option_lengths[type];
     95    upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
     96
     97    dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
     98    dest += sprintf(ret, "%s=", opt_name);
     99
     100    while (len >= optlen) {
     101        unsigned ip_ofs = 0;
     102
     103        switch (type) {
     104        case OPTION_IP_PAIR:
     105            dest += sprint_nip(dest, "", option);
     106            *dest++ = '/';
     107            ip_ofs = 4;
     108            /* fall through */
     109        case OPTION_IP:
     110            dest += sprint_nip(dest, "", option + ip_ofs);
     111            break;
     112//      case OPTION_BOOLEAN:
     113//          dest += sprintf(dest, *option ? "yes" : "no");
     114//          break;
     115        case OPTION_U8:
     116            dest += sprintf(dest, "%u", *option);
     117            break;
     118//      case OPTION_S16:
     119        case OPTION_U16: {
     120            uint16_t val_u16;
     121            move_from_unaligned16(val_u16, option);
     122            dest += sprintf(dest, "%u", ntohs(val_u16));
     123            break;
     124        }
     125        case OPTION_S32:
     126        case OPTION_U32: {
     127            uint32_t val_u32;
     128            move_from_unaligned32(val_u32, option);
     129            dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32));
     130            break;
     131        }
     132        case OPTION_STRING:
     133            memcpy(dest, option, len);
     134            dest[len] = '\0';
     135            return ret;  /* Short circuit this case */
     136        case OPTION_STATIC_ROUTES: {
     137            /* Option binary format:
     138             * mask [one byte, 0..32]
     139             * ip [big endian, 0..4 bytes depending on mask]
     140             * router [big endian, 4 bytes]
     141             * may be repeated
     142             *
     143             * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2"
     144             */
     145            const char *pfx = "";
     146
     147            while (len >= 1 + 4) { /* mask + 0-byte ip + router */
     148                uint32_t nip;
     149                uint8_t *p;
     150                unsigned mask;
     151                int bytes;
     152
     153                mask = *option++;
     154                if (mask > 32)
     155                    break;
     156                len--;
     157
     158                nip = 0;
     159                p = (void*) &nip;
     160                bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */
     161                while (--bytes >= 0) {
     162                    *p++ = *option++;
     163                    len--;
     164                }
     165                if (len < 4)
     166                    break;
     167
     168                /* print ip/mask */
     169                dest += sprint_nip(dest, pfx, (void*) &nip);
     170                pfx = " ";
     171                dest += sprintf(dest, "/%u ", mask);
     172                /* print router */
     173                dest += sprint_nip(dest, "", option);
     174                option += 4;
     175                len -= 4;
     176            }
     177
     178            return ret;
     179        }
     180#if ENABLE_FEATURE_UDHCP_RFC3397
     181        case OPTION_DNS_STRING:
     182            /* unpack option into dest; use ret for prefix (i.e., "optname=") */
     183            dest = dname_dec(option, len, ret);
     184            if (dest) {
     185                free(ret);
     186                return dest;
     187            }
     188            /* error. return "optname=" string */
     189            return ret;
     190        case OPTION_SIP_SERVERS:
     191            /* Option binary format:
     192             * type: byte
     193             * type=0: domain names, dns-compressed
     194             * type=1: IP addrs
     195             */
     196            option++;
     197            len--;
     198            if (option[-1] == 0) {
     199                dest = dname_dec(option, len, ret);
     200                if (dest) {
     201                    free(ret);
     202                    return dest;
     203                }
     204            } else
     205            if (option[-1] == 1) {
     206                const char *pfx = "";
     207                while (1) {
     208                    len -= 4;
     209                    if (len < 0)
     210                        break;
     211                    dest += sprint_nip(dest, pfx, option);
     212                    pfx = " ";
     213                    option += 4;
     214                }
     215            }
     216            return ret;
     217#endif
     218        } /* switch */
     219        option += optlen;
     220        len -= optlen;
     221// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
     222// Should we bail out/warn if we see multi-ip option which is
     223// not allowed to be such (for example, DHCP_BROADCAST)? -
     224        if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */)
     225            break;
     226        *dest++ = ' ';
     227        *dest = '\0';
     228    }
     229    return ret;
     230}
     231
     232/* put all the parameters into the environment */
     233static char **fill_envp(struct dhcp_packet *packet)
     234{
     235    int envc;
     236    int i;
     237    char **envp, **curr;
     238    const char *opt_name;
     239    uint8_t *temp;
     240    uint8_t overload = 0;
     241
     242    /* We need 6 elements for:
     243     * "interface=IFACE"
     244     * "ip=N.N.N.N" from packet->yiaddr
     245     * "siaddr=IP" from packet->siaddr_nip (unless 0)
     246     * "boot_file=FILE" from packet->file (unless overloaded)
     247     * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded)
     248     * terminating NULL
     249     */
     250    envc = 6;
     251    /* +1 element for each option, +2 for subnet option: */
     252    if (packet) {
     253        for (i = 0; dhcp_optflags[i].code; i++) {
     254            if (udhcp_get_option(packet, dhcp_optflags[i].code)) {
     255                if (dhcp_optflags[i].code == DHCP_SUBNET)
     256                    envc++; /* for mton */
     257                envc++;
     258            }
     259        }
     260        temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
     261        if (temp)
     262            overload = *temp;
     263    }
     264    curr = envp = xzalloc(sizeof(char *) * envc);
     265
     266    *curr = xasprintf("interface=%s", client_config.interface);
     267    putenv(*curr++);
     268
     269    if (!packet)
     270        return envp;
     271
     272    *curr = xmalloc(sizeof("ip=255.255.255.255"));
     273    sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
     274    putenv(*curr++);
     275
     276    opt_name = dhcp_option_strings;
     277    i = 0;
     278    while (*opt_name) {
     279        temp = udhcp_get_option(packet, dhcp_optflags[i].code);
     280        if (!temp)
     281            goto next;
     282        *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
     283        putenv(*curr++);
     284        if (dhcp_optflags[i].code == DHCP_SUBNET) {
     285            /* Subnet option: make things like "$ip/$mask" possible */
     286            uint32_t subnet;
     287            move_from_unaligned32(subnet, temp);
     288            *curr = xasprintf("mask=%d", mton(subnet));
     289            putenv(*curr++);
     290        }
     291 next:
     292        opt_name += strlen(opt_name) + 1;
     293        i++;
     294    }
     295    if (packet->siaddr_nip) {
     296        *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
     297        sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
     298        putenv(*curr++);
     299    }
     300    if (!(overload & FILE_FIELD) && packet->file[0]) {
     301        /* watch out for invalid packets */
     302        *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
     303        putenv(*curr++);
     304    }
     305    if (!(overload & SNAME_FIELD) && packet->sname[0]) {
     306        /* watch out for invalid packets */
     307        *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
     308        putenv(*curr++);
     309    }
     310    return envp;
     311}
     312
     313/* Call a script with a par file and env vars */
     314static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
     315{
     316    char **envp, **curr;
     317    char *argv[3];
     318
     319    if (client_config.script == NULL)
     320        return;
     321
     322    envp = fill_envp(packet);
     323
     324    /* call script */
     325    log1("Executing %s %s", client_config.script, name);
     326    argv[0] = (char*) client_config.script;
     327    argv[1] = (char*) name;
     328    argv[2] = NULL;
     329    spawn_and_wait(argv);
     330
     331    for (curr = envp; *curr; curr++) {
     332        log2(" %s", *curr);
     333        bb_unsetenv_and_free(*curr);
     334    }
     335    free(envp);
     336}
     337
     338
     339/*** Sending/receiving packets ***/
     340
     341static ALWAYS_INLINE uint32_t random_xid(void)
     342{
     343    return rand();
     344}
     345
     346/* Initialize the packet with the proper defaults */
     347static void init_packet(struct dhcp_packet *packet, char type)
     348{
     349    /* Fill in: op, htype, hlen, cookie fields; message type option: */
     350    udhcp_init_header(packet, type);
     351
     352    packet->xid = random_xid();
     353
     354    memcpy(packet->chaddr, client_config.client_mac, 6);
     355    if (client_config.clientid)
     356        udhcp_add_binary_option(packet, client_config.clientid);
     357}
     358
     359static void add_client_options(struct dhcp_packet *packet)
     360{
     361    uint8_t c;
     362    int i, end, len;
     363
     364    udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE));
     365
     366    /* Add a "param req" option with the list of options we'd like to have
     367     * from stubborn DHCP servers. Pull the data from the struct in common.c.
     368     * No bounds checking because it goes towards the head of the packet. */
     369    end = udhcp_end_option(packet->options);
     370    len = 0;
     371    for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) {
     372        if ((   (dhcp_optflags[i].flags & OPTION_REQ)
     373             && !client_config.no_default_options
     374            )
     375         || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
     376        ) {
     377            packet->options[end + OPT_DATA + len] = c;
     378            len++;
     379        }
     380    }
     381    if (len) {
     382        packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
     383        packet->options[end + OPT_LEN] = len;
     384        packet->options[end + OPT_DATA + len] = DHCP_END;
     385    }
     386
     387    if (client_config.vendorclass)
     388        udhcp_add_binary_option(packet, client_config.vendorclass);
     389    if (client_config.hostname)
     390        udhcp_add_binary_option(packet, client_config.hostname);
     391    if (client_config.fqdn)
     392        udhcp_add_binary_option(packet, client_config.fqdn);
     393
     394    /* Add -x options if any */
     395    {
     396        struct option_set *curr = client_config.options;
     397        while (curr) {
     398            udhcp_add_binary_option(packet, curr->data);
     399            curr = curr->next;
     400        }
     401//      if (client_config.sname)
     402//          strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1);
     403//      if (client_config.boot_file)
     404//          strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1);
     405    }
     406}
     407
     408/* RFC 2131
     409 * 4.4.4 Use of broadcast and unicast
     410 *
     411 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
     412 * messages, unless the client knows the address of a DHCP server.
     413 * The client unicasts DHCPRELEASE messages to the server. Because
     414 * the client is declining the use of the IP address supplied by the server,
     415 * the client broadcasts DHCPDECLINE messages.
     416 *
     417 * When the DHCP client knows the address of a DHCP server, in either
     418 * INIT or REBOOTING state, the client may use that address
     419 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
     420 * The client may also use unicast to send DHCPINFORM messages
     421 * to a known DHCP server. If the client receives no response to DHCP
     422 * messages sent to the IP address of a known DHCP server, the DHCP
     423 * client reverts to using the IP broadcast address.
    26424 */
    27 static unsigned timeout;
    28 static uint32_t requested_ip; /* = 0 */
    29 static uint32_t server_addr;
    30 static int packet_num; /* = 0 */
     425
     426static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
     427{
     428    return udhcp_send_raw_packet(packet,
     429        /*src*/ INADDR_ANY, CLIENT_PORT,
     430        /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
     431        client_config.ifindex);
     432}
     433
     434/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
     435/* NOINLINE: limit stack usage in caller */
     436static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
     437{
     438    struct dhcp_packet packet;
     439
     440    /* Fill in: op, htype, hlen, cookie, chaddr fields,
     441     * random xid field (we override it below),
     442     * client-id option (unless -C), message type option:
     443     */
     444    init_packet(&packet, DHCPDISCOVER);
     445
     446    packet.xid = xid;
     447    if (requested)
     448        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     449
     450    /* Add options: maxsize,
     451     * optionally: hostname, fqdn, vendorclass,
     452     * "param req" option according to -O, options specified with -x
     453     */
     454    add_client_options(&packet);
     455
     456    bb_info_msg("Sending discover...");
     457    return raw_bcast_from_client_config_ifindex(&packet);
     458}
     459
     460/* Broadcast a DHCP request message */
     461/* RFC 2131 3.1 paragraph 3:
     462 * "The client _broadcasts_ a DHCPREQUEST message..."
     463 */
     464/* NOINLINE: limit stack usage in caller */
     465static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested)
     466{
     467    struct dhcp_packet packet;
     468    struct in_addr addr;
     469
     470/*
     471 * RFC 2131 4.3.2 DHCPREQUEST message
     472 * ...
     473 * If the DHCPREQUEST message contains a 'server identifier'
     474 * option, the message is in response to a DHCPOFFER message.
     475 * Otherwise, the message is a request to verify or extend an
     476 * existing lease. If the client uses a 'client identifier'
     477 * in a DHCPREQUEST message, it MUST use that same 'client identifier'
     478 * in all subsequent messages. If the client included a list
     479 * of requested parameters in a DHCPDISCOVER message, it MUST
     480 * include that list in all subsequent messages.
     481 */
     482    /* Fill in: op, htype, hlen, cookie, chaddr fields,
     483     * random xid field (we override it below),
     484     * client-id option (unless -C), message type option:
     485     */
     486    init_packet(&packet, DHCPREQUEST);
     487
     488    packet.xid = xid;
     489    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     490
     491    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
     492
     493    /* Add options: maxsize,
     494     * optionally: hostname, fqdn, vendorclass,
     495     * "param req" option according to -O, and options specified with -x
     496     */
     497    add_client_options(&packet);
     498
     499    addr.s_addr = requested;
     500    bb_info_msg("Sending select for %s...", inet_ntoa(addr));
     501    return raw_bcast_from_client_config_ifindex(&packet);
     502}
     503
     504/* Unicast or broadcast a DHCP renew message */
     505/* NOINLINE: limit stack usage in caller */
     506static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
     507{
     508    struct dhcp_packet packet;
     509
     510/*
     511 * RFC 2131 4.3.2 DHCPREQUEST message
     512 * ...
     513 * DHCPREQUEST generated during RENEWING state:
     514 *
     515 * 'server identifier' MUST NOT be filled in, 'requested IP address'
     516 * option MUST NOT be filled in, 'ciaddr' MUST be filled in with
     517 * client's IP address. In this situation, the client is completely
     518 * configured, and is trying to extend its lease. This message will
     519 * be unicast, so no relay agents will be involved in its
     520 * transmission.  Because 'giaddr' is therefore not filled in, the
     521 * DHCP server will trust the value in 'ciaddr', and use it when
     522 * replying to the client.
     523 */
     524    /* Fill in: op, htype, hlen, cookie, chaddr fields,
     525     * random xid field (we override it below),
     526     * client-id option (unless -C), message type option:
     527     */
     528    init_packet(&packet, DHCPREQUEST);
     529
     530    packet.xid = xid;
     531    packet.ciaddr = ciaddr;
     532
     533    /* Add options: maxsize,
     534     * optionally: hostname, fqdn, vendorclass,
     535     * "param req" option according to -O, and options specified with -x
     536     */
     537    add_client_options(&packet);
     538
     539    bb_info_msg("Sending renew...");
     540    if (server)
     541        return udhcp_send_kernel_packet(&packet,
     542            ciaddr, CLIENT_PORT,
     543            server, SERVER_PORT);
     544    return raw_bcast_from_client_config_ifindex(&packet);
     545}
     546
     547#if ENABLE_FEATURE_UDHCPC_ARPING
     548/* Broadcast a DHCP decline message */
     549/* NOINLINE: limit stack usage in caller */
     550static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
     551{
     552    struct dhcp_packet packet;
     553
     554    /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
     555     * client-id option (unless -C), message type option:
     556     */
     557    init_packet(&packet, DHCPDECLINE);
     558
     559    /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
     560     * but in case the server is buggy and wants DHCPDECLINE's xid
     561     * to match the xid which started entire handshake,
     562     * we use the same xid we used in initial DHCPDISCOVER:
     563     */
     564    packet.xid = xid;
     565    /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
     566    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     567
     568    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
     569
     570    bb_info_msg("Sending decline...");
     571    return raw_bcast_from_client_config_ifindex(&packet);
     572}
     573#endif
     574
     575/* Unicast a DHCP release message */
     576static int send_release(uint32_t server, uint32_t ciaddr)
     577{
     578    struct dhcp_packet packet;
     579
     580    /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
     581     * client-id option (unless -C), message type option:
     582     */
     583    init_packet(&packet, DHCPRELEASE);
     584
     585    /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */
     586    packet.ciaddr = ciaddr;
     587
     588    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
     589
     590    bb_info_msg("Sending release...");
     591    return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
     592}
     593
     594/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
     595/* NOINLINE: limit stack usage in caller */
     596static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
     597{
     598    int bytes;
     599    struct ip_udp_dhcp_packet packet;
     600    uint16_t check;
     601
     602    memset(&packet, 0, sizeof(packet));
     603    bytes = safe_read(fd, &packet, sizeof(packet));
     604    if (bytes < 0) {
     605        log1("Packet read error, ignoring");
     606        /* NB: possible down interface, etc. Caller should pause. */
     607        return bytes; /* returns -1 */
     608    }
     609
     610    if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
     611        log1("Packet is too short, ignoring");
     612        return -2;
     613    }
     614
     615    if (bytes < ntohs(packet.ip.tot_len)) {
     616        /* packet is bigger than sizeof(packet), we did partial read */
     617        log1("Oversized packet, ignoring");
     618        return -2;
     619    }
     620
     621    /* ignore any extra garbage bytes */
     622    bytes = ntohs(packet.ip.tot_len);
     623
     624    /* make sure its the right packet for us, and that it passes sanity checks */
     625    if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
     626     || packet.ip.ihl != (sizeof(packet.ip) >> 2)
     627     || packet.udp.dest != htons(CLIENT_PORT)
     628    /* || bytes > (int) sizeof(packet) - can't happen */
     629     || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
     630    ) {
     631        log1("Unrelated/bogus packet, ignoring");
     632        return -2;
     633    }
     634
     635    /* verify IP checksum */
     636    check = packet.ip.check;
     637    packet.ip.check = 0;
     638    if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
     639        log1("Bad IP header checksum, ignoring");
     640        return -2;
     641    }
     642
     643    /* verify UDP checksum. IP header has to be modified for this */
     644    memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
     645    /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
     646    packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
     647    check = packet.udp.check;
     648    packet.udp.check = 0;
     649    if (check && check != udhcp_checksum(&packet, bytes)) {
     650        log1("Packet with bad UDP checksum received, ignoring");
     651        return -2;
     652    }
     653
     654    memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
     655
     656    if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
     657        bb_info_msg("Packet with bad magic, ignoring");
     658        return -2;
     659    }
     660    log1("Got valid DHCP packet");
     661    udhcp_dump_packet(dhcp_pkt);
     662    return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
     663}
     664
     665
     666/*** Main ***/
     667
    31668static int sockfd = -1;
    32669
    33 #define LISTEN_NONE 0
     670#define LISTEN_NONE   0
    34671#define LISTEN_KERNEL 1
    35 #define LISTEN_RAW 2
     672#define LISTEN_RAW    2
    36673static smallint listen_mode;
    37674
     675/* initial state: (re)start DHCP negotiation */
     676#define INIT_SELECTING  0
     677/* discover was sent, DHCPOFFER reply received */
     678#define REQUESTING      1
     679/* select/renew was sent, DHCPACK reply received */
     680#define BOUND           2
     681/* half of lease passed, want to renew it by sending unicast renew requests */
     682#define RENEWING        3
     683/* renew requests were not answered, lease is almost over, send broadcast renew */
     684#define REBINDING       4
     685/* manually requested renew (SIGUSR1) */
     686#define RENEW_REQUESTED 5
     687/* release, possibly manually requested (SIGUSR2) */
     688#define RELEASED        6
    38689static smallint state;
    39690
    40 struct client_config_t client_config;
    41 
    42 
    43 /* just a little helper */
    44 static void change_mode(int new_mode)
    45 {
    46     DEBUG("entering %s listen mode",
    47         new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
     691static int udhcp_raw_socket(int ifindex)
     692{
     693    int fd;
     694    struct sockaddr_ll sock;
     695
     696    /*
     697     * Comment:
     698     *
     699     *  I've selected not to see LL header, so BPF doesn't see it, too.
     700     *  The filter may also pass non-IP and non-ARP packets, but we do
     701     *  a more complete check when receiving the message in userspace.
     702     *
     703     * and filter shamelessly stolen from:
     704     *
     705     *  http://www.flamewarmaster.de/software/dhcpclient/
     706     *
     707     * There are a few other interesting ideas on that page (look under
     708     * "Motivation").  Use of netlink events is most interesting.  Think
     709     * of various network servers listening for events and reconfiguring.
     710     * That would obsolete sending HUP signals and/or make use of restarts.
     711     *
     712     * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
     713     * License: GPL v2.
     714     *
     715     * TODO: make conditional?
     716     */
     717#define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
     718    static const struct sock_filter filter_instr[] = {
     719        /* check for udp */
     720        BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
     721        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),     /* L5, L1, is UDP? */
     722        /* ugly check for arp on ethernet-like and IPv4 */
     723        BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                      /* L1: */
     724        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),      /* L3, L4 */
     725        /* skip IP header */
     726        BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),                     /* L5: */
     727        /* check udp source and destination ports */
     728        BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
     729        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
     730        /* returns */
     731        BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ),                   /* L3: pass */
     732        BPF_STMT(BPF_RET|BPF_K, 0),                             /* L4: reject */
     733    };
     734    static const struct sock_fprog filter_prog = {
     735        .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
     736        /* casting const away: */
     737        .filter = (struct sock_filter *) filter_instr,
     738    };
     739
     740    log1("Opening raw socket on ifindex %d", ifindex); //log2?
     741
     742    fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
     743    log1("Got raw socket fd %d", fd); //log2?
     744
     745    if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
     746        /* Use only if standard ports are in use */
     747        /* Ignoring error (kernel may lack support for this) */
     748        if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
     749                sizeof(filter_prog)) >= 0)
     750            log1("Attached filter to raw socket fd %d", fd); // log?
     751    }
     752
     753    sock.sll_family = AF_PACKET;
     754    sock.sll_protocol = htons(ETH_P_IP);
     755    sock.sll_ifindex = ifindex;
     756    xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
     757    log1("Created raw socket");
     758
     759    return fd;
     760}
     761
     762static void change_listen_mode(int new_mode)
     763{
     764    log1("Entering listen mode: %s",
     765        new_mode != LISTEN_NONE
     766            ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
     767            : "none"
     768    );
     769
     770    listen_mode = new_mode;
    48771    if (sockfd >= 0) {
    49772        close(sockfd);
    50773        sockfd = -1;
    51774    }
    52     listen_mode = new_mode;
    53 }
    54 
    55 
    56 /* perform a renew */
     775    if (new_mode == LISTEN_KERNEL)
     776        sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
     777    else if (new_mode != LISTEN_NONE)
     778        sockfd = udhcp_raw_socket(client_config.ifindex);
     779    /* else LISTEN_NONE: sockfd stays closed */
     780}
     781
    57782static void perform_renew(void)
    58783{
     
    60785    switch (state) {
    61786    case BOUND:
    62         change_mode(LISTEN_KERNEL);
     787        change_listen_mode(LISTEN_KERNEL);
    63788    case RENEWING:
    64789    case REBINDING:
     
    69794    case REQUESTING:
    70795    case RELEASED:
    71         change_mode(LISTEN_RAW);
     796        change_listen_mode(LISTEN_RAW);
    72797        state = INIT_SELECTING;
    73798        break;
     
    75800        break;
    76801    }
    77 
    78     /* start things over */
    79     packet_num = 0;
    80 
    81     /* Kill any timeouts because the user wants this to hurry along */
    82     timeout = 0;
    83 }
    84 
    85 
    86 /* perform a release */
    87 static void perform_release(void)
     802}
     803
     804static void perform_release(uint32_t requested_ip, uint32_t server_addr)
    88805{
    89806    char buffer[sizeof("255.255.255.255")];
     
    102819    bb_info_msg("Entering released state");
    103820
    104     change_mode(LISTEN_NONE);
     821    change_listen_mode(LISTEN_NONE);
    105822    state = RELEASED;
    106     timeout = INT_MAX;
    107 }
    108 
    109 
    110 static void client_background(void)
    111 {
    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;
    126     client_config.background_if_no_lease = 0;
    127 }
    128 
     823}
    129824
    130825static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
    131826{
    132827    uint8_t *storage;
    133     int len = strlen(str);
    134     if (len > 255) len = 255;
     828    int len = strnlen(str, 255);
    135829    storage = xzalloc(len + extra + OPT_DATA);
    136830    storage[OPT_CODE] = code;
     
    140834}
    141835
    142 
    143 int udhcpc_main(int argc, char **argv);
    144 int udhcpc_main(int argc, char **argv)
     836#if BB_MMU
     837static void client_background(void)
     838{
     839    bb_daemonize(0);
     840    logmode &= ~LOGMODE_STDIO;
     841    /* rewrite pidfile, as our pid is different now */
     842    write_pidfile(client_config.pidfile);
     843}
     844#endif
     845
     846//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     847//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
     848//usage:#else
     849//usage:# define IF_UDHCP_VERBOSE(...)
     850//usage:#endif
     851//usage:#define udhcpc_trivial_usage
     852//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
     853//usage:       "    [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
     854//usage:#define udhcpc_full_usage "\n"
     855//usage:    IF_LONG_OPTS(
     856//usage:     "\n    -i,--interface IFACE    Interface to use (default eth0)"
     857//usage:     "\n    -p,--pidfile FILE   Create pidfile"
     858//usage:     "\n    -s,--script PROG    Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
     859//usage:     "\n    -t,--retries N      Send up to N discover packets"
     860//usage:     "\n    -T,--timeout N      Pause between packets (default 3 seconds)"
     861//usage:     "\n    -A,--tryagain N     Wait N seconds after failure (default 20)"
     862//usage:     "\n    -f,--foreground     Run in foreground"
     863//usage:    USE_FOR_MMU(
     864//usage:     "\n    -b,--background     Background if lease is not obtained"
     865//usage:    )
     866//usage:     "\n    -n,--now        Exit if lease is not obtained"
     867//usage:     "\n    -q,--quit       Exit after obtaining lease"
     868//usage:     "\n    -R,--release        Release IP on exit"
     869//usage:     "\n    -S,--syslog     Log to syslog too"
     870//usage:    IF_FEATURE_UDHCP_PORT(
     871//usage:     "\n    -P,--client-port N  Use port N (default 68)"
     872//usage:    )
     873//usage:    IF_FEATURE_UDHCPC_ARPING(
     874//usage:     "\n    -a,--arping     Use arping to validate offered address"
     875//usage:    )
     876//usage:     "\n    -O,--request-option OPT Request option OPT from server (cumulative)"
     877//usage:     "\n    -o,--no-default-options Don't request any options (unless -O is given)"
     878//usage:     "\n    -r,--request IP     Request this IP address"
     879//usage:     "\n    -x OPT:VAL      Include option OPT in sent packets (cumulative)"
     880//usage:     "\n                Examples of string, numeric, and hex byte opts:"
     881//usage:     "\n                -x hostname:bbox - option 12"
     882//usage:     "\n                -x lease:3600 - option 51 (lease time)"
     883//usage:     "\n                -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
     884//usage:     "\n    -F,--fqdn NAME      Ask server to update DNS mapping for NAME"
     885//usage:     "\n    -H,-h,--hostname NAME   Send NAME as client hostname (default none)"
     886//usage:     "\n    -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')"
     887//usage:     "\n    -C,--clientid-none  Don't send MAC as client identifier"
     888//usage:    IF_UDHCP_VERBOSE(
     889//usage:     "\n    -v          Verbose"
     890//usage:    )
     891//usage:    )
     892//usage:    IF_NOT_LONG_OPTS(
     893//usage:     "\n    -i IFACE    Interface to use (default eth0)"
     894//usage:     "\n    -p FILE     Create pidfile"
     895//usage:     "\n    -s PROG     Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
     896//usage:     "\n    -t N        Send up to N discover packets"
     897//usage:     "\n    -T N        Pause between packets (default 3 seconds)"
     898//usage:     "\n    -A N        Wait N seconds (default 20) after failure"
     899//usage:     "\n    -f      Run in foreground"
     900//usage:    USE_FOR_MMU(
     901//usage:     "\n    -b      Background if lease is not obtained"
     902//usage:    )
     903//usage:     "\n    -n      Exit if lease is not obtained"
     904//usage:     "\n    -q      Exit after obtaining lease"
     905//usage:     "\n    -R      Release IP on exit"
     906//usage:     "\n    -S      Log to syslog too"
     907//usage:    IF_FEATURE_UDHCP_PORT(
     908//usage:     "\n    -P N        Use port N (default 68)"
     909//usage:    )
     910//usage:    IF_FEATURE_UDHCPC_ARPING(
     911//usage:     "\n    -a      Use arping to validate offered address"
     912//usage:    )
     913//usage:     "\n    -O OPT      Request option OPT from server (cumulative)"
     914//usage:     "\n    -o      Don't request any options (unless -O is given)"
     915//usage:     "\n    -r IP       Request this IP address"
     916//usage:     "\n    -x OPT:VAL  Include option OPT in sent packets (cumulative)"
     917//usage:     "\n            Examples of string, numeric, and hex byte opts:"
     918//usage:     "\n            -x hostname:bbox - option 12"
     919//usage:     "\n            -x lease:3600 - option 51 (lease time)"
     920//usage:     "\n            -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
     921//usage:     "\n    -F NAME     Ask server to update DNS mapping for NAME"
     922//usage:     "\n    -H,-h NAME  Send NAME as client hostname (default none)"
     923//usage:     "\n    -V VENDOR   Vendor identifier (default 'udhcp VERSION')"
     924//usage:     "\n    -C      Don't send MAC as client identifier"
     925//usage:    IF_UDHCP_VERBOSE(
     926//usage:     "\n    -v      Verbose"
     927//usage:    )
     928//usage:    )
     929
     930int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     931int udhcpc_main(int argc UNUSED_PARAM, char **argv)
    145932{
    146933    uint8_t *temp, *message;
    147     char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t;
     934    const char *str_V, *str_h, *str_F, *str_r;
     935    IF_FEATURE_UDHCP_PORT(char *str_P;)
     936    void *clientid_mac_ptr;
     937    llist_t *list_O = NULL;
     938    llist_t *list_x = NULL;
     939    int tryagain_timeout = 20;
     940    int discover_timeout = 3;
     941    int discover_retries = 3;
     942    uint32_t server_addr = server_addr; /* for compiler */
     943    uint32_t requested_ip = 0;
    148944    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;
     945    uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */
     946    int packet_num;
     947    int timeout; /* must be signed */
     948    unsigned already_waited_sec;
    153949    unsigned opt;
    154950    int max_fd;
    155951    int retval;
    156     int len;
    157952    struct timeval tv;
    158     struct in_addr temp_addr;
    159     struct dhcpMessage packet;
     953    struct dhcp_packet packet;
    160954    fd_set rfds;
    161955
    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,
    182     };
    183 #if ENABLE_GETOPT_LONG
     956#if ENABLE_LONG_OPTS
    184957    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"
     958        "clientid-none\0"  No_argument       "C"
     959        "vendorclass\0"    Required_argument "V"
     960        "hostname\0"       Required_argument "H"
     961        "fqdn\0"           Required_argument "F"
     962        "interface\0"      Required_argument "i"
     963        "now\0"            No_argument       "n"
     964        "pidfile\0"        Required_argument "p"
     965        "quit\0"           No_argument       "q"
     966        "release\0"        No_argument       "R"
     967        "request\0"        Required_argument "r"
     968        "script\0"         Required_argument "s"
     969        "timeout\0"        Required_argument "T"
     970        "version\0"        No_argument       "v"
     971        "retries\0"        Required_argument "t"
     972        "tryagain\0"       Required_argument "A"
     973        "syslog\0"         No_argument       "S"
     974        "request-option\0" Required_argument "O"
     975        "no-default-options\0" No_argument   "o"
     976        "foreground\0"     No_argument       "f"
     977        "background\0"     No_argument       "b"
     978        IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")
     979        IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
    204980        ;
    205981#endif
    206     /* Default options. */
     982    enum {
     983        OPT_C = 1 << 0,
     984        OPT_V = 1 << 1,
     985        OPT_H = 1 << 2,
     986        OPT_h = 1 << 3,
     987        OPT_F = 1 << 4,
     988        OPT_i = 1 << 5,
     989        OPT_n = 1 << 6,
     990        OPT_p = 1 << 7,
     991        OPT_q = 1 << 8,
     992        OPT_R = 1 << 9,
     993        OPT_r = 1 << 10,
     994        OPT_s = 1 << 11,
     995        OPT_T = 1 << 12,
     996        OPT_t = 1 << 13,
     997        OPT_S = 1 << 14,
     998        OPT_A = 1 << 15,
     999        OPT_O = 1 << 16,
     1000        OPT_o = 1 << 17,
     1001        OPT_x = 1 << 18,
     1002        OPT_f = 1 << 19,
     1003/* The rest has variable bit positions, need to be clever */
     1004        OPTBIT_f = 19,
     1005        USE_FOR_MMU(             OPTBIT_b,)
     1006        IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
     1007        IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
     1008        USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
     1009        IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
     1010        IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
     1011    };
     1012
     1013    /* Default options */
     1014    IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
     1015    IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
    2071016    client_config.interface = "eth0";
    208     client_config.script = DEFAULT_SCRIPT;
    209     client_config.retries = 3;
    210     client_config.timeout = 3;
     1017    client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
     1018    str_V = "udhcp "BB_VER;
    2111019
    2121020    /* 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;
     1021    /* O,x: list; -T,-t,-A take numeric param */
     1022    opt_complementary = "O::x::T+:t+:A+"
     1023#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     1024        ":vv"
    2171025#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
     1026        ;
     1027    IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
     1028    opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f"
     1029        USE_FOR_MMU("b")
     1030        IF_FEATURE_UDHCPC_ARPING("a")
     1031        IF_FEATURE_UDHCP_PORT("P:")
     1032        "v"
     1033        , &str_V, &str_h, &str_h, &str_F
     1034        , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
     1035        , &client_config.script /* s */
     1036        , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
     1037        , &list_O
     1038        , &list_x
     1039        IF_FEATURE_UDHCP_PORT(, &str_P)
     1040#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     1041        , &dhcp_verbose
     1042#endif
    2221043        );
    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)
     1044    if (opt & (OPT_h|OPT_H))
    2341045        client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
    2351046    if (opt & OPT_F) {
     1047        /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
    2361048        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         */
     1049        /* Flag bits: 0000NEOS
     1050         * S: 1 = Client requests server to update A RR in DNS as well as PTR
     1051         * O: 1 = Server indicates to client that DNS has been updated regardless
     1052         * E: 1 = Name is in DNS format, i.e. <4>host<6>domain<3>com<0>,
     1053         *    not "host.domain.com". Format 0 is obsolete.
     1054         * N: 1 = Client requests server to not update DNS (S must be 0 then)
     1055         * Two [0] bytes which follow are deprecated and must be 0.
     1056         */
    2431057        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;
     1058        /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
     1059        /*client_config.fqdn[OPT_DATA + 2] = 0; */
     1060    }
    2551061    if (opt & OPT_r)
    2561062        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 
     1063#if ENABLE_FEATURE_UDHCP_PORT
     1064    if (opt & OPT_P) {
     1065        CLIENT_PORT = xatou16(str_P);
     1066        SERVER_PORT = CLIENT_PORT - 1;
     1067    }
     1068#endif
     1069    if (opt & OPT_o)
     1070        client_config.no_default_options = 1;
     1071    while (list_O) {
     1072        char *optstr = llist_pop(&list_O);
     1073        unsigned n = udhcp_option_idx(optstr);
     1074        n = dhcp_optflags[n].code;
     1075        client_config.opt_mask[n >> 3] |= 1 << (n & 7);
     1076    }
     1077    while (list_x) {
     1078        char *optstr = llist_pop(&list_x);
     1079        char *colon = strchr(optstr, ':');
     1080        if (colon)
     1081            *colon = ' ';
     1082        /* now it looks similar to udhcpd's config file line:
     1083         * "optname optval", using the common routine: */
     1084        udhcp_str2optset(optstr, &client_config.options);
     1085    }
     1086
     1087    if (udhcp_read_interface(client_config.interface,
     1088            &client_config.ifindex,
     1089            NULL,
     1090            client_config.client_mac)
     1091    ) {
     1092        return 1;
     1093    }
     1094
     1095    clientid_mac_ptr = NULL;
     1096    if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) {
     1097        /* not suppressed and not set, set the default client ID */
     1098        client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
     1099        client_config.clientid[OPT_DATA] = 1; /* type: ethernet */
     1100        clientid_mac_ptr = client_config.clientid + OPT_DATA+1;
     1101        memcpy(clientid_mac_ptr, client_config.client_mac, 6);
     1102    }
     1103    if (str_V[0] != '\0')
     1104        client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
     1105#if !BB_MMU
     1106    /* on NOMMU reexec (i.e., background) early */
     1107    if (!(opt & OPT_f)) {
     1108        bb_daemonize_or_rexec(0 /* flags */, argv);
     1109        logmode = LOGMODE_NONE;
     1110    }
     1111#endif
    2671112    if (opt & OPT_S) {
    268         openlog(applet_name, LOG_PID, LOG_LOCAL0);
     1113        openlog(applet_name, LOG_PID, LOG_DAEMON);
    2691114        logmode |= LOGMODE_SYSLOG;
    2701115    }
    271 
    272     if (read_interface(client_config.interface, &client_config.ifindex,
    273                NULL, client_config.arp))
    274         return 1;
    2751116
    2761117    /* Make sure fd 0,1,2 are open */
     
    2781119    /* Equivalent of doing a fflush after every \n */
    2791120    setlinebuf(stdout);
    280 
    2811121    /* Create pidfile */
    2821122    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 
    288     /* if not set, and not suppressed, setup the default client ID */
    289     if (!client_config.clientid && !(opt & OPT_C)) {
    290         client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
    291         client_config.clientid[OPT_DATA] = 1;
    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);
    297 
    298     /* setup the signal pipe */
     1123    /* Goes to stdout (unless NOMMU) and possibly syslog */
     1124    bb_info_msg("%s (v"BB_VER") started", applet_name);
     1125    /* Set up the signal pipe */
    2991126    udhcp_sp_setup();
     1127    /* We want random_xid to be random... */
     1128    srand(monotonic_us());
    3001129
    3011130    state = INIT_SELECTING;
    3021131    udhcp_run_script(NULL, "deconfig");
    303     change_mode(LISTEN_RAW);
    304     tv.tv_sec = 0;
    305     goto jump_in;
    306 
     1132    change_listen_mode(LISTEN_RAW);
     1133    packet_num = 0;
     1134    timeout = 0;
     1135    already_waited_sec = 0;
     1136
     1137    /* Main event loop. select() waits on signal pipe and possibly
     1138     * on sockfd.
     1139     * "continue" statements in code below jump to the top of the loop.
     1140     */
    3071141    for (;;) {
    308         tv.tv_sec = timeout - monotonic_sec();
    309  jump_in:
     1142        /* silence "uninitialized!" warning */
     1143        unsigned timestamp_before_wait = timestamp_before_wait;
     1144
     1145        //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
     1146
     1147        /* Was opening raw or udp socket here
     1148         * if (listen_mode != LISTEN_NONE && sockfd < 0),
     1149         * but on fast network renew responses return faster
     1150         * than we open sockets. Thus this code is moved
     1151         * to change_listen_mode(). Thus we open listen socket
     1152         * BEFORE we send renew request (see "case BOUND:"). */
     1153
     1154        max_fd = udhcp_sp_fd_set(&rfds, sockfd);
     1155
     1156        tv.tv_sec = timeout - already_waited_sec;
    3101157        tv.tv_usec = 0;
    311 
    312         if (listen_mode != LISTEN_NONE && sockfd < 0) {
    313             if (listen_mode == LISTEN_KERNEL)
    314                 sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
    315             else
    316                 sockfd = raw_socket(client_config.ifindex);
    317         }
    318         max_fd = udhcp_sp_fd_set(&rfds, sockfd);
    319 
    320         retval = 0; /* If we already timed out, fall through, else... */
    321         if (tv.tv_sec > 0) {
    322             DEBUG("Waiting on select...");
     1158        retval = 0;
     1159        /* If we already timed out, fall through with retval = 0, else... */
     1160        if ((int)tv.tv_sec > 0) {
     1161            timestamp_before_wait = (unsigned)monotonic_sec();
     1162            log1("Waiting on select...");
    3231163            retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
    324         }
    325 
    326         now = monotonic_sec();
    327         if (retval < 0) {
    328             /* EINTR? signal was caught, don't panic */
    329             if (errno != EINTR) {
     1164            if (retval < 0) {
     1165                /* EINTR? A signal was caught, don't panic */
     1166                if (errno == EINTR) {
     1167                    already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
     1168                    continue;
     1169                }
    3301170                /* Else: an error occured, panic! */
    3311171                bb_perror_msg_and_die("select");
    3321172            }
    333         } else if (retval == 0) {
    334             /* timeout dropped to zero */
     1173        }
     1174
     1175        /* If timeout dropped to zero, time to become active:
     1176         * resend discover/renew/whatever
     1177         */
     1178        if (retval == 0) {
     1179            /* When running on a bridge, the ifindex may have changed
     1180             * (e.g. if member interfaces were added/removed
     1181             * or if the status of the bridge changed).
     1182             * Refresh ifindex and client_mac:
     1183             */
     1184            if (udhcp_read_interface(client_config.interface,
     1185                    &client_config.ifindex,
     1186                    NULL,
     1187                    client_config.client_mac)
     1188            ) {
     1189                return 1; /* iface is gone? */
     1190            }
     1191            if (clientid_mac_ptr)
     1192                memcpy(clientid_mac_ptr, client_config.client_mac, 6);
     1193
     1194            /* We will restart the wait in any case */
     1195            already_waited_sec = 0;
     1196
    3351197            switch (state) {
    3361198            case INIT_SELECTING:
    337                 if (packet_num < client_config.retries) {
     1199                if (packet_num < discover_retries) {
    3381200                    if (packet_num == 0)
    3391201                        xid = random_xid();
    340 
    341                     /* send discover packet */
    342                     send_discover(xid, requested_ip); /* broadcast */
    343 
    344                     timeout = now + client_config.timeout;
     1202                    /* broadcast */
     1203                    send_discover(xid, requested_ip);
     1204                    timeout = discover_timeout;
    3451205                    packet_num++;
     1206                    continue;
     1207                }
     1208 leasefail:
     1209                udhcp_run_script(NULL, "leasefail");
     1210#if BB_MMU /* -b is not supported on NOMMU */
     1211                if (opt & OPT_b) { /* background if no lease */
     1212                    bb_info_msg("No lease, forking to background");
     1213                    client_background();
     1214                    /* do not background again! */
     1215                    opt = ((opt & ~OPT_b) | OPT_f);
     1216                } else
     1217#endif
     1218                if (opt & OPT_n) { /* abort if no lease */
     1219                    bb_info_msg("No lease, failing");
     1220                    retval = 1;
     1221                    goto ret;
     1222                }
     1223                /* wait before trying again */
     1224                timeout = tryagain_timeout;
     1225                packet_num = 0;
     1226                continue;
     1227            case REQUESTING:
     1228                if (packet_num < discover_retries) {
     1229                    /* send broadcast select packet */
     1230                    send_select(xid, server_addr, requested_ip);
     1231                    timeout = discover_timeout;
     1232                    packet_num++;
     1233                    continue;
     1234                }
     1235                /* Timed out, go back to init state.
     1236                 * "discover...select...discover..." loops
     1237                 * were seen in the wild. Treat them similarly
     1238                 * to "no response to discover" case */
     1239                change_listen_mode(LISTEN_RAW);
     1240                state = INIT_SELECTING;
     1241                goto leasefail;
     1242            case BOUND:
     1243                /* 1/2 lease passed, enter renewing state */
     1244                state = RENEWING;
     1245                change_listen_mode(LISTEN_KERNEL);
     1246                log1("Entering renew state");
     1247                /* fall right through */
     1248            case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
     1249            case_RENEW_REQUESTED:
     1250            case RENEWING:
     1251                if (timeout > 60) {
     1252                    /* send an unicast renew request */
     1253            /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
     1254             * a new UDP socket for sending inside send_renew.
     1255             * I hazard to guess existing listening socket
     1256             * is somehow conflicting with it, but why is it
     1257             * not deterministic then?! Strange.
     1258             * Anyway, it does recover by eventually failing through
     1259             * into INIT_SELECTING state.
     1260             */
     1261                    send_renew(xid, server_addr, requested_ip);
     1262                    timeout >>= 1;
     1263                    continue;
     1264                }
     1265                /* Timed out, enter rebinding state */
     1266                log1("Entering rebinding state");
     1267                state = REBINDING;
     1268                /* fall right through */
     1269            case REBINDING:
     1270                /* Switch to bcast receive */
     1271                change_listen_mode(LISTEN_RAW);
     1272                /* Lease is *really* about to run out,
     1273                 * try to find DHCP server using broadcast */
     1274                if (timeout > 0) {
     1275                    /* send a broadcast renew request */
     1276                    send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
     1277                    timeout >>= 1;
     1278                    continue;
     1279                }
     1280                /* Timed out, enter init state */
     1281                bb_info_msg("Lease lost, entering init state");
     1282                udhcp_run_script(NULL, "deconfig");
     1283                state = INIT_SELECTING;
     1284                /*timeout = 0; - already is */
     1285                packet_num = 0;
     1286                continue;
     1287            /* case RELEASED: */
     1288            }
     1289            /* yah, I know, *you* say it would never happen */
     1290            timeout = INT_MAX;
     1291            continue; /* back to main loop */
     1292        } /* if select timed out */
     1293
     1294        /* select() didn't timeout, something happened */
     1295
     1296        /* Is it a signal? */
     1297        /* note: udhcp_sp_read checks FD_ISSET before reading */
     1298        switch (udhcp_sp_read(&rfds)) {
     1299        case SIGUSR1:
     1300            perform_renew();
     1301            if (state == RENEW_REQUESTED)
     1302                goto case_RENEW_REQUESTED;
     1303            /* Start things over */
     1304            packet_num = 0;
     1305            /* Kill any timeouts, user wants this to hurry along */
     1306            timeout = 0;
     1307            continue;
     1308        case SIGUSR2:
     1309            perform_release(requested_ip, server_addr);
     1310            timeout = INT_MAX;
     1311            continue;
     1312        case SIGTERM:
     1313            bb_info_msg("Received SIGTERM");
     1314            if (opt & OPT_R) /* release on quit */
     1315                perform_release(requested_ip, server_addr);
     1316            goto ret0;
     1317        }
     1318
     1319        /* Is it a packet? */
     1320        if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
     1321            continue; /* no */
     1322
     1323        {
     1324            int len;
     1325
     1326            /* A packet is ready, read it */
     1327            if (listen_mode == LISTEN_KERNEL)
     1328                len = udhcp_recv_kernel_packet(&packet, sockfd);
     1329            else
     1330                len = udhcp_recv_raw_packet(&packet, sockfd);
     1331            if (len == -1) {
     1332                /* Error is severe, reopen socket */
     1333                bb_info_msg("Read error: %s, reopening socket", strerror(errno));
     1334                sleep(discover_timeout); /* 3 seconds by default */
     1335                change_listen_mode(listen_mode); /* just close and reopen */
     1336            }
     1337            /* If this packet will turn out to be unrelated/bogus,
     1338             * we will go back and wait for next one.
     1339             * Be sure timeout is properly decreased. */
     1340            already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
     1341            if (len < 0)
     1342                continue;
     1343        }
     1344
     1345        if (packet.xid != xid) {
     1346            log1("xid %x (our is %x), ignoring packet",
     1347                (unsigned)packet.xid, (unsigned)xid);
     1348            continue;
     1349        }
     1350
     1351        /* Ignore packets that aren't for us */
     1352        if (packet.hlen != 6
     1353         || memcmp(packet.chaddr, client_config.client_mac, 6) != 0
     1354        ) {
     1355//FIXME: need to also check that last 10 bytes are zero
     1356            log1("chaddr does not match, ignoring packet"); // log2?
     1357            continue;
     1358        }
     1359
     1360        message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
     1361        if (message == NULL) {
     1362            bb_error_msg("no message type option, ignoring packet");
     1363            continue;
     1364        }
     1365
     1366        switch (state) {
     1367        case INIT_SELECTING:
     1368            /* Must be a DHCPOFFER to one of our xid's */
     1369            if (*message == DHCPOFFER) {
     1370        /* TODO: why we don't just fetch server's IP from IP header? */
     1371                temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
     1372                if (!temp) {
     1373                    bb_error_msg("no server ID, ignoring packet");
     1374                    continue;
     1375                    /* still selecting - this server looks bad */
     1376                }
     1377                /* it IS unaligned sometimes, don't "optimize" */
     1378                move_from_unaligned32(server_addr, temp);
     1379                /*xid = packet.xid; - already is */
     1380                requested_ip = packet.yiaddr;
     1381
     1382                /* enter requesting state */
     1383                state = REQUESTING;
     1384                timeout = 0;
     1385                packet_num = 0;
     1386                already_waited_sec = 0;
     1387            }
     1388            continue;
     1389        case REQUESTING:
     1390        case RENEWING:
     1391        case RENEW_REQUESTED:
     1392        case REBINDING:
     1393            if (*message == DHCPACK) {
     1394                temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
     1395                if (!temp) {
     1396                    bb_error_msg("no lease time with ACK, using 1 hour lease");
     1397                    lease_seconds = 60 * 60;
    3461398                } else {
    347                     udhcp_run_script(NULL, "leasefail");
    348                     if (client_config.background_if_no_lease) {
    349                         bb_info_msg("No lease, forking to background");
    350                         client_background();
    351                     } else if (client_config.abort_if_no_lease) {
    352                         bb_info_msg("No lease, failing");
    353                         retval = 1;
    354                         goto ret;
    355                     }
    356                     /* wait to try again */
    357                     packet_num = 0;
    358                     timeout = now + 60;
     1399                    /* it IS unaligned sometimes, don't "optimize" */
     1400                    move_from_unaligned32(lease_seconds, temp);
     1401                    lease_seconds = ntohl(lease_seconds);
     1402                    lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
     1403                    if (lease_seconds < 10) /* and not too small */
     1404                        lease_seconds = 10;
    3591405                }
    360                 break;
    361             case RENEW_REQUESTED:
    362             case REQUESTING:
    363                 if (packet_num < client_config.retries) {
    364                     /* send request packet */
    365                     if (state == RENEW_REQUESTED)
    366                         send_renew(xid, server_addr, requested_ip); /* unicast */
    367                     else send_selecting(xid, server_addr, requested_ip); /* broadcast */
    368 
    369                     timeout = now + ((packet_num == 2) ? 10 : 2);
    370                     packet_num++;
    371                 } else {
    372                     /* timed out, go back to init state */
    373                     if (state == RENEW_REQUESTED)
    374                         udhcp_run_script(NULL, "deconfig");
    375                     state = INIT_SELECTING;
    376                     timeout = now;
    377                     packet_num = 0;
    378                     change_mode(LISTEN_RAW);
    379                 }
    380                 break;
    381             case BOUND:
    382                 /* Lease is starting to run out, time to enter renewing state */
    383                 state = RENEWING;
    384                 change_mode(LISTEN_KERNEL);
    385                 DEBUG("Entering renew state");
    386                 /* fall right through */
    387             case RENEWING:
    388                 /* Either set a new T1, or enter REBINDING state */
    389                 if ((t2 - t1) <= (lease / 14400 + 1)) {
    390                     /* timed out, enter rebinding state */
    391                     state = REBINDING;
    392                     timeout = now + (t2 - t1);
    393                     DEBUG("Entering rebinding state");
    394                 } else {
    395                     /* send a request packet */
    396                     send_renew(xid, server_addr, requested_ip); /* unicast */
    397                     t1 = (t2 - t1) / 2 + t1;
    398                     timeout = start + t1;
    399                 }
    400                 break;
    401             case REBINDING:
    402                 /* Either set a new T2, or enter INIT state */
    403                 if ((lease - t2) <= (lease / 14400 + 1)) {
    404                     /* timed out, enter init state */
    405                     state = INIT_SELECTING;
    406                     bb_info_msg("Lease lost, entering init state");
    407                     udhcp_run_script(NULL, "deconfig");
    408                     timeout = now;
    409                     packet_num = 0;
    410                     change_mode(LISTEN_RAW);
    411                 } else {
    412                     /* send a request packet */
    413                     send_renew(xid, 0, requested_ip); /* broadcast */
    414                     t2 = (lease - t2) / 2 + t2;
    415                     timeout = start + t2;
    416                 }
    417                 break;
    418             case RELEASED:
    419                 /* yah, I know, *you* say it would never happen */
    420                 timeout = INT_MAX;
    421                 break;
    422             }
    423         } else if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) {
    424             /* a packet is ready, read it */
    425 
    426             if (listen_mode == LISTEN_KERNEL)
    427                 len = udhcp_get_packet(&packet, sockfd);
    428             else len = get_raw_packet(&packet, sockfd);
    429 
    430             if (len == -1 && errno != EINTR) {
    431                 DEBUG("error on read, %s, reopening socket", strerror(errno));
    432                 change_mode(listen_mode); /* just close and reopen */
    433             }
    434             if (len < 0) continue;
    435 
    436             if (packet.xid != xid) {
    437                 DEBUG("Ignoring XID %x (our xid is %x)",
    438                     (unsigned)packet.xid, (unsigned)xid);
    439                 continue;
    440             }
    441 
    442             /* Ignore packets that aren't for us */
    443             if (memcmp(packet.chaddr, client_config.arp, 6)) {
    444                 DEBUG("Packet does not have our chaddr - ignoring");
    445                 continue;
    446             }
    447 
    448             message = get_option(&packet, DHCP_MESSAGE_TYPE);
    449             if (message == NULL) {
    450                 bb_error_msg("cannot get option from packet - ignoring");
    451                 continue;
    452             }
    453 
    454             switch (state) {
    455             case INIT_SELECTING:
    456                 /* Must be a DHCPOFFER to one of our xid's */
    457                 if (*message == DHCPOFFER) {
    458                     temp = get_option(&packet, DHCP_SERVER_ID);
    459                     if (temp) {
    460                         /* can be misaligned, thus memcpy */
    461                         memcpy(&server_addr, temp, 4);
    462                         xid = packet.xid;
    463                         requested_ip = packet.yiaddr;
    464 
    465                         /* enter requesting state */
    466                         state = REQUESTING;
    467                         timeout = now;
     1406#if ENABLE_FEATURE_UDHCPC_ARPING
     1407                if (opt & OPT_a) {
     1408/* RFC 2131 3.1 paragraph 5:
     1409 * "The client receives the DHCPACK message with configuration
     1410 * parameters. The client SHOULD perform a final check on the
     1411 * parameters (e.g., ARP for allocated network address), and notes
     1412 * the duration of the lease specified in the DHCPACK message. At this
     1413 * point, the client is configured. If the client detects that the
     1414 * address is already in use (e.g., through the use of ARP),
     1415 * the client MUST send a DHCPDECLINE message to the server and restarts
     1416 * the configuration process..." */
     1417                    if (!arpping(packet.yiaddr,
     1418                            NULL,
     1419                            (uint32_t) 0,
     1420                            client_config.client_mac,
     1421                            client_config.interface)
     1422                    ) {
     1423                        bb_info_msg("Offered address is in use "
     1424                            "(got ARP reply), declining");
     1425                        send_decline(xid, server_addr, packet.yiaddr);
     1426
     1427                        if (state != REQUESTING)
     1428                            udhcp_run_script(NULL, "deconfig");
     1429                        change_listen_mode(LISTEN_RAW);
     1430                        state = INIT_SELECTING;
     1431                        requested_ip = 0;
     1432                        timeout = tryagain_timeout;
    4681433                        packet_num = 0;
    469                     } else {
    470                         bb_error_msg("no server ID in message");
     1434                        already_waited_sec = 0;
     1435                        continue; /* back to main loop */
    4711436                    }
    4721437                }
    473                 break;
    474             case RENEW_REQUESTED:
    475             case REQUESTING:
    476             case RENEWING:
    477             case REBINDING:
    478                 if (*message == DHCPACK) {
    479                     temp = get_option(&packet, DHCP_LEASE_TIME);
    480                     if (!temp) {
    481                         bb_error_msg("no lease time with ACK, using 1 hour lease");
    482                         lease = 60 * 60;
    483                     } else {
    484                         /* can be misaligned, thus memcpy */
    485                         memcpy(&lease, temp, 4);
    486                         lease = ntohl(lease);
    487                     }
    488 
    489                     /* enter bound state */
    490                     t1 = lease / 2;
    491 
    492                     /* little fixed point for n * .875 */
    493                     t2 = (lease * 7) >> 3;
     1438#endif
     1439                /* enter bound state */
     1440                timeout = lease_seconds / 2;
     1441                {
     1442                    struct in_addr temp_addr;
    4941443                    temp_addr.s_addr = packet.yiaddr;
    4951444                    bb_info_msg("Lease of %s obtained, lease time %u",
    496                         inet_ntoa(temp_addr), (unsigned)lease);
    497                     start = now;
    498                     timeout = start + t1;
    499                     requested_ip = packet.yiaddr;
    500                     udhcp_run_script(&packet,
    501                            ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
    502 
    503                     state = BOUND;
    504                     change_mode(LISTEN_NONE);
    505                     if (client_config.quit_after_lease) {
    506                         if (client_config.release_on_quit)
    507                             perform_release();
    508                         goto ret0;
    509                     }
    510                     if (!client_config.foreground)
    511                         client_background();
    512 
    513                 } else if (*message == DHCPNAK) {
    514                     /* return to init state */
    515                     bb_info_msg("Received DHCP NAK");
    516                     udhcp_run_script(&packet, "nak");
    517                     if (state != REQUESTING)
    518                         udhcp_run_script(NULL, "deconfig");
    519                     state = INIT_SELECTING;
    520                     timeout = now;
    521                     requested_ip = 0;
    522                     packet_num = 0;
    523                     change_mode(LISTEN_RAW);
    524                     sleep(3); /* avoid excessive network traffic */
     1445                        inet_ntoa(temp_addr), (unsigned)lease_seconds);
    5251446                }
    526                 break;
    527             /* case BOUND, RELEASED: - ignore all packets */
     1447                requested_ip = packet.yiaddr;
     1448                udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
     1449
     1450                state = BOUND;
     1451                change_listen_mode(LISTEN_NONE);
     1452                if (opt & OPT_q) { /* quit after lease */
     1453                    if (opt & OPT_R) /* release on quit */
     1454                        perform_release(requested_ip, server_addr);
     1455                    goto ret0;
     1456                }
     1457                /* future renew failures should not exit (JM) */
     1458                opt &= ~OPT_n;
     1459#if BB_MMU /* NOMMU case backgrounded earlier */
     1460                if (!(opt & OPT_f)) {
     1461                    client_background();
     1462                    /* do not background again! */
     1463                    opt = ((opt & ~OPT_b) | OPT_f);
     1464                }
     1465#endif
     1466                already_waited_sec = 0;
     1467                continue; /* back to main loop */
    5281468            }
    529         } else {
    530             int signo = udhcp_sp_read(&rfds);
    531             switch (signo) {
    532             case SIGUSR1:
    533                 perform_renew();
    534                 break;
    535             case SIGUSR2:
    536                 perform_release();
    537                 break;
    538             case SIGTERM:
    539                 bb_info_msg("Received SIGTERM");
    540                 if (client_config.release_on_quit)
    541                     perform_release();
    542                 goto ret0;
     1469            if (*message == DHCPNAK) {
     1470                /* return to init state */
     1471                bb_info_msg("Received DHCP NAK");
     1472                udhcp_run_script(&packet, "nak");
     1473                if (state != REQUESTING)
     1474                    udhcp_run_script(NULL, "deconfig");
     1475                change_listen_mode(LISTEN_RAW);
     1476                sleep(3); /* avoid excessive network traffic */
     1477                state = INIT_SELECTING;
     1478                requested_ip = 0;
     1479                timeout = 0;
     1480                packet_num = 0;
     1481                already_waited_sec = 0;
    5431482            }
     1483            continue;
     1484        /* case BOUND: - ignore all packets */
     1485        /* case RELEASED: - ignore all packets */
    5441486        }
    545     } /* for (;;) */
     1487        /* back to main loop */
     1488    } /* for (;;) - main loop ends */
     1489
    5461490 ret0:
    5471491    retval = 0;
    5481492 ret:
    549     /*if (client_config.pidfile) - remove_pidfile has it's own check */
     1493    /*if (client_config.pidfile) - remove_pidfile has its own check */
    5501494        remove_pidfile(client_config.pidfile);
    5511495    return retval;
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpc.h */
    3 #ifndef _DHCPC_H
    4 #define _DHCPC_H
     2/*
     3 * Licensed under GPLv2, see file LICENSE in this source tree.
     4 */
     5#ifndef UDHCP_DHCPC_H
     6#define UDHCP_DHCPC_H 1
    57
    6 #define INIT_SELECTING  0
    7 #define REQUESTING  1
    8 #define BOUND       2
    9 #define RENEWING    3
    10 #define REBINDING   4
    11 #define INIT_REBOOT 5
    12 #define RENEW_REQUESTED 6
    13 #define RELEASED    7
     8PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    149
    1510struct client_config_t {
    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 */
     11    uint8_t client_mac[6];          /* Our mac address */
     12    char no_default_options;        /* Do not include default options in request */
     13    IF_FEATURE_UDHCP_PORT(uint16_t port;)
     14    int ifindex;                    /* Index number of the interface to use */
     15    uint8_t opt_mask[256 / 8];      /* Bitmask of options to send (-O option) */
    2316    const char *interface;          /* The name of the interface to use */
    2417    char *pidfile;                  /* Optionally store the process ID */
    2518    const char *script;             /* User script to run at dhcp events */
     19    struct option_set *options;     /* list of DHCP options to send to server */
    2620    uint8_t *clientid;              /* Optional client id to use */
    2721    uint8_t *vendorclass;           /* Optional vendor class-id to use */
    2822    uint8_t *hostname;              /* Optional hostname to use */
    2923    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 */
    34 };
     24} FIX_ALIASING;
    3525
    36 extern struct client_config_t client_config;
     26/* server_config sits in 1st half of bb_common_bufsiz1 */
     27#define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2]))
    3728
     29#if ENABLE_FEATURE_UDHCP_PORT
     30#define CLIENT_PORT (client_config.port)
     31#else
     32#define CLIENT_PORT 68
     33#endif
    3834
    39 /*** clientpacket.h ***/
    40 
    41 uint32_t random_xid(void);
    42 int send_discover(uint32_t xid, uint32_t requested);
    43 int send_selecting(uint32_t xid, uint32_t server, uint32_t requested);
    44 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
    45 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
    46 int send_release(uint32_t server, uint32_t ciaddr);
    47 int get_raw_packet(struct dhcpMessage *payload, int fd);
    48 
     35POP_SAVED_FUNCTION_VISIBILITY
    4936
    5037#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpd.c
    3  *
    4  * udhcp Server
     2/*
     3 * udhcp server
    54 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
    65 *          Chris Trew <ctrew@moreton.com.au>
     
    87 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
    98 *
    10  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * This program is free software; you can redistribute it and/or modify
     10 * it under the terms of the GNU General Public License as published by
     11 * the Free Software Foundation; either version 2 of the License, or
     12 * (at your option) any later version.
     13 *
     14 * This program is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 * GNU General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this program; if not, write to the Free Software
     21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    1122 */
    12 
    1323#include <syslog.h>
    1424#include "common.h"
     25#include "dhcpc.h"
    1526#include "dhcpd.h"
    16 #include "options.h"
     27
     28
     29/* Send a packet to a specific mac address and ip address by creating our own ip packet */
     30static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
     31{
     32    const uint8_t *chaddr;
     33    uint32_t ciaddr;
     34
     35    // Was:
     36    //if (force_broadcast) { /* broadcast */ }
     37    //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
     38    //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
     39    //else { /* unicast to dhcp_pkt->yiaddr */ }
     40    // But this is wrong: yiaddr is _our_ idea what client's IP is
     41    // (for example, from lease file). Client may not know that,
     42    // and may not have UDP socket listening on that IP!
     43    // We should never unicast to dhcp_pkt->yiaddr!
     44    // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
     45    // and can be used.
     46
     47    if (force_broadcast
     48     || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
     49     || dhcp_pkt->ciaddr == 0
     50    ) {
     51        log1("Broadcasting packet to client");
     52        ciaddr = INADDR_BROADCAST;
     53        chaddr = MAC_BCAST_ADDR;
     54    } else {
     55        log1("Unicasting packet to client ciaddr");
     56        ciaddr = dhcp_pkt->ciaddr;
     57        chaddr = dhcp_pkt->chaddr;
     58    }
     59
     60    udhcp_send_raw_packet(dhcp_pkt,
     61        /*src*/ server_config.server_nip, SERVER_PORT,
     62        /*dst*/ ciaddr, CLIENT_PORT, chaddr,
     63        server_config.ifindex);
     64}
     65
     66/* Send a packet to gateway_nip using the kernel ip stack */
     67static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
     68{
     69    log1("Forwarding packet to relay");
     70
     71    udhcp_send_kernel_packet(dhcp_pkt,
     72            server_config.server_nip, SERVER_PORT,
     73            dhcp_pkt->gateway_nip, SERVER_PORT);
     74}
     75
     76static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
     77{
     78    if (dhcp_pkt->gateway_nip)
     79        send_packet_to_relay(dhcp_pkt);
     80    else
     81        send_packet_to_client(dhcp_pkt, force_broadcast);
     82}
     83
     84static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
     85{
     86    /* Sets op, htype, hlen, cookie fields
     87     * and adds DHCP_MESSAGE_TYPE option */
     88    udhcp_init_header(packet, type);
     89
     90    packet->xid = oldpacket->xid;
     91    memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
     92    packet->flags = oldpacket->flags;
     93    packet->gateway_nip = oldpacket->gateway_nip;
     94    packet->ciaddr = oldpacket->ciaddr;
     95    udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
     96}
     97
     98/* Fill options field, siaddr_nip, and sname and boot_file fields.
     99 * TODO: teach this code to use overload option.
     100 */
     101static void add_server_options(struct dhcp_packet *packet)
     102{
     103    struct option_set *curr = server_config.options;
     104
     105    while (curr) {
     106        if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
     107            udhcp_add_binary_option(packet, curr->data);
     108        curr = curr->next;
     109    }
     110
     111    packet->siaddr_nip = server_config.siaddr_nip;
     112
     113    if (server_config.sname)
     114        strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
     115    if (server_config.boot_file)
     116        strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
     117}
     118
     119static uint32_t select_lease_time(struct dhcp_packet *packet)
     120{
     121    uint32_t lease_time_sec = server_config.max_lease_sec;
     122    uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
     123    if (lease_time_opt) {
     124        move_from_unaligned32(lease_time_sec, lease_time_opt);
     125        lease_time_sec = ntohl(lease_time_sec);
     126        if (lease_time_sec > server_config.max_lease_sec)
     127            lease_time_sec = server_config.max_lease_sec;
     128        if (lease_time_sec < server_config.min_lease_sec)
     129            lease_time_sec = server_config.min_lease_sec;
     130    }
     131    return lease_time_sec;
     132}
     133
     134/* We got a DHCP DISCOVER. Send an OFFER. */
     135/* NOINLINE: limit stack usage in caller */
     136static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease)
     137{
     138    struct dhcp_packet packet;
     139    uint32_t lease_time_sec;
     140    struct in_addr addr;
     141
     142    init_packet(&packet, oldpacket, DHCPOFFER);
     143
     144    /* If it is a static lease, use its IP */
     145    packet.yiaddr = static_lease_nip;
     146    /* Else: */
     147    if (!static_lease_nip) {
     148        /* We have no static lease for client's chaddr */
     149        uint32_t req_nip;
     150        uint8_t *req_ip_opt;
     151        const char *p_host_name;
     152
     153        if (lease) {
     154            /* We have a dynamic lease for client's chaddr.
     155             * Reuse its IP (even if lease is expired).
     156             * Note that we ignore requested IP in this case.
     157             */
     158            packet.yiaddr = lease->lease_nip;
     159        }
     160        /* Or: if client has requested an IP */
     161        else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
     162         /* (read IP) */
     163         && (move_from_unaligned32(req_nip, req_ip_opt), 1)
     164         /* and the IP is in the lease range */
     165         && ntohl(req_nip) >= server_config.start_ip
     166         && ntohl(req_nip) <= server_config.end_ip
     167         /* and */
     168         && (  !(lease = find_lease_by_nip(req_nip)) /* is not already taken */
     169            || is_expired_lease(lease) /* or is taken, but expired */
     170            )
     171        ) {
     172            packet.yiaddr = req_nip;
     173        }
     174        else {
     175            /* Otherwise, find a free IP */
     176            packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr);
     177        }
     178
     179        if (!packet.yiaddr) {
     180            bb_error_msg("no free IP addresses. OFFER abandoned");
     181            return;
     182        }
     183        /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
     184        p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
     185        lease = add_lease(packet.chaddr, packet.yiaddr,
     186                server_config.offer_time,
     187                p_host_name,
     188                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
     189        );
     190        if (!lease) {
     191            bb_error_msg("no free IP addresses. OFFER abandoned");
     192            return;
     193        }
     194    }
     195
     196    lease_time_sec = select_lease_time(oldpacket);
     197    udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
     198    add_server_options(&packet);
     199
     200    addr.s_addr = packet.yiaddr;
     201    bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
     202    /* send_packet emits error message itself if it detects failure */
     203    send_packet(&packet, /*force_bcast:*/ 0);
     204}
     205
     206/* NOINLINE: limit stack usage in caller */
     207static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
     208{
     209    struct dhcp_packet packet;
     210
     211    init_packet(&packet, oldpacket, DHCPNAK);
     212
     213    log1("Sending NAK");
     214    send_packet(&packet, /*force_bcast:*/ 1);
     215}
     216
     217/* NOINLINE: limit stack usage in caller */
     218static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
     219{
     220    struct dhcp_packet packet;
     221    uint32_t lease_time_sec;
     222    struct in_addr addr;
     223    const char *p_host_name;
     224
     225    init_packet(&packet, oldpacket, DHCPACK);
     226    packet.yiaddr = yiaddr;
     227
     228    lease_time_sec = select_lease_time(oldpacket);
     229    udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
     230
     231    add_server_options(&packet);
     232
     233    addr.s_addr = yiaddr;
     234    bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
     235    send_packet(&packet, /*force_bcast:*/ 0);
     236
     237    p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
     238    add_lease(packet.chaddr, packet.yiaddr,
     239        lease_time_sec,
     240        p_host_name,
     241        p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
     242    );
     243    if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
     244        /* rewrite the file with leases at every new acceptance */
     245        write_leases();
     246    }
     247}
     248
     249/* NOINLINE: limit stack usage in caller */
     250static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
     251{
     252    struct dhcp_packet packet;
     253
     254    /* "If a client has obtained a network address through some other means
     255     * (e.g., manual configuration), it may use a DHCPINFORM request message
     256     * to obtain other local configuration parameters.  Servers receiving a
     257     * DHCPINFORM message construct a DHCPACK message with any local
     258     * configuration parameters appropriate for the client without:
     259     * allocating a new address, checking for an existing binding, filling
     260     * in 'yiaddr' or including lease time parameters.  The servers SHOULD
     261     * unicast the DHCPACK reply to the address given in the 'ciaddr' field
     262     * of the DHCPINFORM message.
     263     * ...
     264     * The server responds to a DHCPINFORM message by sending a DHCPACK
     265     * message directly to the address given in the 'ciaddr' field
     266     * of the DHCPINFORM message.  The server MUST NOT send a lease
     267     * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
     268     */
     269//TODO: do a few sanity checks: is ciaddr set?
     270//Better yet: is ciaddr == IP source addr?
     271    init_packet(&packet, oldpacket, DHCPACK);
     272    add_server_options(&packet);
     273
     274    send_packet(&packet, /*force_bcast:*/ 0);
     275}
    17276
    18277
    19278/* globals */
    20 struct dhcpOfferedAddr *leases;
    21 struct server_config_t server_config;
    22 
    23 
    24 int udhcpd_main(int argc, char **argv);
    25 int udhcpd_main(int argc, char **argv)
     279struct dyn_lease *g_leases;
     280/* struct server_config_t server_config is in bb_common_bufsiz1 */
     281
     282
     283int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     284int udhcpd_main(int argc UNUSED_PARAM, char **argv)
    26285{
    27286    fd_set rfds;
    28     struct timeval tv;
    29     int server_socket = -1, bytes, retval, max_sock;
    30     struct dhcpMessage packet;
    31     uint8_t *state, *server_id, *requested;
    32     uint32_t server_id_align, requested_align, static_lease_ip;
     287    int server_socket = -1, retval, max_sock;
     288    struct dhcp_packet packet;
     289    uint8_t *state;
     290    uint32_t static_lease_nip;
    33291    unsigned timeout_end;
    34292    unsigned num_ips;
    35293    unsigned opt;
    36294    struct option_set *option;
    37     struct dhcpOfferedAddr *lease, static_lease;
    38 
    39     opt = getopt32(argv, "fS");
    40     argv += optind;
    41 
     295    struct dyn_lease *lease, fake_lease;
     296    IF_FEATURE_UDHCP_PORT(char *str_P;)
     297
     298#if ENABLE_FEATURE_UDHCP_PORT
     299    SERVER_PORT = 67;
     300    CLIENT_PORT = 68;
     301#endif
     302
     303#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     304    opt_complementary = "vv";
     305#endif
     306    opt = getopt32(argv, "fSv"
     307        IF_FEATURE_UDHCP_PORT("P:", &str_P)
     308#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     309        , &dhcp_verbose
     310#endif
     311        );
    42312    if (!(opt & 1)) { /* no -f */
    43313        bb_daemonize_or_rexec(0, argv);
    44         logmode &= ~LOGMODE_STDIO;
    45     }
    46 
     314        logmode = LOGMODE_NONE;
     315    }
     316    /* update argv after the possible vfork+exec in daemonize */
     317    argv += optind;
    47318    if (opt & 2) { /* -S */
    48         openlog(applet_name, LOG_PID, LOG_LOCAL0);
     319        openlog(applet_name, LOG_PID, LOG_DAEMON);
    49320        logmode |= LOGMODE_SYSLOG;
    50321    }
    51 
     322#if ENABLE_FEATURE_UDHCP_PORT
     323    if (opt & 8) { /* -P */
     324        SERVER_PORT = xatou16(str_P);
     325        CLIENT_PORT = SERVER_PORT + 1;
     326    }
     327#endif
    52328    /* Would rather not do read_config before daemonization -
    53329     * otherwise NOMMU machines will parse config twice */
     
    61337    /* Create pidfile */
    62338    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;
     339    /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
     340
     341    bb_info_msg("%s (v"BB_VER") started", applet_name);
     342
     343    option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
     344    server_config.max_lease_sec = DEFAULT_LEASE_TIME;
    69345    if (option) {
    70         memcpy(&server_config.lease, option->data + 2, 4);
    71         server_config.lease = ntohl(server_config.lease);
     346        move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
     347        server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
    72348    }
    73349
     
    80356    }
    81357
    82     leases = xzalloc(server_config.max_leases * sizeof(*leases));
     358    g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0]));
    83359    read_leases(server_config.lease_file);
    84360
    85     if (read_interface(server_config.interface, &server_config.ifindex,
    86                &server_config.server, server_config.arp)) {
     361    if (udhcp_read_interface(server_config.interface,
     362            &server_config.ifindex,
     363            &server_config.server_nip,
     364            server_config.server_mac)
     365    ) {
    87366        retval = 1;
    88367        goto ret;
     
    94373    timeout_end = monotonic_sec() + server_config.auto_time;
    95374    while (1) { /* loop until universe collapses */
     375        int bytes;
     376        struct timeval tv;
     377        uint8_t *server_id_opt;
     378        uint8_t *requested_opt;
     379        uint32_t requested_nip = requested_nip; /* for compiler */
    96380
    97381        if (server_socket < 0) {
    98             server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
     382            server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
    99383                    server_config.interface);
    100384        }
     
    116400        }
    117401        if (retval < 0 && errno != EINTR) {
    118             DEBUG("error on select");
     402            log1("Error on select");
    119403            continue;
    120404        }
     
    122406        switch (udhcp_sp_read(&rfds)) {
    123407        case SIGUSR1:
    124             bb_info_msg("Received a SIGUSR1");
     408            bb_info_msg("Received SIGUSR1");
    125409            write_leases();
    126410            /* why not just reset the timeout, eh */
     
    128412            continue;
    129413        case SIGTERM:
    130             bb_info_msg("Received a SIGTERM");
     414            bb_info_msg("Received SIGTERM");
    131415            goto ret0;
    132         case 0: break;      /* no signal */
    133         default: continue;  /* signal or error (probably EINTR) */
    134         }
    135 
    136         bytes = udhcp_get_packet(&packet, server_socket); /* this waits for a packet - idle */
     416        case 0: /* no signal: read a packet */
     417            break;
     418        default: /* signal or error (probably EINTR): back to select */
     419            continue;
     420        }
     421
     422        bytes = udhcp_recv_kernel_packet(&packet, server_socket);
    137423        if (bytes < 0) {
     424            /* bytes can also be -2 ("bad packet data") */
    138425            if (bytes == -1 && errno != EINTR) {
    139                 DEBUG("error on read, %s, reopening socket", strerror(errno));
     426                log1("Read error: %s, reopening socket", strerror(errno));
    140427                close(server_socket);
    141428                server_socket = -1;
     
    143430            continue;
    144431        }
    145 
    146         state = get_option(&packet, DHCP_MESSAGE_TYPE);
    147         if (state == NULL) {
    148             bb_error_msg("cannot get option from packet, ignoring");
    149             continue;
    150         }
    151 
    152         /* Look for a static lease */
    153         static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);
    154 
    155         if (static_lease_ip) {
    156             bb_info_msg("Found static lease: %x", static_lease_ip);
    157 
    158             memcpy(&static_lease.chaddr, &packet.chaddr, 16);
    159             static_lease.yiaddr = static_lease_ip;
    160             static_lease.expires = 0;
    161 
    162             lease = &static_lease;
     432        if (packet.hlen != 6) {
     433            bb_error_msg("MAC length != 6, ignoring packet");
     434            continue;
     435        }
     436        if (packet.op != BOOTREQUEST) {
     437            bb_error_msg("not a REQUEST, ignoring packet");
     438            continue;
     439        }
     440        state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
     441        if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
     442            bb_error_msg("no or bad message type option, ignoring packet");
     443            continue;
     444        }
     445
     446        /* Look for a static/dynamic lease */
     447        static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
     448        if (static_lease_nip) {
     449            bb_info_msg("Found static lease: %x", static_lease_nip);
     450            memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
     451            fake_lease.lease_nip = static_lease_nip;
     452            fake_lease.expires = 0;
     453            lease = &fake_lease;
    163454        } else {
    164             lease = find_lease_by_chaddr(packet.chaddr);
     455            lease = find_lease_by_mac(packet.chaddr);
     456        }
     457
     458        /* Get REQUESTED_IP and SERVER_ID if present */
     459        server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
     460        if (server_id_opt) {
     461            uint32_t server_id_net;
     462            move_from_unaligned32(server_id_net, server_id_opt);
     463            if (server_id_net != server_config.server_nip) {
     464                /* client talks to somebody else */
     465                log1("server ID doesn't match, ignoring");
     466                continue;
     467            }
     468        }
     469        requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
     470        if (requested_opt) {
     471            move_from_unaligned32(requested_nip, requested_opt);
    165472        }
    166473
    167474        switch (state[0]) {
     475
    168476        case DHCPDISCOVER:
    169             DEBUG("Received DISCOVER");
    170 
    171             if (sendOffer(&packet) < 0) {
    172                 bb_error_msg("send OFFER failed");
     477            log1("Received DISCOVER");
     478
     479            send_offer(&packet, static_lease_nip, lease);
     480            break;
     481
     482        case DHCPREQUEST:
     483            log1("Received REQUEST");
     484/* RFC 2131:
     485
     486o DHCPREQUEST generated during SELECTING state:
     487
     488   Client inserts the address of the selected server in 'server
     489   identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
     490   filled in with the yiaddr value from the chosen DHCPOFFER.
     491
     492   Note that the client may choose to collect several DHCPOFFER
     493   messages and select the "best" offer.  The client indicates its
     494   selection by identifying the offering server in the DHCPREQUEST
     495   message.  If the client receives no acceptable offers, the client
     496   may choose to try another DHCPDISCOVER message.  Therefore, the
     497   servers may not receive a specific DHCPREQUEST from which they can
     498   decide whether or not the client has accepted the offer.
     499
     500o DHCPREQUEST generated during INIT-REBOOT state:
     501
     502   'server identifier' MUST NOT be filled in, 'requested IP address'
     503   option MUST be filled in with client's notion of its previously
     504   assigned address. 'ciaddr' MUST be zero. The client is seeking to
     505   verify a previously allocated, cached configuration. Server SHOULD
     506   send a DHCPNAK message to the client if the 'requested IP address'
     507   is incorrect, or is on the wrong network.
     508
     509   Determining whether a client in the INIT-REBOOT state is on the
     510   correct network is done by examining the contents of 'giaddr', the
     511   'requested IP address' option, and a database lookup. If the DHCP
     512   server detects that the client is on the wrong net (i.e., the
     513   result of applying the local subnet mask or remote subnet mask (if
     514   'giaddr' is not zero) to 'requested IP address' option value
     515   doesn't match reality), then the server SHOULD send a DHCPNAK
     516   message to the client.
     517
     518   If the network is correct, then the DHCP server should check if
     519   the client's notion of its IP address is correct. If not, then the
     520   server SHOULD send a DHCPNAK message to the client. If the DHCP
     521   server has no record of this client, then it MUST remain silent,
     522   and MAY output a warning to the network administrator. This
     523   behavior is necessary for peaceful coexistence of non-
     524   communicating DHCP servers on the same wire.
     525
     526   If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
     527   the same subnet as the server.  The server MUST broadcast the
     528   DHCPNAK message to the 0xffffffff broadcast address because the
     529   client may not have a correct network address or subnet mask, and
     530   the client may not be answering ARP requests.
     531
     532   If 'giaddr' is set in the DHCPREQUEST message, the client is on a
     533   different subnet.  The server MUST set the broadcast bit in the
     534   DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
     535   client, because the client may not have a correct network address
     536   or subnet mask, and the client may not be answering ARP requests.
     537
     538o DHCPREQUEST generated during RENEWING state:
     539
     540   'server identifier' MUST NOT be filled in, 'requested IP address'
     541   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
     542   client's IP address. In this situation, the client is completely
     543   configured, and is trying to extend its lease. This message will
     544   be unicast, so no relay agents will be involved in its
     545   transmission.  Because 'giaddr' is therefore not filled in, the
     546   DHCP server will trust the value in 'ciaddr', and use it when
     547   replying to the client.
     548
     549   A client MAY choose to renew or extend its lease prior to T1.  The
     550   server may choose not to extend the lease (as a policy decision by
     551   the network administrator), but should return a DHCPACK message
     552   regardless.
     553
     554o DHCPREQUEST generated during REBINDING state:
     555
     556   'server identifier' MUST NOT be filled in, 'requested IP address'
     557   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
     558   client's IP address. In this situation, the client is completely
     559   configured, and is trying to extend its lease. This message MUST
     560   be broadcast to the 0xffffffff IP broadcast address.  The DHCP
     561   server SHOULD check 'ciaddr' for correctness before replying to
     562   the DHCPREQUEST.
     563
     564   The DHCPREQUEST from a REBINDING client is intended to accommodate
     565   sites that have multiple DHCP servers and a mechanism for
     566   maintaining consistency among leases managed by multiple servers.
     567   A DHCP server MAY extend a client's lease only if it has local
     568   administrative authority to do so.
     569*/
     570            if (!requested_opt) {
     571                requested_nip = packet.ciaddr;
     572                if (requested_nip == 0) {
     573                    log1("no requested IP and no ciaddr, ignoring");
     574                    break;
     575                }
     576            }
     577            if (lease && requested_nip == lease->lease_nip) {
     578                /* client requested or configured IP matches the lease.
     579                 * ACK it, and bump lease expiration time. */
     580                send_ACK(&packet, lease->lease_nip);
     581                break;
     582            }
     583            if (server_id_opt) {
     584                /* client was talking specifically to us.
     585                 * "No, we don't have this IP for you". */
     586                send_NAK(&packet);
    173587            }
    174588            break;
    175         case DHCPREQUEST:
    176             DEBUG("received REQUEST");
    177 
    178             requested = get_option(&packet, DHCP_REQUESTED_IP);
    179             server_id = get_option(&packet, DHCP_SERVER_ID);
    180 
    181             if (requested) memcpy(&requested_align, requested, 4);
    182             if (server_id) memcpy(&server_id_align, server_id, 4);
    183 
    184             if (lease) {
    185                 if (server_id) {
    186                     /* SELECTING State */
    187                     DEBUG("server_id = %08x", ntohl(server_id_align));
    188                     if (server_id_align == server_config.server && requested
    189                      && requested_align == lease->yiaddr
    190                     ) {
    191                         sendACK(&packet, lease->yiaddr);
    192                     }
    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);
    202                 } else {
    203                     /* don't know what to do!!!! */
    204                     sendNAK(&packet);
    205                 }
    206 
    207             /* what to do if we have no record of the client */
    208             } else if (server_id) {
    209                 /* SELECTING State */
    210 
    211             } else if (requested) {
    212                 /* INIT-REBOOT State */
    213                 lease = find_lease_by_yiaddr(requested_align);
    214                 if (lease) {
    215                     if (lease_expired(lease)) {
    216                         /* probably best if we drop this lease */
    217                         memset(lease->chaddr, 0, 16);
    218                     /* make some contention for this address */
    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                 }
    230 
    231             } else {
    232                 /* RENEWING or REBINDING State */
     589
     590        case DHCPDECLINE:
     591            /* RFC 2131:
     592             * "If the server receives a DHCPDECLINE message,
     593             * the client has discovered through some other means
     594             * that the suggested network address is already
     595             * in use. The server MUST mark the network address
     596             * as not available and SHOULD notify the local
     597             * sysadmin of a possible configuration problem."
     598             *
     599             * SERVER_ID must be present,
     600             * REQUESTED_IP must be present,
     601             * chaddr must be filled in,
     602             * ciaddr must be 0 (we do not check this)
     603             */
     604            log1("Received DECLINE");
     605            if (server_id_opt
     606             && requested_opt
     607             && lease  /* chaddr matches this lease */
     608             && requested_nip == lease->lease_nip
     609            ) {
     610                memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
     611                lease->expires = time(NULL) + server_config.decline_time;
    233612            }
    234613            break;
    235         case DHCPDECLINE:
    236             DEBUG("Received DECLINE");
    237             if (lease) {
    238                 memset(lease->chaddr, 0, 16);
    239                 lease->expires = time(0) + server_config.decline_time;
     614
     615        case DHCPRELEASE:
     616            /* "Upon receipt of a DHCPRELEASE message, the server
     617             * marks the network address as not allocated."
     618             *
     619             * SERVER_ID must be present,
     620             * REQUESTED_IP must not be present (we do not check this),
     621             * chaddr must be filled in,
     622             * ciaddr must be filled in
     623             */
     624            log1("Received RELEASE");
     625            if (server_id_opt
     626             && lease  /* chaddr matches this lease */
     627             && packet.ciaddr == lease->lease_nip
     628            ) {
     629                lease->expires = time(NULL);
    240630            }
    241631            break;
    242         case DHCPRELEASE:
    243             DEBUG("Received RELEASE");
    244             if (lease)
    245                 lease->expires = time(0);
    246             break;
     632
    247633        case DHCPINFORM:
    248             DEBUG("Received INFORM");
     634            log1("Received INFORM");
    249635            send_inform(&packet);
    250636            break;
    251         default:
    252             bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);
    253637        }
    254638    }
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpd.h */
    3 #ifndef _DHCPD_H
    4 #define _DHCPD_H
     2/*
     3 * Licensed under GPLv2, see file LICENSE in this source tree.
     4 */
     5#ifndef UDHCP_DHCPD_H
     6#define UDHCP_DHCPD_H 1
    57
    6 /************************************/
    7 /* Defaults _you_ may want to tweak */
    8 /************************************/
     8PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    99
    10 /* the period of time the client is allowed to use that address */
    11 #define LEASE_TIME              (60*60*24*10) /* 10 days of seconds */
    12 #define LEASES_FILE     "/var/lib/misc/udhcpd.leases"
    13 
    14 /* where to find the DHCP server configuration file */
     10/* Defaults you may want to tweak */
     11/* Default max_lease_sec */
     12#define DEFAULT_LEASE_TIME      (60*60*24 * 10)
     13#define LEASES_FILE             CONFIG_DHCPD_LEASES_FILE
     14/* Where to find the DHCP server configuration file */
    1515#define DHCPD_CONF_FILE         "/etc/udhcpd.conf"
    1616
    17 struct option_set {
    18     uint8_t *data;
    19     struct option_set *next;
    20 };
    2117
    2218struct static_lease {
    2319    struct static_lease *next;
    24     uint8_t *mac;
    25     uint32_t *ip;
     20    uint32_t nip;
     21    uint8_t mac[6];
    2622};
    2723
    2824struct server_config_t {
    29     uint32_t server;                /* Our IP, in network order */
     25    char *interface;                /* interface to use */
     26//TODO: ifindex, server_nip, server_mac
     27// are obtained from interface name.
     28// Instead of querying them *once*, create update_server_network_data_cache()
     29// and call it before any usage of these fields.
     30// update_server_network_data_cache() must re-query data
     31// if more than N seconds have passed after last use.
     32    int ifindex;
     33    uint32_t server_nip;
     34#if ENABLE_FEATURE_UDHCP_PORT
     35    uint16_t port;
     36#endif
     37    uint8_t server_mac[6];          /* our MAC address (used only for ARP probing) */
     38    struct option_set *options;     /* list of DHCP options loaded from the config file */
    3039    /* 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) */
     40    uint32_t start_ip;              /* start address of leases, in host order */
     41    uint32_t end_ip;                /* end of leases, in host order */
     42    uint32_t max_lease_sec;         /* maximum lease time (host order) */
     43    uint32_t min_lease_sec;         /* minimum lease time a client can request */
     44    uint32_t max_leases;            /* maximum number of leases (including reserved addresses) */
    4145    uint32_t auto_time;             /* how long should udhcpd wait before writing a config file.
    4246                                     * if this is zero, it will only write one on SIGUSR1 */
     
    4549    uint32_t conflict_time;         /* how long an arp conflict offender is leased for */
    4650    uint32_t offer_time;            /* how long an offered address is reserved */
    47     uint32_t min_lease;             /* minimum lease a client can request */
     51    uint32_t siaddr_nip;            /* "next server" bootp option */
    4852    char *lease_file;
    4953    char *pidfile;
    50     char *notify_file;              /* What to run whenever leases are written */
    51     uint32_t siaddr;                /* next server bootp option */
     54    char *notify_file;              /* what to run whenever leases are written */
    5255    char *sname;                    /* bootp server name */
    5356    char *boot_file;                /* bootp boot file option */
    5457    struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */
    55 };
     58} FIX_ALIASING;
    5659
    57 extern struct server_config_t server_config;
    58 extern struct dhcpOfferedAddr *leases;
     60#define server_config (*(struct server_config_t*)&bb_common_bufsiz1)
     61/* client_config sits in 2nd half of bb_common_bufsiz1 */
     62
     63#if ENABLE_FEATURE_UDHCP_PORT
     64#define SERVER_PORT (server_config.port)
     65#else
     66#define SERVER_PORT 67
     67#endif
    5968
    6069
    61 /*** leases.h ***/
     70typedef uint32_t leasetime_t;
     71typedef int32_t signed_leasetime_t;
    6272
    63 struct dhcpOfferedAddr {
    64     uint8_t chaddr[16];
    65     uint32_t yiaddr;    /* network order */
    66     uint32_t expires;   /* host order */
    67 };
     73struct dyn_lease {
     74    /* Unix time when lease expires. Kept in memory in host order.
     75     * When written to file, converted to network order
     76     * and adjusted (current time subtracted) */
     77    leasetime_t expires;
     78    /* "nip": IP in network order */
     79    uint32_t lease_nip;
     80    /* We use lease_mac[6], since e.g. ARP probing uses
     81     * only 6 first bytes anyway. We check received dhcp packets
     82     * that their hlen == 6 and thus chaddr has only 6 significant bytes
     83     * (dhcp packet has chaddr[16], not [6])
     84     */
     85    uint8_t lease_mac[6];
     86    char hostname[20];
     87    uint8_t pad[2];
     88    /* total size is a multiply of 4 */
     89} PACKED;
    6890
    69 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease);
    70 int lease_expired(struct dhcpOfferedAddr *lease);
    71 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr);
    72 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr);
    73 uint32_t find_address(int check_expired);
     91extern struct dyn_lease *g_leases;
     92
     93struct dyn_lease *add_lease(
     94        const uint8_t *chaddr, uint32_t yiaddr,
     95        leasetime_t leasetime,
     96        const char *hostname, int hostname_len
     97        ) FAST_FUNC;
     98int is_expired_lease(struct dyn_lease *lease) FAST_FUNC;
     99struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC;
     100struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC;
     101uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC;
    74102
    75103
    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 */
    80 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip);
    81 /* Check to see if a mac has an associated static lease */
    82 uint32_t getIpByMac(struct static_lease *lease_struct, void *arg);
    83 /* Check to see if an ip is reserved as a static ip */
    84 uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip);
     104/* Config file parser will pass static lease info to this function
     105 * which will add it to a data structure that can be searched later */
     106void add_static_lease(struct static_lease **st_lease_pp, uint8_t *mac, uint32_t nip) FAST_FUNC;
     107/* Find static lease IP by mac */
     108uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *arg) FAST_FUNC;
     109/* Check to see if an IP is reserved as a static IP */
     110int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) FAST_FUNC;
    85111/* Print out static leases just to check what's going on (debug code) */
    86 void printStaticLeases(struct static_lease **lease_struct);
     112#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     113void log_static_leases(struct static_lease **st_lease_pp) FAST_FUNC;
     114#else
     115# define log_static_leases(st_lease_pp) ((void)0)
     116#endif
    87117
    88118
    89 /*** serverpacket.h ***/
    90 
    91 int sendOffer(struct dhcpMessage *oldpacket);
    92 int sendNAK(struct dhcpMessage *oldpacket);
    93 int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr);
    94 int send_inform(struct dhcpMessage *oldpacket);
     119void read_config(const char *file) FAST_FUNC;
     120void write_leases(void) FAST_FUNC;
     121void read_leases(const char *file) FAST_FUNC;
    95122
    96123
    97 /*** files.h ***/
    98 
    99 int read_config(const char *file);
    100 void write_leases(void);
    101 void read_leases(const char *file);
    102 struct option_set *find_option(struct option_set *opt_list, char code);
    103 
     124POP_SAVED_FUNCTION_VISIBILITY
    104125
    105126#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcprelay.c

    r1765 r2725  
    22/* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com>
    33 *
    4  * Licensed under GPL v2, see file LICENSE in this tarball for details.
     4 * Licensed under GPLv2, see file LICENSE in this source tree.
    55 *
    66 * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support
     
    1010 * Upstream has GPL v2 or later
    1111 */
    12 
    1312#include "common.h"
    14 #include "dhcpd.h"
    15 #include "options.h"
    16 
    17 /* constants */
    18 #define SELECT_TIMEOUT 5 /* select timeout in sec. */
    19 #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */
    20 #define MAX_INTERFACES 9
    21 
     13
     14#define SERVER_PORT    67
     15
     16/* lifetime of an xid entry in sec. */
     17#define MAX_LIFETIME   2*60
     18/* select timeout in sec. */
     19#define SELECT_TIMEOUT (MAX_LIFETIME / 8)
    2220
    2321/* This list holds information about clients. The xid_* functions manipulate this list. */
    24 static struct xid_item {
     22struct xid_item {
     23    unsigned timestamp;
     24    int client;
    2525    uint32_t xid;
    2626    struct sockaddr_in ip;
    27     int client;
    28     time_t timestamp;
    2927    struct xid_item *next;
    30 } dhcprelay_xid_list = {0, {0}, 0, 0, NULL};
    31 
     28};
     29
     30#define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1)
    3231
    3332static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client)
     
    4241    item->xid = xid;
    4342    item->client = client;
    44     item->timestamp = time(NULL);
     43    item->timestamp = monotonic_sec();
    4544    item->next = dhcprelay_xid_list.next;
    4645    dhcprelay_xid_list.next = item;
     
    5352    struct xid_item *item = dhcprelay_xid_list.next;
    5453    struct xid_item *last = &dhcprelay_xid_list;
    55     time_t current_time = time(NULL);
     54    unsigned current_time = monotonic_sec();
    5655
    5756    while (item != NULL) {
     
    7271    while (item != NULL) {
    7372        if (item->xid == xid) {
    74             return item;
     73            break;
    7574        }
    7675        item = item->next;
    7776    }
    78     return NULL;
     77    return item;
    7978}
    8079
     
    10099 * returns the message type on success, -1 otherwise
    101100 */
    102 static int get_dhcp_packet_type(struct dhcpMessage *p)
     101static int get_dhcp_packet_type(struct dhcp_packet *p)
    103102{
    104103    uint8_t *op;
     
    108107        return -1;
    109108    /* get message type option */
    110     op = get_option(p, DHCP_MESSAGE_TYPE);
     109    op = udhcp_get_option(p, DHCP_MESSAGE_TYPE);
    111110    if (op != NULL)
    112111        return op[0];
     
    115114
    116115/**
    117  * signal_handler - handles signals ;-)
    118  * sig - sent signal
    119  */
    120 static smallint dhcprelay_stopflag;
    121 
    122 static void dhcprelay_signal_handler(int sig)
    123 {
    124     dhcprelay_stopflag = 1;
    125 }
    126 
    127 /**
    128  * get_client_devices - parses the devices list
    129  * dev_list - comma separated list of devices
     116 * make_iface_list - parses client/server interface names
    130117 * returns array
    131118 */
    132 static char **get_client_devices(char *dev_list, int *client_number)
    133 {
    134     char *s, *list, **client_dev;
     119static char **make_iface_list(char **client_and_server_ifaces, int *client_number)
     120{
     121    char *s, **iface_list;
    135122    int i, cn;
    136123
    137     /* copy list */
    138     list = xstrdup(dev_list);
    139     if (list == NULL) return NULL;
    140 
    141124    /* get number of items */
    142     for (s = dev_list, cn = 1; *s; s++)
     125    cn = 2; /* 1 server iface + at least 1 client one */
     126    s = client_and_server_ifaces[0]; /* list of client ifaces */
     127    while (*s) {
    143128        if (*s == ',')
    144129            cn++;
    145 
    146     client_dev = xzalloc(cn * sizeof(*client_dev));
    147 
    148     /* parse list */
    149     s = strtok(list, ",");
    150     i = 0;
    151     while (s != NULL) {
    152         client_dev[i++] = xstrdup(s);
    153         s = strtok(NULL, ",");
    154     }
    155 
    156     /* free copy and exit */
    157     free(list);
     130        s++;
     131    }
    158132    *client_number = cn;
    159     return client_dev;
    160 }
    161 
    162 
    163 /* Creates listen sockets (in fds) and returns the number allocated. */
    164 static int init_sockets(char **client, int num_clients,
    165             char *server, int *fds, int *max_socket)
    166 {
    167     int i;
    168 
    169     /* talk to real server on bootps */
    170     fds[0] = listen_socket(/*INADDR_ANY,*/ 67, server);
    171     *max_socket = fds[0];
    172 
    173     /* array starts at 1 since server is 0 */
    174     num_clients++;
    175 
    176     for (i = 1; i < num_clients; i++) {
    177         /* listen for clients on bootps */
    178         fds[i] = listen_socket(/*NADDR_ANY,*/ 67, client[i-1]);
    179         if (fds[i] > *max_socket)
    180             *max_socket = fds[i];
    181     }
    182 
    183     return i;
    184 }
    185 
     133
     134    /* create vector of pointers */
     135    iface_list = xzalloc(cn * sizeof(iface_list[0]));
     136
     137    iface_list[0] = client_and_server_ifaces[1]; /* server iface */
     138
     139    i = 1;
     140    s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */
     141    goto store_client_iface_name;
     142
     143    while (i < cn) {
     144        if (*s++ == ',') {
     145            s[-1] = '\0';
     146 store_client_iface_name:
     147            iface_list[i++] = s;
     148        }
     149    }
     150
     151    return iface_list;
     152}
     153
     154/* Creates listen sockets (in fds) bound to client and server ifaces,
     155 * and returns numerically max fd.
     156 */
     157static int init_sockets(char **iface_list, int num_clients, int *fds)
     158{
     159    int i, n;
     160
     161    n = 0;
     162    for (i = 0; i < num_clients; i++) {
     163        fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]);
     164        if (n < fds[i])
     165            n = fds[i];
     166    }
     167    return n;
     168}
     169
     170static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to)
     171{
     172    int err;
     173
     174    errno = 0;
     175    err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to));
     176    err -= msg_len;
     177    if (err)
     178        bb_perror_msg("sendto");
     179    return err;
     180}
    186181
    187182/**
    188  * pass_on() - forwards dhcp packets from client to server
     183 * pass_to_server() - forwards dhcp packets from client to server
    189184 * p - packet to send
    190185 * client - number of the client
    191186 */
    192 static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds,
     187static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds,
    193188            struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
    194189{
    195     int res, type;
    196     struct xid_item *item;
     190    int type;
    197191
    198192    /* check packet_type */
     
    206200
    207201    /* create new xid entry */
    208     item = xid_add(p->xid, client_addr, client);
    209 
    210     /* forward request to LAN (server) */
    211     res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr,
    212             sizeof(struct sockaddr_in));
    213     if (res != packet_len) {
    214         bb_perror_msg("pass_on");
    215         return;
    216     }
     202    xid_add(p->xid, client_addr, client);
     203
     204    /* forward request to server */
     205    /* note that we send from fds[0] which is bound to SERVER_PORT (67).
     206     * IOW: we send _from_ SERVER_PORT! Although this may look strange,
     207     * RFC 1542 not only allows, but prescribes this for BOOTP relays.
     208     */
     209    sendto_ip4(fds[0], p, packet_len, server_addr);
    217210}
    218211
    219212/**
    220  * pass_back() - forwards dhcp packets from server to client
     213 * pass_to_client() - forwards dhcp packets from server to client
    221214 * p - packet to send
    222215 */
    223 static void pass_back(struct dhcpMessage *p, int packet_len, int *fds)
    224 {
    225     int res, type;
     216static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
     217{
     218    int type;
    226219    struct xid_item *item;
    227220
     
    238231    }
    239232
     233//TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set!
    240234    if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
    241235        item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    242     if (item->client > MAX_INTERFACES)
    243         return;
    244     res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip),
    245                 sizeof(item->ip));
    246     if (res != packet_len) {
    247         bb_perror_msg("pass_back");
    248         return;
     236
     237    if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) {
     238        return; /* send error occurred */
    249239    }
    250240
     
    253243}
    254244
    255 static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
    256         struct sockaddr_in *server_addr, uint32_t gw_ip)
    257 {
    258     struct dhcpMessage dhcp_msg;
    259     fd_set rfds;
    260     size_t packlen;
    261     socklen_t addr_size;
    262     struct sockaddr_in client_addr;
    263     struct timeval tv;
    264     int i;
    265 
    266     while (!dhcprelay_stopflag) {
     245int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     246int dhcprelay_main(int argc, char **argv)
     247{
     248    struct sockaddr_in server_addr;
     249    char **iface_list;
     250    int *fds;
     251    int num_sockets, max_socket;
     252    uint32_t our_nip;
     253
     254    server_addr.sin_family = AF_INET;
     255    server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
     256    server_addr.sin_port = htons(SERVER_PORT);
     257
     258    /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
     259    if (argc == 4) {
     260        if (!inet_aton(argv[3], &server_addr.sin_addr))
     261            bb_perror_msg_and_die("bad server IP");
     262    } else if (argc != 3) {
     263        bb_show_usage();
     264    }
     265
     266    iface_list = make_iface_list(argv + 1, &num_sockets);
     267
     268    fds = xmalloc(num_sockets * sizeof(fds[0]));
     269
     270    /* Create sockets and bind one to every iface */
     271    max_socket = init_sockets(iface_list, num_sockets, fds);
     272
     273    /* Get our IP on server_iface */
     274    if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL))
     275        return 1;
     276
     277    /* Main loop */
     278    while (1) {
     279// reinit stuff from time to time? go back to make_iface_list
     280// every N minutes?
     281        fd_set rfds;
     282        struct timeval tv;
     283        int i;
     284
    267285        FD_ZERO(&rfds);
    268286        for (i = 0; i < num_sockets; i++)
     
    271289        tv.tv_usec = 0;
    272290        if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
     291            int packlen;
     292            struct dhcp_packet dhcp_msg;
     293
    273294            /* server */
    274295            if (FD_ISSET(fds[0], &rfds)) {
    275                 packlen = udhcp_get_packet(&dhcp_msg, fds[0]);
     296                packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
    276297                if (packlen > 0) {
    277                     pass_back(&dhcp_msg, packlen, fds);
     298                    pass_to_client(&dhcp_msg, packlen, fds);
    278299                }
    279300            }
     301
     302            /* clients */
    280303            for (i = 1; i < num_sockets; i++) {
    281                 /* clients */
     304                struct sockaddr_in client_addr;
     305                socklen_t addr_size;
     306
    282307                if (!FD_ISSET(fds[i], &rfds))
    283308                    continue;
    284                 addr_size = sizeof(struct sockaddr_in);
     309
     310                addr_size = sizeof(client_addr);
    285311                packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
    286                             (struct sockaddr *)(&client_addr), &addr_size);
     312                        (struct sockaddr *)(&client_addr), &addr_size);
    287313                if (packlen <= 0)
    288314                    continue;
    289                 if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL))
    290                     dhcp_msg.giaddr = gw_ip;
    291                 pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr);
     315
     316                /* Get our IP on corresponding client_iface */
     317// RFC 1542
     318// 4.1 General BOOTP Processing for Relay Agents
     319// 4.1.1 BOOTREQUEST Messages
     320//   If the relay agent does decide to relay the request, it MUST examine
     321//   the 'giaddr' ("gateway" IP address) field.  If this field is zero,
     322//   the relay agent MUST fill this field with the IP address of the
     323//   interface on which the request was received.  If the interface has
     324//   more than one IP address logically associated with it, the relay
     325//   agent SHOULD choose one IP address associated with that interface and
     326//   use it consistently for all BOOTP messages it relays.  If the
     327//   'giaddr' field contains some non-zero value, the 'giaddr' field MUST
     328//   NOT be modified.  The relay agent MUST NOT, under any circumstances,
     329//   fill the 'giaddr' field with a broadcast address as is suggested in
     330//   [1] (Section 8, sixth paragraph).
     331
     332// but why? what if server can't route such IP? Client ifaces may be, say, NATed!
     333
     334// 4.1.2 BOOTREPLY Messages
     335//   BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients.
     336//   It is the responsibility of BOOTP servers to send BOOTREPLY messages
     337//   directly to the relay agent identified in the 'giaddr' field.
     338// (yeah right, unless it is impossible... see comment above)
     339//   Therefore, a relay agent may assume that all BOOTREPLY messages it
     340//   receives are intended for BOOTP clients on its directly-connected
     341//   networks.
     342//
     343//   When a relay agent receives a BOOTREPLY message, it should examine
     344//   the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields.
     345//   These fields should provide adequate information for the relay agent
     346//   to deliver the BOOTREPLY message to the client.
     347//
     348//   The 'giaddr' field can be used to identify the logical interface from
     349//   which the reply must be sent (i.e., the host or router interface
     350//   connected to the same network as the BOOTP client).  If the content
     351//   of the 'giaddr' field does not match one of the relay agent's
     352//   directly-connected logical interfaces, the BOOTREPLY messsage MUST be
     353//   silently discarded.
     354                if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) {
     355                    /* Fall back to our IP on server iface */
     356// this makes more sense!
     357                    dhcp_msg.gateway_nip = our_nip;
     358                }
     359// maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)?
     360                pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr);
    292361            }
    293362        }
    294363        xid_expire();
    295     }
    296 }
    297 
    298 int dhcprelay_main(int argc, char **argv);
    299 int dhcprelay_main(int argc, char **argv)
    300 {
    301     int i, num_sockets, max_socket, fds[MAX_INTERFACES];
    302     uint32_t gw_ip;
    303     char **clients;
    304     struct sockaddr_in server_addr;
    305 
    306     server_addr.sin_family = AF_INET;
    307     server_addr.sin_port = htons(67);
    308     if (argc == 4) {
    309         if (!inet_aton(argv[3], &server_addr.sin_addr))
    310             bb_perror_msg_and_die("didn't grok server");
    311     } else if (argc == 3) {
    312         server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    313     } else {
    314         bb_show_usage();
    315     }
    316     clients = get_client_devices(argv[1], &num_sockets);
    317     if (!clients) return 0;
    318 
    319     signal(SIGTERM, dhcprelay_signal_handler);
    320     signal(SIGQUIT, dhcprelay_signal_handler);
    321     signal(SIGINT, dhcprelay_signal_handler);
    322 
    323     num_sockets = init_sockets(clients, num_sockets, argv[2], fds, &max_socket);
    324 
    325     if (read_interface(argv[2], NULL, &gw_ip, NULL))
    326         return 1;
    327 
    328     dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip);
    329 
    330     if (ENABLE_FEATURE_CLEAN_UP) {
    331         for (i = 0; i < num_sockets; i++) {
    332             close(fds[i]);
    333             free(clients[i]);
    334         }
    335     }
    336 
    337     return 0;
    338 }
     364    } /* while (1) */
     365
     366    /* return 0; - not reached */
     367}
  • branches/2.2.9/mindi-busybox/networking/udhcp/domain_codec.c

    r1765 r2725  
    55 * Loosely based on the isc-dhcpd implementation by dhankins@isc.org
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    8  */
    9 
    10 #if ENABLE_FEATURE_RFC3397
    11 
    12 #include "common.h"
    13 #include "options.h"
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     8 */
     9#ifdef DNS_COMPR_TESTING
     10# define FAST_FUNC /* nothing */
     11# define xmalloc malloc
     12# include <stdlib.h>
     13# include <stdint.h>
     14# include <string.h>
     15# include <stdio.h>
     16#else
     17# include "common.h"
     18#endif
    1419
    1520#define NS_MAXDNAME  1025   /* max domain name length */
     
    2025
    2126
    22 /* expand a RFC1035-compressed list of domain names "cstr", of length "clen";
     27/* Expand a RFC1035-compressed list of domain names "cstr", of length "clen";
    2328 * returns a newly allocated string containing the space-separated domains,
    2429 * prefixed with the contents of string pre, or NULL if an error occurs.
    2530 */
    26 char *dname_dec(const uint8_t *cstr, int clen, const char *pre)
    27 {
    28     const uint8_t *c;
    29     int crtpos, retpos, depth, plen = 0, len = 0;
     31char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
     32{
     33    char *ret = ret; /* for compiler */
    3034    char *dst = NULL;
    31 
    32     if (!cstr)
    33         return NULL;
    34 
    35     if (pre)
    36         plen = strlen(pre);
    3735
    3836    /* We make two passes over the cstr string. First, we compute
     
    4341     * buffer, then having to check if it's sufficiently large, etc.
    4442     */
    45 
    46     while (!dst) {
    47 
    48         if (len > 0) {  /* second pass? allocate dst buffer and copy pre */
    49             dst = xmalloc(len + plen);
    50             memcpy(dst, pre, plen);
    51         }
     43    while (1) {
     44        /* note: "return NULL" below are leak-safe since
     45         * dst isn't yet allocated */
     46        const uint8_t *c;
     47        unsigned crtpos, retpos, depth, len;
    5248
    5349        crtpos = retpos = depth = len = 0;
    54 
    5550        while (crtpos < clen) {
    5651            c = cstr + crtpos;
    5752
    58             if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */
    59                 if (crtpos + 2 > clen)      /* no offset to jump to? abort */
     53            if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
     54                /* pointer */
     55                if (crtpos + 2 > clen) /* no offset to jump to? abort */
    6056                    return NULL;
    61                 if (retpos == 0)            /* toplevel? save return spot */
     57                if (retpos == 0) /* toplevel? save return spot */
    6258                    retpos = crtpos + 2;
    6359                depth++;
    64                 crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */
    65             } else if (*c) {            /* label */
    66                 if (crtpos + *c + 1 > clen)     /* label too long? abort */
     60                crtpos = ((c[0] & 0x3f) << 8) | c[1]; /* jump */
     61            } else if (*c) {
     62                /* label */
     63                if (crtpos + *c + 1 > clen) /* label too long? abort */
    6764                    return NULL;
    6865                if (dst)
    69                     memcpy(dst + plen + len, c + 1, *c);
     66                    memcpy(dst + len, c + 1, *c);
    7067                len += *c + 1;
    7168                crtpos += *c + 1;
    7269                if (dst)
    73                     *(dst + plen + len - 1) = '.';
    74             } else {                    /* null: end of current domain name */
    75                 if (retpos == 0) {          /* toplevel? keep going */
     70                    dst[len - 1] = '.';
     71            } else {
     72                /* NUL: end of current domain name */
     73                if (retpos == 0) {
     74                    /* toplevel? keep going */
    7675                    crtpos++;
    77                 } else {                    /* return to toplevel saved spot */
     76                } else {
     77                    /* return to toplevel saved spot */
    7878                    crtpos = retpos;
    7979                    retpos = depth = 0;
    8080                }
    8181                if (dst)
    82                     *(dst + plen + len - 1) = ' ';
    83             }
    84 
    85             if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */
    86                 len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */
     82                    dst[len - 1] = ' ';
     83            }
     84
     85            if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */
     86             || len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */
     87            ) {
    8788                return NULL;
    88         }
    89 
    90         if (!len)           /* expanded string has 0 length? abort */
     89            }
     90        }
     91
     92        if (!len) /* expanded string has 0 length? abort */
    9193            return NULL;
    9294
    93         if (dst)
    94             *(dst + plen + len - 1) = '\0';
    95     }
    96 
    97     return dst;
     95        if (!dst) { /* first pass? */
     96            /* allocate dst buffer and copy pre */
     97            unsigned plen = strlen(pre);
     98            ret = dst = xmalloc(plen + len);
     99            memcpy(dst, pre, plen);
     100            dst += plen;
     101        } else {
     102            dst[len - 1] = '\0';
     103            break;
     104        }
     105    }
     106
     107    return ret;
    98108}
    99109
     
    104114static uint8_t *convert_dname(const char *src)
    105115{
    106     uint8_t c, *res, *lp, *rp;
     116    uint8_t c, *res, *lenptr, *dst;
    107117    int len;
    108118
    109119    res = xmalloc(strlen(src) + 2);
    110     rp = lp = res;
    111     rp++;
     120    dst = lenptr = res;
     121    dst++;
    112122
    113123    for (;;) {
    114124        c = (uint8_t)*src++;
    115         if (c == '.' || c == '\0') {    /* end of label */
    116             len = rp - lp - 1;
     125        if (c == '.' || c == '\0') {  /* end of label */
     126            len = dst - lenptr - 1;
    117127            /* label too long, too short, or two '.'s in a row? abort */
    118128            if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) {
     
    120130                return NULL;
    121131            }
    122             *lp = len;
    123             lp = rp++;
    124             if (c == '\0' || *src == '\0')  /* end of dname */
     132            *lenptr = len;
     133            if (c == '\0' || *src == '\0')  /* "" or ".": end of src */
    125134                break;
    126         } else {
    127             if (c >= 0x41 && c <= 0x5A)     /* uppercase? convert to lower */
    128                 c += 0x20;
    129             *rp++ = c;
    130         }
    131     }
    132 
    133     *lp = 0;
    134     if (rp - res > NS_MAXCDNAME) {  /* dname too long? abort */
     135            lenptr = dst++;
     136            continue;
     137        }
     138        if (c >= 'A' && c <= 'Z')  /* uppercase? convert to lower */
     139            c += ('a' - 'A');
     140        *dst++ = c;
     141    }
     142
     143    if (dst - res >= NS_MAXCDNAME) {  /* dname too long? abort */
    135144        free(res);
    136145        return NULL;
    137146    }
     147
     148    *dst = 0;
    138149    return res;
    139150}
    140151
    141 /* returns the offset within cstr at which dname can be found, or -1
    142  */
     152/* Returns the offset within cstr at which dname can be found, or -1 */
    143153static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
    144154{
    145155    const uint8_t *c, *d;
    146     int off, inc;
     156    int off;
    147157
    148158    /* find all labels in cstr */
     
    151161        c = cstr + off;
    152162
    153         if ((*c & NS_CMPRSFLGS) != 0) { /* pointer, skip */
     163        if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {  /* pointer, skip */
    154164            off += 2;
    155         } else if (*c) {    /* label, try matching dname */
    156             inc = *c + 1;
     165            continue;
     166        }
     167        if (*c) {  /* label, try matching dname */
    157168            d = dname;
    158             while (*c == *d && memcmp(c + 1, d + 1, *c) == 0) {
    159                 if (*c == 0)    /* match, return offset */
     169            while (1) {
     170                unsigned len1 = *c + 1;
     171                if (memcmp(c, d, len1) != 0)
     172                    break;
     173                if (len1 == 1)  /* at terminating NUL - match, return offset */
    160174                    return off;
    161                 d += *c + 1;
    162                 c += *c + 1;
    163                 if ((*c & NS_CMPRSFLGS) != 0)   /* pointer, jump */
    164                     c = cstr + (((*c & 0x3f) << 8) | (*(c + 1) & 0xff));
    165             }
    166             off += inc;
    167         } else {    /* null, skip */
    168             off++;
    169         }
     175                d += len1;
     176                c += len1;
     177                if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS)  /* pointer, jump */
     178                    c = cstr + (((c[0] & 0x3f) << 8) | c[1]);
     179            }
     180            off += cstr[off] + 1;
     181            continue;
     182        }
     183        /* NUL, skip */
     184        off++;
    170185    }
    171186
     
    173188}
    174189
    175 /* computes string to be appended to cstr so that src would be added to
     190/* Computes string to be appended to cstr so that src would be added to
    176191 * the compression (best case, it's a 2-byte pointer to some offset within
    177  * cstr; worst case, it's all of src, converted to rfc3011 format).
     192 * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format).
    178193 * The computed string is returned directly; its length is returned via retlen;
    179194 * NULL and 0, respectively, are returned if an error occurs.
    180195 */
    181 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)
     196uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)
    182197{
    183198    uint8_t *d, *dname;
     
    190205    }
    191206
    192     for (d = dname; *d != 0; d += *d + 1) {
    193         off = find_offset(cstr, clen, d);
    194         if (off >= 0) { /* found a match, add pointer and terminate string */
    195             *d++ = NS_CMPRSFLGS;
    196             *d = off;
    197             break;
    198         }
     207    d = dname;
     208    while (*d) {
     209        if (cstr) {
     210            off = find_offset(cstr, clen, d);
     211            if (off >= 0) { /* found a match, add pointer and return */
     212                *d++ = NS_CMPRSFLGS | (off >> 8);
     213                *d = off;
     214                break;
     215            }
     216        }
     217        d += *d + 1;
    199218    }
    200219
     
    203222}
    204223
    205 #endif /* ENABLE_FEATURE_RFC3397 */
     224#ifdef DNS_COMPR_TESTING
     225/* gcc -Wall -DDNS_COMPR_TESTING domain_codec.c -o domain_codec && ./domain_codec */
     226int main(int argc, char **argv)
     227{
     228    int len;
     229    uint8_t *encoded;
     230
     231#define DNAME_DEC(encoded,pre) dname_dec((uint8_t*)(encoded), sizeof(encoded), (pre))
     232    printf("'%s'\n",       DNAME_DEC("\4host\3com\0", "test1:"));
     233    printf("test2:'%s'\n", DNAME_DEC("\4host\3com\0\4host\3com\0", ""));
     234    printf("test3:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\0", ""));
     235    printf("test4:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5", ""));
     236    printf("test5:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5\1z\xC0\xA", ""));
     237
     238#define DNAME_ENC(cache,source,lenp) dname_enc((uint8_t*)(cache), sizeof(cache), (source), (lenp))
     239    encoded = dname_enc(NULL, 0, "test.net", &len);
     240    printf("test6:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
     241    encoded = DNAME_ENC("\3net\0", "test.net", &len);
     242    printf("test7:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
     243    encoded = DNAME_ENC("\4test\3net\0", "test.net", &len);
     244    printf("test8:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
     245    return 0;
     246}
     247#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dumpleases.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
    5 #include <getopt.h>
    6 
    75#include "common.h"
    86#include "dhcpd.h"
     7#include "unicode.h"
    98
    10 int dumpleases_main(int argc, char **argv);
    11 int dumpleases_main(int argc, char **argv)
     9int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     10int dumpleases_main(int argc UNUSED_PARAM, char **argv)
    1211{
    1312    int fd;
    1413    int i;
    1514    unsigned opt;
    16     time_t expires;
     15    int64_t written_at, curr, expires_abs;
    1716    const char *file = LEASES_FILE;
    18     struct dhcpOfferedAddr lease;
     17    struct dyn_lease lease;
    1918    struct in_addr addr;
    2019
    2120    enum {
    22         OPT_a   = 0x1,  // -a
    23         OPT_r   = 0x2,  // -r
    24         OPT_f   = 0x4,  // -f
     21        OPT_a = 0x1, // -a
     22        OPT_r = 0x2, // -r
     23        OPT_f = 0x4, // -f
    2524    };
    26 #if ENABLE_GETOPT_LONG
     25#if ENABLE_LONG_OPTS
    2726    static const char dumpleases_longopts[] ALIGN1 =
    2827        "absolute\0"  No_argument       "a"
     
    3332    applet_long_options = dumpleases_longopts;
    3433#endif
     34    init_unicode();
     35
    3536    opt_complementary = "=0:a--r:r--a";
    3637    opt = getopt32(argv, "arf:", &file);
     
    3839    fd = xopen(file, O_RDONLY);
    3940
    40     printf("Mac Address       IP-Address      Expires %s\n", (opt & OPT_a) ? "at" : "in");
    41     /*     "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
     41    printf("Mac Address       IP Address      Host Name           Expires %s\n", (opt & OPT_a) ? "at" : "in");
     42    /*     "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */
     43    /*     "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */
     44
     45    xread(fd, &written_at, sizeof(written_at));
     46    written_at = SWAP_BE64(written_at);
     47    curr = time(NULL);
     48    if (curr < written_at)
     49        written_at = curr; /* lease file from future! :) */
     50
    4251    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]);
     52        const char *fmt = ":%02x" + 1;
     53        for (i = 0; i < 6; i++) {
     54            printf(fmt, lease.lease_mac[i]);
     55            fmt = ":%02x";
    4656        }
    47         addr.s_addr = lease.yiaddr;
    48         printf(" %-15s ", inet_ntoa(addr));
    49         expires = ntohl(lease.expires);
     57        addr.s_addr = lease.lease_nip;
     58#if ENABLE_UNICODE_SUPPORT
     59        {
     60            char *uni_name = unicode_conv_to_printable_fixedwidth(NULL, lease.hostname, 19);
     61            printf(" %-16s%s ", inet_ntoa(addr), uni_name);
     62            free(uni_name);
     63        }
     64#else
     65        /* actually, 15+1 and 19+1, +1 is a space between columns */
     66        /* lease.hostname is char[20] and is always NUL terminated */
     67        printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname);
     68#endif
     69        expires_abs = ntohl(lease.expires) + written_at;
     70        if (expires_abs <= curr) {
     71            puts("expired");
     72            continue;
     73        }
    5074        if (!(opt & OPT_a)) { /* no -a */
    51             if (!expires)
    52                 puts("expired");
    53             else {
    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);
    60             }
    61         } else /* -a */
    62             fputs(ctime(&expires), stdout);
     75            unsigned d, h, m;
     76            unsigned expires = expires_abs - curr;
     77            d = expires / (24*60*60); expires %= (24*60*60);
     78            h = expires / (60*60); expires %= (60*60);
     79            m = expires / 60; expires %= 60;
     80            if (d)
     81                printf("%u days ", d);
     82            printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
     83        } else { /* -a */
     84            time_t t = expires_abs;
     85            fputs(ctime(&t), stdout);
     86        }
    6387    }
    6488    /* close(fd); */
  • branches/2.2.9/mindi-busybox/networking/udhcp/files.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * files.c -- DHCP server file manipulation *
     3 * DHCP server config and lease file manipulation
     4 *
    45 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
     6 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    58 */
    6 
    79#include <netinet/ether.h>
    810
    911#include "common.h"
    1012#include "dhcpd.h"
    11 #include "options.h"
    12 
    1313
    1414/* on these functions, make sure your datatype matches */
    15 static 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 
    27 static 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 
    40 static int read_str(const char *line, void *arg)
     15static int FAST_FUNC read_str(const char *line, void *arg)
    4116{
    4217    char **dest = arg;
     
    4722}
    4823
    49 
    50 static int read_u32(const char *line, void *arg)
     24static int FAST_FUNC read_u32(const char *line, void *arg)
    5125{
    5226    *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
     
    5428}
    5529
    56 
    57 static 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 */
    74 struct 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 */
    86 static 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 */
    153 static 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 
    250 static int read_staticlease(const char *const_line, void *arg)
     30static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
    25131{
    25232    char *line;
    25333    char *mac_string;
    25434    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));
     35    struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
     36    uint32_t nip;
    26137
    26238    /* Read mac */
    26339    line = (char *) const_line;
    264     mac_string = strtok(line, " \t");
    265     read_mac(mac_string, mac_bytes);
     40    mac_string = strtok_r(line, " \t", &line);
     41    if (!mac_string || !ether_aton_r(mac_string, &mac_bytes))
     42        return 0;
    26643
    26744    /* 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);
     45    ip_string = strtok_r(NULL, " \t", &line);
     46    if (!ip_string || !udhcp_str2nip(ip_string, &nip))
     47        return 0;
     48
     49    add_static_lease(arg, (uint8_t*) &mac_bytes, nip);
     50
     51    log_static_leases(arg);
    27452
    27553    return 1;
     
    27957struct config_keyword {
    28058    const char *keyword;
    281     int (*handler)(const char *line, void *var);
     59    int (*handler)(const char *line, void *var) FAST_FUNC;
    28260    void *var;
    28361    const char *def;
     
    28563
    28664static 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),      ""},
     65    /* keyword        handler           variable address               default */
     66    {"start"        , udhcp_str2nip   , &server_config.start_ip     , "192.168.0.20"},
     67    {"end"          , udhcp_str2nip   , &server_config.end_ip       , "192.168.0.254"},
     68    {"interface"    , read_str        , &server_config.interface    , "eth0"},
    29369    /* Avoid "max_leases value not sane" warning by setting default
    29470     * 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 */
     71    {"max_leases"   , read_u32        , &server_config.max_leases   , "235"},
     72    {"auto_time"    , read_u32        , &server_config.auto_time    , "7200"},
     73    {"decline_time" , read_u32        , &server_config.decline_time , "3600"},
     74    {"conflict_time", read_u32        , &server_config.conflict_time, "3600"},
     75    {"offer_time"   , read_u32        , &server_config.offer_time   , "60"},
     76    {"min_lease"    , read_u32        , &server_config.min_lease_sec, "60"},
     77    {"lease_file"   , read_str        , &server_config.lease_file   , LEASES_FILE},
     78    {"pidfile"      , read_str        , &server_config.pidfile      , "/var/run/udhcpd.pid"},
     79    {"siaddr"       , udhcp_str2nip   , &server_config.siaddr_nip   , "0.0.0.0"},
     80    /* keywords with no defaults must be last! */
     81    {"option"       , udhcp_str2optset, &server_config.options      , ""},
     82    {"opt"          , udhcp_str2optset, &server_config.options      , ""},
     83    {"notify_file"  , read_str        , &server_config.notify_file  , ""},
     84    {"sname"        , read_str        , &server_config.sname        , ""},
     85    {"boot_file"    , read_str        , &server_config.boot_file    , ""},
     86    {"static_lease" , read_staticlease, &server_config.static_leases, ""},
    31087};
    311 
    312 
    313 /*
    314  * Domain names may have 254 chars, and string options can be 254
    315  * chars long. However, 80 bytes will be enough for most, and won't
    316  * hog up memory. If you have a special application, change it
    317  */
    318 #define READ_CONFIG_BUF_SIZE 80
    319 
    320 int read_config(const char *file)
    321 {
    322     FILE *in;
    323     char buffer[READ_CONFIG_BUF_SIZE], *token, *line;
    324     int i, lm = 0;
    325 
    326     for (i = 0; i < ARRAY_SIZE(keywords); i++)
    327         if (keywords[i].def[0])
    328             keywords[i].handler(keywords[i].def, keywords[i].var);
    329 
    330     in = fopen_or_warn(file, "r");
    331     if (!in) {
    332         return 0;
    333     }
    334 
    335     while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
    336         char debug_orig[READ_CONFIG_BUF_SIZE];
    337         char *p;
    338 
    339         lm++;
    340         p = strchr(buffer, '\n');
    341         if (p) *p = '\0';
    342         if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer);
    343         p = strchr(buffer, '#');
    344         if (p) *p = '\0';
    345 
    346         if (!(token = strtok(buffer, " \t"))) continue;
    347         if (!(line = strtok(NULL, ""))) continue;
    348 
    349         /* eat leading whitespace */
    350         line = skip_whitespace(line);
    351         /* eat trailing whitespace */
    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++)
    357             if (!strcasecmp(token, keywords[i].keyword))
    358                 if (!keywords[i].handler(line, keywords[i].var)) {
    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);
     88enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
     89
     90void FAST_FUNC read_config(const char *file)
     91{
     92    parser_t *parser;
     93    const struct config_keyword *k;
     94    unsigned i;
     95    char *token[2];
     96
     97    for (i = 0; i < KWS_WITH_DEFAULTS; i++)
     98        keywords[i].handler(keywords[i].def, keywords[i].var);
     99
     100    parser = config_open(file);
     101    while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
     102        for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
     103            if (strcasecmp(token[0], k->keyword) == 0) {
     104                if (!k->handler(token[1], k->var)) {
     105                    bb_error_msg("can't parse line %u in %s",
     106                            parser->lineno, file);
    362107                    /* reset back to the default value */
    363                     keywords[i].handler(keywords[i].def, keywords[i].var);
     108                    k->handler(k->def, k->var);
    364109                }
    365     }
    366     fclose(in);
     110                break;
     111            }
     112        }
     113    }
     114    config_close(parser);
    367115
    368116    server_config.start_ip = ntohl(server_config.start_ip);
    369117    server_config.end_ip = ntohl(server_config.end_ip);
    370 
    371     return 1;
    372 }
    373 
    374 
    375 void write_leases(void)
    376 {
    377     int fp;
     118}
     119
     120void FAST_FUNC write_leases(void)
     121{
     122    int fd;
    378123    unsigned i;
    379     time_t curr = time(0);
    380     unsigned long tmp_time;
    381 
    382     fp = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
    383     if (fp < 0) {
     124    leasetime_t curr;
     125    int64_t written_at;
     126
     127    fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
     128    if (fd < 0)
    384129        return;
    385     }
     130
     131    curr = written_at = time(NULL);
     132
     133    written_at = SWAP_BE64(written_at);
     134    full_write(fd, &written_at, sizeof(written_at));
    386135
    387136    for (i = 0; i < server_config.max_leases; i++) {
    388         if (leases[i].yiaddr != 0) {
    389 
    390             /* screw with the time in the struct, for easier writing */
    391             tmp_time = leases[i].expires;
    392 
    393             if (server_config.remaining) {
    394                 if (lease_expired(&(leases[i])))
    395                     leases[i].expires = 0;
    396                 else leases[i].expires -= curr;
    397             } /* else stick with the time we got */
    398             leases[i].expires = htonl(leases[i].expires);
    399             // FIXME: error check??
    400             full_write(fp, &leases[i], sizeof(leases[i]));
    401 
    402             /* then restore it when done */
    403             leases[i].expires = tmp_time;
    404         }
    405     }
    406     close(fp);
     137        leasetime_t tmp_time;
     138
     139        if (g_leases[i].lease_nip == 0)
     140            continue;
     141
     142        /* Screw with the time in the struct, for easier writing */
     143        tmp_time = g_leases[i].expires;
     144
     145        g_leases[i].expires -= curr;
     146        if ((signed_leasetime_t) g_leases[i].expires < 0)
     147            g_leases[i].expires = 0;
     148        g_leases[i].expires = htonl(g_leases[i].expires);
     149
     150        /* No error check. If the file gets truncated,
     151         * we lose some leases on restart. Oh well. */
     152        full_write(fd, &g_leases[i], sizeof(g_leases[i]));
     153
     154        /* Then restore it when done */
     155        g_leases[i].expires = tmp_time;
     156    }
     157    close(fd);
    407158
    408159    if (server_config.notify_file) {
    409         char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file);
    410         system(cmd);
    411         free(cmd);
    412     }
    413 }
    414 
    415 
    416 void read_leases(const char *file)
    417 {
    418     int fp;
    419     unsigned int i = 0;
    420     struct dhcpOfferedAddr lease;
    421 
    422     fp = open_or_warn(file, O_RDONLY);
    423     if (fp < 0) {
     160        char *argv[3];
     161        argv[0] = server_config.notify_file;
     162        argv[1] = server_config.lease_file;
     163        argv[2] = NULL;
     164        spawn_and_wait(argv);
     165    }
     166}
     167
     168void FAST_FUNC read_leases(const char *file)
     169{
     170    struct dyn_lease lease;
     171    int64_t written_at, time_passed;
     172    int fd;
     173#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     174    unsigned i = 0;
     175#endif
     176
     177    fd = open_or_warn(file, O_RDONLY);
     178    if (fd < 0)
    424179        return;
    425     }
    426 
    427     while (i < server_config.max_leases
    428      && full_read(fp, &lease, sizeof(lease)) == sizeof(lease)
    429     ) {
    430         /* ADDME: is it a static lease */
    431         uint32_t y = ntohl(lease.yiaddr);
     180
     181    if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
     182        goto ret;
     183    written_at = SWAP_BE64(written_at);
     184
     185    time_passed = time(NULL) - written_at;
     186    /* Strange written_at, or lease file from old version of udhcpd
     187     * which had no "written_at" field? */
     188    if ((uint64_t)time_passed > 12 * 60 * 60)
     189        goto ret;
     190
     191    while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
     192//FIXME: what if it matches some static lease?
     193        uint32_t y = ntohl(lease.lease_nip);
    432194        if (y >= server_config.start_ip && y <= server_config.end_ip) {
    433             lease.expires = ntohl(lease.expires);
    434             if (!server_config.remaining)
    435                 lease.expires -= time(0);
    436             if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
     195            signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
     196            if (expires <= 0)
     197                continue;
     198            /* NB: add_lease takes "relative time", IOW,
     199             * lease duration, not lease deadline. */
     200            if (add_lease(lease.lease_mac, lease.lease_nip,
     201                    expires,
     202                    lease.hostname, sizeof(lease.hostname)
     203                ) == 0
     204            ) {
    437205                bb_error_msg("too many leases while loading %s", file);
    438206                break;
    439207            }
     208#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
    440209            i++;
     210#endif
    441211        }
    442212    }
    443     DEBUG("Read %d leases", i);
    444     close(fp);
    445 }
     213    log1("Read %d leases", i);
     214 ret:
     215    close(fd);
     216}
  • branches/2.2.9/mindi-busybox/networking/udhcp/leases.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * leases.c -- tools to manage DHCP leases
    43 * Russ Dill <Russ.Dill@asu.edu> July 2001
     4 *
     5 * Licensed under GPLv2, see file LICENSE in this source tree.
    56 */
    6 
    77#include "common.h"
    88#include "dhcpd.h"
    99
    10 
    1110/* Find the oldest expired lease, NULL if there are no expired leases */
    12 static struct dhcpOfferedAddr *oldest_expired_lease(void)
     11static struct dyn_lease *oldest_expired_lease(void)
    1312{
    14     struct dhcpOfferedAddr *oldest = NULL;
    15 // TODO: use monotonic_sec()
    16     unsigned long oldest_lease = time(0);
     13    struct dyn_lease *oldest_lease = NULL;
     14    leasetime_t oldest_time = time(NULL);
    1715    unsigned i;
    1816
    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]);
     17    /* Unexpired leases have g_leases[i].expires >= current time
     18     * and therefore can't ever match */
     19    for (i = 0; i < server_config.max_leases; i++) {
     20        if (g_leases[i].expires < oldest_time) {
     21            oldest_time = g_leases[i].expires;
     22            oldest_lease = &g_leases[i];
    2323        }
    24     return oldest;
     24    }
     25    return oldest_lease;
    2526}
    2627
     28/* Clear out all leases with matching nonzero chaddr OR yiaddr.
     29 * If chaddr == NULL, this is a conflict lease.
     30 */
     31static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr)
     32{
     33    unsigned i;
    2734
    28 /* clear every lease out that chaddr OR yiaddr matches and is nonzero */
    29 static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
    30 {
    31     unsigned i, j;
    32 
    33     for (j = 0; j < 16 && !chaddr[j]; j++)
    34         continue;
    35 
    36     for (i = 0; i < server_config.max_leases; i++)
    37         if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0)
    38          || (yiaddr && leases[i].yiaddr == yiaddr)
     35    for (i = 0; i < server_config.max_leases; i++) {
     36        if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0)
     37         || (yiaddr && g_leases[i].lease_nip == yiaddr)
    3938        ) {
    40             memset(&(leases[i]), 0, sizeof(leases[i]));
     39            memset(&g_leases[i], 0, sizeof(g_leases[i]));
    4140        }
     41    }
    4242}
    4343
    44 
    45 /* add a lease into the table, clearing out any old ones */
    46 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
     44/* Add a lease into the table, clearing out any old ones.
     45 * If chaddr == NULL, this is a conflict lease.
     46 */
     47struct dyn_lease* FAST_FUNC add_lease(
     48        const uint8_t *chaddr, uint32_t yiaddr,
     49        leasetime_t leasetime,
     50        const char *hostname, int hostname_len)
    4751{
    48     struct dhcpOfferedAddr *oldest;
     52    struct dyn_lease *oldest;
    4953
    5054    /* clean out any old ones */
    51     clear_lease(chaddr, yiaddr);
     55    clear_leases(chaddr, yiaddr);
    5256
    5357    oldest = oldest_expired_lease();
    5458
    5559    if (oldest) {
    56         memcpy(oldest->chaddr, chaddr, 16);
    57         oldest->yiaddr = yiaddr;
    58         oldest->expires = time(0) + lease;
     60        memset(oldest, 0, sizeof(*oldest));
     61        if (hostname) {
     62            char *p;
     63
     64            hostname_len++; /* include NUL */
     65            if (hostname_len > sizeof(oldest->hostname))
     66                hostname_len = sizeof(oldest->hostname);
     67            p = safe_strncpy(oldest->hostname, hostname, hostname_len);
     68            /* sanitization (s/non-ASCII/^/g) */
     69            while (*p) {
     70                if (*p < ' ' || *p > 126)
     71                    *p = '^';
     72                p++;
     73            }
     74        }
     75        if (chaddr)
     76            memcpy(oldest->lease_mac, chaddr, 6);
     77        oldest->lease_nip = yiaddr;
     78        oldest->expires = time(NULL) + leasetime;
    5979    }
    6080
     
    6282}
    6383
    64 
    65 /* true if a lease has expired */
    66 int lease_expired(struct dhcpOfferedAddr *lease)
     84/* True if a lease has expired */
     85int FAST_FUNC is_expired_lease(struct dyn_lease *lease)
    6786{
    68     return (lease->expires < (unsigned long) time(0));
     87    return (lease->expires < (leasetime_t) time(NULL));
    6988}
    7089
    71 
    72 /* Find the first lease that matches chaddr, NULL if no match */
    73 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr)
     90/* Find the first lease that matches MAC, NULL if no match */
     91struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac)
    7492{
    7593    unsigned i;
    7694
    7795    for (i = 0; i < server_config.max_leases; i++)
    78         if (!memcmp(leases[i].chaddr, chaddr, 16))
    79             return &(leases[i]);
     96        if (memcmp(g_leases[i].lease_mac, mac, 6) == 0)
     97            return &g_leases[i];
    8098
    8199    return NULL;
    82100}
    83101
    84 
    85 /* Find the first lease that matches yiaddr, NULL is no match */
    86 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr)
     102/* Find the first lease that matches IP, NULL is no match */
     103struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip)
    87104{
    88105    unsigned i;
    89106
    90107    for (i = 0; i < server_config.max_leases; i++)
    91         if (leases[i].yiaddr == yiaddr)
    92             return &(leases[i]);
     108        if (g_leases[i].lease_nip == nip)
     109            return &g_leases[i];
    93110
    94111    return NULL;
    95112}
    96113
    97 
    98 /* check is an IP is taken, if it is, add it to the lease table */
    99 static int nobody_responds_to_arp(uint32_t addr)
     114/* Check if the IP is taken; if it is, add it to the lease table */
     115static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac)
    100116{
    101     static const uint8_t blank_chaddr[16]; /* 16 zero bytes */
    102 
    103117    struct in_addr temp;
    104118    int r;
    105119
    106     r = arpping(addr, server_config.server, server_config.arp, server_config.interface);
     120    r = arpping(nip, safe_mac,
     121            server_config.server_nip,
     122            server_config.server_mac,
     123            server_config.interface);
    107124    if (r)
    108125        return r;
    109126
    110     temp.s_addr = addr;
     127    temp.s_addr = nip;
    111128    bb_info_msg("%s belongs to someone, reserving it for %u seconds",
    112129        inet_ntoa(temp), (unsigned)server_config.conflict_time);
    113     add_lease(blank_chaddr, addr, server_config.conflict_time);
     130    add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
    114131    return 0;
    115132}
    116133
    117 
    118 /* find an assignable address, if check_expired is true, we check all the expired leases as well.
    119  * Maybe this should try expired leases by age... */
    120 uint32_t find_address(int check_expired)
     134/* Find a new usable (we think) address */
     135uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac)
    121136{
    122     uint32_t addr, ret;
    123     struct dhcpOfferedAddr *lease = NULL;
     137    uint32_t addr;
     138    struct dyn_lease *oldest_lease = NULL;
    124139
    125140    addr = server_config.start_ip; /* addr is in host order here */
    126141    for (; addr <= server_config.end_ip; addr++) {
     142        uint32_t nip;
     143        struct dyn_lease *lease;
     144
    127145        /* ie, 192.168.55.0 */
    128         if (!(addr & 0xFF))
     146        if ((addr & 0xff) == 0)
    129147            continue;
    130148        /* ie, 192.168.55.255 */
    131         if ((addr & 0xFF) == 0xFF)
     149        if ((addr & 0xff) == 0xff)
    132150            continue;
    133         /* Only do if it isn't assigned as a static lease */
    134         ret = htonl(addr);
    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             }
     151        nip = htonl(addr);
     152        /* is this a static lease addr? */
     153        if (is_nip_reserved(server_config.static_leases, nip))
     154            continue;
     155
     156        lease = find_lease_by_nip(nip);
     157        if (!lease) {
     158//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
     159            if (nobody_responds_to_arp(nip, safe_mac))
     160                return nip;
     161        } else {
     162            if (!oldest_lease || lease->expires < oldest_lease->expires)
     163                oldest_lease = lease;
    144164        }
    145165    }
     166
     167    if (oldest_lease
     168     && is_expired_lease(oldest_lease)
     169     && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac)
     170    ) {
     171        return oldest_lease->lease_nip;
     172    }
     173
    146174    return 0;
    147175}
  • branches/2.2.9/mindi-busybox/networking/udhcp/packet.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 
     2/*
     3 * Packet ops
     4 *
     5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
     6 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
     8 */
    39#include <netinet/in.h>
    410#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    5 #include <netpacket/packet.h>
    6 #include <net/ethernet.h>
     11# include <netpacket/packet.h>
     12# include <net/ethernet.h>
    713#else
    8 #include <asm/types.h>
    9 #include <linux/if_packet.h>
    10 #include <linux/if_ether.h>
     14# include <asm/types.h>
     15# include <linux/if_packet.h>
     16# include <linux/if_ether.h>
    1117#endif
    1218
    1319#include "common.h"
    1420#include "dhcpd.h"
    15 #include "options.h"
    16 
    17 
    18 void udhcp_init_header(struct dhcpMessage *packet, char type)
    19 {
    20     memset(packet, 0, sizeof(struct dhcpMessage));
     21
     22void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type)
     23{
     24    memset(packet, 0, sizeof(*packet));
     25    packet->op = BOOTREQUEST; /* if client to a server */
    2126    switch (type) {
    22     case DHCPDISCOVER:
    23     case DHCPREQUEST:
    24     case DHCPRELEASE:
    25     case DHCPINFORM:
    26         packet->op = BOOTREQUEST;
    27         break;
    2827    case DHCPOFFER:
    2928    case DHCPACK:
    3029    case DHCPNAK:
    31         packet->op = BOOTREPLY;
    32     }
    33     packet->htype = ETH_10MB;
    34     packet->hlen = ETH_10MB_LEN;
     30        packet->op = BOOTREPLY; /* if server to client */
     31    }
     32    packet->htype = 1; /* ethernet */
     33    packet->hlen = 6;
    3534    packet->cookie = htonl(DHCP_MAGIC);
    36     packet->options[0] = DHCP_END;
    37     add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
    38 }
    39 
    40 
    41 /* read a packet from socket fd, return -1 on read error, -2 on packet error */
    42 int udhcp_get_packet(struct dhcpMessage *packet, int fd)
    43 {
    44 #if 0
    45     static const char broken_vendors[][8] = {
    46         "MSFT 98",
    47         ""
    48     };
     35    if (DHCP_END != 0)
     36        packet->options[0] = DHCP_END;
     37    udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
     38}
     39
     40#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     41void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet)
     42{
     43    char buf[sizeof(packet->chaddr)*2 + 1];
     44
     45    if (dhcp_verbose < 2)
     46        return;
     47
     48    bb_info_msg(
     49        //" op %x"
     50        //" htype %x"
     51        " hlen %x"
     52        //" hops %x"
     53        " xid %x"
     54        //" secs %x"
     55        //" flags %x"
     56        " ciaddr %x"
     57        " yiaddr %x"
     58        " siaddr %x"
     59        " giaddr %x"
     60        //" chaddr %s"
     61        //" sname %s"
     62        //" file %s"
     63        //" cookie %x"
     64        //" options %s"
     65        //, packet->op
     66        //, packet->htype
     67        , packet->hlen
     68        //, packet->hops
     69        , packet->xid
     70        //, packet->secs
     71        //, packet->flags
     72        , packet->ciaddr
     73        , packet->yiaddr
     74        , packet->siaddr_nip
     75        , packet->gateway_nip
     76        //, packet->chaddr[16]
     77        //, packet->sname[64]
     78        //, packet->file[128]
     79        //, packet->cookie
     80        //, packet->options[]
     81    );
     82    *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
     83    bb_info_msg(" chaddr %s", buf);
     84}
    4985#endif
     86
     87/* Read a packet from socket fd, return -1 on read error, -2 on packet error */
     88int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
     89{
    5090    int bytes;
    5191    unsigned char *vendor;
    5292
    5393    memset(packet, 0, sizeof(*packet));
    54     bytes = read(fd, packet, sizeof(*packet));
     94    bytes = safe_read(fd, packet, sizeof(*packet));
    5595    if (bytes < 0) {
    56         DEBUG("cannot read on listening socket, ignoring");
    57         return -1;
    58     }
    59 
    60     if (ntohl(packet->cookie) != DHCP_MAGIC) {
    61         bb_error_msg("received bogus message, ignoring");
     96        log1("Packet read error, ignoring");
     97        return bytes; /* returns -1 */
     98    }
     99
     100    if (packet->cookie != htonl(DHCP_MAGIC)) {
     101        bb_info_msg("Packet with bad magic, ignoring");
    62102        return -2;
    63103    }
    64     DEBUG("Received a packet");
     104    log1("Received a packet");
     105    udhcp_dump_packet(packet);
    65106
    66107    if (packet->op == BOOTREQUEST) {
    67         vendor = get_option(packet, DHCP_VENDOR);
     108        vendor = udhcp_get_option(packet, DHCP_VENDOR);
    68109        if (vendor) {
    69110#if 0
     111            static const char broken_vendors[][8] = {
     112                "MSFT 98",
     113                ""
     114            };
    70115            int i;
    71116            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])
     117                if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i])
     118                 && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0
    74119                ) {
    75                     DEBUG("broken client (%s), forcing broadcast",
     120                    log1("Broken client (%s), forcing broadcast replies",
    76121                        broken_vendors[i]);
    77122                    packet->flags |= htons(BROADCAST_FLAG);
     
    79124            }
    80125#else
    81             if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1)
     126            if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1)
    82127             && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0
    83128            ) {
    84                 DEBUG("broken client (%s), forcing broadcast", "MSFT 98");
     129                log1("Broken client (%s), forcing broadcast replies", "MSFT 98");
    85130                packet->flags |= htons(BROADCAST_FLAG);
    86131            }
     
    92137}
    93138
    94 
    95 uint16_t udhcp_checksum(void *addr, int count)
     139uint16_t FAST_FUNC udhcp_checksum(void *addr, int count)
    96140{
    97141    /* Compute Internet Checksum for "count" bytes
    98      *         beginning at location "addr".
     142     * beginning at location "addr".
    99143     */
    100144    int32_t sum = 0;
     
    112156         * with little and big endian hosts */
    113157        uint16_t tmp = 0;
    114         *(uint8_t *) (&tmp) = * (uint8_t *) source;
     158        *(uint8_t*)&tmp = *(uint8_t*)source;
    115159        sum += tmp;
    116160    }
     
    122166}
    123167
    124 
    125 /* Construct a ip/udp header for a packet, and specify the source and dest hardware address */
    126 void BUG_sizeof_struct_udp_dhcp_packet_must_be_576(void);
    127 int 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)
    130 {
     168/* Construct a ip/udp header for a packet, send packet */
     169int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
     170        uint32_t source_nip, int source_port,
     171        uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
     172        int ifindex)
     173{
     174    struct sockaddr_ll dest_sll;
     175    struct ip_udp_dhcp_packet packet;
     176    unsigned padding;
    131177    int fd;
    132     int result;
    133     struct sockaddr_ll dest;
    134     struct udp_dhcp_packet packet;
     178    int result = -1;
     179    const char *msg;
    135180
    136181    fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
    137182    if (fd < 0) {
    138         bb_perror_msg("socket");
    139         return -1;
    140     }
    141 
    142     memset(&dest, 0, sizeof(dest));
    143     memset(&packet, 0, sizeof(packet));
    144 
    145     dest.sll_family = AF_PACKET;
    146     dest.sll_protocol = htons(ETH_P_IP);
    147     dest.sll_ifindex = ifindex;
    148     dest.sll_halen = 6;
    149     memcpy(dest.sll_addr, dest_arp, 6);
    150     if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
    151         bb_perror_msg("bind");
    152         close(fd);
    153         return -1;
    154     }
     183        msg = "socket(%s)";
     184        goto ret_msg;
     185    }
     186
     187    memset(&dest_sll, 0, sizeof(dest_sll));
     188    memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data));
     189    packet.data = *dhcp_pkt; /* struct copy */
     190
     191    dest_sll.sll_family = AF_PACKET;
     192    dest_sll.sll_protocol = htons(ETH_P_IP);
     193    dest_sll.sll_ifindex = ifindex;
     194    dest_sll.sll_halen = 6;
     195    memcpy(dest_sll.sll_addr, dest_arp, 6);
     196
     197    if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
     198        msg = "bind(%s)";
     199        goto ret_close;
     200    }
     201
     202    /* We were sending full-sized DHCP packets (zero padded),
     203     * but some badly configured servers were seen dropping them.
     204     * Apparently they drop all DHCP packets >576 *ethernet* octets big,
     205     * whereas they may only drop packets >576 *IP* octets big
     206     * (which for typical Ethernet II means 590 octets: 6+6+2 + 576).
     207     *
     208     * In order to work with those buggy servers,
     209     * we truncate packets after end option byte.
     210     */
     211    padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options);
    155212
    156213    packet.ip.protocol = IPPROTO_UDP;
    157     packet.ip.saddr = source_ip;
    158     packet.ip.daddr = dest_ip;
     214    packet.ip.saddr = source_nip;
     215    packet.ip.daddr = dest_nip;
    159216    packet.udp.source = htons(source_port);
    160217    packet.udp.dest = htons(dest_port);
    161     packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */
     218    /* size, excluding IP header: */
     219    packet.udp.len = htons(UDP_DHCP_SIZE - padding);
     220    /* for UDP checksumming, ip.len is set to UDP packet len */
    162221    packet.ip.tot_len = packet.udp.len;
    163     memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
    164     packet.udp.check = udhcp_checksum(&packet, sizeof(struct udp_dhcp_packet));
    165 
    166     packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
     222    packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding);
     223    /* but for sending, it is set to IP packet len */
     224    packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
    167225    packet.ip.ihl = sizeof(packet.ip) >> 2;
    168226    packet.ip.version = IPVERSION;
    169227    packet.ip.ttl = IPDEFTTL;
    170     packet.ip.check = udhcp_checksum(&(packet.ip), sizeof(packet.ip));
    171 
    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));
    177     if (result <= 0) {
    178         bb_perror_msg("sendto");
    179     }
     228    packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip));
     229
     230    udhcp_dump_packet(dhcp_pkt);
     231    result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
     232            (struct sockaddr *) &dest_sll, sizeof(dest_sll));
     233    msg = "sendto";
     234 ret_close:
    180235    close(fd);
     236    if (result < 0) {
     237 ret_msg:
     238        bb_perror_msg(msg, "PACKET");
     239    }
    181240    return result;
    182241}
    183242
    184 
    185243/* Let the kernel do all the work for packet generation */
    186 int udhcp_kernel_packet(struct dhcpMessage *payload,
    187         uint32_t source_ip, int source_port,
    188         uint32_t dest_ip, int dest_port)
    189 {
    190     int fd, result;
     244int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
     245        uint32_t source_nip, int source_port,
     246        uint32_t dest_nip, int dest_port)
     247{
    191248    struct sockaddr_in client;
     249    unsigned padding;
     250    int fd;
     251    int result = -1;
     252    const char *msg;
    192253
    193254    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    194     if (fd < 0)
    195         return -1;
    196 
     255    if (fd < 0) {
     256        msg = "socket(%s)";
     257        goto ret_msg;
     258    }
    197259    setsockopt_reuseaddr(fd);
    198260
     
    200262    client.sin_family = AF_INET;
    201263    client.sin_port = htons(source_port);
    202     client.sin_addr.s_addr = source_ip;
    203 
     264    client.sin_addr.s_addr = source_nip;
    204265    if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
    205         close(fd);
    206         return -1;
     266        msg = "bind(%s)";
     267        goto ret_close;
    207268    }
    208269
     
    210271    client.sin_family = AF_INET;
    211272    client.sin_port = htons(dest_port);
    212     client.sin_addr.s_addr = dest_ip;
    213 
    214     if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) {
    215         close(fd);
    216         return -1;
    217     }
    218 
    219     result = write(fd, payload, sizeof(struct dhcpMessage));
     273    client.sin_addr.s_addr = dest_nip;
     274    if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
     275        msg = "connect";
     276        goto ret_close;
     277    }
     278
     279    udhcp_dump_packet(dhcp_pkt);
     280
     281    padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
     282    result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
     283    msg = "write";
     284 ret_close:
    220285    close(fd);
     286    if (result < 0) {
     287 ret_msg:
     288        bb_perror_msg(msg, "UDP");
     289    }
    221290    return result;
    222291}
  • branches/2.2.9/mindi-busybox/networking/udhcp/signalpipe.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* signalpipe.c
    3  *
     2/*
    43 * Signal pipe infrastructure. A reliable way of delivering signals.
    54 *
     
    2019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    2120 */
    22 
    2321#include "common.h"
    2422
    25 
    26 static int signal_pipe[2];
     23/* Global variable: we access it from signal handler */
     24static struct fd_pair signal_pipe;
    2725
    2826static void signal_handler(int sig)
    2927{
    3028    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");
     29    if (write(signal_pipe.wr, &ch, 1) != 1)
     30        bb_perror_msg("can't send signal");
    3331}
    34 
    3532
    3633/* Call this before doing anything else. Sets up the socket pair
    3734 * and installs the signal handler */
    38 void udhcp_sp_setup(void)
     35void FAST_FUNC udhcp_sp_setup(void)
    3936{
    4037    /* was socketpair, but it needs AF_UNIX in kernel */
    41     xpipe(signal_pipe);
    42     fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
    43     fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
    44     fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK);
    45     signal(SIGUSR1, signal_handler);
    46     signal(SIGUSR2, signal_handler);
    47     signal(SIGTERM, signal_handler);
     38    xpiped_pair(signal_pipe);
     39    close_on_exec_on(signal_pipe.rd);
     40    close_on_exec_on(signal_pipe.wr);
     41    ndelay_on(signal_pipe.wr);
     42    bb_signals(0
     43        + (1 << SIGUSR1)
     44        + (1 << SIGUSR2)
     45        + (1 << SIGTERM)
     46        , signal_handler);
    4847}
    49 
    5048
    5149/* Quick little function to setup the rfds. Will return the
    5250 * max_fd for use with select. Limited in that you can only pass
    5351 * one extra fd */
    54 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
     52int FAST_FUNC udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
    5553{
    5654    FD_ZERO(rfds);
    57     FD_SET(signal_pipe[0], rfds);
     55    FD_SET(signal_pipe.rd, rfds);
    5856    if (extra_fd >= 0) {
    59         fcntl(extra_fd, F_SETFD, FD_CLOEXEC);
     57        close_on_exec_on(extra_fd);
    6058        FD_SET(extra_fd, rfds);
    6159    }
    62     return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd;
     60    return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd;
    6361}
    64 
    6562
    6663/* Read a signal from the signal pipe. Returns 0 if there is
    6764 * no signal, -1 on error (and sets errno appropriately), and
    6865 * your signal on success */
    69 int udhcp_sp_read(fd_set *rfds)
     66int FAST_FUNC udhcp_sp_read(const fd_set *rfds)
    7067{
    7168    unsigned char sig;
    7269
    73     if (!FD_ISSET(signal_pipe[0], rfds))
     70    if (!FD_ISSET(signal_pipe.rd, rfds))
    7471        return 0;
    7572
    76     if (read(signal_pipe[0], &sig, 1) != 1)
     73    if (safe_read(signal_pipe.rd, &sig, 1) != 1)
    7774        return -1;
    7875
  • branches/2.2.9/mindi-busybox/networking/udhcp/socket.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * socket.c -- DHCP server client/server socket creation
     3 * DHCP server client/server socket creation
    44 *
    55 * udhcp client/server
     
    2323 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    2424 */
    25 
    2625#include <net/if.h>
    27 #include <features.h>
    2826#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    29 #include <netpacket/packet.h>
    30 #include <net/ethernet.h>
     27# include <netpacket/packet.h>
     28# include <net/ethernet.h>
    3129#else
    32 #include <asm/types.h>
    33 #include <linux/if_packet.h>
    34 #include <linux/if_ether.h>
     30# include <asm/types.h>
     31# include <linux/if_packet.h>
     32# include <linux/if_ether.h>
    3533#endif
    3634
    3735#include "common.h"
    3836
    39 
    40 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp)
     37int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac)
    4138{
    4239    int fd;
     
    4845
    4946    ifr.ifr_addr.sa_family = AF_INET;
    50     strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
    51     if (addr) {
     47    strncpy_IFNAMSIZ(ifr.ifr_name, interface);
     48    if (nip) {
    5249        if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr,
    5350            "is interface %s up and configured?", interface)
     
    5754        }
    5855        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));
     56        *nip = our_ip->sin_addr.s_addr;
     57        log1("IP %s", inet_ntoa(our_ip->sin_addr));
    6158    }
    6259
     
    6663            return -1;
    6764        }
    68         DEBUG("adapter index %d", ifr.ifr_ifindex);
     65        log1("Adapter index %d", ifr.ifr_ifindex);
    6966        *ifindex = ifr.ifr_ifindex;
    7067    }
    7168
    72     if (arp) {
     69    if (mac) {
    7370        if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) {
    7471            close(fd);
    7572            return -1;
    7673        }
    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]);
     74        memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
     75        log1("MAC %02x:%02x:%02x:%02x:%02x:%02x",
     76            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    8077    }
    8178
     
    8683/* 1. None of the callers expects it to ever fail */
    8784/* 2. ip was always INADDR_ANY */
    88 int listen_socket(/*uint32_t ip,*/ int port, const char *inf)
     85int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
    8986{
    9087    int fd;
    91     struct ifreq interface;
    9288    struct sockaddr_in addr;
    9389
    94     DEBUG("Opening listen socket on *:%d %s", port, inf);
     90    log1("Opening listen socket on *:%d %s", port, inf);
    9591    fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    9692
     
    9995        bb_perror_msg_and_die("SO_BROADCAST");
    10096
    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");
     97    /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
     98    if (setsockopt_bindtodevice(fd, inf))
     99        xfunc_die(); /* warning is already printed */
    104100
    105101    memset(&addr, 0, sizeof(addr));
  • branches/2.2.9/mindi-busybox/networking/udhcp/static_leases.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * static_leases.c -- Couple of functions to assist with storing and
    4  * retrieving data for static leases
     3 * Storing and retrieving data for static leases
    54 *
    65 * Wade Berrier <wberrier@myrealbox.com> September 2004
    76 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    9 
    109#include "common.h"
    1110#include "dhcpd.h"
    1211
     12/* Takes the address of the pointer to the static_leases linked list,
     13 * address to a 6 byte mac address,
     14 * 4 byte IP address */
     15void FAST_FUNC add_static_lease(struct static_lease **st_lease_pp,
     16        uint8_t *mac,
     17        uint32_t nip)
     18{
     19    struct static_lease *st_lease;
    1320
    14 /* Takes the address of the pointer to the static_leases linked list,
    15  *   Address to a 6 byte mac address
    16  *   Address to a 4 byte ip address */
    17 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip)
     21    /* Find the tail of the list */
     22    while ((st_lease = *st_lease_pp) != NULL) {
     23        st_lease_pp = &st_lease->next;
     24    }
     25
     26    /* Add new node */
     27    *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease));
     28    memcpy(st_lease->mac, mac, 6);
     29    st_lease->nip = nip;
     30    /*st_lease->next = NULL;*/
     31}
     32
     33/* Find static lease IP by mac */
     34uint32_t FAST_FUNC get_static_nip_by_mac(struct static_lease *st_lease, void *mac)
     35{
     36    while (st_lease) {
     37        if (memcmp(st_lease->mac, mac, 6) == 0)
     38            return st_lease->nip;
     39        st_lease = st_lease->next;
     40    }
     41
     42    return 0;
     43}
     44
     45/* Check to see if an IP is reserved as a static IP */
     46int FAST_FUNC is_nip_reserved(struct static_lease *st_lease, uint32_t nip)
     47{
     48    while (st_lease) {
     49        if (st_lease->nip == nip)
     50            return 1;
     51        st_lease = st_lease->next;
     52    }
     53
     54    return 0;
     55}
     56
     57#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     58/* Print out static leases just to check what's going on */
     59/* Takes the address of the pointer to the static_leases linked list */
     60void FAST_FUNC log_static_leases(struct static_lease **st_lease_pp)
    1861{
    1962    struct static_lease *cur;
    20     struct static_lease *new_static_lease;
    2163
    22     /* Build new node */
    23     new_static_lease = xmalloc(sizeof(struct static_lease));
    24     new_static_lease->mac = mac;
    25     new_static_lease->ip = ip;
    26     new_static_lease->next = NULL;
     64    if (dhcp_verbose < 2)
     65        return;
    2766
    28     /* If it's the first node to be added... */
    29     if (*lease_struct == NULL) {
    30         *lease_struct = new_static_lease;
    31     } else {
    32         cur = *lease_struct;
    33         while (cur->next) {
    34             cur = cur->next;
    35         }
    36 
    37         cur->next = new_static_lease;
    38     }
    39 
    40     return 1;
    41 }
    42 
    43 /* Check to see if a mac has an associated static lease */
    44 uint32_t getIpByMac(struct static_lease *lease_struct, void *arg)
    45 {
    46     uint32_t return_ip;
    47     struct static_lease *cur = lease_struct;
    48     uint8_t *mac = arg;
    49 
    50     return_ip = 0;
    51 
     67    cur = *st_lease_pp;
    5268    while (cur) {
    53         /* If the client has the correct mac  */
    54         if (memcmp(cur->mac, mac, 6) == 0) {
    55             return_ip = *(cur->ip);
    56         }
    57 
    58         cur = cur->next;
    59     }
    60 
    61     return return_ip;
    62 }
    63 
    64 /* Check to see if an ip is reserved as a static ip */
    65 uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip)
    66 {
    67     struct static_lease *cur = lease_struct;
    68 
    69     uint32_t return_val = 0;
    70 
    71     while (cur) {
    72         /* If the client has the correct ip  */
    73         if (*cur->ip == ip)
    74             return_val = 1;
    75 
    76         cur = cur->next;
    77     }
    78 
    79     return return_val;
    80 }
    81 
    82 #if ENABLE_FEATURE_UDHCP_DEBUG
    83 /* Print out static leases just to check what's going on */
    84 /* Takes the address of the pointer to the static_leases linked list */
    85 void printStaticLeases(struct static_lease **arg)
    86 {
    87     /* Get a pointer to the linked list */
    88     struct static_lease *cur = *arg;
    89 
    90     while (cur) {
    91         /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */
    92         printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac));
    93         /* printf("PrintStaticLeases: Lease ip Address: %x\n", cur->ip); */
    94         printf("PrintStaticLeases: Lease ip Value: %x\n", *(cur->ip));
    95 
     69        bb_info_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
     70            cur->mac[0], cur->mac[1], cur->mac[2],
     71            cur->mac[3], cur->mac[4], cur->mac[5],
     72            cur->nip
     73        );
    9674        cur = cur->next;
    9775    }
  • branches/2.2.9/mindi-busybox/networking/vconfig.c

    r1765 r2725  
    55 * Copyright (C) 2001  Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
     
    4848};
    4949
    50 #define VLAN_GROUP_ARRAY_LEN 4096
    51 #define SIOCSIFVLAN 0x8983      /* Set 802.1Q VLAN options */
     50#define VLAN_GROUP_ARRAY_LEN  4096
     51#define SIOCSIFVLAN           0x8983  /* Set 802.1Q VLAN options */
    5252
    53 /* On entry, table points to the length of the current string plus
    54  * nul terminator plus data length for the subsequent entry.  The
    55  * return value is the last data entry for the matching string. */
     53/* On entry, table points to the length of the current string
     54 * plus NUL terminator plus data length for the subsequent entry.
     55 * The return value is the last data entry for the matching string. */
    5656static const char *xfind_str(const char *table, const char *str)
    5757{
    5858    while (strcasecmp(str, table+1) != 0) {
    59         if (!*(table += table[0])) {
     59        table += table[0];
     60        if (!*table) {
    6061            bb_show_usage();
    6162        }
     
    107108static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config";
    108109
    109 int vconfig_main(int argc, char **argv);
     110int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    110111int vconfig_main(int argc, char **argv)
    111112{
     
    122123    xopen(conf_file_name, O_RDONLY);
    123124
    124     memset(&ifr, 0, sizeof(struct vlan_ioctl_args));
     125    memset(&ifr, 0, sizeof(ifr));
    125126
    126127    ++argv;
     
    134135        ifr.u.name_type = *xfind_str(name_types+1, argv[1]);
    135136    } else {
    136         if (strlen(argv[1]) >= IF_NAMESIZE) {
    137             bb_error_msg_and_die("if_name >= %d chars", IF_NAMESIZE);
    138         }
    139         strcpy(ifr.device1, argv[1]);
     137        strncpy_IFNAMSIZ(ifr.device1, argv[1]);
    140138        p = argv[2];
    141139
  • branches/2.2.9/mindi-busybox/networking/wget.c

    r1765 r2725  
    44 *
    55 * Chip Rosenthal Covad Communications <chip@laserlink.net>
     6 * Licensed under GPLv2, see file LICENSE in this source tree.
    67 *
     8 * Copyright (C) 2010 Bradley M. Kuhn <bkuhn@ebb.org>
     9 * Kuhn's copyrights are licensed GPLv2-or-later.  File as a whole remains GPLv2.
    710 */
    8 
    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 */
    1411#include "libbb.h"
    1512
     
    1714    // May be used if we ever will want to free() all xstrdup()s...
    1815    /* char *allocated; */
    19     char *host;
    20     int port;
    21     char *path;
    22     int is_ftp;
    23     char *user;
     16    const char *path;
     17    const char *user;
     18    char       *host;
     19    int         port;
     20    smallint    is_ftp;
    2421};
    2522
    26 static void parse_url(char *url, struct host_info *h);
    27 static FILE *open_socket(len_and_sockaddr *lsa);
    28 static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
    29 static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf);
    30 
    31 /* Globals (can be accessed from signal handlers */
    32 static off_t content_len;        /* Content-length of the file */
    33 static off_t beg_range;          /* Range at which continue begins */
     23
     24/* Globals */
     25struct globals {
     26    off_t content_len;        /* Content-length of the file */
     27    off_t beg_range;          /* Range at which continue begins */
    3428#if ENABLE_FEATURE_WGET_STATUSBAR
    35 static off_t transferred;        /* Number of bytes transferred so far */
    36 #endif
    37 static bool chunked;                     /* chunked transfer encoding */
     29    off_t transferred;        /* Number of bytes transferred so far */
     30    const char *curfile;      /* Name of current file being transferred */
     31    bb_progress_t pmt;
     32#endif
     33#if ENABLE_FEATURE_WGET_TIMEOUT
     34    unsigned timeout_seconds;
     35#endif
     36    smallint chunked;         /* chunked transfer encoding */
     37    smallint got_clen;        /* got content-length: from server  */
     38} FIX_ALIASING;
     39#define G (*(struct globals*)&bb_common_bufsiz1)
     40struct BUG_G_too_big {
     41    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     42};
     43#define INIT_G() do { \
     44    IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \
     45} while (0)
     46
     47
     48/* Must match option string! */
     49enum {
     50    WGET_OPT_CONTINUE   = (1 << 0),
     51    WGET_OPT_SPIDER     = (1 << 1),
     52    WGET_OPT_QUIET      = (1 << 2),
     53    WGET_OPT_OUTNAME    = (1 << 3),
     54    WGET_OPT_PREFIX     = (1 << 4),
     55    WGET_OPT_PROXY      = (1 << 5),
     56    WGET_OPT_USER_AGENT = (1 << 6),
     57    WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 7),
     58    WGET_OPT_RETRIES    = (1 << 8),
     59    WGET_OPT_PASSIVE    = (1 << 9),
     60    WGET_OPT_HEADER     = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
     61    WGET_OPT_POST_DATA  = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
     62};
     63
     64enum {
     65    PROGRESS_START = -1,
     66    PROGRESS_END   = 0,
     67    PROGRESS_BUMP  = 1,
     68};
    3869#if ENABLE_FEATURE_WGET_STATUSBAR
    39 static void progressmeter(int flag);
    40 static const char *curfile;             /* Name of current file being transferred */
    41 enum {
    42     STALLTIME = 5                   /* Seconds when xfer considered "stalled" */
    43 };
     70static void progress_meter(int flag)
     71{
     72    if (option_mask32 & WGET_OPT_QUIET)
     73        return;
     74
     75    if (flag == PROGRESS_START)
     76        bb_progress_init(&G.pmt);
     77
     78    bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred,
     79               G.chunked ? 0 : G.beg_range + G.transferred + G.content_len);
     80
     81    if (flag == PROGRESS_END) {
     82        bb_putchar_stderr('\n');
     83        G.transferred = 0;
     84    }
     85}
    4486#else
    45 static ALWAYS_INLINE void progressmeter(int flag) {}
    46 #endif
     87static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) { }
     88#endif
     89
     90
     91/* IPv6 knows scoped address types i.e. link and site local addresses. Link
     92 * local addresses can have a scope identifier to specify the
     93 * interface/link an address is valid on (e.g. fe80::1%eth0). This scope
     94 * identifier is only valid on a single node.
     95 *
     96 * RFC 4007 says that the scope identifier MUST NOT be sent across the wire,
     97 * unless all nodes agree on the semantic. Apache e.g. regards zone identifiers
     98 * in the Host header as invalid requests, see
     99 * https://issues.apache.org/bugzilla/show_bug.cgi?id=35122
     100 */
     101static void strip_ipv6_scope_id(char *host)
     102{
     103    char *scope, *cp;
     104
     105    /* bbox wget actually handles IPv6 addresses without [], like
     106     * wget "http://::1/xxx", but this is not standard.
     107     * To save code, _here_ we do not support it. */
     108
     109    if (host[0] != '[')
     110        return; /* not IPv6 */
     111
     112    scope = strchr(host, '%');
     113    if (!scope)
     114        return;
     115
     116    /* Remove the IPv6 zone identifier from the host address */
     117    cp = strchr(host, ']');
     118    if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
     119        /* malformed address (not "[xx]:nn" or "[xx]") */
     120        return;
     121    }
     122
     123    /* cp points to "]...", scope points to "%eth0]..." */
     124    overlapping_strcpy(scope, cp);
     125}
    47126
    48127/* Read NMEMB bytes into PTR from STREAM.  Returns the number of bytes read,
     
    55134    do {
    56135        clearerr(stream);
     136        errno = 0;
    57137        ret = fread(p, 1, nmemb, stream);
    58138        p += ret;
     
    71151    do {
    72152        clearerr(stream);
     153        errno = 0;
    73154        ret = fgets(s, size, stream);
    74155    } while (ret == NULL && ferror(stream) && errno == EINTR);
     
    89170#endif
    90171
    91 int wget_main(int argc, char **argv);
    92 int wget_main(int argc, char **argv)
    93 {
    94     char buf[512];
    95     struct host_info server, target;
    96     len_and_sockaddr *lsa;
    97     int n, status;
    98     int port;
    99     int try = 5;
    100     unsigned opt;
    101     char *str;
    102     char *proxy = 0;
    103     char *dir_prefix = NULL;
    104 #if ENABLE_FEATURE_WGET_LONG_OPTIONS
    105     char *extra_headers = NULL;
    106     llist_t *headers_llist = NULL;
    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                 );
    155     if (strcmp(proxy_flag, "off") == 0) {
    156         /* Use the proxy if necessary */
    157         use_proxy = 0;
    158     }
    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);
    169         while (headers_llist) {
    170             cp += sprintf(cp, "%s\r\n", headers_llist->data);
    171             headers_llist = headers_llist->link;
    172         }
    173     }
    174 #endif
    175 
    176     parse_url(argv[optind], &target);
    177     server.host = target.host;
    178     server.port = target.port;
    179 
    180     /* Use the proxy if necessary */
    181     if (use_proxy) {
    182         proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
    183         if (proxy && *proxy) {
    184             parse_url(proxy, &server);
    185         } else {
    186             use_proxy = 0;
    187         }
    188     }
    189 
    190     /* Guess an output filename */
    191     if (!fname_out) {
    192         // Dirty hack. Needed because bb_get_last_path_component
    193         // will destroy trailing / by storing '\0' in last byte!
    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
    207         }
    208         if (dir_prefix != NULL)
    209             fname_out = concat_path_file(dir_prefix, fname_out);
    210 #if ENABLE_FEATURE_WGET_STATUSBAR
    211     } else {
    212         curfile = bb_get_last_path_component(fname_out);
    213 #endif
    214     }
    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 */
    231     }
    232 
    233     /* We want to do exactly _one_ DNS lookup, since some
    234      * sites (i.e. ftp.us.debian.org) use round-robin DNS
    235      * and we want to connect to only one IP... */
    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 */
    241     }
    242 
    243     if (use_proxy || !target.is_ftp) {
    244         /*
    245          *  HTTP session
    246          */
    247         do {
    248             got_clen = chunked = 0;
    249 
    250             if (!--try)
    251                 bb_error_msg_and_die("too many redirections");
    252 
    253             /* Open socket to http server */
    254             if (sfp) fclose(sfp);
    255             sfp = open_socket(lsa);
    256 
    257             /* Send HTTP request.  */
    258             if (use_proxy) {
    259                 fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n",
    260                     target.is_ftp ? "f" : "ht", target.host,
    261                     target.path);
    262             } else {
    263                 fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
    264             }
    265 
    266             fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",
    267                 target.host, user_agent);
    268 
    269 #if ENABLE_FEATURE_WGET_AUTHENTICATION
    270             if (target.user) {
    271                 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
    272                     base64enc_512(buf, target.user));
    273             }
    274             if (use_proxy && server.user) {
    275                 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
    276                     base64enc_512(buf, server.user));
    277             }
    278 #endif
    279 
    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");
    287 
    288             /*
    289             * Retrieve HTTP response line and check for "200" status code.
    290             */
    291  read_response:
    292             if (fgets(buf, sizeof(buf), sfp) == NULL)
    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)
    316                     break;
    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);
    322             }
    323 
    324             /*
    325              * Retrieve HTTP headers.
    326              */
    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);
    334                     }
    335                     got_clen = 1;
    336                     continue;
    337                 }
    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;
    342                 }
    343                 if (key == KEY_location) {
    344                     if (str[0] == '/')
    345                         /* free(target.allocated); */
    346                         target.path = /* target.allocated = */ xstrdup(str+1);
    347                     else {
    348                         parse_url(str, &target);
    349                         if (use_proxy == 0) {
    350                             server.host = target.host;
    351                             server.port = target.port;
    352                         }
    353                         free(lsa);
    354                         lsa = xhost2sockaddr(server.host, server.port);
    355                         break;
    356                     }
    357                 }
    358             }
    359         } while (status >= 300);
    360 
    361         dfp = sfp;
    362 
    363     } else {
    364 
    365         /*
    366          *  FTP session
    367          */
    368         if (!target.user)
    369             target.user = xstrdup("anonymous:busybox@");
    370 
    371         sfp = open_socket(lsa);
    372         if (ftpcmd(NULL, NULL, sfp, buf) != 220)
    373             bb_error_msg_and_die("%s", buf+4);
    374 
    375         /*
    376          * Splitting username:password pair,
    377          * trying to log in
    378          */
    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)
    387                 break;
    388             /* FALLTHRU (failed login) */
    389         default:
    390             bb_error_msg_and_die("ftp login: %s", buf+4);
    391         }
    392 
    393         ftpcmd("TYPE I", NULL, sfp, buf);
    394 
    395         /*
    396          * Querying file size
    397          */
    398         if (ftpcmd("SIZE ", target.path, sfp, buf) == 213) {
    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");
    402             }
    403             got_clen = 1;
    404         }
    405 
    406         /*
    407          * Entering passive mode
    408          */
    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;
    432         }
    433 
    434         if (ftpcmd("RETR ", target.path, sfp, buf) > 150)
    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     }
    442 
    443     /*
    444      * Retrieve file
    445      */
    446     if (chunked) {
    447         fgets(buf, sizeof(buf), dfp);
    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))
    458         progressmeter(-1);
     172static char* sanitize_string(char *s)
     173{
     174    unsigned char *p = (void *) s;
     175    while (*p >= ' ')
     176        p++;
     177    *p = '\0';
     178    return s;
     179}
     180
     181static FILE *open_socket(len_and_sockaddr *lsa)
     182{
     183    FILE *fp;
     184
     185    /* glibc 2.4 seems to try seeking on it - ??! */
     186    /* hopefully it understands what ESPIPE means... */
     187    fp = fdopen(xconnect_stream(lsa), "r+");
     188    if (fp == NULL)
     189        bb_perror_msg_and_die("fdopen");
     190
     191    return fp;
     192}
     193
     194static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
     195{
     196    int result;
     197    if (s1) {
     198        if (!s2) s2 = "";
     199        fprintf(fp, "%s%s\r\n", s1, s2);
     200        fflush(fp);
     201    }
    459202
    460203    do {
    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) {
    469                 bb_perror_msg_and_die(bb_msg_write_error);
    470             }
    471 #if ENABLE_FEATURE_WGET_STATUSBAR
    472             transferred += n;
    473 #endif
    474             if (got_clen) {
    475                 content_len -= n;
    476             }
    477         }
    478 
    479         if (chunked) {
    480             safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
    481             safe_fgets(buf, sizeof(buf), dfp);
    482             content_len = STRTOOFF(buf, NULL, 16);
    483             /* FIXME: error check? */
    484             if (content_len == 0) {
    485                 chunked = 0; /* all done! */
    486             }
    487         }
    488 
    489         if (n == 0 && ferror(dfp)) {
    490             bb_perror_msg_and_die(bb_msg_read_error);
    491         }
    492     } while (chunked);
    493 
    494     if (!(opt & WGET_OPT_QUIET))
    495         progressmeter(1);
    496 
    497     if ((use_proxy == 0) && target.is_ftp) {
    498         fclose(dfp);
    499         if (ftpcmd(NULL, NULL, sfp, buf) != 226)
    500             bb_error_msg_and_die("ftp error: %s", buf+4);
    501         ftpcmd("QUIT", NULL, sfp, buf);
    502     }
    503 done:
    504     exit(EXIT_SUCCESS);
    505 }
    506 
     204        char *buf_ptr;
     205
     206        if (fgets(buf, 510, fp) == NULL) {
     207            bb_perror_msg_and_die("error getting response");
     208        }
     209        buf_ptr = strstr(buf, "\r\n");
     210        if (buf_ptr) {
     211            *buf_ptr = '\0';
     212        }
     213    } while (!isdigit(buf[0]) || buf[3] != ' ');
     214
     215    buf[3] = '\0';
     216    result = xatoi_positive(buf);
     217    buf[3] = ' ';
     218    return result;
     219}
    507220
    508221static void parse_url(char *src_url, struct host_info *h)
     
    521234        h->is_ftp = 1;
    522235    } else
    523         bb_error_msg_and_die("not an http or ftp url: %s", url);
     236        bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url));
    524237
    525238    // FYI:
     
    539252    p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p;
    540253    if (!sp) {
    541         /* must be writable because of bb_get_last_path_component() */
    542         static char nullstr[] ALIGN1 = "";
    543         h->path = nullstr;
     254        h->path = "";
    544255    } else if (*sp == '/') {
    545256        *sp = '\0';
     
    549260        // memmove converts to:
    550261        // http:/busybox.nett?login=john@doe...
    551         memmove(h->host-1, h->host, sp - h->host);
     262        memmove(h->host - 1, h->host, sp - h->host);
    552263        h->host--;
    553264        sp[-1] = '\0';
     
    555266    }
    556267
     268    // We used to set h->user to NULL here, but this interferes
     269    // with handling of code 302 ("object was moved")
     270
    557271    sp = strrchr(h->host, '@');
    558     h->user = NULL;
    559272    if (sp != NULL) {
    560273        h->user = h->host;
     
    566279}
    567280
    568 
    569 static FILE *open_socket(len_and_sockaddr *lsa)
    570 {
    571     FILE *fp;
    572 
    573     /* glibc 2.4 seems to try seeking on it - ??! */
    574     /* hopefully it understands what ESPIPE means... */
    575     fp = fdopen(xconnect_stream(lsa), "r+");
    576     if (fp == NULL)
    577         bb_perror_msg_and_die("fdopen");
    578 
    579     return fp;
    580 }
    581 
    582 
    583 static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
     281static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
    584282{
    585283    char *s, *hdrval;
    586284    int c;
    587285
    588     *istrunc = 0;
     286    /* *istrunc = 0; */
    589287
    590288    /* retrieve header line */
     
    594292    /* see if we are at the end of the headers */
    595293    for (s = buf; *s == '\r'; ++s)
    596         ;
    597     if (s[0] == '\n')
     294        continue;
     295    if (*s == '\n')
    598296        return NULL;
    599297
    600298    /* convert the header name to lower case */
    601     for (s = buf; isalnum(*s) || *s == '-'; ++s)
    602         *s = tolower(*s);
     299    for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) {
     300        /* tolower for "A-Z", no-op for "0-9a-z-." */
     301        *s = (*s | 0x20);
     302    }
    603303
    604304    /* verify we are at the end of the header name */
    605305    if (*s != ':')
    606         bb_error_msg_and_die("bad header line: %s", buf);
     306        bb_error_msg_and_die("bad header line: %s", sanitize_string(buf));
    607307
    608308    /* locate the start of the header value */
    609     for (*s++ = '\0'; *s == ' ' || *s == '\t'; ++s)
    610         ;
    611     hdrval = s;
     309    *s++ = '\0';
     310    hdrval = skip_whitespace(s);
    612311
    613312    /* locate the end of header */
    614     while (*s != '\0' && *s != '\r' && *s != '\n')
     313    while (*s && *s != '\r' && *s != '\n')
    615314        ++s;
    616315
    617316    /* end of header found */
    618     if (*s != '\0') {
     317    if (*s) {
    619318        *s = '\0';
    620319        return hdrval;
    621320    }
    622321
    623     /* Rats!  The buffer isn't big enough to hold the entire header value. */
     322    /* Rats! The buffer isn't big enough to hold the entire header value */
    624323    while (c = getc(fp), c != EOF && c != '\n')
     324        continue;
     325    /* *istrunc = 1; */
     326    return hdrval;
     327}
     328
     329#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     330static char *URL_escape(const char *str)
     331{
     332    /* URL encode, see RFC 2396 */
     333    char *dst;
     334    char *res = dst = xmalloc(strlen(str) * 3 + 1);
     335    unsigned char c;
     336
     337    while (1) {
     338        c = *str++;
     339        if (c == '\0'
     340        /* || strchr("!&'()*-.=_~", c) - more code */
     341         || c == '!'
     342         || c == '&'
     343         || c == '\''
     344         || c == '('
     345         || c == ')'
     346         || c == '*'
     347         || c == '-'
     348         || c == '.'
     349         || c == '='
     350         || c == '_'
     351         || c == '~'
     352         || (c >= '0' && c <= '9')
     353         || ((c|0x20) >= 'a' && (c|0x20) <= 'z')
     354        ) {
     355            *dst++ = c;
     356            if (c == '\0')
     357                return res;
     358        } else {
     359            *dst++ = '%';
     360            *dst++ = bb_hexdigits_upcase[c >> 4];
     361            *dst++ = bb_hexdigits_upcase[c & 0xf];
     362        }
     363    }
     364}
     365#endif
     366
     367static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
     368{
     369    char buf[512];
     370    FILE *sfp;
     371    char *str;
     372    int port;
     373
     374    if (!target->user)
     375        target->user = xstrdup("anonymous:busybox@");
     376
     377    sfp = open_socket(lsa);
     378    if (ftpcmd(NULL, NULL, sfp, buf) != 220)
     379        bb_error_msg_and_die("%s", sanitize_string(buf+4));
     380
     381    /*
     382     * Splitting username:password pair,
     383     * trying to log in
     384     */
     385    str = strchr(target->user, ':');
     386    if (str)
     387        *str++ = '\0';
     388    switch (ftpcmd("USER ", target->user, sfp, buf)) {
     389    case 230:
     390        break;
     391    case 331:
     392        if (ftpcmd("PASS ", str, sfp, buf) == 230)
     393            break;
     394        /* fall through (failed login) */
     395    default:
     396        bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4));
     397    }
     398
     399    ftpcmd("TYPE I", NULL, sfp, buf);
     400
     401    /*
     402     * Querying file size
     403     */
     404    if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) {
     405        G.content_len = BB_STRTOOFF(buf+4, NULL, 10);
     406        if (G.content_len < 0 || errno) {
     407            bb_error_msg_and_die("SIZE value is garbage");
     408        }
     409        G.got_clen = 1;
     410    }
     411
     412    /*
     413     * Entering passive mode
     414     */
     415    if (ftpcmd("PASV", NULL, sfp, buf) != 227) {
     416 pasv_error:
     417        bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf));
     418    }
     419    // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
     420    // Server's IP is N1.N2.N3.N4 (we ignore it)
     421    // Server's port for data connection is P1*256+P2
     422    str = strrchr(buf, ')');
     423    if (str) str[0] = '\0';
     424    str = strrchr(buf, ',');
     425    if (!str) goto pasv_error;
     426    port = xatou_range(str+1, 0, 255);
     427    *str = '\0';
     428    str = strrchr(buf, ',');
     429    if (!str) goto pasv_error;
     430    port += xatou_range(str+1, 0, 255) * 256;
     431    set_nport(lsa, htons(port));
     432
     433    *dfpp = open_socket(lsa);
     434
     435    if (G.beg_range) {
     436        sprintf(buf, "REST %"OFF_FMT"u", G.beg_range);
     437        if (ftpcmd(buf, NULL, sfp, buf) == 350)
     438            G.content_len -= G.beg_range;
     439    }
     440
     441    if (ftpcmd("RETR ", target->path, sfp, buf) > 150)
     442        bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf));
     443
     444    return sfp;
     445}
     446
     447static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
     448{
     449    char buf[512];
     450#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
     451# if ENABLE_FEATURE_WGET_TIMEOUT
     452    unsigned second_cnt;
     453# endif
     454    struct pollfd polldata;
     455
     456    polldata.fd = fileno(dfp);
     457    polldata.events = POLLIN | POLLPRI;
     458    ndelay_on(polldata.fd);
     459#endif
     460    progress_meter(PROGRESS_START);
     461
     462    if (G.chunked)
     463        goto get_clen;
     464
     465    /* Loops only if chunked */
     466    while (1) {
     467        while (1) {
     468            int n;
     469            unsigned rdsz;
     470
     471            rdsz = sizeof(buf);
     472            if (G.got_clen) {
     473                if (G.content_len < (off_t)sizeof(buf)) {
     474                    if ((int)G.content_len <= 0)
     475                        break;
     476                    rdsz = (unsigned)G.content_len;
     477                }
     478            }
     479#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
     480# if ENABLE_FEATURE_WGET_TIMEOUT
     481            second_cnt = G.timeout_seconds;
     482# endif
     483            while (1) {
     484                if (safe_poll(&polldata, 1, 1000) != 0)
     485                    break; /* error, EOF, or data is available */
     486# if ENABLE_FEATURE_WGET_TIMEOUT
     487                if (second_cnt != 0 && --second_cnt == 0) {
     488                    progress_meter(PROGRESS_END);
     489                    bb_perror_msg_and_die("download timed out");
     490                }
     491# endif
     492                /* Needed for "stalled" indicator */
     493                progress_meter(PROGRESS_BUMP);
     494            }
     495#endif
     496            n = safe_fread(buf, rdsz, dfp);
     497            if (n <= 0) {
     498                if (ferror(dfp)) {
     499                    /* perror will not work: ferror doesn't set errno */
     500                    bb_error_msg_and_die(bb_msg_read_error);
     501                }
     502                break;
     503            }
     504            xwrite(output_fd, buf, n);
     505#if ENABLE_FEATURE_WGET_STATUSBAR
     506            G.transferred += n;
     507            progress_meter(PROGRESS_BUMP);
     508#endif
     509            if (G.got_clen)
     510                G.content_len -= n;
     511        }
     512
     513        if (!G.chunked)
     514            break;
     515
     516        safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
     517 get_clen:
     518        safe_fgets(buf, sizeof(buf), dfp);
     519        G.content_len = STRTOOFF(buf, NULL, 16);
     520        /* FIXME: error check? */
     521        if (G.content_len == 0)
     522            break; /* all done! */
     523        G.got_clen = 1;
     524    }
     525
     526    progress_meter(PROGRESS_END);
     527}
     528
     529int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     530int wget_main(int argc UNUSED_PARAM, char **argv)
     531{
     532    char buf[512];
     533    struct host_info server, target;
     534    len_and_sockaddr *lsa;
     535    unsigned opt;
     536    int redir_limit;
     537    char *proxy = NULL;
     538    char *dir_prefix = NULL;
     539#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     540    char *post_data;
     541    char *extra_headers = NULL;
     542    llist_t *headers_llist = NULL;
     543#endif
     544    FILE *sfp;                      /* socket to web/ftp server         */
     545    FILE *dfp;                      /* socket to ftp server (data)      */
     546    char *fname_out;                /* where to direct output (-O)      */
     547    int output_fd = -1;
     548    bool use_proxy;                 /* Use proxies if env vars are set  */
     549    const char *proxy_flag = "on";  /* Use proxies if env vars are set  */
     550    const char *user_agent = "Wget";/* "User-Agent" header field        */
     551
     552    static const char keywords[] ALIGN1 =
     553        "content-length\0""transfer-encoding\0""chunked\0""location\0";
     554    enum {
     555        KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location
     556    };
     557#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     558    static const char wget_longopts[] ALIGN1 =
     559        /* name, has_arg, val */
     560        "continue\0"         No_argument       "c"
     561        "spider\0"           No_argument       "s"
     562        "quiet\0"            No_argument       "q"
     563        "output-document\0"  Required_argument "O"
     564        "directory-prefix\0" Required_argument "P"
     565        "proxy\0"            Required_argument "Y"
     566        "user-agent\0"       Required_argument "U"
     567#if ENABLE_FEATURE_WGET_TIMEOUT
     568        "timeout\0"          Required_argument "T"
     569#endif
     570        /* Ignored: */
     571        // "tries\0"            Required_argument "t"
     572        /* Ignored (we always use PASV): */
     573        "passive-ftp\0"      No_argument       "\xff"
     574        "header\0"           Required_argument "\xfe"
     575        "post-data\0"        Required_argument "\xfd"
     576        /* Ignored (we don't do ssl) */
     577        "no-check-certificate\0" No_argument   "\xfc"
    625578        ;
    626     *istrunc = 1;
    627     return hdrval;
    628 }
    629 
    630 static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
    631 {
    632     int result;
    633     if (s1) {
    634         if (!s2) s2 = "";
    635         fprintf(fp, "%s%s\r\n", s1, s2);
    636         fflush(fp);
    637     }
    638 
    639     do {
    640         char *buf_ptr;
    641 
    642         if (fgets(buf, 510, fp) == NULL) {
    643             bb_perror_msg_and_die("error getting response");
    644         }
    645         buf_ptr = strstr(buf, "\r\n");
    646         if (buf_ptr) {
    647             *buf_ptr = '\0';
    648         }
    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 
     579#endif
     580
     581    INIT_G();
     582
     583#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     584    applet_long_options = wget_longopts;
     585#endif
     586    /* server.allocated = target.allocated = NULL; */
     587    opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
     588    opt = getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:",
     589                &fname_out, &dir_prefix,
     590                &proxy_flag, &user_agent,
     591                IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL),
     592                NULL /* -t RETRIES */
     593                IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
     594                IF_FEATURE_WGET_LONG_OPTIONS(, &post_data)
     595                );
     596#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     597    if (headers_llist) {
     598        int size = 1;
     599        char *cp;
     600        llist_t *ll = headers_llist;
     601        while (ll) {
     602            size += strlen(ll->data) + 2;
     603            ll = ll->link;
     604        }
     605        extra_headers = cp = xmalloc(size);
     606        while (headers_llist) {
     607            cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist));
     608        }
     609    }
     610#endif
     611
     612    /* TODO: compat issue: should handle "wget URL1 URL2..." */
     613
     614    target.user = NULL;
     615    parse_url(argv[optind], &target);
     616
     617    /* Use the proxy if necessary */
     618    use_proxy = (strcmp(proxy_flag, "off") != 0);
     619    if (use_proxy) {
     620        proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
     621        if (proxy && proxy[0]) {
     622            server.user = NULL;
     623            parse_url(proxy, &server);
     624        } else {
     625            use_proxy = 0;
     626        }
     627    }
     628    if (!use_proxy) {
     629        server.port = target.port;
     630        if (ENABLE_FEATURE_IPV6) {
     631            server.host = xstrdup(target.host);
     632        } else {
     633            server.host = target.host;
     634        }
     635    }
     636
     637    if (ENABLE_FEATURE_IPV6)
     638        strip_ipv6_scope_id(target.host);
     639
     640    /* Guess an output filename, if there was no -O FILE */
     641    if (!(opt & WGET_OPT_OUTNAME)) {
     642        fname_out = bb_get_last_path_component_nostrip(target.path);
     643        /* handle "wget http://kernel.org//" */
     644        if (fname_out[0] == '/' || !fname_out[0])
     645            fname_out = (char*)"index.html";
     646        /* -P DIR is considered only if there was no -O FILE */
     647        if (dir_prefix)
     648            fname_out = concat_path_file(dir_prefix, fname_out);
     649    } else {
     650        if (LONE_DASH(fname_out)) {
     651            /* -O - */
     652            output_fd = 1;
     653            opt &= ~WGET_OPT_CONTINUE;
     654        }
     655    }
    657656#if ENABLE_FEATURE_WGET_STATUSBAR
    658 /* Stuff below is from BSD rcp util.c, as added to openshh.
    659  * Original copyright notice is retained at the end of this file.
    660  */
    661 static int
    662 getttywidth(void)
    663 {
    664     int width;
    665     get_terminal_width_height(0, &width, NULL);
    666     return width;
    667 }
    668 
    669 static void
    670 updateprogressmeter(int ignore)
    671 {
    672     int save_errno = errno;
    673 
    674     progressmeter(0);
    675     errno = save_errno;
    676 }
    677 
    678 static void alarmtimer(int iwait)
    679 {
    680     struct itimerval itv;
    681 
    682     itv.it_value.tv_sec = iwait;
    683     itv.it_value.tv_usec = 0;
    684     itv.it_interval = itv.it_value;
    685     setitimer(ITIMER_REAL, &itv, NULL);
    686 }
    687 
    688 static void
    689 progressmeter(int flag)
    690 {
    691     static unsigned lastupdate_sec;
    692     static unsigned start_sec;
    693     static off_t lastsize, totalsize;
    694 
    695     off_t abbrevsize;
    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;
    703         lastsize = 0;
    704         totalsize = content_len + beg_range; /* as content_len changes.. */
    705     }
    706 
    707     ratio = 100;
    708     if (totalsize != 0 && !chunked) {
    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;
    712     }
    713 
    714     fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
    715 
    716     barlength = getttywidth() - 49;
    717     if (barlength > 0) {
    718         /* god bless gcc for variable arrays :) */
    719         i = barlength * ratio / 100;
    720         {
    721             char buf[i+1];
    722             memset(buf, '*', i);
    723             buf[i] = '\0';
    724             fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
    725         }
    726     }
    727     i = 0;
    728     abbrevsize = transferred + beg_range;
    729     while (abbrevsize >= 100000) {
    730         i++;
    731         abbrevsize >>= 10;
    732     }
    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;
    741     if (transferred > lastsize) {
    742         lastupdate_sec = elapsed;
    743         lastsize = transferred;
    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) {
    754         fprintf(stderr, " - stalled -");
     657    G.curfile = bb_get_last_path_component_nostrip(fname_out);
     658#endif
     659
     660    /* Impossible?
     661    if ((opt & WGET_OPT_CONTINUE) && !fname_out)
     662        bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)");
     663    */
     664
     665    /* Determine where to start transfer */
     666    if (opt & WGET_OPT_CONTINUE) {
     667        output_fd = open(fname_out, O_WRONLY);
     668        if (output_fd >= 0) {
     669            G.beg_range = xlseek(output_fd, 0, SEEK_END);
     670        }
     671        /* File doesn't exist. We do not create file here yet.
     672         * We are not sure it exists on remove side */
     673    }
     674
     675    redir_limit = 5;
     676 resolve_lsa:
     677    lsa = xhost2sockaddr(server.host, server.port);
     678    if (!(opt & WGET_OPT_QUIET)) {
     679        char *s = xmalloc_sockaddr2dotted(&lsa->u.sa);
     680        fprintf(stderr, "Connecting to %s (%s)\n", server.host, s);
     681        free(s);
     682    }
     683 establish_session:
     684    if (use_proxy || !target.is_ftp) {
     685        /*
     686         *  HTTP session
     687         */
     688        char *str;
     689        int status;
     690
     691        /* Open socket to http server */
     692        sfp = open_socket(lsa);
     693
     694        /* Send HTTP request */
     695        if (use_proxy) {
     696            fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n",
     697                target.is_ftp ? "f" : "ht", target.host,
     698                target.path);
     699        } else {
     700            if (opt & WGET_OPT_POST_DATA)
     701                fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path);
     702            else
     703                fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
     704        }
     705
     706        fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",
     707            target.host, user_agent);
     708
     709#if ENABLE_FEATURE_WGET_AUTHENTICATION
     710        if (target.user) {
     711            fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
     712                base64enc_512(buf, target.user));
     713        }
     714        if (use_proxy && server.user) {
     715            fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
     716                base64enc_512(buf, server.user));
     717        }
     718#endif
     719
     720        if (G.beg_range)
     721            fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range);
     722#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     723        if (extra_headers)
     724            fputs(extra_headers, sfp);
     725
     726        if (opt & WGET_OPT_POST_DATA) {
     727            char *estr = URL_escape(post_data);
     728            fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n");
     729            fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s",
     730                    (int) strlen(estr), estr);
     731            /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/
     732            /*fprintf(sfp, "%s\r\n", estr);*/
     733            free(estr);
     734        } else
     735#endif
     736        { /* If "Connection:" is needed, document why */
     737            fprintf(sfp, /* "Connection: close\r\n" */ "\r\n");
     738        }
     739
     740        fflush(sfp);
     741
     742        /*
     743         * Retrieve HTTP response line and check for "200" status code.
     744         */
     745 read_response:
     746        if (fgets(buf, sizeof(buf), sfp) == NULL)
     747            bb_error_msg_and_die("no response from server");
     748
     749        str = buf;
     750        str = skip_non_whitespace(str);
     751        str = skip_whitespace(str);
     752        // FIXME: no error check
     753        // xatou wouldn't work: "200 OK"
     754        status = atoi(str);
     755        switch (status) {
     756        case 0:
     757        case 100:
     758            while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL)
     759                /* eat all remaining headers */;
     760            goto read_response;
     761        case 200:
     762/*
     763Response 204 doesn't say "null file", it says "metadata
     764has changed but data didn't":
     765
     766"10.2.5 204 No Content
     767The server has fulfilled the request but does not need to return
     768an entity-body, and might want to return updated metainformation.
     769The response MAY include new or updated metainformation in the form
     770of entity-headers, which if present SHOULD be associated with
     771the requested variant.
     772
     773If the client is a user agent, it SHOULD NOT change its document
     774view from that which caused the request to be sent. This response
     775is primarily intended to allow input for actions to take place
     776without causing a change to the user agent's active document view,
     777although any new or updated metainformation SHOULD be applied
     778to the document currently in the user agent's active view.
     779
     780The 204 response MUST NOT include a message-body, and thus
     781is always terminated by the first empty line after the header fields."
     782
     783However, in real world it was observed that some web servers
     784(e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero.
     785*/
     786        case 204:
     787            break;
     788        case 300:  /* redirection */
     789        case 301:
     790        case 302:
     791        case 303:
     792            break;
     793        case 206:
     794            if (G.beg_range)
     795                break;
     796            /* fall through */
     797        default:
     798            bb_error_msg_and_die("server returned error: %s", sanitize_string(buf));
     799        }
     800
     801        /*
     802         * Retrieve HTTP headers.
     803         */
     804        while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) {
     805            /* gethdr converted "FOO:" string to lowercase */
     806            smalluint key;
     807            /* strip trailing whitespace */
     808            char *s = strchrnul(str, '\0') - 1;
     809            while (s >= str && (*s == ' ' || *s == '\t')) {
     810                *s = '\0';
     811                s--;
     812            }
     813            key = index_in_strings(keywords, buf) + 1;
     814            if (key == KEY_content_length) {
     815                G.content_len = BB_STRTOOFF(str, NULL, 10);
     816                if (G.content_len < 0 || errno) {
     817                    bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str));
     818                }
     819                G.got_clen = 1;
     820                continue;
     821            }
     822            if (key == KEY_transfer_encoding) {
     823                if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked)
     824                    bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str));
     825                G.chunked = G.got_clen = 1;
     826            }
     827            if (key == KEY_location && status >= 300) {
     828                if (--redir_limit == 0)
     829                    bb_error_msg_and_die("too many redirections");
     830                fclose(sfp);
     831                G.got_clen = 0;
     832                G.chunked = 0;
     833                if (str[0] == '/')
     834                    /* free(target.allocated); */
     835                    target.path = /* target.allocated = */ xstrdup(str+1);
     836                    /* lsa stays the same: it's on the same server */
     837                else {
     838                    parse_url(str, &target);
     839                    if (!use_proxy) {
     840                        server.host = target.host;
     841                        /* strip_ipv6_scope_id(target.host); - no! */
     842                        /* we assume remote never gives us IPv6 addr with scope id */
     843                        server.port = target.port;
     844                        free(lsa);
     845                        goto resolve_lsa;
     846                    } /* else: lsa stays the same: we use proxy */
     847                }
     848                goto establish_session;
     849            }
     850        }
     851//      if (status >= 300)
     852//          bb_error_msg_and_die("bad redirection (no Location: header from server)");
     853
     854        /* For HTTP, data is pumped over the same connection */
     855        dfp = sfp;
     856
    755857    } else {
    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 */
    769         struct sigaction sa;
    770         sa.sa_handler = updateprogressmeter;
    771         sigemptyset(&sa.sa_mask);
    772         sa.sa_flags = SA_RESTART;
    773         sigaction(SIGALRM, &sa, NULL);
    774         alarmtimer(1);
    775     } else if (flag == 1) { /* last call to progressmeter */
    776         alarmtimer(0);
    777         transferred = 0;
    778         putc('\n', stderr);
    779     }
    780 }
    781 #endif /* FEATURE_WGET_STATUSBAR */
    782 
    783 /* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
    784  * much of which was blatantly stolen from openssh.  */
    785 
    786 /*-
    787  * Copyright (c) 1992, 1993
    788  *  The Regents of the University of California.  All rights reserved.
    789  *
    790  * Redistribution and use in source and binary forms, with or without
    791  * modification, are permitted provided that the following conditions
    792  * are met:
    793  * 1. Redistributions of source code must retain the above copyright
    794  *    notice, this list of conditions and the following disclaimer.
    795  * 2. Redistributions in binary form must reproduce the above copyright
    796  *    notice, this list of conditions and the following disclaimer in the
    797  *    documentation and/or other materials provided with the distribution.
    798  *
    799  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
    800  *      ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
    801  *
    802  * 4. Neither the name of the University nor the names of its contributors
    803  *    may be used to endorse or promote products derived from this software
    804  *    without specific prior written permission.
    805  *
    806  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    807  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    808  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    809  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    810  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    811  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    812  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    813  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    814  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    815  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    816  * SUCH DAMAGE.
    817  *
    818  */
     858        /*
     859         *  FTP session
     860         */
     861        sfp = prepare_ftp_session(&dfp, &target, lsa);
     862    }
     863
     864    if (opt & WGET_OPT_SPIDER) {
     865        if (ENABLE_FEATURE_CLEAN_UP)
     866            fclose(sfp);
     867        return EXIT_SUCCESS;
     868    }
     869
     870    if (output_fd < 0) {
     871        int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL;
     872        /* compat with wget: -O FILE can overwrite */
     873        if (opt & WGET_OPT_OUTNAME)
     874            o_flags = O_WRONLY | O_CREAT | O_TRUNC;
     875        output_fd = xopen(fname_out, o_flags);
     876    }
     877
     878    retrieve_file_data(dfp, output_fd);
     879    xclose(output_fd);
     880
     881    if (dfp != sfp) {
     882        /* It's ftp. Close it properly */
     883        fclose(dfp);
     884        if (ftpcmd(NULL, NULL, sfp, buf) != 226)
     885            bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4));
     886        /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */
     887    }
     888
     889    return EXIT_SUCCESS;
     890}
  • branches/2.2.9/mindi-busybox/networking/zcip.c

    r1765 r2725  
    77 * Copyright (C) 2004 by David Brownell
    88 *
    9  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 */
    1111
     
    2424// - link status monitoring (restart on link-up; stop on link-down)
    2525
    26 #include <syslog.h>
    27 #include <poll.h>
    28 #include <sys/wait.h>
    2926#include <netinet/ether.h>
    3027#include <net/ethernet.h>
     
    3532
    3633#include "libbb.h"
     34#include <syslog.h>
    3735
    3836/* We don't need more than 32 bits of the counter */
     
    4038
    4139struct arp_packet {
    42     struct ether_header hdr;
     40    struct ether_header eth;
    4341    struct ether_arp arp;
    44 } ATTRIBUTE_PACKED;
     42} PACKED;
    4543
    4644enum {
     
    7068};
    7169
    72 #define VDBG(fmt,args...) \
    73     do { } while (0)
     70#define VDBG(...) do { } while (0)
     71
     72
     73enum {
     74    sock_fd = 3
     75};
     76
     77struct globals {
     78    struct sockaddr saddr;
     79    struct ether_addr eth_addr;
     80} FIX_ALIASING;
     81#define G (*(struct globals*)&bb_common_bufsiz1)
     82#define saddr    (G.saddr   )
     83#define eth_addr (G.eth_addr)
     84
    7485
    7586/**
     
    7788 * the first and last 256 addresses are reserved.
    7889 */
    79 static void pick(struct in_addr *ip)
     90static uint32_t pick(void)
    8091{
    8192    unsigned tmp;
     
    8495        tmp = rand() & IN_CLASSB_HOST;
    8596    } while (tmp > (IN_CLASSB_HOST - 0x0200));
    86     ip->s_addr = htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
     97    return htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
    8798}
    8899
     
    90101 * Broadcast an ARP packet.
    91102 */
    92 static void arp(int fd, struct sockaddr *saddr, int op,
    93     const struct ether_addr *source_addr, struct in_addr source_ip,
    94     const struct ether_addr *target_addr, struct in_addr target_ip)
     103static void arp(
     104    /* int op, - always ARPOP_REQUEST */
     105    /* const struct ether_addr *source_eth, - always &eth_addr */
     106                    struct in_addr source_ip,
     107    const struct ether_addr *target_eth, struct in_addr target_ip)
    95108{
     109    enum { op = ARPOP_REQUEST };
     110#define source_eth (&eth_addr)
     111
    96112    struct arp_packet p;
    97113    memset(&p, 0, sizeof(p));
    98114
    99115    // ether header
    100     p.hdr.ether_type = htons(ETHERTYPE_ARP);
    101     memcpy(p.hdr.ether_shost, source_addr, ETH_ALEN);
    102     memset(p.hdr.ether_dhost, 0xff, ETH_ALEN);
     116    p.eth.ether_type = htons(ETHERTYPE_ARP);
     117    memcpy(p.eth.ether_shost, source_eth, ETH_ALEN);
     118    memset(p.eth.ether_dhost, 0xff, ETH_ALEN);
    103119
    104120    // arp request
     
    108124    p.arp.arp_pln = 4;
    109125    p.arp.arp_op = htons(op);
    110     memcpy(&p.arp.arp_sha, source_addr, ETH_ALEN);
     126    memcpy(&p.arp.arp_sha, source_eth, ETH_ALEN);
    111127    memcpy(&p.arp.arp_spa, &source_ip, sizeof(p.arp.arp_spa));
    112     memcpy(&p.arp.arp_tha, target_addr, ETH_ALEN);
     128    memcpy(&p.arp.arp_tha, target_eth, ETH_ALEN);
    113129    memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa));
    114130
    115131    // send it
    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;
     132    // Even though sock_fd is already bound to saddr, just send()
     133    // won't work, because "socket is not connected"
     134    // (and connect() won't fix that, "operation not supported").
     135    // Thus we sendto() to saddr. I wonder which sockaddr
     136    // (from bind() or from sendto()?) kernel actually uses
     137    // to determine iface to emit the packet from...
     138    xsendto(sock_fd, &p, sizeof(p), &saddr, sizeof(saddr));
     139#undef source_eth
    121140}
    122141
    123142/**
    124  * Run a script. argv[2] is already NULL.
    125  */
    126 static int run(char *argv[3], const char *intf, struct in_addr *ip)
     143 * Run a script.
     144 * argv[0]:intf argv[1]:script_name argv[2]:junk argv[3]:NULL
     145 */
     146static int run(char *argv[3], const char *param, struct in_addr *ip)
    127147{
    128148    int status;
    129 
    130     VDBG("%s run %s %s\n", intf, argv[0], argv[1]);
     149    char *addr = addr; /* for gcc */
     150    const char *fmt = "%s %s %s" + 3;
     151
     152    argv[2] = (char*)param;
     153
     154    VDBG("%s run %s %s\n", argv[0], argv[1], argv[2]);
    131155
    132156    if (ip) {
    133         char *addr = inet_ntoa(*ip);
    134         setenv("ip", addr, 1);
    135         bb_info_msg("%s %s %s", argv[1], intf, addr);
     157        addr = inet_ntoa(*ip);
     158        xsetenv("ip", addr);
     159        fmt -= 3;
    136160    }
    137 
    138     status = wait4pid(spawn(argv));
     161    bb_info_msg(fmt, argv[2], argv[0], addr);
     162
     163    status = spawn_and_wait(argv + 1);
    139164    if (status < 0) {
    140         bb_perror_msg("%s %s", argv[1], intf);
     165        bb_perror_msg("%s %s %s" + 3, argv[2], argv[0]);
    141166        return -errno;
    142167    }
    143168    if (status != 0)
    144         bb_error_msg("script %s %s failed, exitcode=%d", argv[0], argv[1], status);
     169        bb_error_msg("script %s %s failed, exitcode=%d", argv[1], argv[2], status & 0xff);
    145170    return status;
    146171}
     
    149174 * Return milliseconds of random delay, up to "secs" seconds.
    150175 */
    151 static unsigned ALWAYS_INLINE ms_rdelay(unsigned secs)
     176static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs)
    152177{
    153178    return rand() % (secs * 1000);
     
    157182 * main program
    158183 */
    159 int zcip_main(int argc, char **argv);
    160 int zcip_main(int argc, char **argv)
     184int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     185int zcip_main(int argc UNUSED_PARAM, char **argv)
    161186{
    162     int state = PROBE;
    163     struct ether_addr eth_addr;
    164     const char *why;
    165     int fd;
     187    int state;
    166188    char *r_opt;
    167189    unsigned opts;
    168190
    169     /* Ugly trick, but I want these zeroed in one go */
     191    // ugly trick, but I want these zeroed in one go
    170192    struct {
    171193        const struct in_addr null_ip;
    172194        const struct ether_addr null_addr;
    173         struct sockaddr saddr;
    174195        struct in_addr ip;
    175196        struct ifreq ifr;
    176         char *intf;
    177         char *script_av[3];
    178197        int timeout_ms; /* must be signed */
    179198        unsigned conflicts;
     
    185204#define null_ip    (L.null_ip   )
    186205#define null_addr  (L.null_addr )
    187 #define saddr      (L.saddr     )
    188206#define ip         (L.ip        )
    189207#define ifr        (L.ifr       )
    190 #define intf       (L.intf      )
    191 #define script_av  (L.script_av )
    192208#define timeout_ms (L.timeout_ms)
    193209#define conflicts  (L.conflicts )
     
    205221    opt_complementary = "=2:vv:vf";
    206222    opts = getopt32(argv, "fqr:v", &r_opt, &verbose);
     223#if !BB_MMU
     224    // on NOMMU reexec early (or else we will rerun things twice)
     225    if (!FOREGROUND)
     226        bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv);
     227#endif
     228    // open an ARP socket
     229    // (need to do it before openlog to prevent openlog from taking
     230    // fd 3 (sock_fd==3))
     231    xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd);
    207232    if (!FOREGROUND) {
    208         /* Do it early, before all bb_xx_msg calls */
     233        // do it before all bb_xx_msg calls
    209234        openlog(applet_name, 0, LOG_DAEMON);
    210235        logmode |= LOGMODE_SYSLOG;
     
    217242        }
    218243    }
    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);
     244    argv += optind - 1;
     245
     246    /* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */
     247    /* We need to make space for script argument: */
     248    argv[0] = argv[1];
     249    argv[1] = argv[2];
     250    /* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */
     251#define argv_intf (argv[0])
     252
     253    xsetenv("interface", argv_intf);
    230254
    231255    // initialize the interface (modprobe, ifup, etc)
    232     script_av[1] = (char*)"init";
    233     if (run(script_av, intf, NULL))
     256    if (run(argv, "init", NULL))
    234257        return EXIT_FAILURE;
    235258
    236259    // initialize saddr
     260    // saddr is: { u16 sa_family; u8 sa_data[14]; }
    237261    //memset(&saddr, 0, sizeof(saddr));
    238     safe_strncpy(saddr.sa_data, intf, sizeof(saddr.sa_data));
    239 
    240     // open an ARP socket
    241     fd = xsocket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
     262    //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?!
     263    safe_strncpy(saddr.sa_data, argv_intf, sizeof(saddr.sa_data));
     264
    242265    // bind to the interface's ARP socket
    243     xbind(fd, &saddr, sizeof(saddr));
     266    xbind(sock_fd, &saddr, sizeof(saddr));
    244267
    245268    // get the interface's ethernet address
    246269    //memset(&ifr, 0, sizeof(ifr));
    247     strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name));
    248     xioctl(fd, SIOCGIFHWADDR, &ifr);
     270    strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf);
     271    xioctl(sock_fd, SIOCGIFHWADDR, &ifr);
    249272    memcpy(&eth_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
    250273
    251274    // start with some stable ip address, either a function of
    252275    // the hardware address or else the last address we used.
     276    // we are taking low-order four bytes, as top-order ones
     277    // aren't random enough.
    253278    // NOTE: the sequence of addresses we try changes only
    254279    // depending on when we detect conflicts.
    255     srand(*(unsigned*)&ifr.ifr_hwaddr.sa_data);
     280    {
     281        uint32_t t;
     282        move_from_unaligned32(t, ((char *)&eth_addr + 2));
     283        srand(t);
     284    }
    256285    if (ip.s_addr == 0)
    257         pick(&ip);
     286        ip.s_addr = pick();
    258287
    259288    // FIXME cases to handle:
     
    264293    if (!FOREGROUND) {
    265294#if BB_MMU
    266         bb_daemonize(DAEMON_CHDIR_ROOT);
     295        bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/);
    267296#endif
    268         bb_info_msg("start, interface %s", intf);
     297        bb_info_msg("start, interface %s", argv_intf);
    269298    }
    270299
     
    273302    //  - start with some address we want to try
    274303    //  - short random delay
    275     //  - arp probes to see if another host else uses it
     304    //  - arp probes to see if another host uses it
    276305    //  - arp announcements that we're claiming it
    277306    //  - use it
    278307    //  - defend it, within limits
     308    // exit if:
     309    // - address is successfully obtained and -q was given:
     310    //   run "<script> config", then exit with exitcode 0
     311    // - poll error (when does this happen?)
     312    // - read error (when does this happen?)
     313    // - sendto error (in arp()) (when does this happen?)
     314    // - revents & POLLERR (link down). run "<script> deconfig" first
     315    state = PROBE;
    279316    while (1) {
    280317        struct pollfd fds[1];
    281318        unsigned deadline_us;
    282319        struct arp_packet p;
    283 
    284         int source_ip_conflict = 0;
    285         int target_ip_conflict = 0;
    286 
    287         fds[0].fd = fd;
     320        int source_ip_conflict;
     321        int target_ip_conflict;
     322
     323        fds[0].fd = sock_fd;
    288324        fds[0].events = POLLIN;
    289325        fds[0].revents = 0;
     
    291327        // poll, being ready to adjust current timeout
    292328        if (!timeout_ms) {
    293             timeout_ms = ms_rdelay(PROBE_WAIT);
    294             // FIXME setsockopt(fd, SO_ATTACH_FILTER, ...) to
     329            timeout_ms = random_delay_ms(PROBE_WAIT);
     330            // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to
    295331            // make the kernel filter out all packets except
    296332            // ones we'd care about.
     
    300336
    301337        VDBG("...wait %d %s nprobes=%u, nclaims=%u\n",
    302                 timeout_ms, intf, nprobes, nclaims);
    303         switch (poll(fds, 1, timeout_ms)) {
     338                timeout_ms, argv_intf, nprobes, nclaims);
     339
     340        switch (safe_poll(fds, 1, timeout_ms)) {
     341
     342        default:
     343            //bb_perror_msg("poll"); - done in safe_poll
     344            return EXIT_FAILURE;
    304345
    305346        // timeout
     
    313354                    nprobes++;
    314355                    VDBG("probe/%u %s@%s\n",
    315                             nprobes, intf, inet_ntoa(ip));
    316                     arp(fd, &saddr, ARPOP_REQUEST,
    317                             &eth_addr, null_ip,
     356                            nprobes, argv_intf, inet_ntoa(ip));
     357                    arp(/* ARPOP_REQUEST, */
     358                            /* &eth_addr, */ null_ip,
    318359                            &null_addr, ip);
    319360                    timeout_ms = PROBE_MIN * 1000;
    320                     timeout_ms += ms_rdelay(PROBE_MAX - PROBE_MIN);
     361                    timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
    321362                }
    322363                else {
     
    325366                    nclaims = 0;
    326367                    VDBG("announce/%u %s@%s\n",
    327                             nclaims, intf, inet_ntoa(ip));
    328                     arp(fd, &saddr, ARPOP_REQUEST,
    329                             &eth_addr, ip,
     368                            nclaims, argv_intf, inet_ntoa(ip));
     369                    arp(/* ARPOP_REQUEST, */
     370                            /* &eth_addr, */ ip,
    330371                            &eth_addr, ip);
    331372                    timeout_ms = ANNOUNCE_INTERVAL * 1000;
     
    338379                nclaims = 0;
    339380                VDBG("announce/%u %s@%s\n",
    340                         nclaims, intf, inet_ntoa(ip));
    341                 arp(fd, &saddr, ARPOP_REQUEST,
    342                         &eth_addr, ip,
     381                        nclaims, argv_intf, inet_ntoa(ip));
     382                arp(/* ARPOP_REQUEST, */
     383                        /* &eth_addr, */ ip,
    343384                        &eth_addr, ip);
    344385                timeout_ms = ANNOUNCE_INTERVAL * 1000;
     
    350391                    nclaims++;
    351392                    VDBG("announce/%u %s@%s\n",
    352                             nclaims, intf, inet_ntoa(ip));
    353                     arp(fd, &saddr, ARPOP_REQUEST,
    354                             &eth_addr, ip,
     393                            nclaims, argv_intf, inet_ntoa(ip));
     394                    arp(/* ARPOP_REQUEST, */
     395                            /* &eth_addr, */ ip,
    355396                            &eth_addr, ip);
    356397                    timeout_ms = ANNOUNCE_INTERVAL * 1000;
     
    361402                    // link is ok to use earlier
    362403                    // FIXME update filters
    363                     script_av[1] = (char*)"config";
    364                     run(script_av, intf, &ip);
     404                    run(argv, "config", &ip);
    365405                    ready = 1;
    366406                    conflicts = 0;
     
    382422                // Invalid, should never happen.  Restart the whole protocol.
    383423                state = PROBE;
    384                 pick(&ip);
     424                ip.s_addr = pick();
    385425                timeout_ms = 0;
    386426                nprobes = 0;
     
    389429            } // switch (state)
    390430            break; // case 0 (timeout)
    391         // packets arriving
     431
     432        // packets arriving, or link went down
    392433        case 1:
    393434            // We need to adjust the timeout in case we didn't receive
     
    402443                } else {
    403444                    VDBG("adjusting timeout\n");
    404                     timeout_ms = diff / 1000;
    405                     if (!timeout_ms) timeout_ms = 1;
     445                    timeout_ms = (diff / 1000) | 1; /* never 0 */
    406446                }
    407447            }
     
    411451                    // FIXME: links routinely go down;
    412452                    // this shouldn't necessarily exit.
    413                     bb_error_msg("%s: poll error", intf);
     453                    bb_error_msg("iface %s is down", argv_intf);
    414454                    if (ready) {
    415                         script_av[1] = (char*)"deconfig";
    416                         run(script_av, intf, &ip);
     455                        run(argv, "deconfig", &ip);
    417456                    }
    418457                    return EXIT_FAILURE;
     
    422461
    423462            // read ARP packet
    424             if (recv(fd, &p, sizeof(p), 0) < 0) {
    425                 why = "recv";
    426                 goto bad;
     463            if (safe_read(sock_fd, &p, sizeof(p)) < 0) {
     464                bb_perror_msg_and_die(bb_msg_read_error);
    427465            }
    428             if (p.hdr.ether_type != htons(ETHERTYPE_ARP))
     466            if (p.eth.ether_type != htons(ETHERTYPE_ARP))
    429467                continue;
    430 
    431468#ifdef DEBUG
    432469            {
    433                 struct ether_addr * sha = (struct ether_addr *) p.arp.arp_sha;
    434                 struct ether_addr * tha = (struct ether_addr *) p.arp.arp_tha;
    435                 struct in_addr * spa = (struct in_addr *) p.arp.arp_spa;
    436                 struct in_addr * tpa = (struct in_addr *) p.arp.arp_tpa;
     470                struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha;
     471                struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha;
     472                struct in_addr *spa = (struct in_addr *) p.arp.arp_spa;
     473                struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa;
    437474                VDBG("%s recv arp type=%d, op=%d,\n",
    438                     intf, ntohs(p.hdr.ether_type),
     475                    argv_intf, ntohs(p.eth.ether_type),
    439476                    ntohs(p.arp.arp_op));
    440477                VDBG("\tsource=%s %s\n",
     
    447484#endif
    448485            if (p.arp.arp_op != htons(ARPOP_REQUEST)
    449                     && p.arp.arp_op != htons(ARPOP_REPLY))
     486             && p.arp.arp_op != htons(ARPOP_REPLY))
    450487                continue;
    451488
    452             if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
    453                 memcmp(&eth_addr, &p.arp.arp_sha, ETH_ALEN) != 0) {
     489            source_ip_conflict = 0;
     490            target_ip_conflict = 0;
     491
     492            if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0
     493             && memcmp(&p.arp.arp_sha, &eth_addr, ETH_ALEN) != 0
     494            ) {
    454495                source_ip_conflict = 1;
    455496            }
    456             if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
    457                 p.arp.arp_op == htons(ARPOP_REQUEST) &&
    458                 memcmp(&eth_addr, &p.arp.arp_tha, ETH_ALEN) != 0) {
     497            if (p.arp.arp_op == htons(ARPOP_REQUEST)
     498             && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0
     499             && memcmp(&p.arp.arp_tha, &eth_addr, ETH_ALEN) != 0
     500            ) {
    459501                target_ip_conflict = 1;
    460502            }
     
    470512                    conflicts++;
    471513                    if (conflicts >= MAX_CONFLICTS) {
    472                         VDBG("%s ratelimit\n", intf);
     514                        VDBG("%s ratelimit\n", argv_intf);
    473515                        timeout_ms = RATE_LIMIT_INTERVAL * 1000;
    474516                        state = RATE_LIMIT_PROBE;
     
    476518
    477519                    // restart the whole protocol
    478                     pick(&ip);
     520                    ip.s_addr = pick();
    479521                    timeout_ms = 0;
    480522                    nprobes = 0;
     
    488530                    state = DEFEND;
    489531                    timeout_ms = DEFEND_INTERVAL * 1000;
    490                     arp(fd, &saddr,
    491                             ARPOP_REQUEST,
    492                             &eth_addr, ip,
    493                             &eth_addr, ip);
     532                    arp(/* ARPOP_REQUEST, */
     533                        /* &eth_addr, */ ip,
     534                        &eth_addr, ip);
    494535                }
    495536                break;
     
    500541                    VDBG("defend conflict -- starting over\n");
    501542                    ready = 0;
    502                     script_av[1] = (char*)"deconfig";
    503                     run(script_av, intf, &ip);
     543                    run(argv, "deconfig", &ip);
    504544
    505545                    // restart the whole protocol
    506                     pick(&ip);
     546                    ip.s_addr = pick();
    507547                    timeout_ms = 0;
    508548                    nprobes = 0;
     
    514554                VDBG("invalid state -- starting over\n");
    515555                state = PROBE;
    516                 pick(&ip);
     556                ip.s_addr = pick();
    517557                timeout_ms = 0;
    518558                nprobes = 0;
     
    520560                break;
    521561            } // switch state
    522 
    523562            break; // case 1 (packets arriving)
    524         default:
    525             why = "poll";
    526             goto bad;
    527563        } // switch poll
    528     }
    529  bad:
    530     bb_perror_msg("%s, %s", intf, why);
    531     return EXIT_FAILURE;
     564    } // while (1)
     565#undef argv_intf
    532566}
Note: See TracChangeset for help on using the changeset viewer.