Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (14 years ago)
- 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 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 6 7 menu "Networking Utilities" 7 8 9 config NBDCLIENT 10 bool "nbd-client" 11 default y 12 help 13 Network block device client 14 config NC 15 bool "nc" 16 default y 17 help 18 A simple Unix utility which reads and writes data across network 19 connections. 20 21 config 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 28 config 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 37 config 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 8 47 config FEATURE_IPV6 9 48 bool "Enable IPv6 support" 10 default n49 default y 11 50 help 12 51 Enable IPv6 support in busybox. 13 52 This adds IPv6 support in the networking applets. 53 54 config 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 65 config 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. 14 79 15 80 config VERBOSE_RESOLUTION_ERRORS … … 23 88 config ARP 24 89 bool "arp" 25 default n 90 default y 91 depends on PLATFORM_LINUX 26 92 help 27 93 Manipulate the system ARP cache. … … 29 95 config ARPING 30 96 bool "arping" 31 default n 97 default y 98 depends on PLATFORM_LINUX 32 99 help 33 100 Ping hosts by ARP packets. 101 102 config 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 110 config 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 121 config 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 34 128 35 129 config DNSD 36 130 bool "dnsd" 37 default n131 default y 38 132 help 39 133 Small and static DNS server daemon. … … 41 135 config ETHER_WAKE 42 136 bool "ether-wake" 43 default n 137 default y 138 depends on PLATFORM_LINUX 44 139 help 45 140 Send a magic packet to wake up sleeping machines. … … 47 142 config FAKEIDENTD 48 143 bool "fakeidentd" 49 default n144 default y 50 145 select FEATURE_SYSLOG 51 146 help … … 53 148 fake value on any query. 54 149 150 config FTPD 151 bool "ftpd" 152 default y 153 help 154 simple FTP daemon. You have to run it via inetd. 155 156 config 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 163 config 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 55 174 config FTPGET 56 175 bool "ftpget" 57 default n176 default y 58 177 help 59 178 Retrieve a remote file via FTP. … … 61 180 config FTPPUT 62 181 bool "ftpput" 63 default n182 default y 64 183 help 65 184 Store a remote file via FTP. … … 67 186 config FEATURE_FTPGETPUT_LONG_OPTIONS 68 187 bool "Enable long options in ftpget/ftpput" 69 default n70 depends on GETOPT_LONG&& (FTPGET || FTPPUT)188 default y 189 depends on LONG_OPTS && (FTPGET || FTPPUT) 71 190 help 72 191 Support long options for the ftpget/ftpput applet. … … 74 193 config HOSTNAME 75 194 bool "hostname" 76 default n195 default y 77 196 help 78 197 Show or set the system's host name. … … 80 199 config HTTPD 81 200 bool "httpd" 82 default n201 default y 83 202 help 84 203 Serve web pages via an HTTP server. 204 205 config 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. 85 213 86 214 config FEATURE_HTTPD_USE_SENDFILE 87 215 bool "Use sendfile system call" 88 default n216 default y 89 217 depends on HTTPD 90 218 help … … 92 220 instead of read/write loop. 93 221 94 config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP95 bool "Support reloading the global config file using hup signal"96 default n97 depends on HTTPD98 help99 This option enables processing of SIGHUP to reload cached100 configuration settings.101 102 222 config FEATURE_HTTPD_SETUID 103 223 bool "Enable -u <user> option" 104 default n224 default y 105 225 depends on HTTPD 106 226 help … … 120 240 config FEATURE_HTTPD_AUTH_MD5 121 241 bool "Support MD5 crypted passwords for http Authentication" 122 default n242 default y 123 243 depends on FEATURE_HTTPD_BASIC_AUTH 124 244 help … … 126 246 using md5 passwords. 127 247 128 config FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES129 bool "Support loading additional MIME types at run-time"130 default n131 depends on HTTPD132 help133 This option enables support for additional MIME types at134 run-time to be specified in the configuration file.135 136 248 config FEATURE_HTTPD_CGI 137 249 bool "Support Common Gateway Interface (CGI)" … … 143 255 144 256 config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 145 bool " Enable support for running scripts through an interpreter"146 default n257 bool "Support for running scripts through an interpreter" 258 default y 147 259 depends on FEATURE_HTTPD_CGI 148 260 help … … 154 266 155 267 config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 156 bool "S upport theREMOTE_PORT environment variable for CGI"157 default n268 bool "Set REMOTE_PORT environment variable for CGI" 269 default y 158 270 depends on FEATURE_HTTPD_CGI 159 271 help … … 162 274 163 275 config 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)" 165 277 default y 166 278 depends on HTTPD 167 279 help 168 This option allows html encoding arbitrary169 strings for display of the browser.Output goes to stdout.170 For example, httpd -e "<Hello World>" as280 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 171 283 "<Hello World>". 172 284 173 285 config FEATURE_HTTPD_ERROR_PAGES 174 bool " Enable support for custom error pages"175 default n286 bool "Support for custom error pages" 287 default y 176 288 depends on HTTPD 177 289 help … … 184 296 message. 185 297 298 config 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 310 config 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 186 318 config IFCONFIG 187 319 bool "ifconfig" 188 default n 320 default y 321 depends on PLATFORM_LINUX 189 322 help 190 323 Ifconfig is used to configure the kernel-resident network interfaces. … … 200 333 config FEATURE_IFCONFIG_SLIP 201 334 bool "Enable slip-specific options \"keepalive\" and \"outfill\"" 202 default n335 default y 203 336 depends on IFCONFIG 204 337 help 205 Allow "keepalive" and "outfill" support for SLIP. 338 Allow "keepalive" and "outfill" support for SLIP. If you're not 206 339 planning on using serial lines, leave this unchecked. 207 340 208 341 config FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 209 342 bool "Enable options \"mem_start\", \"io_addr\", and \"irq\"" 210 default n343 default y 211 344 depends on IFCONFIG 212 345 help … … 220 353 help 221 354 Set the hardware address of this interface, if the device driver 222 supports this operation. 355 supports this operation. Currently, we only support the 'ether' 223 356 class. 224 357 225 358 config FEATURE_IFCONFIG_BROADCAST_PLUS 226 359 bool "Set the broadcast automatically" 227 default n360 default y 228 361 depends on IFCONFIG 229 362 help … … 231 364 automatically if the value '+' is used. 232 365 366 config 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 374 config IFPLUGD 375 bool "ifplugd" 376 default y 377 depends on PLATFORM_LINUX 378 help 379 Network interface plug detection daemon. 380 233 381 config IFUPDOWN 234 382 bool "ifupdown" 235 default n236 help 237 Activate or deactivate the specified interfaces. 383 default y 384 help 385 Activate or deactivate the specified interfaces. This applet makes 238 386 use of either "ifconfig" and "route" or the "ip" command to actually 239 configure network interfaces. 387 configure network interfaces. Therefore, you will probably also want 240 388 to enable either IFCONFIG and ROUTE, or enable 241 FEATURE_IFUPDOWN_IP and the various IP options. 389 FEATURE_IFUPDOWN_IP and the various IP options. Of 242 390 course you could use non-busybox versions of these programs, so 243 391 against my better judgement (since this will surely result in plenty 244 392 of support questions on the mailing list), I do not force you to 245 enable these additional options. 393 enable these additional options. It is up to you to supply either 246 394 "ifconfig", "route" and "run-parts" or the "ip" command, either 247 395 via busybox or via standalone utilities. … … 250 398 string "Absolute path to ifstate file" 251 399 default "/var/run/ifstate" 400 depends on IFUPDOWN 252 401 help 253 402 ifupdown keeps state information in a file called ifstate. … … 259 408 config FEATURE_IFUPDOWN_IP 260 409 bool "Use ip applet" 261 default n410 default y 262 411 depends on IFUPDOWN 263 412 help … … 268 417 bool "Use busybox ip applet" 269 418 default y 270 depends on FEATURE_IFUPDOWN_IP 419 depends on FEATURE_IFUPDOWN_IP && PLATFORM_LINUX 271 420 select IP 272 421 select FEATURE_IP_ADDRESS … … 281 430 config FEATURE_IFUPDOWN_IFCONFIG_BUILTIN 282 431 bool "Use busybox ifconfig and route applets" 283 default y432 default n 284 433 depends on IFUPDOWN && !FEATURE_IFUPDOWN_IP 285 434 select IFCONFIG … … 294 443 295 444 config FEATURE_IFUPDOWN_IPV4 296 bool " Enable support for IPv4"445 bool "Support for IPv4" 297 446 default y 298 447 depends on IFUPDOWN … … 301 450 302 451 config FEATURE_IFUPDOWN_IPV6 303 bool " Enable support for IPv6"304 default n452 bool "Support for IPv6" 453 default y 305 454 depends on IFUPDOWN && FEATURE_IPV6 306 455 help … … 308 457 309 458 ### UNUSED 310 ### 311 ### bool "Enable support for IPX"312 ### default n313 ### 314 ### 315 ### 316 ### 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. 317 466 318 467 config FEATURE_IFUPDOWN_MAPPING 319 468 bool "Enable mapping support" 320 default n469 default y 321 470 depends on IFUPDOWN 322 471 help … … 325 474 326 475 config FEATURE_IFUPDOWN_EXTERNAL_DHCP 327 bool " Enable support for external dhcp clients"476 bool "Support for external dhcp clients" 328 477 default n 329 478 depends on IFUPDOWN … … 336 485 config INETD 337 486 bool "inetd" 338 default n487 default y 339 488 select FEATURE_SYSLOG 340 489 help … … 378 527 config FEATURE_INETD_RPC 379 528 bool "Support RPC services" 380 default n529 default y 381 530 depends on INETD 382 531 select FEATURE_HAVE_RPC … … 386 535 config IP 387 536 bool "ip" 388 default n 537 default y 538 depends on PLATFORM_LINUX 389 539 help 390 540 The "ip" applet is a TCP/IP interface configuration and routing 391 utility. 541 utility. You generally don't need "ip" to use busybox with 392 542 TCP/IP. 393 543 … … 415 565 config FEATURE_IP_TUNNEL 416 566 bool "ip tunnel" 417 default n567 default y 418 568 depends on IP 419 569 help … … 422 572 config FEATURE_IP_RULE 423 573 bool "ip rule" 424 default n574 default y 425 575 depends on IP 426 576 help … … 428 578 429 579 config FEATURE_IP_SHORT_FORMS 430 bool "Support short forms of ip commands ."431 default n580 bool "Support short forms of ip commands" 581 default y 432 582 depends on IP 433 583 help … … 442 592 object commands. 443 593 594 config 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 444 604 config IPADDR 445 605 bool … … 469 629 config IPCALC 470 630 bool "ipcalc" 471 default n631 default y 472 632 help 473 633 ipcalc takes an IP address and netmask and calculates the … … 479 639 depends on IPCALC 480 640 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". 482 643 483 644 config FEATURE_IPCALC_LONG_OPTIONS 484 645 bool "Enable long options" 485 default n486 depends on IPCALC && GETOPT_LONG646 default y 647 depends on IPCALC && LONG_OPTS 487 648 help 488 649 Support long options for the ipcalc applet. … … 490 651 config NAMEIF 491 652 bool "nameif" 492 default n 653 default y 654 depends on PLATFORM_LINUX 493 655 select FEATURE_SYSLOG 494 656 help … … 497 659 It is possible to use a file (default: /etc/mactab) 498 660 with list of new interface names and MACs. 499 Maximum interface name length: IF _NAMESIZE= 16661 Maximum interface name length: IFNAMSIZ = 16 500 662 File fields are separated by space or tab. 501 663 File format: … … 503 665 new_interface_name XX:XX:XX:XX:XX:XX 504 666 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). 667 config 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 527 679 528 680 config NETSTAT 529 681 bool "netstat" 530 default n 682 default y 683 depends on PLATFORM_LINUX 531 684 help 532 685 netstat prints information about the Linux networking subsystem. 533 686 534 687 config FEATURE_NETSTAT_WIDE 535 bool " 536 default n688 bool "Enable wide netstat output" 689 default y 537 690 depends on NETSTAT 538 691 help … … 540 693 (-W option). 541 694 695 config 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 542 703 config NSLOOKUP 543 704 bool "nslookup" 544 default n705 default y 545 706 help 546 707 nslookup is a tool to query Internet name servers. 708 709 config NTPD 710 bool "ntpd" 711 default y 712 depends on PLATFORM_LINUX 713 help 714 The NTP client/server daemon. 715 716 config 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. 547 723 548 724 config PING 549 725 bool "ping" 550 default n 726 default y 727 depends on PLATFORM_LINUX 551 728 help 552 729 ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to … … 555 732 config PING6 556 733 bool "ping6" 557 default n734 default y 558 735 depends on FEATURE_IPV6 && PING 559 736 help 560 737 This will give you a ping that can talk IPv6. 738 739 config 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. 561 746 562 747 config PSCAN 563 748 bool "pscan" 564 default n749 default y 565 750 help 566 751 Simple network port scanner. 567 568 config FEATURE_FANCY_PING569 bool "Enable fancy ping output"570 default y571 depends on PING572 help573 Make the output from the ping applet include statistics, and at the574 same time provide full support for ICMP packets.575 752 576 753 config ROUTE 577 754 bool "route" 578 default n 755 default y 756 depends on PLATFORM_LINUX 579 757 help 580 758 Route displays or manipulates the kernel's IP routing tables. … … 582 760 config SLATTACH 583 761 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 778 config 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. 587 784 588 785 config TELNET 589 786 bool "telnet" 590 default n787 default y 591 788 help 592 789 Telnet is an interface to the TELNET protocol, but is also commonly … … 599 796 help 600 797 Setting this option will forward the TERM environment variable to the 601 remote host you are connecting to. 798 remote host you are connecting to. This is useful to make sure that 602 799 things like ANSI colors and other control sequences behave. 603 800 … … 614 811 config TELNETD 615 812 bool "telnetd" 616 default n813 default y 617 814 select FEATURE_SYSLOG 618 815 help 619 816 A daemon for the TELNET protocol, allowing you to log onto the host 620 running the daemon. 621 sends passwords in plain text. 622 SSH daemon and you trust your network, you may say 'y' here. 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 623 820 more secure alternative, you should seriously consider installing the 624 821 very small Dropbear SSH daemon instead: … … 645 842 mount -t devpts devpts /dev/pts 646 843 647 You need to be sure that Busybox has LOGIN and648 FEATURE_SUID enabled. 844 You need to be sure that busybox has LOGIN and 845 FEATURE_SUID enabled. And finally, you should make 649 846 certain that Busybox has been installed setuid root: 650 847 … … 657 854 config FEATURE_TELNETD_STANDALONE 658 855 bool "Support standalone telnetd (not inetd only)" 659 default n856 default y 660 857 depends on TELNETD 661 858 help 662 859 Selecting this will make telnetd able to run standalone. 860 861 config 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. 663 881 664 882 config TFTP 665 883 bool "tftp" 666 default n667 help 668 This enables the Trivial File Transfer Protocol client program. 884 default y 885 help 886 This enables the Trivial File Transfer Protocol client program. TFTP 669 887 is usually used for simple, small transfers such as a root image 670 888 for a network-enabled bootloader. 671 889 890 config 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 900 comment "Common options for tftp/tftpd" 901 depends on TFTP || TFTPD 902 672 903 config 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. 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 678 909 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)! 679 914 680 915 config 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. 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 686 921 a client to transfer a file to a TFTP server. 922 Also enable download support in tftpd, if tftpd is selected. 687 923 688 924 config 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 932 config 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 939 config TFTP_DEBUG 696 940 bool "Enable debug" 697 941 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]. 703 946 704 947 config TRACEROUTE 705 948 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 954 config TRACEROUTE6 955 bool "traceroute6" 956 default y 957 depends on FEATURE_IPV6 && TRACEROUTE 958 help 959 Utility to trace the route of IPv6 packets. 709 960 710 961 config FEATURE_TRACEROUTE_VERBOSE 711 962 bool "Enable verbose output" 712 default n963 default y 713 964 depends on TRACEROUTE 714 965 help 715 Add some verbosity to traceroute. This includes amongstother things966 Add some verbosity to traceroute. This includes among other things 716 967 hostnames and ICMP response types. 717 968 … … 729 980 depends on TRACEROUTE 730 981 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 984 config TUNCTL 985 bool "tunctl" 986 default y 987 depends on PLATFORM_LINUX 988 help 989 tunctl creates or deletes tun devices. 990 991 config 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. 732 998 733 999 source networking/udhcp/Config.in 1000 1001 config 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 1010 config 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. 734 1016 735 1017 config VCONFIG 736 1018 bool "vconfig" 737 default n 1019 default y 1020 depends on PLATFORM_LINUX 738 1021 help 739 1022 Creates, removes, and configures VLAN interfaces … … 741 1024 config WGET 742 1025 bool "wget" 743 default n1026 default y 744 1027 help 745 1028 wget is a utility for non-interactive download of files from HTTP, … … 762 1045 config FEATURE_WGET_LONG_OPTIONS 763 1046 bool "Enable long options" 764 default n765 depends on WGET && GETOPT_LONG1047 default y 1048 depends on WGET && LONG_OPTS 766 1049 help 767 1050 Support long options for the wget applet. 1051 1052 config 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. 768 1063 769 1064 config ZCIP 770 1065 bool "zcip" 771 default n 1066 default y 1067 depends on PLATFORM_LINUX 772 1068 select FEATURE_SYSLOG 773 1069 help -
branches/2.2.9/mindi-busybox/networking/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 4 5 # 5 # Licensed under the GPL v2, see the file LICENSE in this tarball.6 # Licensed under GPLv2, see file LICENSE in this source tree. 6 7 7 8 lib-y:= 9 10 lib-$(CONFIG_NBDCLIENT) += nbd-client.o 8 11 lib-$(CONFIG_ARP) += arp.o interface.o 9 12 lib-$(CONFIG_ARPING) += arping.o 13 lib-$(CONFIG_BRCTL) += brctl.o 10 14 lib-$(CONFIG_DNSD) += dnsd.o 11 15 lib-$(CONFIG_ETHER_WAKE) += ether-wake.o 12 16 lib-$(CONFIG_FAKEIDENTD) += isrv_identd.o isrv.o 17 lib-$(CONFIG_FTPD) += ftpd.o 13 18 lib-$(CONFIG_FTPGET) += ftpgetput.o 14 19 lib-$(CONFIG_FTPPUT) += ftpgetput.o … … 16 21 lib-$(CONFIG_HTTPD) += httpd.o 17 22 lib-$(CONFIG_IFCONFIG) += ifconfig.o interface.o 23 lib-$(CONFIG_IFENSLAVE) += ifenslave.o interface.o 24 lib-$(CONFIG_IFPLUGD) += ifplugd.o 18 25 lib-$(CONFIG_IFUPDOWN) += ifupdown.o 19 26 lib-$(CONFIG_INETD) += inetd.o … … 24 31 lib-$(CONFIG_NETSTAT) += netstat.o 25 32 lib-$(CONFIG_NSLOOKUP) += nslookup.o 33 lib-$(CONFIG_NTPD) += ntpd.o 26 34 lib-$(CONFIG_PING) += ping.o 27 35 lib-$(CONFIG_PING6) += ping.o … … 29 37 lib-$(CONFIG_ROUTE) += route.o 30 38 lib-$(CONFIG_SLATTACH) += slattach.o 39 lib-$(CONFIG_TC) += tc.o 31 40 lib-$(CONFIG_TELNET) += telnet.o 32 41 lib-$(CONFIG_TELNETD) += telnetd.o 33 42 lib-$(CONFIG_TFTP) += tftp.o 43 lib-$(CONFIG_TFTPD) += tftp.o 34 44 lib-$(CONFIG_TRACEROUTE) += traceroute.o 45 lib-$(CONFIG_TUNCTL) += tunctl.o 35 46 lib-$(CONFIG_VCONFIG) += vconfig.o 36 47 lib-$(CONFIG_WGET) += wget.o 37 48 lib-$(CONFIG_ZCIP) += zcip.o 49 50 lib-$(CONFIG_TCPSVD) += tcpudp.o tcpudp_perhost.o 51 lib-$(CONFIG_UDPSVD) += tcpudp.o tcpudp_perhost.o -
branches/2.2.9/mindi-busybox/networking/arp.c
r1765 r2725 28 28 #define DFLT_HW "ether" 29 29 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 */ 30 enum { 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 44 enum { 45 sockfd = 3, /* active socket descriptor */ 46 }; 47 48 struct 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 48 64 49 65 static const char options[] ALIGN1 = … … 201 217 bb_error_msg("device '%s' has HW address %s '%s'", 202 218 ifname, xhw->name, 203 xhw->print(( char *) &ifr.ifr_hwaddr.sa_data));219 xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data)); 204 220 } 205 221 } … … 314 330 char *hwa, char *mask, char *dev) 315 331 { 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 316 352 const struct hwtype *xhw; 317 353 … … 334 370 printf("netmask %s ", mask); 335 371 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); 352 374 } 353 375 … … 377 399 host = xstrdup(ap->sprint(&sa, 1)); 378 400 } 379 fp = xfopen ("/proc/net/arp", "r");401 fp = xfopen_for_read("/proc/net/arp"); 380 402 /* Bypass header -- read one line */ 381 403 fgets(line, sizeof(line), fp); … … 435 457 } 436 458 437 int arp_main(int argc, char **argv) ;438 int arp_main(int argc , char **argv)459 int arp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 460 int arp_main(int argc UNUSED_PARAM, char **argv) 439 461 { 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); 444 469 ap = get_aftype(DFLT_AF); 445 470 if (!ap) 446 471 bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family"); 447 472 448 getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol,473 opts = getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol, 449 474 &hw_type, &hw_type, &device); 450 475 argv += optind; 451 if (opt ion_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) {476 if (opts & (ARP_OPT_A | ARP_OPT_p)) { 452 477 ap = get_aftype(protocol); 453 478 if (ap == NULL) 454 479 bb_error_msg_and_die("%s: unknown %s", protocol, "address family"); 455 480 } 456 if (opt ion_mask32 & ARP_OPT_A || option_mask32 & ARP_OPT_p) {481 if (opts & (ARP_OPT_A | ARP_OPT_p)) { 457 482 hw = get_hwtype(hw_type); 458 483 if (hw == NULL) … … 460 485 hw_set = 1; 461 486 } 462 //if (opt ion_mask32& ARP_OPT_i)... -i487 //if (opts & ARP_OPT_i)... -i 463 488 464 489 if (ap->af != AF_INET) { … … 477 502 hw->name, "hardware type"); 478 503 } 479 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);480 504 481 505 /* Now see what we have to do here... */ 482 if (opt ion_mask32 & (ARP_OPT_d|ARP_OPT_s)) {506 if (opts & (ARP_OPT_d | ARP_OPT_s)) { 483 507 if (argv[0] == NULL) 484 508 bb_error_msg_and_die("need host name"); 485 if (opt ion_mask32& ARP_OPT_s)509 if (opts & ARP_OPT_s) 486 510 return arp_set(argv); 487 511 return arp_del(argv); 488 512 } 489 //if (opt ion_mask32& ARP_OPT_a) - default513 //if (opts & ARP_OPT_a) - default 490 514 return arp_show(argv[0]); 491 515 } -
branches/2.2.9/mindi-busybox/networking/arping.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * arping.c - Ping hosts by ARP requests/replies3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 * 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> 8 6 * Busybox port: Nick Fedchik <nick@fedchik.org.ua> 9 7 */ … … 18 16 /* We don't expect to see 1000+ seconds delay, unsigned is enough */ 19 17 #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;26 18 27 19 enum { … … 35 27 }; 36 28 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; 29 struct 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 //} 45 72 46 73 static int send_pack(struct in_addr *src_addr, … … 49 76 { 50 77 int err; 51 unsigned now;52 78 unsigned char buf[256]; 53 79 struct arphdr *ah = (struct arphdr *) buf; 54 80 unsigned char *p = (unsigned char *) (ah + 1); 55 81 56 ah->ar_hrd = htons(ME->sll_hatype);57 82 ah->ar_hrd = htons(ARPHRD_ETHER); 58 83 ah->ar_pro = htons(ETH_P_IP); … … 61 86 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); 62 87 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); 68 90 69 91 if (option_mask32 & ADVERT) 70 memcpy(p, &ME->sll_addr, ah->ar_hln);92 p = mempcpy(p, &ME->sll_addr, ah->ar_hln); 71 93 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)); 80 99 if (err == p - buf) { 81 last = now;100 last = MONOTONIC_US(); 82 101 sent++; 83 102 if (!(option_mask32 & UNICASTING)) … … 87 106 } 88 107 89 static void finish(void) ATTRIBUTE_NORETURN;108 static void finish(void) NORETURN; 90 109 static void finish(void) 91 110 { … … 101 120 exit(!!received); 102 121 if (option_mask32 & UNSOLICITED) 103 exit( 0);122 exit(EXIT_SUCCESS); 104 123 exit(!received); 105 124 } … … 107 126 static void catcher(void) 108 127 { 109 static unsigned start;110 111 128 unsigned now; 112 129 … … 115 132 start = now; 116 133 117 if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000)))134 if (count == 0 || (timeout_us && (now - start) > timeout_us)) 118 135 finish(); 119 136 120 count--; 137 /* count < 0 means "infinite count" */ 138 if (count > 0) 139 count--; 121 140 122 141 if (last == 0 || (now - last) > 500000) { … … 128 147 } 129 148 130 static intrecv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)149 static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) 131 150 { 132 151 struct arphdr *ah = (struct arphdr *) buf; 133 152 unsigned char *p = (unsigned char *) (ah + 1); 134 153 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 }; 135 163 136 164 /* Filter out wild packets */ … … 138 166 && FROM->sll_pkttype != PACKET_BROADCAST 139 167 && FROM->sll_pkttype != PACKET_MULTICAST) 140 return 0;141 142 /* Only these types are recogni sed */168 return false; 169 170 /* Only these types are recognized */ 143 171 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY)) 144 return 0;172 return false; 145 173 146 174 /* ARPHRD check and this darned FDDI hack here :-( */ 147 175 if (ah->ar_hrd != htons(FROM->sll_hatype) 148 176 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) 149 return 0;177 return false; 150 178 151 179 /* 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; 162 191 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; 169 195 } else { 170 196 /* DAD packet was: … … 181 207 dst_ip/dst_hw do not matter. 182 208 */ 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; 189 212 } 190 213 if (!(option_mask32 & QUIET)) { … … 208 231 209 232 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); 211 235 } else { 212 236 printf(" UNSOLICITED?\n"); 213 237 } 214 fflush (stdout);238 fflush_all(); 215 239 } 216 240 received++; … … 225 249 option_mask32 |= UNICASTING; 226 250 } 227 return 1;251 return true; 228 252 } 229 253 230 int arping_main(int argc, char **argv) ;231 int arping_main(int argc , char **argv)254 int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 255 int arping_main(int argc UNUSED_PARAM, char **argv) 232 256 { 233 257 const char *device = "eth0"; 234 int ifindex;235 258 char *source = NULL; 236 259 char *target; 237 260 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); 240 266 241 267 // 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); 244 272 { 245 273 unsigned opt; 246 char *str_ count, *str_timeout;274 char *str_timeout; 247 275 248 276 /* Dad also sets quit_on_reply. 249 277 * Advert also sets unsolicited. 250 278 */ 251 opt_complementary = "=1:Df:AU ";279 opt_complementary = "=1:Df:AU:c+"; 252 280 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); 256 282 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; 263 284 //if (opt & 0x200) /* -s: source */ 264 285 option_mask32 &= 0x3f; /* set respective flags */ … … 273 294 274 295 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); 280 303 281 304 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"); 283 306 } 284 307 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"); 286 309 return (option_mask32 & DAD ? 0 : 2); 287 310 } 288 311 } 289 312 290 if (!inet_aton(target, &dst)){313 /* if (!inet_aton(target, &dst)) - not needed */ { 291 314 len_and_sockaddr *lsa; 292 315 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; 294 317 if (ENABLE_FEATURE_CLEAN_UP) 295 318 free(lsa); … … 300 323 } 301 324 302 if ( !(option_mask32 & DAD) && (option_mask32 & UNSOLICITED)&& src.s_addr == 0)325 if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0) 303 326 src = dst; 304 327 … … 307 330 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 308 331 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); 313 333 memset(&saddr, 0, sizeof(saddr)); 314 334 saddr.sin_family = AF_INET; 315 335 if (src.s_addr) { 336 /* Check that this is indeed our IP */ 316 337 saddr.sin_addr = src; 317 338 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 */ 319 341 socklen_t alen = sizeof(saddr); 320 342 … … 323 345 324 346 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)"); 326 348 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"); 330 355 src = saddr.sin_addr; 331 356 } … … 334 359 335 360 me.sll_family = AF_PACKET; 336 me.sll_ifindex = ifindex;361 //me.sll_ifindex = ifindex; - done before 337 362 me.sll_protocol = htons(ETH_P_ARP); 338 xbind(sock , (struct sockaddr *) &me, sizeof(me));363 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); 339 364 340 365 { 341 366 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"); 346 371 } 347 372 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)"); 349 374 return (option_mask32 & DAD ? 0 : 2); 350 375 } … … 353 378 354 379 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); 376 387 377 388 catcher(); … … 384 395 int cc; 385 396 386 cc = recvfrom(sock , packet, 4096, 0, (struct sockaddr *) &from, &alen);397 cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); 387 398 if (cc < 0) { 388 399 bb_perror_msg("recvfrom"); -
branches/2.2.9/mindi-busybox/networking/dnsd.c
r1765 r2725 7 7 * Copyright (C) 2003 Paul Sheer 8 8 * 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. 10 10 * 11 11 * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote … … 18 18 */ 19 19 20 #include "libbb.h" 20 21 #include <syslog.h> 21 #include "libbb.h"22 22 23 23 //#define DEBUG 1 … … 25 25 26 26 enum { 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"), 43 34 REQ_A = 1, 44 REQ_PTR = 12 35 REQ_PTR = 12, 45 36 }; 46 37 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 */ 39 struct dns_head { 54 40 uint16_t id; 55 41 uint16_t flags; 56 uint16_t nquer; // accepts 057 uint16_t nansw; // 1 in response58 uint16_t nauth; // 059 uint16_t nadd; // 042 uint16_t nquer; 43 uint16_t nansw; 44 uint16_t nauth; 45 uint16_t nadd; 60 46 }; 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: */ 52 struct 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 */ 57 struct 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]; 64 62 }; 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 93 67 94 68 /* 95 69 * Insert length of substrings instead of dots 96 70 */ 97 static void undot( uint8_t *rip)71 static void undot(char *rip) 98 72 { 99 int i = 0, s = 0; 73 int i = 0; 74 int s = 0; 75 100 76 while (rip[i]) 101 77 i++; … … 104 80 rip[i] = s; 105 81 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++; 132 84 } 133 85 } 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;153 86 } 154 87 … … 156 89 * Read hostname/IP records from file 157 90 */ 158 static void dnsentryinit(void)91 static struct dns_entry *parse_conf_file(const char *fileconf) 159 92 { 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); 168 116 /*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; 179 136 } 180 137 181 138 /* 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 */ 141 static char *table_lookup(struct dns_entry *d, 142 uint16_t type, 143 char* query_string) 186 144 { 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 */ 191 148 #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 ); 198 156 #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; 205 173 #if DEBUG 206 fprintf(stderr, " OK as:%s\n", as);174 fprintf(stderr, "Found IP:%x\n", (int)d->ip); 207 175 #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; 215 177 } 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: 216 190 d = d->next; 217 } while (d); 218 return -1; 191 } 192 193 return NULL; 219 194 } 220 221 195 222 196 /* 223 197 * Decode message and generate answer 224 198 */ 225 static int process_packet(uint8_t * buf) 199 /* RFC 1035 200 ... 201 Whenever an octet represents a numeric quantity, the left most bit 202 in the diagram is the high order or most significant bit. 203 That is, the bit labeled 0 is the most significant bit. 204 ... 205 206 4.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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 221 ID 16 bit random identifier assigned by querying peer. 222 Used to match query/response. 223 QR message is a query (0), or a response (1). 224 OPCODE 0 standard query (QUERY) 225 1 inverse query (IQUERY) 226 2 server status request (STATUS) 227 AA 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. 232 TC TrunCation - this message was truncated. 233 RD 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. 237 RA 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. 240 RCODE 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. 250 QDCOUNT number of entries in the question section. 251 ANCOUNT number of records in the answer section. 252 NSCOUNT number of records in the authority records section. 253 ARCOUNT number of records in the additional records section. 254 255 4.1.2. Question section format 256 257 The 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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 267 QNAME 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. 273 QTYPE 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 295 QCLASS 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 300 4.1.3. Resource Record format 301 302 The answer, authority, and additional sections all share the same format: 303 a variable number of resource records, where the number of records 304 is specified in the corresponding count field in the header. 305 Each 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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 323 NAME a domain name to which this resource record pertains. 324 TYPE two octets containing one of the RR type codes. This 325 field specifies the meaning of the data in the RDATA field. 326 CLASS two octets which specify the class of the data in the RDATA field. 327 TTL a 32 bit unsigned integer that specifies the time interval 328 (in seconds) that the record may be cached. 329 RDLENGTH a 16 bit integer, length in octets of the RDATA field. 330 RDATA 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 335 4.1.4. Message compression 336 337 In order to reduce the size of messages, domain names coan be compressed. 338 An entire domain name or a list of labels at the end of a domain name 339 is replaced with a pointer to a prior occurance of the same name. 340 341 The pointer takes the form of a two octet sequence: 342 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 343 | 1 1| OFFSET | 344 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 345 The first two bits are ones. This allows a pointer to be distinguished 346 from a label, since the label must begin with two zero bits because 347 labels are restricted to 63 octets or less. The OFFSET field specifies 348 an offset from the start of the message (i.e., the first octet 349 of the ID field in the domain header). 350 A zero offset specifies the first byte of the ID field, etc. 351 Domain 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 */ 356 static int process_packet(struct dns_entry *conf_data, 357 uint32_t conf_ttl, 358 uint8_t *buf) 226 359 { 227 360 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; 237 371 238 372 head = (struct dns_head *)buf; 239 373 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"; 266 398 goto empty_packet; 267 399 } 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"; 271 403 goto empty_packet; 272 273 // We have a standard query274 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 auth404 } 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"; 278 410 goto empty_packet; 279 411 } 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 ); 285 465 } 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; 319 474 } 320 475 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) 476 int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 477 int dnsd_main(int argc UNUSED_PARAM, char **argv) 333 478 { 334 479 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; 335 483 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; 338 487 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 347 499 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 356 501 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); 357 502 openlog(applet_name, LOG_PID, LOG_DAEMON); … … 359 504 } 360 505 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); 372 507 373 508 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 } 379 521 380 522 while (1) { 381 523 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); 393 533 continue; 394 534 } 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); 396 539 if (r <= 0) 397 540 continue; 398 send to(udps, buf, r, 0, &lsa->sa, fromlen);541 send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len); 399 542 } 400 543 return 0; -
branches/2.2.9/mindi-busybox/networking/ether-wake.c
r1765 r2725 3 3 * ether-wake.c - Send a magic packet to wake up sleeping machines. 4 4 * 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. 6 6 * 7 7 * Author: Donald Becker, http://www.scyld.com/"; http://www.scyld.com/wakeonlan.html … … 93 93 for (i = 0; i < pktsize; ++i) { 94 94 printf("%2.2x ", outpack[i]); 95 if (i % 20 == 19) puts("");95 if (i % 20 == 19) bb_putchar('\n'); 96 96 } 97 97 printf("\n\n"); … … 112 112 struct ether_addr *eap; 113 113 114 eap = ether_aton (hostid);114 eap = ether_aton_r(hostid, eaddr); 115 115 if (eap) { 116 *eaddr = *eap; 117 bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr)); 118 #if !defined(__UCLIBC__) 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) 119 121 } else if (ether_hostton(hostid, eaddr) == 0) { 120 122 bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr)); 121 123 #endif 122 } else 124 } else { 123 125 bb_show_usage(); 126 } 124 127 } 125 128 … … 165 168 &passwd[0], &passwd[1], &passwd[2], &passwd[3]); 166 169 if (byte_cnt < 4) { 167 bb_error_msg("can not read Wake-On-LAN pass");170 bb_error_msg("can't read Wake-On-LAN pass"); 168 171 return 0; 169 172 } … … 179 182 } 180 183 181 int ether_wake_main(int argc, char **argv) ;182 int ether_wake_main(int argc , char **argv)184 int ether_wake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 185 int ether_wake_main(int argc UNUSED_PARAM, char **argv) 183 186 { 184 187 const char *ifname = "eth0"; … … 187 190 unsigned char wol_passwd[6]; 188 191 int wol_passwd_sz = 0; 189 int s; 192 int s; /* Raw socket */ 190 193 int pktsize; 191 194 unsigned char outpack[1000]; 192 195 193 196 struct ether_addr eaddr; 194 struct whereto_t whereto; 197 struct whereto_t whereto; /* who to wake up */ 195 198 196 199 /* handle misc user options */ … … 220 223 struct ifreq if_hwaddr; 221 224 222 strncpy (if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name));225 strncpy_IFNAMSIZ(if_hwaddr.ifr_name, ifname); 223 226 ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname); 224 227 … … 256 259 { 257 260 struct ifreq ifr; 258 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));261 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 259 262 xioctl(s, SIOCGIFINDEX, &ifr); 260 263 memset(&whereto, 0, sizeof(whereto)); -
branches/2.2.9/mindi-busybox/networking/ftpgetput.c
r1765 r2725 6 6 * 7 7 * 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 9 9 * 10 10 * Based on wget.c by Chip Rosenthal Covad Communications 11 11 * <chip@laserlink.net> 12 12 * 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. 14 14 */ 15 15 16 #include <getopt.h>17 16 #include "libbb.h" 18 17 19 typedef struct ftp_host_info_s {18 struct globals { 20 19 const char *user; 21 20 const char *password; 22 21 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) 28 enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) }; 29 struct 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 42 static void ftp_die(const char *msg) NORETURN; 43 static void ftp_die(const char *msg) 44 { 45 char *cp = buf; /* buf holds peer's response */ 46 31 47 /* 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 55 static int ftpcmd(const char *s1, const char *s2) 41 56 { 42 57 unsigned n; 58 43 59 if (verbose_flag) { 44 60 bb_error_msg("cmd %s %s", s1, s2); … … 46 62 47 63 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 54 69 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); 63 73 } 64 74 } while (!isdigit(buf[0]) || buf[3] != ' '); … … 70 80 } 71 81 72 static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) 82 static 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 111 static int xconnect_ftpdata(void) 73 112 { 74 113 char *buf_ptr; 75 unsigned short port_num; 114 unsigned port_num; 115 116 /* 117 TODO: PASV command will not work for IPv6. RFC2428 describes 118 IPv6-capable "extended PASV" - EPSV. 119 120 "EPSV [protocol]" asks server to bind to and listen on a data port 121 in specified protocol. Protocol is 1 for IPv4, 2 for IPv6. 122 If not specified, defaults to "same as used for control connection". 123 If server understood you, it should answer "229 <some text>(|||port|)" 124 where "|" are literal pipe chars and "port" is ASCII decimal port#. 125 126 There is also an IPv6-capable replacement for PORT (EPRT), 127 but we don't need that. 128 129 NB: PASV may still work for some servers even over IPv6. 130 For example, vsftp happily answers 131 "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual. 132 133 TODO2: need to stop ignoring IP address in PASV response. 134 */ 135 136 if (ftpcmd("PASV", NULL) != 227) { 137 ftp_die("PASV"); 138 } 76 139 77 140 /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] … … 89 152 port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; 90 153 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 158 static 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; 127 177 } 128 178 129 179 #if !ENABLE_FTPGET 130 int ftp_receive(ftp_host_info_t *server, FILE *control_stream, 131 const char *local_path, char *server_path); 180 int ftp_receive(const char *local_path, char *server_path); 132 181 #else 133 182 static 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) 183 int ftp_receive(const char *local_path, char *server_path) 184 { 141 185 int fd_data; 142 186 int fd_local = -1; 143 187 off_t beg_range = 0; 144 188 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) { 156 193 do_continue = 0; 157 194 } … … 164 201 if (do_continue) { 165 202 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"); 168 206 } 169 207 if (sbuf.st_size > 0) { … … 175 213 176 214 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) { 179 217 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 */ 191 226 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); 216 234 } 217 235 #endif 218 236 219 237 #if !ENABLE_FTPPUT 220 int ftp_send(ftp_host_info_t *server, FILE *control_stream, 221 const char *server_path, char *local_path); 238 int ftp_send(const char *server_path, char *local_path); 222 239 #else 223 240 static 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]; 241 int ftp_send(const char *server_path, char *local_path) 242 { 229 243 int fd_data; 230 244 int fd_local; 231 245 int response; 232 246 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(); 238 249 239 250 /* get the local file */ 240 251 fd_local = STDIN_FILENO; 241 if (NOT_LONE_DASH(local_path)) {252 if (NOT_LONE_DASH(local_path)) 242 253 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); 258 256 switch (response) { 259 257 case 125: … … 261 259 break; 262 260 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 288 267 289 268 #if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS … … 297 276 #endif 298 277 299 int ftpgetput_main(int argc, char **argv); 300 int ftpgetput_main(int argc, char **argv) 301 { 302 /* content-length of the file */ 278 int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 279 int ftpgetput_main(int argc UNUSED_PARAM, char **argv) 280 { 303 281 unsigned opt; 304 282 const char *port = "ftp"; 305 283 /* socket to ftp server */ 306 FILE *control_stream;307 /* continue previous transfer (-c) */308 ftp_host_info_t *server;309 284 310 285 #if ENABLE_FTPPUT && !ENABLE_FTPGET … … 313 288 # define ftp_action ftp_receive 314 289 #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 316 292 /* Check to see if the command is ftpget or ftput */ 317 293 if (applet_name[3] == 'g') { … … 320 296 #endif 321 297 298 INIT_G(); 322 299 /* Set default values */ 323 server = xmalloc(sizeof(*server)); 324 server->user = "anonymous"; 325 server->password = "busybox@"; 300 user = "anonymous"; 301 password = "busybox@"; 326 302 327 303 /* … … 331 307 applet_long_options = ftpgetput_longopts; 332 308 #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); 335 312 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 }344 313 345 314 /* We want to do exactly _one_ DNS lookup, since some 346 315 * sites (i.e. ftp.us.debian.org) use round-robin DNS 347 316 * 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)); 349 318 if (verbose_flag) { 350 319 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 5 5 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> 6 6 * 7 * adjusted by Erik Andersen <andersen@codepoet.org> to remove7 * Adjusted by Erik Andersen <andersen@codepoet.org> to remove 8 8 * use of long options and GNU getopt. Improved the usage info. 9 9 * 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. 13 11 */ 14 15 12 #include "libbb.h" 16 13 17 14 static void do_sethostname(char *s, int isfile) 18 15 { 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); 39 22 } 40 23 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"); 42 29 } 43 30 } 44 31 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 */ 82 int hostname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 83 int hostname_main(int argc UNUSED_PARAM, char **argv) 47 84 { 48 85 enum { … … 55 92 }; 56 93 57 char buf[256]; 94 unsigned opts; 95 char *buf; 58 96 char *hostname_str; 59 97 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 ; 62 109 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; 64 118 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) */ 67 121 struct hostent *hp; 68 122 char *p; 69 gethostname(buf, sizeof(buf)); 123 70 124 hp = xgethostbyname(buf); 71 p = strchr (hp->h_name, '.');72 if (opt ion_mask32& OPT_f) {125 p = strchrnul(hp->h_name, '.'); 126 if (opts & OPT_f) { 73 127 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'); 77 142 } 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("");87 143 } 88 } 89 /* Set the hostname */ 90 else if (option_mask32 & OPT_F) { 144 } else if (opts & OPT_F) { 145 /* Set the hostname */ 91 146 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 */ 99 152 puts(buf); 100 153 } 101 return 0; 154 155 if (ENABLE_FEATURE_CLEAN_UP) 156 free(buf); 157 return EXIT_SUCCESS; 102 158 } -
branches/2.2.9/mindi-busybox/networking/httpd.c
r1772 r2725 6 6 * Copyright (C) 2003-2006 Vladimir Oleynik <dzo@simtreas.ru> 7 7 * 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. 11 9 * 12 10 ***************************************************************************** 13 11 * 14 12 * 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 25 22 * after setting QUERY_STRING and other environment variables. 26 23 * … … 28 25 * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html 29 26 * 30 * The server can also be invoked as aurl arg decoder and html text encoder27 * The applet can also be invoked as an url arg decoder and html text encoder 31 28 * as follows: 32 * foo=`httpd -d $foo`# decode "Hello%20World" as "Hello World"33 * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>"29 * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" 30 * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>" 34 31 * 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 html32 * presentation. -d decodes an url-encoded argument while -e encodes in html 36 33 * for page display. 37 34 * 38 35 * httpd.conf has the following format: 39 36 * 37 * H:/serverroot # define the server root. It will override -h 40 38 * A:172.20. # Allow address from 172.20.0.0/16 41 39 * A:10.0.0.0/25 # Allow any address from 10.0.0.0-10.0.0.127 … … 44 42 * D:* # Deny from other IP connections 45 43 * 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 * 46 50 * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ 47 51 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ 48 52 * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ 49 53 * .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). 61 59 * - 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. 65 61 * 66 62 * Example: … … 96 92 * 97 93 */ 94 /* TODO: use TCP_CORK, parse_config() */ 98 95 99 96 #include "libbb.h" 100 97 #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 107 100 /* amount of buffering in a pipe */ 108 101 #ifndef PIPE_BUF … … 110 103 #endif 111 104 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 113 111 114 112 #define HEADER_READ_TIMEOUT 60 115 113 116 static const char default_path_httpd_conf[] ALIGN1 = "/etc";117 static const char httpd_conf[] ALIGN1 = "httpd.conf";114 static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; 115 static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; 118 116 static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; 117 static const char index_html[] ALIGN1 = "index.html"; 119 118 120 119 typedef struct has_next_ptr { … … 137 136 } Htaccess_IP; 138 137 138 /* Must have "next" as a first member */ 139 typedef struct Htaccess_Proxy { 140 struct Htaccess_Proxy *next; 141 char *url_from; 142 char *host_port; 143 char *url_to; 144 } Htaccess_Proxy; 145 139 146 enum { 140 147 HTTP_OK = 200, 148 HTTP_PARTIAL_CONTENT = 206, 141 149 HTTP_MOVED_TEMPORARILY = 302, 142 150 HTTP_BAD_REQUEST = 400, /* malformed syntax */ … … 160 168 HTTP_BAD_GATEWAY = 502, 161 169 HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */ 162 HTTP_RESPONSE_SETSIZE = 0xffffffff163 170 #endif 164 171 }; … … 166 173 static const uint16_t http_response_type[] ALIGN2 = { 167 174 HTTP_OK, 175 #if ENABLE_FEATURE_HTTPD_RANGES 176 HTTP_PARTIAL_CONTENT, 177 #endif 168 178 HTTP_MOVED_TEMPORARILY, 169 179 HTTP_REQUEST_TIMEOUT, 170 180 HTTP_NOT_IMPLEMENTED, 171 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 181 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 172 182 HTTP_UNAUTHORIZED, 173 183 #endif … … 193 203 } http_response[ARRAY_SIZE(http_response_type)] = { 194 204 { "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 }, 196 209 { "Request Timeout", "No request appeared within 60 seconds" }, 197 210 { "Not Implemented", "The requested method is not recognized" }, … … 219 232 smallint flg_deny_all; 220 233 221 unsigned rmt_ip; 234 unsigned rmt_ip; /* used for IP-based allow/deny rules */ 222 235 time_t last_mod; 223 off_t ContentLength; /* -1 - unknown */224 236 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ 225 237 const char *bind_addr_or_port; 226 238 227 239 const char *g_query; 228 const char * configFile;240 const char *opt_c_configFile; 229 241 const char *home_httpd; 242 const char *index_page; 230 243 231 244 const char *found_mime_type; … … 233 246 Htaccess_IP *ip_a_d; /* config allow/deny lines */ 234 247 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 239 262 240 263 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 241 264 Htaccess *g_auth; /* config user:password lines */ 242 265 #endif 243 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES244 266 Htaccess *mime_a; /* config mime types */ 245 #endif246 267 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 247 268 Htaccess *script_i; /* config script interpreters */ 248 269 #endif 249 char *iobuf; 270 char *iobuf; /* [IOBUF_SIZE] */ 250 271 #define hdr_buf bb_common_bufsiz1 251 272 char *hdr_ptr; … … 253 274 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 254 275 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; 255 283 #endif 256 284 }; … … 261 289 #define bind_addr_or_port (G.bind_addr_or_port) 262 290 #define g_query (G.g_query ) 263 #define configFile (G.configFile)291 #define opt_c_configFile (G.opt_c_configFile ) 264 292 #define home_httpd (G.home_httpd ) 293 #define index_page (G.index_page ) 265 294 #define found_mime_type (G.found_mime_type ) 266 295 #define found_moved_temporarily (G.found_moved_temporarily) 267 #define ContentLength (G.ContentLength )268 296 #define last_mod (G.last_mod ) 269 297 #define ip_a_d (G.ip_a_d ) … … 272 300 #define referer (G.referer ) 273 301 #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 311 enum { 312 range_start = 0, 313 range_end = MAXINT(off_t) - 1, 314 range_len = MAXINT(off_t), 315 }; 316 #endif 274 317 #define rmt_ip_str (G.rmt_ip_str ) 275 318 #define g_auth (G.g_auth ) … … 280 323 #define hdr_cnt (G.hdr_cnt ) 281 324 #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 282 331 #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";) \ 285 334 bind_addr_or_port = "80"; \ 286 ContentLength = -1; \ 335 index_page = index_html; \ 336 file_size = -1; \ 287 337 } while (0) 288 338 … … 291 341 292 342 /* Prototypes */ 293 static void send_file_and_exit(const char *url, int headers) ATTRIBUTE_NORETURN; 343 enum { 344 SEND_HEADERS = (1 << 0), 345 SEND_BODY = (1 << 1), 346 SEND_HEADERS_AND_BODY = SEND_HEADERS + SEND_BODY, 347 }; 348 static void send_file_and_exit(const char *url, int what) NORETURN; 294 349 295 350 static void free_llist(has_next_ptr **pptr) … … 304 359 } 305 360 306 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \307 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \308 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR309 361 static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr) 310 362 { 311 363 free_llist((has_next_ptr**)pptr); 312 364 } 313 #endif314 365 315 366 static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr) … … 406 457 * Parse configuration file into in-memory linked list. 407 458 * 408 * The first non-white character is examined to determine if the config line409 * is one of the following:410 * .ext:mime/type # new mime type not compiled into httpd411 * [adAD]:from # ip address allow/deny, * for wildcard412 * /path:user:pass # username/password413 * Ennn:error.html # error page for status nnn414 *415 459 * Any previous IP rules are discarded. 416 460 * If the flag argument is not SUBDIR_PARSE then all /path and mime rules … … 422 466 * flag Type of the parse request. 423 467 */ 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: */ 469 enum { 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 }; 429 474 static void parse_conf(const char *path, int flag) 430 475 { 476 /* internally used extra flag state */ 477 enum { TRY_CURDIR_PARSE = 3 }; 478 431 479 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; 441 481 char buf[160]; 442 char *p0 = NULL;443 char *c, *p;444 Htaccess_IP *pip;445 482 446 483 /* discard old rules */ 447 484 free_Htaccess_IP_list(&ip_a_d); 448 485 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_INTERPR452 486 /* retain previous auth and mime config only for subdir parse */ 453 487 if (flag != SUBDIR_PARSE) { 488 free_Htaccess_list(&mime_a); 454 489 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 455 490 free_Htaccess_list(&g_auth); 456 491 #endif 457 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES458 free_Htaccess_list(&mime_a);459 #endif460 492 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 461 493 free_Htaccess_list(&script_i); 462 494 #endif 463 495 } 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 */ 473 505 /* config file not found, no changes to config */ 474 506 return; 475 507 } 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; 480 517 } 481 518 482 519 #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); 499 579 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); 509 586 continue; 510 587 } 511 588 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; 522 596 } 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) { 527 616 ip_a_d = pip; 528 617 } 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; 539 621 } 540 622 } … … 543 625 544 626 #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 551 631 if (status < HTTP_CONTINUE) { 552 bb_error_msg("config error '%s' in '%s'", buf, cf); 553 continue; 554 } 555 632 goto config_error; 633 } 556 634 /* then error page; find matching status */ 557 635 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { 558 636 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); 560 641 break; 561 642 } … … 565 646 #endif 566 647 567 #if ENABLE_FEATURE_HTTPD_ BASIC_AUTH568 if ( *p0 == '/') {569 /* make full path from httpd root / current_path / config_line_path */570 c f = (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 c f = 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 */ 618 699 cur->next = mime_a; 619 700 mime_a = cur; 620 continue; 621 } 622 #endif 701 } 623 702 #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 */ 626 705 cur->next = script_i; 627 706 script_i = cur; 628 continue; 629 } 630 #endif 707 } 708 #endif 709 continue; 710 } 711 631 712 #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; 652 746 break; 653 747 } 654 if (prev_hti != hti) 655 prev_hti = prev_hti->next; 748 authp = &auth->next; 656 749 } 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 666 761 fclose(f); 667 762 } … … 685 780 char ch; 686 781 687 while ((ch = *string++) ) {782 while ((ch = *string++) != '\0') { 688 783 /* very simple check for what to encode */ 689 784 if (isalnum(ch)) … … 695 790 return out; 696 791 } 697 #endif /* FEATURE_HTTPD_ENCODE_URL_STR */792 #endif 698 793 699 794 /* 700 795 * Given a URL encoded string, convert it to plain ascii. 701 796 * Since decoding always makes strings smaller, the decode is done in-place. 702 * Thus, callers should strdup() the argument if they do not want the797 * Thus, callers should xstrdup() the argument if they do not want the 703 798 * argument modified. The return is the original pointer, allowing this 704 799 * function to be easily used as arguments to other functions. … … 722 817 return v + 10; 723 818 return ~0; 724 }725 819 /* For testing: 726 820 void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } … … 728 822 t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } 729 823 */ 824 } 730 825 static char *decodeString(char *orig, int option_d) 731 826 { … … 821 916 static int openServer(void) 822 917 { 823 intn = bb_strtou(bind_addr_or_port, NULL, 10);918 unsigned n = bb_strtou(bind_addr_or_port, NULL, 10); 824 919 if (!errno && n && n <= 0xffff) 825 920 n = create_and_bind_stream_or_die(NULL, n); … … 833 928 * Log the connection closure and exit. 834 929 */ 835 static void log_and_exit(void) ATTRIBUTE_NORETURN;930 static void log_and_exit(void) NORETURN; 836 931 static void log_and_exit(void) 837 932 { … … 839 934 * or be confused by us just exiting without SHUT_WR. Oh well. */ 840 935 shutdown(1, SHUT_WR); 936 /* Why?? 937 (this also messes up stdin when user runs httpd -i from terminal) 841 938 ndelay_on(0); 842 while (read( 0, iobuf, IOBUF_SIZE) > 0)939 while (read(STDIN_FILENO, iobuf, IOBUF_SIZE) > 0) 843 940 continue; 941 */ 844 942 845 943 if (verbose > 2) … … 863 961 const char *mime_type; 864 962 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 865 const char *error_page = 0;963 const char *error_page = NULL; 866 964 #endif 867 965 unsigned i; 868 time_t timer = time( 0);966 time_t timer = time(NULL); 869 967 char tmp_str[80]; 870 968 int len; … … 909 1007 910 1008 #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) { 912 1010 strcat(iobuf, "\r\n"); 913 1011 len += 2; … … 915 1013 if (DEBUG) 916 1014 fprintf(stderr, "headers: '%s'\n", iobuf); 917 full_write( 1, iobuf, len);1015 full_write(STDOUT_FILENO, iobuf, len); 918 1016 if (DEBUG) 919 1017 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 */ 925 1023 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 929 1047 iobuf[len++] = '\r'; 930 1048 iobuf[len++] = '\n'; … … 938 1056 if (DEBUG) 939 1057 fprintf(stderr, "headers: '%s'\n", iobuf); 940 if (full_write( 1, iobuf, len) != len) {1058 if (full_write(STDOUT_FILENO, iobuf, len) != len) { 941 1059 if (verbose > 1) 942 1060 bb_perror_msg("error"); … … 945 1063 } 946 1064 947 static void send_headers_and_exit(int responseNum) ATTRIBUTE_NORETURN;1065 static void send_headers_and_exit(int responseNum) NORETURN; 948 1066 static void send_headers_and_exit(int responseNum) 949 1067 { … … 964 1082 char c; 965 1083 1084 alarm(HEADER_READ_TIMEOUT); 966 1085 while (1) { 967 1086 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)); 969 1088 if (hdr_cnt <= 0) 970 1089 break; … … 978 1097 if (c == '\n') { 979 1098 iobuf[count] = '\0'; 980 return count;1099 break; 981 1100 } 982 1101 if (count < (IOBUF_SIZE - 1)) /* check overflow */ … … 986 1105 } 987 1106 1107 #if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY 1108 1109 /* gcc 4.2.1 fares better with NOINLINE */ 1110 static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post_len) NORETURN; 1111 static 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 988 1284 #if ENABLE_FEATURE_HTTPD_CGI 1285 989 1286 static void setenv1(const char *name, const char *value) 990 1287 { … … 996 1293 * 997 1294 * Environment variables are set up and the script is invoked with pipes 998 * for stdin/stdout. If a postis being done the script is fed the POST1295 * for stdin/stdout. If a POST is being done the script is fed the POST 999 1296 * data in addition to setting the QUERY_STRING variable (for GETs or POSTs). 1000 1297 * 1001 1298 * Parameters: 1002 1299 * const char *url The requested URL (with leading /). 1003 * int bodyLen Length of the postbody.1300 * int post_len Length of the POST body. 1004 1301 * const char *cookie For set HTTP_COOKIE. 1005 1302 * const char *content_type For set CONTENT_TYPE. … … 1008 1305 const char *url, 1009 1306 const char *request, 1010 int bodyLen,1307 int post_len, 1011 1308 const char *cookie, 1012 const char *content_type) ATTRIBUTE_NORETURN;1309 const char *content_type) NORETURN; 1013 1310 static void send_cgi_and_exit( 1014 1311 const char *url, 1015 1312 const char *request, 1016 int bodyLen,1313 int post_len, 1017 1314 const char *cookie, 1018 1315 const char *content_type) 1019 1316 { 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 */ 1023 1319 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); 1028 1325 1029 1326 /* 1030 1327 * We are mucking with environment _first_ and then vfork/exec, 1031 * this allows us to use vfork safely. Parent do n't care about1328 * this allows us to use vfork safely. Parent doesn't care about 1032 1329 * these environment changes anyway. 1033 1330 */ 1034 1331 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; 1040 1334 while ((script = strchr(script + 1, '/')) != NULL) { 1041 /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */1042 struct stat sb;1043 1044 1335 *script = '\0'; 1045 if (!is_directory( purl + 1, 1, &sb)) {1336 if (!is_directory(url + 1, 1, NULL)) { 1046 1337 /* not directory, found script.cgi/PATH_INFO */ 1047 1338 *script = '/'; 1048 1339 break; 1049 1340 } 1050 *script = '/'; 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 "" */ 1053 1344 setenv1("REQUEST_METHOD", request); 1054 1345 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)); 1056 1347 } else { 1057 setenv1("REQUEST_URI", purl);1348 setenv1("REQUEST_URI", url); 1058 1349 } 1059 1350 if (script != NULL) 1060 1351 *script = '\0'; /* cut off /PATH_INFO */ 1061 1352 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 } 1065 1358 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ 1066 setenv1("SCRIPT_NAME", purl);1359 setenv1("SCRIPT_NAME", url); 1067 1360 /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html: 1068 1361 * QUERY_STRING: The information which follows the ? in the URL … … 1096 1389 } 1097 1390 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)); 1100 1397 if (cookie) 1101 1398 setenv1("HTTP_COOKIE", cookie); … … 1110 1407 if (referer) 1111 1408 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); 1115 1415 1116 1416 pid = vfork(); … … 1122 1422 if (!pid) { 1123 1423 /* Child process */ 1424 char *argv[3]; 1425 1124 1426 xfunc_error_retval = 242; 1125 1427 1428 /* NB: close _first_, then move fds! */ 1429 close(toCgi.wr); 1430 close(fromCgi.rd); 1126 1431 xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */ 1127 1432 xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */ 1128 close(fromCgi.rd);1129 close(toCgi.wr);1130 1433 /* User seeing stderr output can be a security problem. 1131 1434 * If CGI really wants that, it can always do dup itself. */ 1132 1435 /* dup2(1, 2); */ 1133 1436 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 1142 1453 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1143 char *interpr = NULL;1144 char *suffix = strrchr( purl, '.');1454 { 1455 char *suffix = strrchr(script, '.'); 1145 1456 1146 1457 if (suffix) { … … 1148 1459 for (cur = script_i; cur; cur = cur->next) { 1149 1460 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; 1151 1465 break; 1152 1466 } 1153 1467 } 1154 1468 } 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]); 1167 1484 error_execing_cgi: 1168 1485 /* send to stdout … … 1173 1490 /* Parent process */ 1174 1491 1175 /* First, restore variables possibly changed by child */1492 /* Restore variables possibly changed by child */ 1176 1493 xfunc_error_retval = 0; 1177 1494 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 */ 1182 1496 close(fromCgi.wr); 1183 1497 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 1340 1501 #endif /* FEATURE_HTTPD_CGI */ 1341 1502 1342 1503 /* 1343 1504 * Send a file response to a HTTP request, and exit 1344 * 1505 * 1345 1506 * Parameters: 1346 * const char *url 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). 1348 1509 */ 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 1510 static NOINLINE void send_file_and_exit(const char *url, int what) 1511 { 1373 1512 char *suffix; 1374 int f; 1375 const char *const *table; 1376 const char *try_suffix; 1513 int fd; 1377 1514 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"; 1382 1549 suffix = strrchr(url, '.'); 1383 1384 /* If not found, set default as "application/octet-stream"; */1385 found_mime_type = "application/octet-stream";1386 1550 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 ; 1388 1576 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 */ 1401 1602 for (cur = mime_a; cur; cur = cur->next) { 1402 1603 if (strcmp(cur->before_colon, suffix) == 0) { … … 1405 1606 } 1406 1607 } 1407 #endif1408 1608 } 1409 1609 … … 1412 1612 url, found_mime_type); 1413 1613 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) 1423 1638 send_headers(HTTP_OK); 1424 1425 /* If you want to know about EPIPE below1426 * (happens if you abort downloads from local httpd): */1427 signal(SIGPIPE, SIG_IGN);1428 1429 1639 #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); 1446 1662 if (count != n) 1447 1663 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 } 1454 1673 log_and_exit(); 1455 1674 } … … 1459 1678 Htaccess_IP *cur; 1460 1679 1461 /* This could stand some work */1462 1680 for (cur = ip_a_d; cur; cur = cur->next) { 1463 1681 #if DEBUG … … 1476 1694 #endif 1477 1695 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:*" */ 1483 1700 } 1484 1701 1485 1702 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1486 1703 /* 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. 1496 1711 */ 1497 static int check Perm(const char *path, const char *request)1712 static int check_user_passwd(const char *path, const char *user_and_passwd) 1498 1713 { 1499 1714 Htaccess *cur; 1500 const char *p;1501 const char *p0;1502 1503 1715 const char *prev = NULL; 1504 1716 1505 /* This could stand some work */1506 1717 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 1513 1728 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')) 1519 1736 ) { 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) { 1536 1757 continue; 1537 1758 } 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) { 1552 1773 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 */ 1559 1777 } 1560 1778 } /* for */ 1561 1779 1562 return prev == NULL; 1780 /* 0(bad) if prev is set: matches were found but passwd was wrong */ 1781 return (prev == NULL); 1563 1782 } 1564 1783 #endif /* FEATURE_HTTPD_BASIC_AUTH */ 1784 1785 #if ENABLE_FEATURE_HTTPD_PROXY 1786 static 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 1565 1796 1566 1797 /* 1567 1798 * Handle timeouts 1568 1799 */ 1569 static void exit_on_signal(int sig) ATTRIBUTE_NORETURN;1570 static void exit_on_signal(int sig)1800 static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; 1801 static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) 1571 1802 { 1572 1803 send_headers_and_exit(HTTP_REQUEST_TIMEOUT); … … 1576 1807 * Handle an incoming http request and exit. 1577 1808 */ 1578 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN;1809 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) NORETURN; 1579 1810 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) 1580 1811 { 1581 1812 static const char request_GET[] ALIGN1 = "GET"; 1582 1583 1813 struct stat sb; 1584 1814 char *urlcopy; 1585 1815 char *urlp; 1586 1816 char *tptr; 1587 int http_major_version;1588 int ip_allowed;1589 1817 #if ENABLE_FEATURE_HTTPD_CGI 1818 static const char request_HEAD[] ALIGN1 = "HEAD"; 1590 1819 const char *prequest; 1820 char *cookie = NULL; 1821 char *content_type = NULL; 1591 1822 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 1596 1827 #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; 1598 1837 #endif 1599 1838 … … 1603 1842 1604 1843 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); 1607 1846 } 1608 1847 #if ENABLE_FEATURE_IPV6 1609 if (fromAddr-> sa.sa_family == AF_INET61610 && fromAddr-> sin6.sin6_addr.s6_addr32[0] == 01611 && fromAddr-> sin6.sin6_addr.s6_addr32[1] == 01612 && 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]); 1614 1853 #endif 1615 1854 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); 1617 1857 } 1618 1858 if (verbose) { 1619 1859 /* this trick makes -v logging much simpler */ 1620 applet_name = rmt_ip_str; 1860 if (rmt_ip_str) 1861 applet_name = rmt_ip_str; 1621 1862 if (verbose > 2) 1622 1863 bb_error_msg("connected"); 1623 1864 } 1624 1865 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); 1632 1868 1633 1869 if (!get_line()) /* EOF or error or empty line */ … … 1642 1878 prequest = request_GET; 1643 1879 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 } 1647 1886 } 1648 1887 #else … … 1655 1894 1656 1895 /* 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';) 1658 1898 tptr = strchrnul(urlp, ' '); 1659 1899 /* 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 } 1662 1904 *tptr = '\0'; 1663 1905 1664 1906 /* 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)); 1666 1908 /*if (urlcopy == NULL) 1667 1909 * send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/ … … 1670 1912 1671 1913 /* Extract url args if present */ 1914 g_query = NULL; 1672 1915 tptr = strchr(urlcopy, '?'); 1673 g_query = NULL;1674 1916 if (tptr) { 1675 1917 *tptr++ = '\0'; … … 1688 1930 /* Canonicalize path */ 1689 1931 /* 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 */ 1691 1933 urlp = tptr = urlcopy; 1692 1934 do { … … 1697 1939 } 1698 1940 if (*tptr == '.') { 1699 /* skip extra '.'*/1941 /* skip extra "/./" */ 1700 1942 if (tptr[1] == '/' || !tptr[1]) { 1701 1943 continue; 1702 1944 } 1703 /* '..': be careful */1945 /* "..": be careful */ 1704 1946 if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) { 1705 1947 ++tptr; … … 1713 1955 *++urlp = *tptr; 1714 1956 } while (*++tptr); 1715 *++urlp = '\0'; /* so keep last character */ 1716 tptr = urlp; /* end ptr */ 1957 *++urlp = '\0'; /* terminate after last character */ 1717 1958 1718 1959 /* 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)) { 1721 1962 found_moved_temporarily = urlcopy; 1722 1963 } … … 1732 1973 /* have path1/path2 */ 1733 1974 *tptr = '\0'; 1734 if (is_directory(urlcopy + 1, 1, &sb)) {1735 /* may be havingsubdir config */1975 if (is_directory(urlcopy + 1, 1, NULL)) { 1976 /* may have subdir config */ 1736 1977 parse_conf(urlcopy + 1, SUBDIR_PARSE); 1737 1978 ip_allowed = checkPermIP(); … … 1739 1980 *tptr = '/'; 1740 1981 } 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') { 1742 1990 /* Request was with "... HTTP/nXXX", and n >= 0 */ 1743 1991 1744 /* Read until blank line for HTTP version specified, else parse immediate*/1992 /* Read until blank line */ 1745 1993 while (1) { 1746 alarm(HEADER_READ_TIMEOUT);1747 1994 if (!get_line()) 1748 1995 break; /* EOF or error or empty line */ … … 1750 1997 bb_error_msg("header: '%s'", iobuf); 1751 1998 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 */ 1754 2016 if ((STRNCASECMP(iobuf, "Content-length:") == 0)) { 1755 2017 /* 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); 1758 2024 if (!tptr[0]) 1759 2025 send_headers_and_exit(HTTP_BAD_REQUEST); 1760 errno = 0;1761 2026 /* not using strtoul: it ignores leading minus! */ 1762 length = strtol(tptr, &tptr, 10);2027 length = bb_strtou(tptr, NULL, 10); 1763 2028 /* 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) 1767 2030 send_headers_and_exit(HTTP_BAD_REQUEST); 1768 2031 } 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)); 1771 2037 } 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)); 1773 2039 } else if (STRNCASECMP(iobuf, "Referer:") == 0) { 1774 referer = strdup(skip_whitespace(iobuf + sizeof("Referer:")-1));2040 referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1)); 1775 2041 } 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)); 1777 2049 } 1778 2050 #endif … … 1780 2052 if (STRNCASECMP(iobuf, "Authorization:") == 0) { 1781 2053 /* We only allow Basic credentials. 1782 * It shows up as "Authorization: Basic <user id:password>" where1783 * the userid:passwordis base64 encoded.2054 * It shows up as "Authorization: Basic <user>:<passwd>" where 2055 * "<user>:<passwd>" is base64 encoded. 1784 2056 */ 1785 2057 tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); … … 1789 2061 /* decodeBase64() skips whitespace itself */ 1790 2062 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 1794 2100 } /* while extra header reading */ 1795 2101 } 1796 2102 1797 /* We readheaders, disable peer timeout */2103 /* We are done reading headers, disable peer timeout */ 1798 2104 alarm(0); 1799 2105 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 */ 1802 2108 send_headers_and_exit(HTTP_FORBIDDEN); 1803 2109 } 1804 2110 1805 2111 #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) 1807 2117 send_headers_and_exit(HTTP_UNAUTHORIZED); 1808 }1809 2118 #endif 1810 2119 … … 1812 2121 send_headers_and_exit(HTTP_MOVED_TEMPORARILY); 1813 2122 } 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 1814 2152 1815 2153 tptr = urlcopy + 1; /* skip first '/' */ … … 1823 2161 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); 1824 2162 } 2163 #endif 2164 2165 if (urlp[-1] == '/') 2166 strcpy(urlp, index_page); 2167 if (stat(tptr, &sb) == 0) { 1825 2168 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1826 {1827 2169 char *suffix = strrchr(tptr, '.'); 1828 2170 if (suffix) { … … 1834 2176 } 1835 2177 } 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; 1848 2180 last_mod = sb.st_mtime; 1849 2181 } … … 1858 2190 } 1859 2191 } 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 1867 2204 } 1868 2205 … … 1874 2211 */ 1875 2212 #if BB_MMU 1876 static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN;2213 static void mini_httpd(int server_socket) NORETURN; 1877 2214 static void mini_httpd(int server_socket) 1878 2215 { … … 1885 2222 int n; 1886 2223 len_and_sockaddr fromAddr; 1887 2224 1888 2225 /* Wait for connections... */ 1889 2226 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); 1892 2228 if (n < 0) 1893 2229 continue; 2230 1894 2231 /* set the KEEPALIVE option to cull dead connections */ 1895 2232 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); … … 1897 2234 if (fork() == 0) { 1898 2235 /* child */ 1899 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP1900 2236 /* Do not reload config on HUP */ 1901 2237 signal(SIGHUP, SIG_IGN); 1902 #endif1903 2238 close(server_socket); 1904 2239 xmove_fd(n, 0); … … 1913 2248 } 1914 2249 #else 1915 static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN;2250 static void mini_httpd_nommu(int server_socket, int argc, char **argv) NORETURN; 1916 2251 static void mini_httpd_nommu(int server_socket, int argc, char **argv) 1917 2252 { … … 1930 2265 int n; 1931 2266 len_and_sockaddr fromAddr; 1932 2267 1933 2268 /* Wait for connections... */ 1934 2269 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); 1937 2271 if (n < 0) 1938 2272 continue; 2273 1939 2274 /* set the KEEPALIVE option to cull dead connections */ 1940 2275 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); … … 1942 2277 if (vfork() == 0) { 1943 2278 /* child */ 1944 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP1945 2279 /* Do not reload config on HUP */ 1946 2280 signal(SIGHUP, SIG_IGN); 1947 #endif1948 2281 close(server_socket); 1949 2282 xmove_fd(n, 0); … … 1964 2297 * Never returns. 1965 2298 */ 1966 static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN;2299 static void mini_httpd_inetd(void) NORETURN; 1967 2300 static void mini_httpd_inetd(void) 1968 2301 { 1969 2302 len_and_sockaddr fromAddr; 1970 2303 2304 memset(&fromAddr, 0, sizeof(fromAddr)); 1971 2305 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); 1973 2308 handle_incoming_and_exit(&fromAddr); 1974 2309 } 1975 2310 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 2311 static void sighup_handler(int sig UNUSED_PARAM) 2312 { 2313 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); 2314 } 1990 2315 1991 2316 enum { … … 1993 2318 d_opt_decode_url, 1994 2319 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 ,) 1999 2324 p_opt_port , 2000 2325 p_opt_inetd , … … 2004 2329 OPT_DECODE_URL = 1 << d_opt_decode_url, 2005 2330 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, 2010 2335 OPT_PORT = 1 << p_opt_port, 2011 2336 OPT_INETD = 1 << p_opt_inetd, … … 2015 2340 2016 2341 2017 int httpd_main(int argc, char **argv) ;2018 int httpd_main(int argc , char **argv)2342 int httpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 2343 int httpd_main(int argc UNUSED_PARAM, char **argv) 2019 2344 { 2020 2345 int server_socket = server_socket; /* for gcc */ 2021 2346 unsigned opt; 2022 2347 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;) 2027 2352 2028 2353 INIT_G(); … … 2037 2362 opt_complementary = "vv:if"; 2038 2363 /* We do not "absolutize" path given by -h (home) opt. 2039 * If user gives relative path in -h, $SCRIPT_FILENAME can end up2040 * relative too. */2364 * If user gives relative path in -h, 2365 * $SCRIPT_FILENAME will not be set. */ 2041 2366 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:") 2046 2371 "p:ifv", 2047 & configFile, &url_for_decode, &home_httpd2048 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) 2052 2377 , &bind_addr_or_port 2053 2378 , &verbose … … 2065 2390 #if ENABLE_FEATURE_HTTPD_AUTH_MD5 2066 2391 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)); 2068 2398 return 0; 2069 2399 } … … 2071 2401 #if ENABLE_FEATURE_HTTPD_SETUID 2072 2402 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); 2076 2404 } 2077 2405 #endif … … 2100 2428 } 2101 2429 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. */ 2103 2437 { 2104 2438 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): */ 2106 2440 clearenv(); 2107 2441 if (p) … … 2112 2446 #endif 2113 2447 2114 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 2448 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); 2115 2449 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); 2120 2451 2121 2452 xfunc_error_retval = 0; -
branches/2.2.9/mindi-busybox/networking/httpd_indexcgi.c
r1765 r2725 2 2 * Copyright (c) 2007 Denys Vlasenko <vda.linux@googlemail.com> 3 3 * 4 * Licensed under GPLv2, see file LICENSE in this tarball for details.4 * Licensed under GPLv2, see file LICENSE in this source tree. 5 5 */ 6 6 … … 29 29 /* Currently malloc machinery is the biggest part of libc we pull in. */ 30 30 /* 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): 32 33 * text data bss dec hex filename 33 34 * 13036 44 3052 16132 3f04 index.cgi … … 126 127 if (buffer + (BUFFER_SIZE-HEADROOM) - dst >= size) 127 128 return; 128 write( 1, buffer, dst - buffer);129 write(STDOUT_FILENO, buffer, dst - buffer); 129 130 dst = buffer; 130 131 } … … 149 150 *dst = c; 150 151 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 */ 152 153 && !strchr("._-+@", c) 153 154 ) { … … 211 212 } 212 213 213 int main( void)214 int main(int argc, char *argv[]) 214 215 { 215 216 dir_list_t *dir_list; … … 226 227 if (!QUERY_STRING 227 228 || QUERY_STRING[0] != '/' 229 || strstr(QUERY_STRING, "//") 228 230 || strstr(QUERY_STRING, "/../") 229 231 || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0 … … 290 292 cdir = dir_list; 291 293 while (dir_list_count--) { 292 struct tm * tm;294 struct tm *ptm; 293 295 294 296 if (S_ISDIR(cdir->dl_mode)) { … … 314 316 fmt_ull(cdir->dl_size); 315 317 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); 323 325 *dst++ = '\n'; 324 326 -
branches/2.2.9/mindi-busybox/networking/ifconfig.c
r1765 r2725 11 11 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> 12 12 * 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. 14 14 */ 15 15 … … 37 37 #include <netinet/if_ether.h> 38 38 #endif 39 #include "libbb.h" 39 40 #include "inet_common.h" 40 #include "libbb.h"41 41 42 42 #if ENABLE_FEATURE_IFCONFIG_SLIP … … 165 165 struct arg1opt { 166 166 const char *name; 167 int selector;167 unsigned short selector; 168 168 unsigned short ifr_offset; 169 169 }; … … 184 184 185 185 static 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) }, 196 196 #ifdef SIOCSKEEPALIVE 197 { "SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},197 { "SKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data) }, 198 198 #endif 199 199 #ifdef SIOCSOUTFILL 200 { "SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)},200 { "SOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data) }, 201 201 #endif 202 202 #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) }, 206 206 #endif 207 207 /* Last entry if for unmatched (possibly hostname) arg. */ 208 208 #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) }, 213 213 }; 214 214 215 215 static 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 }, 226 226 #ifdef SIOCSKEEPALIVE 227 { "keepalive", N_ARG, ARG_KEEPALIVE, 0},227 { "keepalive", N_ARG, ARG_KEEPALIVE, 0 }, 228 228 #endif 229 229 #ifdef SIOCSOUTFILL 230 { "outfill", N_ARG, ARG_OUTFILL, 0},230 { "outfill", N_ARG, ARG_OUTFILL, 0 }, 231 231 #endif 232 232 #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 }, 236 236 #endif 237 237 #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) } 250 250 }; 251 251 … … 253 253 * A couple of prototypes. 254 254 */ 255 256 255 #if ENABLE_FEATURE_IFCONFIG_HW 257 256 static int in_ether(const char *bufp, struct sockaddr *sap); … … 261 260 * Our main function. 262 261 */ 263 264 int ifconfig_main(int argc, char **argv); 265 int ifconfig_main(int argc, char **argv) 262 int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 263 int ifconfig_main(int argc UNUSED_PARAM, char **argv) 266 264 { 267 265 struct ifreq ifr; … … 294 292 /* skip argv[0] */ 295 293 ++argv; 296 --argc;297 294 298 295 #if ENABLE_FEATURE_IFCONFIG_STATUS 299 if (arg c > 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])) { 300 297 interface_opt_a = 1; 301 --argc;302 298 ++argv; 303 299 } 304 300 #endif 305 301 306 if ( argc <= 1) {302 if (!argv[0] || !argv[1]) { /* one or no args */ 307 303 #if ENABLE_FEATURE_IFCONFIG_STATUS 308 return display_interfaces(arg c ? *argv : NULL);304 return display_interfaces(argv[0] /* can be NULL */); 309 305 #else 310 306 bb_error_msg_and_die("no support for status display"); … … 316 312 317 313 /* get interface name */ 318 s afe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);314 strncpy_IFNAMSIZ(ifr.ifr_name, *argv); 319 315 320 316 /* Process the remaining arguments. */ … … 375 371 sai.sin_family = AF_INET; 376 372 sai.sin_port = 0; 377 if ( !strcmp(host, bb_str_default)) {373 if (strcmp(host, "default") == 0) { 378 374 /* Default is special, meaning 0.0.0.0. */ 379 375 sai.sin_addr.s_addr = INADDR_ANY; … … 393 389 lsa = xhost2sockaddr(host, 0); 394 390 #if ENABLE_FEATURE_IPV6 395 if (lsa-> sa.sa_family == AF_INET6) {391 if (lsa->u.sa.sa_family == AF_INET6) { 396 392 int sockfd6; 397 393 struct in6_ifreq ifr6; 398 394 399 395 memcpy((char *) &ifr6.ifr6_addr, 400 (char *) &(lsa-> sin6.sin6_addr),396 (char *) &(lsa->u.sin6.sin6_addr), 401 397 sizeof(struct in6_addr)); 402 398 … … 406 402 ifr6.ifr6_ifindex = ifr.ifr_ifindex; 407 403 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); 409 405 if (ENABLE_FEATURE_CLEAN_UP) 410 406 free(lsa); … … 412 408 } 413 409 #endif 414 sai.sin_addr = lsa-> sin.sin_addr;410 sai.sin_addr = lsa->u.sin.sin_addr; 415 411 if (ENABLE_FEATURE_CLEAN_UP) 416 412 free(lsa); … … 426 422 } else { /* A_CAST_HOST_COPY_IN_ETHER */ 427 423 /* 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) 429 427 bb_show_usage(); 430 428 /*safe_strncpy(host, *argv, sizeof(host));*/ 431 429 host = *argv; 432 if ( in_ether(host, &sa))430 if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa)) 433 431 bb_error_msg_and_die("invalid hw-addr %s", host); 434 432 p = (char *) &sa; … … 458 456 } 459 457 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); 461 459 #ifdef QUESTIONABLE_ALIAS_CASE 462 460 if (mask & A_COLON_CHK) { … … 507 505 508 506 sap->sa_family = ARPHRD_ETHER; 509 ptr = sap->sa_data;507 ptr = (char *) sap->sa_data; 510 508 511 509 i = 0; -
branches/2.2.9/mindi-busybox/networking/ifupdown.c
r1765 r2725 2 2 /* 3 3 * ifupdown for busybox 4 * Copyright (c) 2002 Glenn McGrath <bug1@iinet.net.au>4 * Copyright (c) 2002 Glenn McGrath 5 5 * Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org> 6 6 * … … 15 15 * configuration. 16 16 * 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. 18 18 */ 19 19 20 #include "libbb.h" 21 /* After libbb.h, since it needs sys/types.h on some systems */ 20 22 #include <sys/utsname.h> 21 23 #include <fnmatch.h> 22 #include <getopt.h>23 24 #include "libbb.h"25 24 26 25 #define MAX_OPT_DEPTH 10 … … 33 32 #endif 34 33 34 #define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS 35 35 36 #define debug_noise(args...) /*fprintf(stderr, args)*/ 36 37 … … 42 43 struct method_t { 43 44 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; 46 47 }; 47 48 … … 87 88 }; 88 89 89 #define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:" 90 91 #define OPTION_STR "anvf" IF_FEATURE_IFUPDOWN_MAPPING("m") "i:" 90 92 enum { 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, 95 97 OPT_no_mappings = 0x10, 96 98 }; 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) 101 103 #define NO_MAPPINGS (option_mask32 & OPT_no_mappings) 102 104 103 static char **my_environ; 104 105 static const char *startup_PATH; 105 106 struct 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 106 113 107 114 #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 … … 126 133 127 134 if (i == 0) 128 return - r[llen];135 return - (unsigned char)r[llen]; 129 136 return i; 130 137 } … … 135 142 136 143 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; 145 155 } 146 156 if (strncmpz(id, "label", idlen) == 0) { … … 155 165 } 156 166 157 # if ENABLE_FEATURE_IFUPDOWN_IP167 # if ENABLE_FEATURE_IFUPDOWN_IP 158 168 static int count_netmask_bits(const char *dotted_quad) 159 169 { … … 186 196 return result; 187 197 } 188 # endif198 # endif 189 199 190 200 static char *parse(const char *command, struct interface_defn_t *ifd) … … 249 259 250 260 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 251 269 addstr(&result, varvalue, strlen(varvalue)); 252 270 } else { 253 # if ENABLE_FEATURE_IFUPDOWN_IP271 # if ENABLE_FEATURE_IFUPDOWN_IP 254 272 /* Sigh... Add a special case for 'ip' to convert from 255 273 * dotted quad to bit count style netmasks. */ … … 267 285 } 268 286 } 269 # endif287 # endif 270 288 okay[opt_depth - 1] = 0; 271 289 } … … 312 330 return 1; 313 331 } 314 #endif 332 333 #endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */ 334 315 335 316 336 #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 338 static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec) 339 { 340 # if ENABLE_FEATURE_IFUPDOWN_IP 320 341 int result; 321 342 result = execute("ip addr add ::1 dev %iface%", ifd, exec); 322 343 result += execute("ip link set %iface% up", ifd, exec); 323 344 return ((result == 2) ? 2 : 0); 324 # else345 # else 325 346 return execute("ifconfig %iface% add ::1", ifd, exec); 326 # endif327 } 328 329 static int loopback_down6(struct interface_defn_t *ifd, execfn *exec)330 { 331 # if ENABLE_FEATURE_IFUPDOWN_IP347 # endif 348 } 349 350 static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec) 351 { 352 # if ENABLE_FEATURE_IFUPDOWN_IP 332 353 return execute("ip link set %iface% down", ifd, exec); 333 # else354 # else 334 355 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 359 static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) 360 { 361 return 1; 362 } 363 364 static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec) 339 365 { 340 366 int result; 341 # if ENABLE_FEATURE_IFUPDOWN_IP367 # if ENABLE_FEATURE_IFUPDOWN_IP 342 368 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); 343 result += execute("ip link set[[ mtu %mtu%]][[ addr ess%hwaddress%]] %iface% up", ifd, exec);369 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 344 370 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ 345 371 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); 346 # else372 # else 347 373 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); 348 374 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); 349 375 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); 350 # endif376 # endif 351 377 return ((result == 3) ? 3 : 0); 352 378 } 353 379 354 static int static_down6(struct interface_defn_t *ifd, execfn *exec)355 { 356 # if ENABLE_FEATURE_IFUPDOWN_IP380 static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec) 381 { 382 # if ENABLE_FEATURE_IFUPDOWN_IP 357 383 return execute("ip link set %iface% down", ifd, exec); 358 # else384 # else 359 385 return execute("ifconfig %iface% down", ifd, exec); 360 # endif361 } 362 363 # if ENABLE_FEATURE_IFUPDOWN_IP364 static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)386 # endif 387 } 388 389 # if ENABLE_FEATURE_IFUPDOWN_IP 390 static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec) 365 391 { 366 392 int result; … … 373 399 } 374 400 375 static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)401 static int FAST_FUNC v4tunnel_down(struct interface_defn_t * ifd, execfn * exec) 376 402 { 377 403 return execute("ip tunnel del %iface%", ifd, exec); 378 404 } 379 # endif405 # endif 380 406 381 407 static 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 , }, 387 414 }; 388 415 … … 392 419 methods6 393 420 }; 421 394 422 #endif /* FEATURE_IFUPDOWN_IPV6 */ 395 423 424 396 425 #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 427 static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec) 428 { 429 # if ENABLE_FEATURE_IFUPDOWN_IP 400 430 int result; 401 431 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec); 402 432 result += execute("ip link set %iface% up", ifd, exec); 403 433 return ((result == 2) ? 2 : 0); 404 # else434 # else 405 435 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec); 406 # endif407 } 408 409 static int loopback_down(struct interface_defn_t *ifd, execfn *exec)410 { 411 # if ENABLE_FEATURE_IFUPDOWN_IP436 # endif 437 } 438 439 static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec) 440 { 441 # if ENABLE_FEATURE_IFUPDOWN_IP 412 442 int result; 413 443 result = execute("ip addr flush dev %iface%", ifd, exec); 414 444 result += execute("ip link set %iface% down", ifd, exec); 415 445 return ((result == 2) ? 2 : 0); 416 # else446 # else 417 447 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec); 418 # endif419 } 420 421 static int static_up(struct interface_defn_t *ifd, execfn *exec)448 # endif 449 } 450 451 static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) 422 452 { 423 453 int result; 424 # if ENABLE_FEATURE_IFUPDOWN_IP454 # if ENABLE_FEATURE_IFUPDOWN_IP 425 455 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " 426 456 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); 427 result += execute("ip link set[[ mtu %mtu%]][[ addr ess%hwaddress%]] %iface% up", ifd, exec);457 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 428 458 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); 429 459 return ((result == 3) ? 3 : 0); 430 # else460 # else 431 461 /* ifconfig said to set iface up before it processes hw %hwaddress%, 432 462 * which then of course fails. Thus we run two separate ifconfig */ … … 438 468 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); 439 469 return ((result == 3) ? 3 : 0); 440 # endif441 } 442 443 static int static_down(struct interface_defn_t *ifd, execfn *exec)470 # endif 471 } 472 473 static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec) 444 474 { 445 475 int result; 446 # if ENABLE_FEATURE_IFUPDOWN_IP476 # if ENABLE_FEATURE_IFUPDOWN_IP 447 477 result = execute("ip addr flush dev %iface%", ifd, exec); 448 478 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; 451 484 result += execute("ifconfig %iface% down", ifd, exec); 452 # endif485 # endif 453 486 return ((result == 2) ? 2 : 0); 454 487 } 455 488 456 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 457 struct dhcp_client_t 458 { 489 # if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 490 struct dhcp_client_t { 459 491 const char *name; 460 492 const char *startcmd; … … 464 496 static const struct dhcp_client_t ext_dhcp_clients[] = { 465 497 { "dhcpcd", 466 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %client id%]][[ -l %leasetime%]] %iface%",498 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %client%]][[ -l %leasetime%]] %iface%", 467 499 "dhcpcd -k %iface%", 468 500 }, … … 476 508 }, 477 509 { "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%]]", 479 512 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", 480 513 }, 481 514 }; 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 inti;488 # if ENABLE_FEATURE_IFUPDOWN_IP515 # endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ 516 517 # if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 518 static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) 519 { 520 unsigned i; 521 # if ENABLE_FEATURE_IFUPDOWN_IP 489 522 /* 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)) 491 524 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 493 530 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { 494 531 if (exists_execable(ext_dhcp_clients[i].name)) … … 497 534 bb_error_msg("no dhcp clients found"); 498 535 return 0; 499 #elif ENABLE_APP_UDHCPC 500 #if ENABLE_FEATURE_IFUPDOWN_IP 536 } 537 # elif ENABLE_UDHCPC 538 static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) 539 { 540 # if ENABLE_FEATURE_IFUPDOWN_IP 501 541 /* 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)) 503 543 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%]]", 507 551 ifd, exec); 508 #else 552 } 553 # else 554 static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM, 555 execfn *exec UNUSED_PARAM) 556 { 509 557 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 562 static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) 563 { 564 int result = 0; 565 unsigned i; 566 517 567 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 585 static 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 602 static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM, 603 execfn *exec UNUSED_PARAM) 604 { 527 605 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 609 static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) 532 610 { 533 611 return 1; 534 612 } 535 613 536 static int bootp_up(struct interface_defn_t *ifd, execfn *exec)614 static int FAST_FUNC bootp_up(struct interface_defn_t *ifd, execfn *exec) 537 615 { 538 616 return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%" … … 541 619 } 542 620 543 static int ppp_up(struct interface_defn_t *ifd, execfn *exec)621 static int FAST_FUNC ppp_up(struct interface_defn_t *ifd, execfn *exec) 544 622 { 545 623 return execute("pon[[ %provider%]]", ifd, exec); 546 624 } 547 625 548 static int ppp_down(struct interface_defn_t *ifd, execfn *exec)626 static int FAST_FUNC ppp_down(struct interface_defn_t *ifd, execfn *exec) 549 627 { 550 628 return execute("poff[[ %provider%]]", ifd, exec); 551 629 } 552 630 553 static int wvdial_up(struct interface_defn_t *ifd, execfn *exec)631 static int FAST_FUNC wvdial_up(struct interface_defn_t *ifd, execfn *exec) 554 632 { 555 633 return execute("start-stop-daemon --start -x wvdial " … … 557 635 } 558 636 559 static int wvdial_down(struct interface_defn_t *ifd, execfn *exec)637 static int FAST_FUNC wvdial_down(struct interface_defn_t *ifd, execfn *exec) 560 638 { 561 639 return execute("start-stop-daemon --stop -x wvdial " … … 564 642 565 643 static 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 , }, 573 651 }; 574 652 … … 579 657 }; 580 658 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 */ 583 665 static char *next_word(char **buf) 584 666 { 585 unsigned shortlength;667 unsigned length; 586 668 char *word; 587 588 if (!buf || !*buf || !**buf) {589 return NULL;590 }591 669 592 670 /* Skip over leading whitespace */ 593 671 word = skip_whitespace(*buf); 594 672 595 /* S kip over comments*/596 if (*word == ' #') {673 /* Stop on EOL */ 674 if (*word == '\0') 597 675 return NULL; 598 } 599 600 /* Find the length of this word */ 676 677 /* Find the length of this word (can't be 0) */ 601 678 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); 611 685 612 686 return word; … … 634 708 if (!name) 635 709 return NULL; 636 710 /* TODO: use index_in_str_array() */ 637 711 for (i = 0; i < af->n_methods; i++) { 638 712 if (strcmp(af->method[i].name, name) == 0) { … … 643 717 } 644 718 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 659 719 static struct interfaces_file_t *read_interfaces(const char *filename) 660 720 { 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 */ 661 735 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 662 736 struct mapping_defn_t *currmap = NULL; … … 665 739 struct interfaces_file_t *defn; 666 740 FILE *f; 667 char *firstword;668 741 char *buf; 669 742 char *first_word; 743 char *rest_of_line; 670 744 enum { NONE, IFACE, MAPPING } currently_processing = NONE; 671 745 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); 681 759 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) { 686 772 #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;*/ 701 783 { 702 784 struct mapping_defn_t **where = &defn->mappings; … … 705 787 } 706 788 *where = currmap; 707 currmap->next = NULL;789 /*currmap->next = NULL;*/ 708 790 } 709 791 debug_noise("Added mapping\n"); 710 792 #endif 711 793 currently_processing = MAPPING; 712 } else if (strcmp(first word, "iface") == 0) {794 } else if (strcmp(first_word, "iface") == 0) { 713 795 static const struct address_family_t *const addr_fams[] = { 714 796 #if ENABLE_FEATURE_IFUPDOWN_IPV4 … … 720 802 NULL 721 803 }; 722 723 804 char *iface_name; 724 805 char *address_family_name; … … 726 807 llist_t *iface_list; 727 808 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); 737 816 738 817 /* 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); 745 822 746 823 currif->iface = xstrdup(iface_name); 747 824 748 825 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); 753 828 754 829 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); 759 832 760 833 for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) { 761 834 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); 766 839 } 767 840 } … … 770 843 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name); 771 844 currently_processing = IFACE; 772 } else if (strcmp(first word, "auto") == 0) {773 while ((first word = next_word(&buf_ptr)) != NULL) {845 } else if (strcmp(first_word, "auto") == 0) { 846 while ((first_word = next_word(&rest_of_line)) != NULL) { 774 847 775 848 /* Check the interface isnt already listed */ 776 if ( find_list_string(defn->autointerfaces, firstword)) {849 if (llist_find_str(defn->autointerfaces, first_word)) { 777 850 bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf); 778 851 } 779 852 780 853 /* Add the interface to the list */ 781 llist_add_to_end(&(defn->autointerfaces), xstrdup(first word));782 debug_noise("\nauto %s\n", first word);854 llist_add_to_end(&(defn->autointerfaces), xstrdup(first_word)); 855 debug_noise("\nauto %s\n", first_word); 783 856 } 784 857 currently_processing = NONE; … … 786 859 switch (currently_processing) { 787 860 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 ) { 789 869 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); 794 873 } 795 796 if (strcmp(firstword, "up") != 0797 && strcmp(firstword, "down") != 0798 && strcmp(firstword, "pre-up") != 0799 && 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 }807 874 } 808 875 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); 827 883 currif->n_options++; 828 884 break; 829 885 case MAPPING: 830 886 #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); 837 896 } 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)); 844 898 currmap->n_mappings++; 845 899 } else { 846 bb_error_msg("misplaced option \"%s\"", buf); 847 return NULL; 900 bb_error_msg_and_die("misplaced option \"%s\"", buf); 848 901 } 849 902 #endif … … 851 904 case NONE: 852 905 default: 853 bb_error_msg("misplaced option \"%s\"", buf); 854 return NULL; 906 bb_error_msg_and_die("misplaced option \"%s\"", buf); 855 907 } 856 908 } 857 909 free(buf); 858 } 910 } /* while (fgets) */ 911 859 912 if (ferror(f) != 0) { 860 913 /* ferror does NOT set errno! */ … … 869 922 { 870 923 char *result; 871 char *here; 872 char *there; 924 char *dst; 925 char *src; 926 char c; 873 927 874 928 result = xasprintf(format, name, value); 875 929 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); 888 939 889 940 return result; … … 892 943 static void set_environ(struct interface_defn_t *iface, const char *mode) 893 944 { 894 char **environend;895 945 int i; 896 c onst 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; 908 958 909 959 for (i = 0; i < iface->n_options; i++) { … … 915 965 continue; 916 966 } 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); 925 976 } 926 977 … … 934 985 int status; 935 986 936 fflush (NULL);937 child = fork();987 fflush_all(); 988 child = vfork(); 938 989 switch (child) { 939 990 case -1: /* failure */ 940 991 return 0; 941 992 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); 946 997 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 947 998 return 0; … … 994 1045 995 1046 #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]; 1047 static int popen2(FILE **in, FILE **out, char *command, char *param) 1048 { 1049 char *argv[3] = { command, param, NULL }; 1050 struct fd_pair infd, outfd; 1002 1051 pid_t pid; 1003 1052 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 1076 static char *run_mapping(char *physical, struct mapping_defn_t *map) 1050 1077 { 1051 1078 FILE *in, *out; … … 1055 1082 char *logical = xstrdup(physical); 1056 1083 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); 1063 1086 1064 1087 /* Write mappings to stdin of mapping script. */ … … 1067 1090 } 1068 1091 fclose(in); 1069 waitpid(pid, &status, 0);1092 safe_waitpid(pid, &status, 0); 1070 1093 1071 1094 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { … … 1073 1096 * grab a line of output and use that as the name of the 1074 1097 * 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) { 1078 1101 /* If we are able to read a line of output from the script, 1079 1102 * remove any trailing whitespace and use this value … … 1086 1109 free(logical); 1087 1110 logical = new_logical; 1088 } else {1089 /* If we are UNABLE to read a line of output, discard our1090 * freshly allocated memory. */1091 free(new_logical);1092 1111 } 1093 1112 } … … 1101 1120 static llist_t *find_iface_state(llist_t *state_list, const char *iface) 1102 1121 { 1103 unsigned shortiface_len = strlen(iface);1122 unsigned iface_len = strlen(iface); 1104 1123 llist_t *search = state_list; 1105 1124 1106 1125 while (search) { 1107 1126 if ((strncmp(search->data, iface, iface_len) == 0) 1108 && (search->data[iface_len] == '=')) { 1127 && (search->data[iface_len] == '=') 1128 ) { 1109 1129 return search; 1110 1130 } … … 1118 1138 { 1119 1139 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); 1121 1141 1122 1142 if (state_fp) { … … 1134 1154 1135 1155 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;1156 int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1157 int ifupdown_main(int argc UNUSED_PARAM, char **argv) 1158 { 1159 int (*cmds)(struct interface_defn_t *); 1140 1160 struct interfaces_file_t *defn; 1141 1161 llist_t *target_list = NULL; … … 1143 1163 bool any_failures = 0; 1144 1164 1165 INIT_G(); 1166 1167 G.startup_PATH = getenv("PATH"); 1168 1145 1169 cmds = iface_down; 1146 1170 if (applet_name[2] == 'u') { … … 1150 1174 1151 1175 getopt32(argv, OPTION_STR, &interfaces); 1152 if (argc - optind > 0) { 1176 argv += optind; 1177 if (argv[0]) { 1153 1178 if (DO_ALL) bb_show_usage(); 1154 1179 } else { … … 1159 1184 defn = read_interfaces(interfaces); 1160 1185 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 = "";1168 1186 1169 1187 /* Create a list of interfaces to work on */ … … 1171 1189 target_list = defn->autointerfaces; 1172 1190 } else { 1173 llist_add_to_end(&target_list, argv[ optind]);1191 llist_add_to_end(&target_list, argv[0]); 1174 1192 } 1175 1193 … … 1182 1200 char *pch; 1183 1201 bool okay = 0; 1184 unsignedcmds_ret;1202 int cmds_ret; 1185 1203 1186 1204 iface = xstrdup(target_list->data); … … 1260 1278 } 1261 1279 if (VERBOSE) { 1262 puts("");1280 bb_putchar('\n'); 1263 1281 } 1264 1282 … … 1288 1306 1289 1307 /* Actually write the new state */ 1290 state_fp = xfopen (CONFIG_IFUPDOWN_IFSTATE_PATH, "w");1308 state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH); 1291 1309 state = state_list; 1292 1310 while (state) { -
branches/2.2.9/mindi-busybox/networking/inetd.c
r1772 r2725 4 4 /* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */ 5 5 /* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */ 6 /* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */ 6 7 /* 7 8 * Copyright (c) 1983,1991 The Regents of the University of California. … … 39 40 /* Inetd - Internet super-server 40 41 * 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 43 45 * connection is made, by creating a process. This process 44 46 * is passed the connection as file descriptor 0 and is 45 * expected to do a getpeername to find out the sourcehost47 * expected to do a getpeername to find out peer's host 46 48 * and port. 47 *48 49 * Datagram oriented services are invoked when a datagram 49 50 * 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. 56 53 * 57 54 * Inetd uses a configuration file which is read at startup … … 61 58 * a space or tab. All fields must be present in each entry. 62 59 * 63 * service 64 * socket 60 * service_name must be in /etc/services 61 * socket_type stream/dgram/raw/rdm/seqpacket 65 62 * protocol must be in /etc/protocols 63 * (usually "tcp" or "udp") 66 64 * wait/nowait[.max] single-threaded/multi-threaded, max # 67 65 * user[.group] or user[:group] user/group to run daemon as 68 * server 69 * server programarguments maximum of MAXARGS (20)66 * server_program full path name 67 * server_program_arguments maximum of MAXARGS (20) 70 68 * 71 69 * For RPC services 72 * service 73 * socket 74 * protocol must be in /etc/protocols70 * service_name/version must be in /etc/rpc 71 * socket_type stream/dgram/raw/rdm/seqpacket 72 * rpc/protocol "rpc/tcp" etc 75 73 * wait/nowait[.max] single-threaded/multi-threaded 76 74 * user[.group] or user[:group] user to run daemon as 77 * server 78 * server programarguments maximum of MAXARGS (20)75 * server_program full path name 76 * server_program_arguments maximum of MAXARGS (20) 79 77 * 80 78 * For non-RPC services, the "service name" can be of the form 81 79 * hostaddress:servicename, in which case the hostaddress is used 82 80 * 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. 84 82 * 85 83 * A line can also consist of just … … 102 100 * specifiers are different. 103 101 * 104 * Comment lines are indicated by a `#' in column 1.102 * Comment lines are indicated by a '#' in column 1. 105 103 */ 106 104 … … 121 119 * for new service requests to spawn new servers. Datagram servers which 122 120 * 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) 124 122 * utilities are both examples of the latter type of datagram server. The 125 123 * tftpd(8) utility is an example of a multi-threaded datagram server. … … 135 133 */ 136 134 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: 141 144 * 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) 145 147 * setuid() 146 * 147 * 2) set-group-option on. 148 * 148 * 2) group is specified: 149 149 * a) user = root: setgid(specified group) 150 150 * NO initgroups() 151 151 * 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) 155 154 * setuid() 156 155 */ 157 156 158 #include "libbb.h"159 157 #include <syslog.h> 160 158 #include <sys/un.h> 161 159 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" 169 161 170 162 #if ENABLE_FEATURE_INETD_RPC … … 173 165 #endif 174 166 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 177 173 178 174 #define _PATH_INETDPID "/var/run/inetd.pid" 179 175 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 182 180 183 181 #ifndef RLIMIT_NOFILE … … 191 189 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ 192 190 #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 200 typedef 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]" */ 218 209 #if ENABLE_FEATURE_INETD_RPC 219 210 int se_rpcprog; /* rpc program number */ 220 int se_rpcver sl;/* rpc program lowest version */221 int se_rpcver sh;/* rpc program highest version */222 #define is rpcservice(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) 223 214 #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 */ 228 227 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 */ 234 235 #define MAXARGV 20 235 236 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_IPV6241 struct sockaddr_in6 se_un_ctrladdr_in6;242 #endif243 struct sockaddr_un se_un_ctrladdr_un;244 } se_un; /* bound address */245 #define se_ctrladdr se_un.se_un_ctrladdr246 #define se_ctrladdr_in se_un.se_un_ctrladdr_in247 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6248 #define se_ctrladdr_un se_un.se_un_ctrladdr_un249 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;254 237 } servtab_t; 255 238 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 242 static void FAST_FUNC echo_stream(int, servtab_t *); 243 static void FAST_FUNC echo_dg(int, servtab_t *); 244 #endif 245 /* Internet /dev/null */ 246 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 247 static void FAST_FUNC discard_stream(int, servtab_t *); 248 static 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 252 static void FAST_FUNC machtime_stream(int, servtab_t *); 253 static void FAST_FUNC machtime_dg(int, servtab_t *); 254 #endif 255 /* Return human-readable time */ 256 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 257 static void FAST_FUNC daytime_stream(int, servtab_t *); 258 static void FAST_FUNC daytime_dg(int, servtab_t *); 259 #endif 260 /* Familiar character generator */ 261 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 262 static void FAST_FUNC chargen_stream(int, servtab_t *); 263 static void FAST_FUNC chargen_dg(int, servtab_t *); 264 #endif 265 259 266 struct 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; 265 272 }; 266 267 /* Echo received data */268 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO269 static void echo_stream(int, servtab_t *);270 static void echo_dg(int, servtab_t *);271 #endif272 /* Internet /dev/null */273 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD274 static void discard_stream(int, servtab_t *);275 static void discard_dg(int, servtab_t *);276 #endif277 /* Return 32 bit time since 1900 */278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME279 static void machtime_stream(int, servtab_t *);280 static void machtime_dg(int, servtab_t *);281 #endif282 /* Return human-readable time */283 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME284 static void daytime_stream(int, servtab_t *);285 static void daytime_dg(int, servtab_t *);286 #endif287 /* Familiar character generator */288 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN289 static void chargen_stream(int, servtab_t *);290 static void chargen_dg(int, servtab_t *);291 #endif292 273 293 274 static const struct builtin builtins[] = { 294 275 #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 }, 298 277 #endif 299 278 #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 }, 303 283 #endif 304 284 #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 }, 308 286 #endif 309 287 #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 293 struct 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; 314 308 #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) 318 enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) }; 319 struct BUG_G_too_big { 320 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 320 321 }; 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 347 static void maybe_close(int fd) 348 { 349 if (fd >= 0) 350 close(fd); 351 } 352 353 // TODO: move to libbb? 354 static 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 372 static void rearm_alarm(void) 373 { 374 if (!alarm_armed) { 375 alarm_armed = 1; 376 alarm(RETRYTIME); 377 } 378 } 379 380 static 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 389 static void restore_sigmask(sigset_t *m) 390 { 391 sigprocmask(SIG_SETMASK, m, NULL); 365 392 } 366 393 … … 370 397 int n; 371 398 struct sockaddr_in ir_sin; 372 struct protoent *pp;373 399 socklen_t size; 374 400 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"); 377 404 return; 378 405 } 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 416 static 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 427 static 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 450 static void remove_fd_from_set(int fd) 451 { 452 if (fd >= 0) { 453 FD_CLR(fd, &allsock); 454 maxsock = -1; 455 } 456 } 457 458 static 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 470 static 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 487 static 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", 382 534 sep->se_service, sep->se_proto); 535 close(fd); 536 rearm_alarm(); 383 537 return; 384 538 } 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 546 static 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 556 static void close_config_file(void) 557 { 558 if (parser) { 559 config_close(parser); 560 parser = NULL; 561 } 562 } 563 564 static void free_servtab_strings(servtab_t *cp) 407 565 { 408 566 int i; 409 567 410 free(cp->se_ hostaddr);568 free(cp->se_local_hostname); 411 569 free(cp->se_service); 412 570 free(cp->se_proto); 413 571 free(cp->se_user); 414 572 free(cp->se_group); 415 free(cp->se_server); 573 free(cp->se_lsa); /* not a string in fact */ 574 free(cp->se_program); 416 575 for (i = 0; i < MAXARGV; i++) 417 576 free(cp->se_argv[i]); 418 577 } 419 578 420 static int bump_nofile(void)421 {422 #define FD_CHUNK 32423 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_RPC459 if (isrpcservice(sep)) {460 struct passwd *pwd;461 462 /*463 * for RPC services, attempt to use a reserved port464 * 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 } else486 #endif487 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_bufsiz1514 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 567 579 static servtab_t *new_servtab(void) 568 580 { 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 586 static servtab_t *dup_servtab(servtab_t *sep) 573 587 { 574 588 servtab_t *newtab; … … 576 590 577 591 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); 596 599 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 */ 599 604 600 605 return newtab; 601 606 } 602 607 603 static servtab_t *getconfigent(void) 604 { 608 /* gcc generates much more code if this is inlined */ 609 static servtab_t *parse_one_line(void) 610 { 611 int argc; 612 char *token[6+MAXARGV]; 613 char *p, *arg; 614 char *hostdelim; 605 615 servtab_t *sep; 606 int argc;607 char *cp, *arg;608 char *hostdelim;609 616 servtab_t *nsep; 610 servtab_t *psep; 611 617 new: 612 618 sep = new_servtab(); 613 614 /* memset(sep, 0, sizeof *sep); */615 619 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); 621 623 return NULL; 622 624 } 623 625 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]; 632 629 hostdelim = strrchr(arg, ':'); 633 630 if (hostdelim) { 634 631 *hostdelim = '\0'; 635 sep->se_ hostaddr= xstrdup(arg);632 sep->se_local_hostname = xstrdup(arg); 636 633 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; 648 640 } 649 641 } 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) { 671 675 sep->se_family = AF_UNIX; 672 676 } else { 677 char *six; 673 678 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) { 675 681 #if ENABLE_FEATURE_IPV6 682 *six = '\0'; 676 683 sep->se_family = AF_INET6; 677 684 #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) { 681 690 #if ENABLE_FEATURE_INETD_RPC 682 char *p, *ccp; 683 long l; 684 691 unsigned n; 692 arg += 4; 685 693 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; 689 697 } 690 698 *p++ = '\0'; 691 l = strtol(p, &ccp,0);692 if ( ccp == p || l < 0 || l> INT_MAX) {693 bad afterall: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; 696 704 } 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; 706 715 #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; 708 718 #endif 709 719 } 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]); 727 749 arg = strchr(sep->se_user, '.'); 728 750 if (arg == NULL) … … 732 754 sep->se_group = xstrdup(arg); 733 755 } 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 } 761 777 #endif 762 778 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. */ 782 809 *hostdelim++ = '\0'; 783 nsep->se_hostaddr = xstrdup(hostdelim); 784 810 nsep->se_local_hostname = xstrdup(hostdelim); 785 811 nsep->se_next = sep->se_next; 786 812 sep->se_next = nsep; 787 813 } 788 814 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 :( */ 859 818 860 819 return sep; 861 820 } 862 821 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) 822 static servtab_t *insert_in_servlist(servtab_t *cp) 872 823 { 873 824 servtab_t *sep; … … 875 826 876 827 sep = new_servtab(); 877 *sep = *cp; 828 *sep = *cp; /* struct copy */ 878 829 sep->se_fd = -1; 879 830 #if ENABLE_FEATURE_INETD_RPC 880 831 sep->se_rpcprog = -1; 881 832 #endif 882 Block_Using_Signals(omask);883 sep->se_next = serv tab;884 serv tab= 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); 886 837 return sep; 887 838 } 888 839 889 static int matchconf(servtab_t *old, servtab_t *new) 890 { 840 static 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; 891 844 if (strcmp(old->se_service, new->se_service) != 0) 892 845 return 0; 893 894 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)895 return 0;896 897 846 if (strcmp(old->se_proto, new->se_proto) != 0) 898 847 return 0; 899 900 /*901 * If the new servtab is bound to a specific address, check that the902 * old servtab is bound to the same entry. If the new service is not903 * bound to a specific address then the check of se_hostaddr above904 * 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_IPV6914 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 #endif920 848 return 1; 921 849 } 922 850 923 static void config(int sig ATTRIBUTE_UNUSED)851 static void reread_config_file(int sig UNUSED_PARAM) 924 852 { 925 853 servtab_t *sep, *cp, **sepp; 854 len_and_sockaddr *lsa; 926 855 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) 935 863 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) 940 871 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 { 943 881 int i; 944 882 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); 964 905 for (i = 0; i < MAXARGV; i++) 965 SWAP(char 906 SWAP(char*, sep->se_argv[i], cp->se_argv[i]); 966 907 #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); 968 927 #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) { 1007 933 bb_error_msg("%s: unknown rpc service", sep->se_service); 1008 goto serv_unknown;934 goto next_cp; 1009 935 } 1010 936 sep->se_rpcprog = rp->r_number; 1011 937 } 1012 938 if (sep->se_fd == -1) 1013 setup(sep);939 prepare_socket_fd(sep); 1014 940 if (sep->se_fd != -1) 1015 941 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; 1032 957 } 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; 1041 971 } 1042 if (sep->se_fd == -1)1043 setup(sep);1044 972 } 1045 973 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); 1100 988 } 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; 1118 1002 while ((sep = *sepp)) { 1119 1003 if (sep->se_checked) { … … 1122 1006 } 1123 1007 *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); 1129 1010 #if ENABLE_FEATURE_INETD_RPC 1130 if (is rpcservice(sep))1011 if (is_rpc_service(sep)) 1131 1012 unregister_rpc(sep); 1132 1013 #endif 1133 1014 if (sep->se_family == AF_UNIX) 1134 (void)unlink(sep->se_service);1135 free config(sep);1015 unlink(sep->se_service); 1016 free_servtab_strings(sep); 1136 1017 free(sep); 1137 1018 } 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 1024 static void reap_child(int sig UNUSED_PARAM) 1143 1025 { 1144 1026 pid_t pid; 1145 int s ave_errno = errno, status;1027 int status; 1146 1028 servtab_t *sep; 1029 int save_errno = errno; 1147 1030 1148 1031 for (;;) { 1149 pid = wait 3(&status, WNOHANG, NULL);1032 pid = wait_any_nohang(&status); 1150 1033 if (pid <= 0) 1151 1034 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 } 1164 1049 } 1165 1050 errno = save_errno; 1166 1051 } 1167 1052 1168 static void retry(int sig ATTRIBUTE_UNUSED) 1169 { 1053 static void retry_network_setup(int sig UNUSED_PARAM) 1054 { 1055 int save_errno = errno; 1170 1056 servtab_t *sep; 1171 1057 1172 timingout= 0;1173 for (sep = serv tab; sep; sep = sep->se_next) {1058 alarm_armed = 0; 1059 for (sep = serv_list; sep; sep = sep->se_next) { 1174 1060 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); 1182 1062 #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 1188 1066 } 1189 1067 } 1190 } 1191 1192 static void goaway(int sig ATTRIBUTE_UNUSED) 1068 errno = save_errno; 1069 } 1070 1071 static void clean_up_and_exit(int sig UNUSED_PARAM) 1193 1072 { 1194 1073 servtab_t *sep; 1195 1074 1196 1075 /* XXX signal race walking sep list */ 1197 for (sep = serv tab; sep; sep = sep->se_next) {1076 for (sep = serv_list; sep; sep = sep->se_next) { 1198 1077 if (sep->se_fd == -1) 1199 1078 continue; … … 1201 1080 switch (sep->se_family) { 1202 1081 case AF_UNIX: 1203 (void)unlink(sep->se_service);1082 unlink(sep->se_service); 1204 1083 break; 1205 case AF_INET: 1206 #if ENABLE_FEATURE_IPV6 1207 case AF_INET6: 1208 #endif 1084 default: /* case AF_INET, AF_INET6 */ 1209 1085 #if ENABLE_FEATURE_INETD_RPC 1210 if (sep->se_wait == 1 && is rpcservice(sep))1086 if (sep->se_wait == 1 && is_rpc_service(sep)) 1211 1087 unregister_rpc(sep); /* XXX signal race */ 1212 1088 #endif 1213 1089 break; 1214 1090 } 1215 (void) close(sep->se_fd); 1091 if (ENABLE_FEATURE_CLEAN_UP) 1092 close(sep->se_fd); 1216 1093 } 1217 1094 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 1098 int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1099 int inetd_main(int argc UNUSED_PARAM, char **argv) 1100 { 1101 struct sigaction sa, saved_pipe_handler; 1102 servtab_t *sep, *sep2; 1257 1103 struct passwd *pwd; 1258 struct group *grp = NULL; 1259 int tmpint; 1260 struct sigaction sa, sapipe; 1104 struct group *grp = grp; /* for compiler */ 1261 1105 int opt; 1262 1106 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 */ 1280 1113 config_filename = NULL; 1281 1114 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); 1285 1117 argv += optind; 1286 argc -= optind;1287 if (arg c)1118 //argc -= optind; 1119 if (argv[0]) 1288 1120 config_filename = argv[0]; 1289 1121 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"); 1292 1123 if (!(opt & 2)) 1293 1124 bb_daemonize_or_rexec(0, argv - optind); 1294 1125 else 1295 1126 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 */ 1301 1139 gid_t gid = getgid(); 1302 1140 setgroups(1, &gid); … … 1305 1143 write_pidfile(_PATH_INETDPID); 1306 1144 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 */ 1317 1153 sigaddset(&sa.sa_mask, SIGALRM); 1318 1154 sigaddset(&sa.sa_mask, SIGCHLD); 1319 1155 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); 1331 1166 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 */ 1344 1170 1345 1171 for (;;) { 1346 int n, ctrl = -1; 1172 int ready_fd_cnt; 1173 int ctrl, accepted_fd, new_udp_fd; 1347 1174 fd_set readable; 1348 1175 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) { 1360 1186 bb_perror_msg("select"); 1361 1187 sleep(1); … … 1364 1190 } 1365 1191 1366 for (sep = serv tab; n&& sep; sep = sep->se_next) {1192 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { 1367 1193 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) 1368 1194 continue; 1369 1195 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); 1391 1206 continue; 1392 1207 } 1393 1208 } 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); 1439 1226 continue; 1440 1227 } 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; 1469 1235 } 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);1507 1236 } 1508 1237 } 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); 1511 1395 } /* for (sep = servtab...) */ 1512 1396 } /* for (;;) */ 1513 1397 } 1398 1399 #if !BB_MMU 1400 static const char *const cat_args[] = { "cat", NULL }; 1401 #endif 1514 1402 1515 1403 /* 1516 1404 * Internet services provided internally by inetd: 1517 1405 */ 1518 #define BUFSIZE 40961519 1520 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \1521 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \1522 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME1523 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 #endif1533 1534 1406 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1535 /* Echo service -- echo data back */1407 /* Echo service -- echo data back. */ 1536 1408 /* 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); 1409 static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM) 1410 { 1411 #if BB_MMU 1544 1412 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 } 1430 static 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. */ 1554 1449 /* 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 */ 1450 static 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 } 1576 1468 /* 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)); 1469 static 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); 1598 1473 } 1599 1474 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */ … … 1602 1477 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1603 1478 #define LINESIZ 72 1604 static char ring[128]; 1605 static char *endring; 1606 1607 static void 1608 initring(void) 1479 static void init_ring(void) 1609 1480 { 1610 1481 int i; 1611 1482 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. */ 1620 1488 /* ARGSUSED */ 1621 static void 1622 chargen_stream(int s, servtab_t *sep) 1489 static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM) 1623 1490 { 1624 1491 char *rs; … … 1626 1493 char text[LINESIZ + 2]; 1627 1494 1628 inetd_setproctitle(sep->se_service, s); 1629 1630 if (!endring) { 1631 initring(); 1495 if (!end_ring) { 1496 init_ring(); 1632 1497 rs = ring; 1633 1498 } … … 1637 1502 rs = ring; 1638 1503 for (;;) { 1639 len = end ring - rs;1504 len = end_ring - rs; 1640 1505 if (len >= LINESIZ) 1641 1506 memmove(text, rs, LINESIZ); … … 1644 1509 memmove(text + len, ring, LINESIZ - len); 1645 1510 } 1646 if (++rs == end ring)1511 if (++rs == end_ring) 1647 1512 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 } 1655 1516 /* 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; 1517 static void FAST_FUNC chargen_dg(int s, servtab_t *sep) 1518 { 1662 1519 int len; 1663 1520 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) 1673 1527 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); 1679 1537 else { 1680 memmove(text, r s, len);1538 memmove(text, ring_pos, len); 1681 1539 memmove(text + len, ring, LINESIZ - len); 1682 1540 } 1683 if (++r s == endring)1684 r s = ring;1541 if (++ring_pos == end_ring) 1542 ring_pos = ring; 1685 1543 text[LINESIZ] = '\r'; 1686 1544 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); 1688 1546 } 1689 1547 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */ … … 1698 1556 * some seventy years Bell Labs was asleep. 1699 1557 */ 1700 1701 static unsigned machtime(void) 1558 static uint32_t machtime(void) 1702 1559 { 1703 1560 struct timeval tv; 1704 1561 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 } 1712 1565 /* ARGSUSED */ 1713 static void 1714 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1715 { 1716 unsigned result; 1566 static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM) 1567 { 1568 uint32_t result; 1717 1569 1718 1570 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 } 1573 static 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) 1734 1580 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 1740 1582 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); 1742 1584 } 1743 1585 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */ … … 1747 1589 /* Return human-readable time of day */ 1748 1590 /* ARGSUSED */ 1749 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1750 { 1751 char buffer[32]; 1591 static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM) 1592 { 1752 1593 time_t t; 1753 1594 1754 1595 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 } 1598 static void FAST_FUNC daytime_dg(int s, servtab_t *sep) 1599 { 1767 1600 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; 1771 1606 1772 1607 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); 1781 1610 } 1782 1611 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */ -
branches/2.2.9/mindi-busybox/networking/interface.c
r1765 r2725 20 20 * and others. Copyright 1993 MicroWalt Corporation 21 21 * 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. 23 23 * 24 24 * Patched to support 'add' and 'del' keywords for INET(4) addresses … … 31 31 * (default AF was wrong) 32 32 */ 33 34 33 #include <net/if.h> 35 34 #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" 36 41 #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 38 48 39 49 #if ENABLE_FEATURE_IPV6 … … 47 57 48 58 #ifdef HAVE_AFINET6 49 50 #ifndef _LINUX_IN6_H 59 # ifndef _LINUX_IN6_H 51 60 /* 52 * This is in linux/include/net/ipv6.h.61 * This is from linux/include/net/ipv6.h 53 62 */ 54 55 63 struct in6_ifreq { 56 64 struct in6_addr ifr6_addr; … … 58 66 unsigned int ifr6_ifindex; 59 67 }; 60 61 #endif 62 68 # endif 63 69 #endif /* HAVE_AFINET6 */ 64 70 65 71 /* Defines for glibc2.0 users. */ 66 72 #ifndef SIOCSIFTXQLEN 67 # define SIOCSIFTXQLEN 0x894368 # define SIOCGIFTXQLEN 0x894273 # define SIOCSIFTXQLEN 0x8943 74 # define SIOCGIFTXQLEN 0x8942 69 75 #endif 70 76 71 77 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ 72 78 #ifndef ifr_qlen 73 # define ifr_qlen ifr_ifru.ifru_mtu79 # define ifr_qlen ifr_ifru.ifru_mtu 74 80 #endif 75 81 76 82 #ifndef HAVE_TXQUEUELEN 77 # define HAVE_TXQUEUELEN 183 # define HAVE_TXQUEUELEN 1 78 84 #endif 79 85 80 86 #ifndef IFF_DYNAMIC 81 # define IFF_DYNAMIC 0x8000/* dialup device with changing addresses */87 # define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ 82 88 #endif 83 89 84 90 /* Display an Internet socket address. */ 85 static const char *INET_sprint(struct sockaddr *sap, int numeric)86 { 87 static char *buff; 91 static const char* FAST_FUNC INET_sprint(struct sockaddr *sap, int numeric) 92 { 93 static char *buff; /* defaults to NULL */ 88 94 89 95 free(buff); … … 137 143 #endif 138 144 139 static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)145 static int FAST_FUNC INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap) 140 146 { 141 147 return INET_resolve(bufp, (struct sockaddr_in *) sap, 0); … … 153 159 154 160 static const struct aftype inet_aftype = { 155 .name ="inet",156 .title ="DARPA Internet",157 .af =AF_INET,158 .alen =4,159 .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, 161 167 }; 162 168 … … 165 171 /* Display an Internet socket address. */ 166 172 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ 167 static const char *INET6_sprint(struct sockaddr *sap, int numeric)173 static const char* FAST_FUNC INET6_sprint(struct sockaddr *sap, int numeric) 168 174 { 169 175 static char *buff; … … 192 198 #endif 193 199 194 static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)200 static int FAST_FUNC INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap) 195 201 { 196 202 return INET6_resolve(bufp, (struct sockaddr_in6 *) sap); … … 206 212 207 213 static const struct aftype inet6_aftype = { 208 .name ="inet6",209 .title ="IPv6",210 .af =AF_INET6,211 .alen =sizeof(struct in6_addr),212 .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, 214 220 }; 215 221 … … 217 223 218 224 /* Display an UNSPEC address. */ 219 static char *UNSPEC_print(unsigned char *ptr)225 static char* FAST_FUNC UNSPEC_print(unsigned char *ptr) 220 226 { 221 227 static char *buff; … … 224 230 unsigned int i; 225 231 226 if (!buff) ;232 if (!buff) 227 233 buff = xmalloc(sizeof(struct sockaddr) * 3 + 1); 228 234 pos = buff; … … 238 244 239 245 /* Display an UNSPEC socket address. */ 240 static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric)246 static const char* FAST_FUNC UNSPEC_sprint(struct sockaddr *sap, int numeric UNUSED_PARAM) 241 247 { 242 248 if (sap->sa_family == 0xFFFF || sap->sa_family == 0) … … 249 255 .title = "UNSPEC", 250 256 .af = AF_UNSPEC, 251 .alen 257 .alen = 0, 252 258 .print = UNSPEC_print, 253 259 .sprint = UNSPEC_sprint, … … 264 270 265 271 /* Check our protocol family table for this family. */ 266 const struct aftype *get_aftype(const char *name)272 const struct aftype* FAST_FUNC get_aftype(const char *name) 267 273 { 268 274 const struct aftype *const *afp; … … 322 328 struct interface { 323 329 struct interface *next, *prev; 324 char name[IFNAMSIZ]; 325 short type; 326 short flags; 327 int metric; 328 int mtu; 329 int tx_queue_len; 330 struct ifmap map; 331 struct sockaddr addr; 332 struct sockaddr dstaddr; 333 struct sockaddr broadaddr; 334 struct sockaddr netmask; 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 */ 335 341 int has_ip; 336 char hwaddr[32]; 342 char hwaddr[32]; /* HW address */ 337 343 int statistics_valid; 338 struct user_net_device_stats stats; 339 int keepalive; 340 int outfill; 344 struct user_net_device_stats stats; /* statistics */ 345 int keepalive; /* keepalive value for SLIP */ 346 int outfill; /* outfill value for SLIP */ 341 347 }; 342 348 … … 389 395 390 396 new = xzalloc(sizeof(*new)); 391 s afe_strncpy(new->name, name, IFNAMSIZ);397 strncpy_IFNAMSIZ(new->name, name); 392 398 nextp = ife ? &ife->next : &int_list; 393 399 new->prev = ife; … … 404 410 { 405 411 /* 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)) 413 420 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; 419 426 } else { 420 427 /* Interface name too large */ 421 name[0] ='\0';428 name[0] = '\0'; 422 429 } 423 430 } else { 424 431 /* trailing ':' not found - return empty */ 425 name[0] ='\0';432 name[0] = '\0'; 426 433 } 427 434 return p + 1; … … 491 498 } 492 499 493 static in line int procnetdev_version(char *buf)500 static int procnetdev_version(char *buf) 494 501 { 495 502 if (strstr(buf, "compressed")) … … 525 532 goto out; 526 533 } 527 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {534 if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) { 528 535 /* assume it overflowed and try again */ 529 536 numreqs += 10; … … 560 567 proc_read = 1; 561 568 562 fh = fopen (_PATH_PROCNET_DEV, "r");569 fh = fopen_or_warn(_PATH_PROCNET_DEV, "r"); 563 570 if (!fh) { 564 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);565 571 return if_readconf(); 566 572 } … … 608 614 skfd = xsocket(AF_INET, SOCK_DGRAM, 0); 609 615 610 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));616 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 611 617 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { 612 618 close(skfd); … … 615 621 ife->flags = ifr.ifr_flags; 616 622 617 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));623 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 618 624 memset(ife->hwaddr, 0, 32); 619 625 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) … … 622 628 ife->type = ifr.ifr_hwaddr.sa_family; 623 629 624 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));630 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 625 631 ife->metric = 0; 626 632 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) 627 633 ife->metric = ifr.ifr_metric; 628 634 629 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));635 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 630 636 ife->mtu = 0; 631 637 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) … … 634 640 memset(&ife->map, 0, sizeof(struct ifmap)); 635 641 #ifdef SIOCGIFMAP 636 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));642 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 637 643 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) 638 644 ife->map = ifr.ifr_map; … … 640 646 641 647 #ifdef HAVE_TXQUEUELEN 642 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));648 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 643 649 ife->tx_queue_len = -1; /* unknown value */ 644 650 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) … … 648 654 #endif 649 655 650 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));656 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 651 657 ifr.ifr_addr.sa_family = AF_INET; 652 658 memset(&ife->addr, 0, sizeof(struct sockaddr)); … … 654 660 ife->has_ip = 1; 655 661 ife->addr = ifr.ifr_addr; 656 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));662 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 657 663 memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); 658 664 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) 659 665 ife->dstaddr = ifr.ifr_dstaddr; 660 666 661 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));667 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 662 668 memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); 663 669 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) 664 670 ife->broadaddr = ifr.ifr_broadaddr; 665 671 666 strncpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));672 strncpy_IFNAMSIZ(ifr.ifr_name, ifname); 667 673 memset(&ife->netmask, 0, sizeof(struct sockaddr)); 668 674 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) … … 673 679 return 0; 674 680 } 675 676 681 677 682 static int do_if_fetch(struct interface *ife) … … 706 711 }; 707 712 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 #else713 #include <linux/if_ether.h>714 #endif715 716 713 /* Display an Ethernet address in readable format. */ 717 static char *pr_ether(unsigned char *ptr)714 static char* FAST_FUNC ether_print(unsigned char *ptr) 718 715 { 719 716 static char *buff; … … 727 724 } 728 725 729 static int in_ether(const char *bufp, struct sockaddr *sap);726 static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap); 730 727 731 728 static const struct hwtype ether_hwtype = { 732 .name ="ether",733 .title = 734 .type =ARPHRD_ETHER,735 .alen =ETH_ALEN,736 .print = pr_ether,737 .input = in_ether729 .name = "ether", 730 .title = "Ethernet", 731 .type = ARPHRD_ETHER, 732 .alen = ETH_ALEN, 733 .print = ether_print, 734 .input = ether_input 738 735 }; 739 736 … … 749 746 750 747 /* Input an Ethernet address and convert to binary. */ 751 static int in_ether(const char *bufp, struct sockaddr *sap)748 static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap) 752 749 { 753 750 unsigned char *ptr; … … 789 786 } 790 787 791 #include <net/if_arp.h>792 793 788 static const struct hwtype ppp_hwtype = { 794 789 .name = "ppp", … … 806 801 }; 807 802 #endif 803 #if ENABLE_FEATURE_HWIB 804 static 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 808 814 809 815 static const struct hwtype *const hwtypes[] = { … … 814 820 #if ENABLE_FEATURE_IPV6 815 821 &sit_hwtype, 822 #endif 823 #if ENABLE_FEATURE_HWIB 824 &ib_hwtype, 816 825 #endif 817 826 NULL … … 833 842 834 843 /* Check our hardware type table for this type. */ 835 const struct hwtype *get_hwtype(const char *name)844 const struct hwtype* FAST_FUNC get_hwtype(const char *name) 836 845 { 837 846 const struct hwtype *const *hwp; … … 847 856 848 857 /* Check our hardware type table for this type. */ 849 const struct hwtype *get_hwntype(int type)858 const struct hwtype* FAST_FUNC get_hwntype(int type) 850 859 { 851 860 const struct hwtype *const *hwp; … … 863 872 static int hw_null_address(const struct hwtype *hw, void *ap) 864 873 { 865 unsignedint i;874 int i; 866 875 unsigned char *address = (unsigned char *) ap; 867 876 … … 897 906 } 898 907 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;905 908 906 909 #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 928 static void ife_print6(struct interface *ptr) 929 { 907 930 FILE *f; 908 931 char addr6[40], devname[20]; … … 910 933 int plen, scope, dad_status, if_idx; 911 934 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 984 static 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; 913 990 914 991 ap = get_afntype(ptr->addr.sa_family); … … 925 1002 hw = get_hwntype(-1); 926 1003 927 printf("%-9 .9s Link encap:%s ", ptr->name, hw->title);1004 printf("%-9s Link encap:%s ", ptr->name, hw->title); 928 1005 /* For some hardware types (eg Ash, ATM) we don't print the 929 1006 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 ) { 932 1010 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr)); 1011 } 933 1012 #ifdef IFF_PORTSEL 934 1013 if (ptr->flags & IFF_PORTSEL) { … … 938 1017 } 939 1018 #endif 940 puts("");1019 bb_putchar('\n'); 941 1020 942 1021 if (ptr->has_ip) { … … 952 1031 } 953 1032 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); 1016 1034 1017 1035 printf(" "); … … 1074 1092 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive); 1075 1093 #endif 1076 puts("");1094 bb_putchar('\n'); 1077 1095 1078 1096 /* If needed, display the interface statistics. */ … … 1105 1123 print_bytes_scaled(ptr->stats.rx_bytes, " T"); 1106 1124 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 ) { 1112 1130 printf(" "); 1113 1131 if (ptr->map.irq) … … 1123 1141 if (ptr->map.dma) 1124 1142 printf("DMA chan:%x ", ptr->map.dma); 1125 puts(""); 1126 } 1127 puts(""); 1128 } 1129 1143 bb_putchar('\n'); 1144 } 1145 bb_putchar('\n'); 1146 } 1130 1147 1131 1148 static int do_if_print(struct interface *ife) /*, int *opt_a)*/ … … 1161 1178 for (ife = int_list; ife; ife = ife->next) { 1162 1179 int err = doit(ife, cookie); 1163 1164 1180 if (err) 1165 1181 return err; … … 1193 1209 } 1194 1210 1195 int display_interfaces(char *ifname) 1211 #if ENABLE_FEATURE_HWIB 1212 /* Input an Infiniband address and convert to binary. */ 1213 int 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 1225 int FAST_FUNC display_interfaces(char *ifname) 1196 1226 { 1197 1227 int status; -
branches/2.2.9/mindi-busybox/networking/ip.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * ip.c "ip" utility frontend.3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 * 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> 9 6 * 10 7 * 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 14 10 */ 15 11 … … 25 21 || ENABLE_FEATURE_IP_RULE 26 22 27 static int ATTRIBUTE_NORETURN ip_print_help(int ATTRIBUTE_UNUSED ac, char ATTRIBUTE_UNUSED **av)23 static int FAST_FUNC ip_print_help(char **argv UNUSED_PARAM) 28 24 { 29 25 bb_show_usage(); 30 26 } 31 27 32 static int (*ip_func)(int argc, char **argv) = ip_print_help;28 typedef int FAST_FUNC (*ip_func_ptr_t)(char**); 33 29 34 static int ip_do(i nt argc, char **argv)30 static int ip_do(ip_func_ptr_t ip_func, char **argv) 35 31 { 36 ip_parse_common_args(&argc, &argv);37 return ip_func(arg c-1, argv+1);32 argv = ip_parse_common_args(argv + 1); 33 return ip_func(argv); 38 34 } 39 35 40 36 #if ENABLE_FEATURE_IP_ADDRESS 41 int ipaddr_main(int argc, char **argv) ;42 int ipaddr_main(int argc , char **argv)37 int ipaddr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 38 int ipaddr_main(int argc UNUSED_PARAM, char **argv) 43 39 { 44 ip_func = do_ipaddr; 45 return ip_do(argc, argv); 40 return ip_do(do_ipaddr, argv); 46 41 } 47 42 #endif 48 43 #if ENABLE_FEATURE_IP_LINK 49 int iplink_main(int argc, char **argv) ;50 int iplink_main(int argc , char **argv)44 int iplink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 45 int iplink_main(int argc UNUSED_PARAM, char **argv) 51 46 { 52 ip_func = do_iplink; 53 return ip_do(argc, argv); 47 return ip_do(do_iplink, argv); 54 48 } 55 49 #endif 56 50 #if ENABLE_FEATURE_IP_ROUTE 57 int iproute_main(int argc, char **argv) ;58 int iproute_main(int argc , char **argv)51 int iproute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 52 int iproute_main(int argc UNUSED_PARAM, char **argv) 59 53 { 60 ip_func = do_iproute; 61 return ip_do(argc, argv); 54 return ip_do(do_iproute, argv); 62 55 } 63 56 #endif 64 57 #if ENABLE_FEATURE_IP_RULE 65 int iprule_main(int argc, char **argv) ;66 int iprule_main(int argc , char **argv)58 int iprule_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 59 int iprule_main(int argc UNUSED_PARAM, char **argv) 67 60 { 68 ip_func = do_iprule; 69 return ip_do(argc, argv); 61 return ip_do(do_iprule, argv); 70 62 } 71 63 #endif 72 64 #if ENABLE_FEATURE_IP_TUNNEL 73 int iptunnel_main(int argc, char **argv) ;74 int iptunnel_main(int argc , char **argv)65 int iptunnel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 66 int iptunnel_main(int argc UNUSED_PARAM, char **argv) 75 67 { 76 ip_func = do_iptunnel; 77 return ip_do(argc, argv); 68 return ip_do(do_iptunnel, argv); 78 69 } 79 70 #endif 80 71 81 72 82 int ip_main(int argc, char **argv) ;83 int ip_main(int argc , char **argv)73 int ip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 74 int ip_main(int argc UNUSED_PARAM, char **argv) 84 75 { 85 76 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") 91 84 ; 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,) 99 94 }; 95 ip_func_ptr_t ip_func; 96 int key; 100 97 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); 128 103 } 129 104 -
branches/2.2.9/mindi-busybox/networking/ipcalc.c
r1765 r2725 10 10 * is no denying that this is a loving reimplementation 11 11 * 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. 13 13 */ 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 */ 17 16 #include <arpa/inet.h> 18 17 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) 24 21 25 22 static unsigned long get_netmask(unsigned long ipaddr) … … 65 62 #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS 66 63 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] 70 67 # 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 74 71 # endif 75 72 ; 76 73 #endif 77 74 78 int ipcalc_main(int argc, char **argv) ;79 int ipcalc_main(int argc , char **argv)75 int ipcalc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 76 int ipcalc_main(int argc UNUSED_PARAM, char **argv) 80 77 { 81 78 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) 85 88 char *ipstr; 86 89 … … 88 91 applet_long_options = ipcalc_longopts; 89 92 #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")); 92 95 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]) 98 103 bb_show_usage(); 99 104 } 100 if (opt & SILENT)101 logmode = LOGMODE_NONE; /* Suppress error_msg() output */102 105 103 106 ipstr = argv[0]; … … 110 113 while (*prefixstr) { 111 114 if (*prefixstr == '/') { 112 *prefixstr = (char)0; 113 prefixstr++; 115 *prefixstr++ = '\0'; 114 116 if (*prefixstr) { 115 117 unsigned msk; … … 132 134 } 133 135 } 134 ipaddr = inet_aton(ipstr, &a);135 136 136 if (i paddr== 0) {137 if (inet_aton(ipstr, &s_ipaddr) == 0) { 137 138 bb_error_msg_and_die("bad IP address: %s", argv[0]); 138 139 } 139 ipaddr = a.s_addr;140 140 141 if (arg c == 2) {141 if (argv[1]) { 142 142 if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) { 143 143 bb_error_msg_and_die("use prefix or netmask, not both"); 144 144 } 145 146 netmask = inet_aton(argv[1], &a); 147 if (netmask == 0) { 145 if (inet_aton(argv[1], &s_netmask) == 0) { 148 146 bb_error_msg_and_die("bad netmask: %s", argv[1]); 149 147 } 150 netmask = a.s_addr;151 148 } else { 152 153 149 /* JHC - If the netmask wasn't provided then calculate it */ 154 150 if (!ENABLE_FEATURE_IPCALC_FANCY || !have_netmask) … … 157 153 158 154 if (opt & NETMASK) { 159 printf("NETMASK=%s\n", inet_ntoa( (*(struct in_addr *) &netmask)));155 printf("NETMASK=%s\n", inet_ntoa(s_netmask)); 160 156 } 161 157 162 158 if (opt & BROADCAST) { 163 159 broadcast = (ipaddr & netmask) | ~netmask; 164 printf("BROADCAST=%s\n", inet_ntoa( (*(struct in_addr *) &broadcast)));160 printf("BROADCAST=%s\n", inet_ntoa(s_broadcast)); 165 161 } 166 162 167 163 if (opt & NETWORK) { 168 164 network = ipaddr & netmask; 169 printf("NETWORK=%s\n", inet_ntoa( (*(struct in_addr *) &network)));165 printf("NETWORK=%s\n", inet_ntoa(s_network)); 170 166 } 171 167 … … 177 173 if (opt & HOSTNAME) { 178 174 struct hostent *hostinfo; 179 int x;180 175 181 176 hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET); 182 177 if (!hostinfo) { 183 bb_herror_msg_and_die("can not find hostname for %s", argv[0]);178 bb_herror_msg_and_die("can't find hostname for %s", argv[0]); 184 179 } 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); 188 181 189 182 printf("HOSTNAME=%s\n", hostinfo->h_name); -
branches/2.2.9/mindi-busybox/networking/isrv.c
r1765 r2725 4 4 * Intended to make writing telnetd-type servers easier. 5 5 * 6 * Copyright (C) 2007 Den is Vlasenko6 * Copyright (C) 2007 Denys Vlasenko 7 7 * 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. 9 9 */ 10 10 -
branches/2.2.9/mindi-busybox/networking/isrv.h
r1765 r2725 4 4 * Intended to make writing telnetd-type servers easier. 5 5 * 6 * Copyright (C) 2007 Den is Vlasenko6 * Copyright (C) 2007 Denys Vlasenko 7 7 * 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. 9 9 */ 10 11 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 10 12 11 13 /* opaque structure */ … … 32 34 int linger_timeout 33 35 ); 36 37 POP_SAVED_FUNCTION_VISIBILITY -
branches/2.2.9/mindi-busybox/networking/isrv_identd.c
r1765 r2725 3 3 * Fake identd server. 4 4 * 5 * Copyright (C) 2007 Den is Vlasenko5 * Copyright (C) 2007 Denys Vlasenko 6 6 * 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. 8 8 */ 9 9 10 #include "libbb.h" 10 11 #include <syslog.h> 11 #include "libbb.h"12 12 #include "isrv.h" 13 13 … … 62 62 if (p) 63 63 *p = '\0'; 64 if (!p && sz && buf->pos <= sizeof(buf->buf))64 if (!p && sz && buf->pos <= (int)sizeof(buf->buf)) 65 65 goto ok; 66 66 /* Terminate session. If we are in server mode, then … … 77 77 } 78 78 79 static int do_timeout(void **paramp )79 static int do_timeout(void **paramp UNUSED_PARAM) 80 80 { 81 81 return 1; /* terminate session */ … … 93 93 } 94 94 95 int fakeidentd_main(int argc, char **argv) ;96 int fakeidentd_main(int argc , char **argv)95 int fakeidentd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 96 int fakeidentd_main(int argc UNUSED_PARAM, char **argv) 97 97 { 98 98 enum { … … 114 114 115 115 /* Daemonize if no -f and no -i and no -w */ 116 if (!(opt & OPT_fiw)) ;116 if (!(opt & OPT_fiw)) 117 117 bb_daemonize_or_rexec(0, argv); 118 118 … … 123 123 * (Or maybe we need yet another option "log to syslog") */ 124 124 if (!(opt & OPT_fiw) /* || (opt & OPT_syslog) */) { 125 openlog(applet_name, 0, LOG_DAEMON);125 openlog(applet_name, LOG_PID, LOG_DAEMON); 126 126 logmode = LOGMODE_SYSLOG; 127 127 } -
branches/2.2.9/mindi-busybox/networking/libiproute/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 4 5 # 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. 6 7 # 7 8 8 9 lib-y:= 10 11 9 12 10 13 lib-$(CONFIG_SLATTACH) += \ … … 63 66 rt_names.o \ 64 67 utils.o 65 -
branches/2.2.9/mindi-busybox/networking/libiproute/ip_common.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 #ifndef _IP_COMMON_H3 #define _IP_COMMON_H 12 #ifndef IP_COMMON_H 3 #define IP_COMMON_H 1 4 4 5 5 #include "libbb.h" … … 14 14 #endif 15 15 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); 16 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 22 17 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 */ 18 char FAST_FUNC **ip_parse_common_args(char **argv); 19 //int FAST_FUNC print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); 20 int 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 24 int FAST_FUNC do_ipaddr(char **argv); 25 int FAST_FUNC do_iproute(char **argv); 26 int FAST_FUNC do_iprule(char **argv); 27 //int FAST_FUNC do_ipneigh(char **argv); 28 int FAST_FUNC do_iptunnel(char **argv); 29 int 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 34 POP_SAVED_FUNCTION_VISIBILITY 35 36 #endif -
branches/2.2.9/mindi-busybox/networking/libiproute/ip_parse_common_args.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 12 9 * 13 10 * Changes: 14 11 * 15 * Rani Assaf <rani@magic.metawire.com> 980929: 12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 16 13 */ 17 14 … … 19 16 #include "utils.h" 20 17 21 int preferred_family = AF_UNSPEC;18 family_t preferred_family = AF_UNSPEC; 22 19 smallint oneline; 23 20 char _SL_; 24 21 25 void ip_parse_common_args(int *argcp, char ***argvp)22 char** FAST_FUNC ip_parse_common_args(char **argv) 26 23 { 27 int argc = *argcp;28 char **argv = *argvp;29 24 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 ; 32 31 enum { 33 ARG_family = 1, 34 ARG_inet, 35 ARG_inet6, 36 ARG_link, 32 ARG_oneline, 33 ARG_family, 37 34 ARG_IPv4, 38 35 ARG_IPv6, 39 36 ARG_packet, 40 ARG_oneline41 37 }; 42 smalluint arg; 38 static const family_t af_numbers[] = { AF_INET, AF_INET6, AF_PACKET }; 39 int arg; 43 40 44 while ( argc > 1) {45 char *opt = argv[1];41 while (*argv) { 42 char *opt = *argv; 46 43 47 if (strcmp(opt,"--") == 0) {48 argc--;49 argv++;50 break;51 }52 44 if (opt[0] != '-') 53 45 break; 54 if (opt[1] == '-') 46 opt++; 47 if (opt[0] == '-') { 55 48 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 } 57 62 if (arg == ARG_family) { 58 argc--; 63 static const char families[] ALIGN1 = 64 "inet" "\0" "inet6" "\0" "link" "\0"; 59 65 argv++; 60 if (! argv[1])66 if (!*argv) 61 67 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 */ 79 72 } else { 80 bb_show_usage(); 73 arg -= ARG_IPv4; 74 /* now arg == 0, 1 or 2 */ 81 75 } 82 argc--;76 preferred_family = af_numbers[arg]; 83 77 argv++; 84 78 } 85 79 _SL_ = oneline ? '\\' : '\n'; 86 *argcp = argc; 87 *argvp = argv; 80 return argv; 88 81 } -
branches/2.2.9/mindi-busybox/networking/libiproute/ipaddress.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * ipaddress.c "ip address".3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 * 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> 8 6 * 9 7 * Changes: 10 * 8 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated 11 9 */ 12 10 13 //#include <sys/socket.h>14 //#include <sys/ioctl.h>15 11 #include <fnmatch.h> 16 12 #include <net/if.h> … … 21 17 #include "utils.h" 22 18 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 24 struct filter_t { 25 char *label; 26 char *flushb; 27 struct rtnl_handle *rth; 30 28 int scope, scopemask; 31 29 int flags, flagmask; 32 int up;33 char *label;34 int flushed;35 char *flushb;36 30 int flushp; 37 31 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; 40 typedef struct filter_t filter_t; 41 42 #define G_filter (*(filter_t*)&bb_common_bufsiz1) 43 44 45 static 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,"); 47 57 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);56 58 #if 0 57 59 _PF(ALLMULTI); … … 65 67 _PF(NOTRAILERS); 66 68 #endif 67 _PF(UP); 68 #undef _PF 69 flags = print_flags_separated(flag_masks, flag_labels, flags, ","); 69 70 if (flags) 70 fprintf(fp,"%x", flags);71 printf("%x", flags); 71 72 if (mdown) 72 fprintf(fp,",M-DOWN");73 fprintf(fp,"> ");73 printf(",M-DOWN"); 74 printf("> "); 74 75 } 75 76 … … 84 85 85 86 memset(&ifr, 0, sizeof(ifr)); 86 strncpy (ifr.ifr_name, name, sizeof(ifr.ifr_name));87 strncpy_IFNAMSIZ(ifr.ifr_name, name); 87 88 if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) { 88 89 close(s); … … 95 96 } 96 97 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; 98 static NOINLINE int print_linkinfo(const struct nlmsghdr *n) 99 { 101 100 struct ifinfomsg *ifi = NLMSG_DATA(n); 102 struct rtattr * 101 struct rtattr *tb[IFLA_MAX+1]; 103 102 int len = n->nlmsg_len; 104 unsigned m_flag = 0;105 103 106 104 if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) … … 111 109 return -1; 112 110 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)) 116 114 return 0; 117 115 … … 122 120 return -1; 123 121 } 124 if ( filter.label125 && (! 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) 127 125 ) { 128 126 return 0; … … 130 128 131 129 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 } 151 154 152 155 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])); 154 157 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])); 156 159 #ifdef IFLA_MASTER 157 160 if (tb[IFLA_MASTER]) { 158 161 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)); 160 163 } 161 164 #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) 163 173 print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); 164 174 165 if (! filter.family ||filter.family == AF_PACKET) {175 if (!G_filter.family || G_filter.family == AF_PACKET) { 166 176 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)); 168 178 169 179 if (tb[IFLA_ADDRESS]) { 170 fp rintf(fp, "%s",ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),180 fputs(ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), 171 181 RTA_PAYLOAD(tb[IFLA_ADDRESS]), 172 182 ifi->ifi_type, 173 b1, sizeof(b1)) );183 b1, sizeof(b1)), stdout); 174 184 } 175 185 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 "); 178 188 else 179 fprintf(fp," brd ");180 fp rintf(fp, "%s",ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),189 printf(" brd "); 190 fputs(ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), 181 191 RTA_PAYLOAD(tb[IFLA_BROADCAST]), 182 192 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();*/ 188 198 return 0; 189 199 } … … 191 201 static int flush_update(void) 192 202 { 193 if (rtnl_send( filter.rth, filter.flushb,filter.flushp) < 0) {194 bb_perror_msg(" failed tosend 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"); 195 205 return -1; 196 206 } 197 filter.flushp = 0;207 G_filter.flushp = 0; 198 208 return 0; 199 209 } 200 210 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; 211 static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM, 212 struct nlmsghdr *n, void *arg UNUSED_PARAM) 213 { 205 214 struct ifaddrmsg *ifa = NLMSG_DATA(n); 206 215 int len = n->nlmsg_len; … … 217 226 } 218 227 219 if ( filter.flushb && n->nlmsg_type != RTM_NEWADDR)228 if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR) 220 229 return 0; 221 230 … … 228 237 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; 229 238 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) { 237 246 const char *label; 238 247 if (rta_tb[IFA_LABEL]) … … 240 249 else 241 250 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) 243 252 return 0; 244 253 } 245 if ( filter.pfx.family) {254 if (G_filter.pfx.family) { 246 255 if (rta_tb[IFA_LOCAL]) { 247 256 inet_prefix dst; … … 249 258 dst.family = ifa->ifa_family; 250 259 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)) 252 261 return 0; 253 262 } 254 263 } 255 264 256 if ( filter.flushb) {265 if (G_filter.flushb) { 257 266 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) { 259 268 if (flush_update()) 260 269 return -1; 261 270 } 262 fn = (struct nlmsghdr*)( filter.flushb + NLMSG_ALIGN(filter.flushp));271 fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); 263 272 memcpy(fn, n, n->nlmsg_len); 264 273 fn->nlmsg_type = RTM_DELADDR; 265 274 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; 269 278 return 0; 270 279 } 271 280 272 281 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)); 277 286 if (ifa->ifa_family == AF_INET) 278 fprintf(fp," inet ");287 printf(" inet "); 279 288 else if (ifa->ifa_family == AF_INET6) 280 fprintf(fp," inet6 ");289 printf(" inet6 "); 281 290 else 282 fprintf(fp," family %d ", ifa->ifa_family);291 printf(" family %d ", ifa->ifa_family); 283 292 284 293 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, 287 295 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); 293 302 } else { 294 fprintf(fp," peer %s/%d ",303 printf(" peer %s/%d ", 295 304 rt_addr_n2a(ifa->ifa_family, 296 RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),297 305 RTA_DATA(rta_tb[IFA_ADDRESS]), 298 306 abuf, sizeof(abuf)), … … 302 310 303 311 if (rta_tb[IFA_BROADCAST]) { 304 fprintf(fp,"brd %s ",312 printf("brd %s ", 305 313 rt_addr_n2a(ifa->ifa_family, 306 RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),307 314 RTA_DATA(rta_tb[IFA_BROADCAST]), 308 315 abuf, sizeof(abuf))); 309 316 } 310 317 if (rta_tb[IFA_ANYCAST]) { 311 fprintf(fp,"any %s ",318 printf("any %s ", 312 319 rt_addr_n2a(ifa->ifa_family, 313 RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),314 320 RTA_DATA(rta_tb[IFA_ANYCAST]), 315 321 abuf, sizeof(abuf))); 316 322 } 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) { 319 325 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) { 323 329 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) { 327 333 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 "); 332 338 } else 333 339 ifa->ifa_flags &= ~IFA_F_PERMANENT; 334 340 if (ifa->ifa_flags) 335 fprintf(fp,"flags %02x ", ifa->ifa_flags);341 printf("flags %02x ", ifa->ifa_flags); 336 342 if (rta_tb[IFA_LABEL]) 337 fp rintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));343 fputs((char*)RTA_DATA(rta_tb[IFA_LABEL]), stdout); 338 344 if (rta_tb[IFA_CACHEINFO]) { 339 345 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); 340 346 char buf[128]; 341 fputc(_SL_, fp);347 bb_putchar(_SL_); 342 348 if (ci->ifa_valid == 0xFFFFFFFFU) 343 349 sprintf(buf, "valid_lft forever"); … … 348 354 else 349 355 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();*/ 354 360 return 0; 355 361 } 356 362 357 363 358 struct nlmsg_list 359 { 364 struct nlmsg_list { 360 365 struct nlmsg_list *next; 361 struct nlmsghdr 366 struct nlmsghdr h; 362 367 }; 363 368 364 static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo , FILE *fp)369 static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo) 365 370 { 366 371 for (; ainfo; ainfo = ainfo->next) { … … 370 375 if (n->nlmsg_type != RTM_NEWADDR) 371 376 continue; 372 373 377 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa))) 374 378 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 ) { 378 382 continue; 379 380 print_addrinfo(NULL, n, fp);383 } 384 print_addrinfo(NULL, n, NULL); 381 385 } 382 386 return 0; … … 384 388 385 389 386 static int store_nlmsg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)390 static int FAST_FUNC store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 387 391 { 388 392 struct nlmsg_list **linfo = (struct nlmsg_list**)arg; … … 390 394 struct nlmsg_list **lp; 391 395 392 h = malloc(n->nlmsg_len+sizeof(void*)); 393 if (h == NULL) 394 return -1; 396 h = xzalloc(n->nlmsg_len + sizeof(void*)); 395 397 396 398 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; 400 403 *lp = h; 401 404 … … 406 409 static void ipaddr_reset_filter(int _oneline) 407 410 { 408 memset(& filter, 0, sizeof(filter));409 filter.oneline = _oneline;411 memset(&G_filter, 0, sizeof(G_filter)); 412 G_filter.oneline = _oneline; 410 413 } 411 414 412 415 /* Return value becomes exitcode. It's okay to not return at all */ 413 int ipaddr_list_or_flush(int argc,char **argv, int flush)416 int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush) 414 417 { 415 418 static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; … … 423 426 424 427 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; 429 432 430 433 if (flush) { 431 if ( argc <= 0) {434 if (!*argv) { 432 435 bb_error_msg_and_die(bb_msg_requires_arg, "flush"); 433 436 } 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 */ 443 469 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; 478 473 } 479 474 argv++; 480 argc--;481 475 } 482 476 … … 487 481 488 482 if (filter_dev) { 489 filter.ifindex = xll_name_to_index(filter_dev);483 G_filter.ifindex = xll_name_to_index(filter_dev); 490 484 } 491 485 … … 493 487 char flushb[4096-512]; 494 488 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; 499 493 500 494 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) { 505 499 return 0; 506 500 } 507 if (flush_update() < 0) 501 if (flush_update() < 0) { 508 502 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); 514 509 xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); 515 510 } 516 511 517 512 518 if ( filter.family &&filter.family != AF_PACKET) {513 if (G_filter.family && G_filter.family != AF_PACKET) { 519 514 struct nlmsg_list **lp; 520 lp =&linfo;521 522 if ( filter.oneline)515 lp = &linfo; 516 517 if (G_filter.oneline) 523 518 no_link = 1; 524 519 525 while ((l =*lp)!=NULL) {520 while ((l = *lp) != NULL) { 526 521 int ok = 0; 527 522 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 528 523 struct nlmsg_list *a; 529 524 530 for (a =ainfo; a; a=a->next) {525 for (a = ainfo; a; a = a->next) { 531 526 struct nlmsghdr *n = &a->h; 532 527 struct ifaddrmsg *ifa = NLMSG_DATA(n); 533 528 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 ) { 536 532 continue; 537 if ((filter.scope^ifa->ifa_scope)&filter.scopemask) 533 } 534 if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask) 538 535 continue; 539 if (( filter.flags^ifa->ifa_flags)&filter.flagmask)536 if ((G_filter.flags ^ ifa->ifa_flags) & G_filter.flagmask) 540 537 continue; 541 if ( filter.pfx.family ||filter.label) {538 if (G_filter.pfx.family || G_filter.label) { 542 539 struct rtattr *tb[IFA_MAX+1]; 543 540 memset(tb, 0, sizeof(tb)); … … 546 543 tb[IFA_LOCAL] = tb[IFA_ADDRESS]; 547 544 548 if ( filter.pfx.family && tb[IFA_LOCAL]) {545 if (G_filter.pfx.family && tb[IFA_LOCAL]) { 549 546 inet_prefix dst; 550 547 memset(&dst, 0, sizeof(dst)); 551 548 dst.family = ifa->ifa_family; 552 549 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)) 554 551 continue; 555 552 } 556 if ( filter.label) {553 if (G_filter.label) { 557 554 SPRINT_BUF(b1); 558 555 const char *label; … … 561 558 else 562 559 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) 564 561 continue; 565 562 } … … 577 574 578 575 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) { 580 577 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 } 585 581 } 586 582 … … 598 594 599 595 /* Return value becomes exitcode. It's okay to not return at all */ 600 static int ipaddr_modify(int cmd, int argc,char **argv)596 static int ipaddr_modify(int cmd, char **argv) 601 597 { 602 598 static const char option[] ALIGN1 = … … 626 622 req.ifa.ifa_family = preferred_family; 627 623 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 */ 633 685 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 } 717 696 argv++; 718 697 } 719 698 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\""); 723 702 } 724 703 if (l && strncmp(d, l, strlen(d)) != 0) { … … 767 746 768 747 /* Return value becomes exitcode. It's okay to not return at all */ 769 int do_ipaddr(int argc,char **argv)748 int FAST_FUNC do_ipaddr(char **argv) 770 749 { 771 750 static const char commands[] ALIGN1 = 772 751 "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; 776 753 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 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * iplink.c "ip link".4 *5 3 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 6 4 * 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. 8 6 */ 9 10 //#include <sys/ioctl.h>11 //#include <sys/socket.h>12 7 #include <net/if.h> 13 8 #include <net/if_packet.h> … … 19 14 #include "utils.h" 20 15 16 #ifndef IFLA_LINKINFO 17 # define IFLA_LINKINFO 18 18 # define IFLA_INFO_KIND 1 19 #endif 20 21 21 /* 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 */ 29 23 30 24 /* Exits on error */ … … 48 42 int fd; 49 43 50 strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name));44 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 51 45 fd = get_ctl_fd(); 52 46 xioctl(fd, SIOCGIFFLAGS, &ifr); … … 65 59 int fd; 66 60 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); 69 63 fd = get_ctl_fd(); 70 64 xioctl(fd, SIOCSIFNAME, &ifr); … … 80 74 s = get_ctl_fd(); 81 75 memset(&ifr, 0, sizeof(ifr)); 82 strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name));76 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 83 77 ifr.ifr_qlen = qlen; 84 78 xioctl(s, SIOCSIFTXQLEN, &ifr); … … 94 88 s = get_ctl_fd(); 95 89 memset(&ifr, 0, sizeof(ifr)); 96 strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name));90 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 97 91 ifr.ifr_mtu = mtu; 98 92 xioctl(s, SIOCSIFMTU, &ifr); … … 111 105 112 106 memset(&ifr, 0, sizeof(ifr)); 113 strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name));107 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 114 108 xioctl(s, SIOCGIFINDEX, &ifr); 115 109 … … 119 113 me.sll_protocol = htons(ETH_P_LOOP); 120 114 xbind(s, (struct sockaddr*)&me, sizeof(me)); 121 122 115 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"); 126 120 close(s); 127 121 *htype = me.sll_hatype; … … 135 129 136 130 memset(ifr, 0, sizeof(*ifr)); 137 strncpy (ifr->ifr_name, dev, sizeof(ifr->ifr_name));131 strncpy_IFNAMSIZ(ifr->ifr_name, dev); 138 132 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); 140 136 if (alen < 0) 141 exit( 1);137 exit(EXIT_FAILURE); 142 138 if (alen != halen) { 143 139 bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen); … … 159 155 160 156 157 static void die_must_be_on_off(const char *msg) NORETURN; 158 static 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 161 163 /* Return value becomes exitcode. It's okay to not return at all */ 162 static int do_set( int argc,char **argv)164 static int do_set(char **argv) 163 165 { 164 166 char *dev = NULL; … … 173 175 int htype, halen; 174 176 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 }; 179 183 smalluint key; 180 184 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); 183 189 if (key == ARG_up) { 184 190 mask |= IFF_UP; … … 194 200 if (mtu != -1) 195 201 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"); 218 208 } else if (key == ARG_addr) { 219 209 NEXT_ARG(); 220 210 newaddr = *argv; 221 } else {211 } else if (key >= ARG_dev) { 222 212 if (key == ARG_dev) { 223 213 NEXT_ARG(); … … 226 216 duparg2("dev", *argv); 227 217 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++; 230 241 } 231 242 … … 238 249 if (newaddr) { 239 250 parse_address(dev, htype, halen, newaddr, &ifr0); 251 set_address(&ifr0, 0); 240 252 } 241 253 if (newbrd) { 242 254 parse_address(dev, htype, halen, newbrd, &ifr1); 255 set_address(&ifr1, 1); 243 256 } 244 257 } … … 254 267 set_mtu(dev, mtu); 255 268 } 256 if (newaddr || newbrd) {257 if (newbrd) {258 set_address(&ifr1, 1);259 }260 if (newaddr) {261 set_address(&ifr0, 0);262 }263 }264 269 if (mask) 265 270 do_chflags(dev, flags, mask); … … 267 272 } 268 273 269 static int ipaddr_list_link( int argc,char **argv)274 static int ipaddr_list_link(char **argv) 270 275 { 271 276 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 275 284 /* Return value becomes exitcode. It's okay to not return at all */ 276 int do_iplink(int argc, char **argv)285 static int do_change(char **argv, const unsigned rtm) 277 286 { 278 287 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 */ 368 int 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 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * iproute.c "ip route".3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 * 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> 9 6 * 10 7 * Changes: 11 8 * 12 * Rani Assaf <rani@magic.metawire.com> 980929: 9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 13 10 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized 14 11 */ 15 12 16 #include "ip_common.h" 13 #include "ip_common.h" /* #include "libbb.h" is inside */ 17 14 #include "rt_names.h" 18 15 #include "utils.h" … … 23 20 24 21 25 typedefstruct filter_t {22 struct filter_t { 26 23 int tb; 27 int flushed;24 smallint flushed; 28 25 char *flushb; 29 26 int flushp; 30 27 int flushe; 31 28 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 36 34 int iif, iifmask; 37 35 int oif, oifmask; 38 int realm, realmmask;39 inet_prefix rprefsrc;36 //int realm, realmmask; - unused 37 //inet_prefix rprefsrc; - read-only 40 38 inet_prefix rvia; 41 39 inet_prefix rdst; … … 43 41 inet_prefix rsrc; 44 42 inet_prefix msrc; 45 } filter_t; 46 47 #define filter (*(filter_t*)&bb_common_bufsiz1) 43 } FIX_ALIASING; 44 typedef struct filter_t filter_t; 45 46 #define G_filter (*(filter_t*)&bb_common_bufsiz1) 48 47 49 48 static int flush_update(void) 50 49 { 51 if (rtnl_send( filter.rth, filter.flushb,filter.flushp) < 0) {52 bb_perror_msg(" failed tosend 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"); 53 52 return -1; 54 53 } 55 filter.flushp = 0;54 G_filter.flushp = 0; 56 55 return 0; 57 56 } … … 65 64 return hz_internal; 66 65 67 fp = fopen ("/proc/net/psched", "r");66 fp = fopen_for_read("/proc/net/psched"); 68 67 if (fp) { 69 68 unsigned nom, denom; … … 79 78 } 80 79 81 static int print_route(struct sockaddr_nl *who ATTRIBUTE_UNUSED,82 struct nlmsghdr *n, void *arg )80 static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, 81 struct nlmsghdr *n, void *arg UNUSED_PARAM) 83 82 { 84 FILE *fp = (FILE*)arg;85 83 struct rtmsg *r = NLMSG_DATA(n); 86 84 int len = n->nlmsg_len; … … 92 90 SPRINT_BUF(b1); 93 91 94 95 92 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { 96 93 fprintf(stderr, "Not a route: %08x %08x %08x\n", … … 98 95 return 0; 99 96 } 100 if ( filter.flushb && n->nlmsg_type != RTM_NEWROUTE)97 if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE) 101 98 return 0; 102 99 len -= NLMSG_LENGTH(sizeof(*r)); … … 110 107 111 108 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)) { 115 112 return 0; 116 113 } 117 114 } else { 118 if (r->rtm_flags &RTM_F_CLONED) {115 if (r->rtm_flags & RTM_F_CLONED) { 119 116 return 0; 120 117 } 121 if ( filter.tb == RT_TABLE_LOCAL) {118 if (G_filter.tb == RT_TABLE_LOCAL) { 122 119 if (r->rtm_type != RTN_LOCAL) { 123 120 return 0; 124 121 } 125 } else if ( filter.tb == RT_TABLE_MAIN) {122 } else if (G_filter.tb == RT_TABLE_MAIN) { 126 123 if (r->rtm_type == RTN_LOCAL) { 127 124 return 0; … … 133 130 } 134 131 } else { 135 if ( filter.tb > 0 &&filter.tb != r->rtm_table) {132 if (G_filter.tb > 0 && G_filter.tb != r->rtm_table) { 136 133 return 0; 137 134 } 138 135 } 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 ) { 155 158 return 0; 156 159 } … … 159 162 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 160 163 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) { 182 196 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) { 184 198 if (flush_update()) 185 199 bb_error_msg_and_die("flush"); 186 200 } 187 fn = (struct nlmsghdr*)( filter.flushb + NLMSG_ALIGN(filter.flushp));201 fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); 188 202 memcpy(fn, n, n->nlmsg_len); 189 203 fn->nlmsg_type = RTM_DELROUTE; 190 204 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; 194 208 return 0; 195 209 } 196 210 197 211 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)); 202 216 } 203 217 204 218 if (tb[RTA_DST]) { 205 219 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 ); 212 225 } else { 213 fprintf(fp,"%s ", format_host(r->rtm_family,214 215 216 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 ); 218 231 } 219 232 } else if (r->rtm_dst_len) { 220 fprintf(fp,"0/%d ", r->rtm_dst_len);233 printf("0/%d ", r->rtm_dst_len); 221 234 } else { 222 fprintf(fp,"default ");235 printf("default "); 223 236 } 224 237 if (tb[RTA_SRC]) { 225 238 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 ); 232 244 } else { 233 fprintf(fp,"from %s ", format_host(r->rtm_family,234 235 236 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 ); 238 250 } 239 251 } 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) { 254 265 /* Do not use format_host(). It is our local addr 255 266 and symbolic name will not be useful. 256 267 */ 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))); 262 271 } 263 272 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])); 265 274 } 266 275 if (r->rtm_family == AF_INET6) { … … 271 280 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { 272 281 if (r->rtm_flags & RTM_F_CLONED) { 273 fprintf(fp,"%c cache ", _SL_);282 printf("%c cache ", _SL_); 274 283 } 275 284 if (ci->rta_expires) { 276 fprintf(fp," expires %dsec", ci->rta_expires / get_hz());285 printf(" expires %dsec", ci->rta_expires / get_hz()); 277 286 } 278 287 if (ci->rta_error != 0) { 279 fprintf(fp," error %d", ci->rta_error);288 printf(" error %d", ci->rta_error); 280 289 } 281 290 } else if (ci) { 282 291 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'); 291 299 return 0; 292 300 } 293 301 294 302 /* 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)303 static int iproute_modify(int cmd, unsigned flags, char **argv) 296 304 { 297 305 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"; 300 308 enum { 301 309 ARG_src, … … 303 311 ARG_mtu, PARM_lock, 304 312 ARG_protocol, 305 USE_FEATURE_IP_RULE(ARG_table,)313 IF_FEATURE_IP_RULE(ARG_table,) 306 314 ARG_dev, 307 315 ARG_oif, 308 ARG_to 316 ARG_to, 317 ARG_metric, 309 318 }; 310 319 enum { … … 316 325 struct rtnl_handle rth; 317 326 struct { 318 struct nlmsghdr 319 struct rtmsg 320 char 327 struct nlmsghdr n; 328 struct rtmsg r; 329 char buf[1024]; 321 330 } req; 322 331 char mxbuf[256]; … … 330 339 331 340 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; 333 342 req.n.nlmsg_type = cmd; 334 343 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; 337 348 338 349 if (cmd != RTM_DELROUTE) { … … 345 356 mxrta->rta_len = RTA_LENGTH(0); 346 357 347 while ( argc > 0) {358 while (*argv) { 348 359 arg = index_in_substrings(keywords, *argv); 349 360 if (arg == ARG_src) { … … 367 378 NEXT_ARG(); 368 379 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"); 374 384 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); 375 385 } else if (arg == ARG_protocol) { … … 391 401 NEXT_ARG(); 392 402 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); 393 408 } else { 394 409 int type; … … 399 414 } 400 415 if ((**argv < '0' || **argv > '9') 401 416 && rtnl_rtntype_a2n(&type, *argv) == 0) { 402 417 NEXT_ARG(); 403 418 req.r.rtm_type = type; … … 418 433 } 419 434 } 420 arg c--; argv++;435 argv++; 421 436 } 422 437 … … 443 458 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT) 444 459 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 ) { 448 465 req.r.rtm_scope = RT_SCOPE_LINK; 466 } 449 467 else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) { 450 468 if (cmd == RTM_DELROUTE) … … 478 496 479 497 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 */ 483 503 req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 484 504 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; 486 507 487 508 return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr)); … … 498 519 499 520 if (write(flush_fd, "-1", 2) < 2) { 500 bb_perror_msg("can not flush routing cache");521 bb_perror_msg("can't flush routing cache"); 501 522 return; 502 523 } … … 506 527 static void iproute_reset_filter(void) 507 528 { 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; 511 532 } 512 533 513 534 /* 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)535 static int iproute_list_or_flush(char **argv, int flush) 515 536 { 516 537 int do_ipv6 = preferred_family; … … 519 540 char *od = NULL; 520 541 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 ; 523 553 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, 532 563 }; 533 564 int arg, parm; 565 534 566 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) 538 570 bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\""); 539 571 540 while ( argc > 0) {572 while (*argv) { 541 573 arg = index_in_substrings(keywords, *argv); 542 if (arg == ARG_proto) {574 if (arg == KW_proto) { 543 575 uint32_t prot = 0; 544 576 NEXT_ARG(); 545 filter.protocolmask = -1;577 //G_filter.protocolmask = -1; 546 578 if (rtnl_rtprot_a2n(&prot, *argv)) { 547 if (index_in_strings(keywords, *argv) != PARM_all)579 if (index_in_strings(keywords, *argv) != KW_all) 548 580 invarg(*argv, "protocol"); 549 581 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) { 554 586 NEXT_ARG(); 555 587 od = *argv; 556 } else if (arg == ARG_iif) {588 } else if (arg == KW_iif) { 557 589 NEXT_ARG(); 558 590 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 */ 563 595 NEXT_ARG(); 564 596 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 570 608 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) { 572 616 NEXT_ARG(); 573 617 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); 580 624 } else { 581 if (parm == PARM_exact)625 if (parm == KW_exact) 582 626 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) { 589 632 NEXT_ARG(); 590 633 arg = index_in_substrings(keywords, *argv); 591 634 } 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) 600 644 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 } 606 649 argv++; 607 650 } 608 651 609 if (do_ipv6 == AF_UNSPEC && filter.tb) {652 if (do_ipv6 == AF_UNSPEC && G_filter.tb) { 610 653 do_ipv6 = AF_INET; 611 654 } 612 655 613 656 xrtnl_open(&rth); 614 615 657 ll_init_map(&rth); 616 658 … … 620 662 if (id) { 621 663 idx = xll_name_to_index(id); 622 filter.iif = idx;623 filter.iifmask = -1;664 G_filter.iif = idx; 665 G_filter.iifmask = -1; 624 666 } 625 667 if (od) { 626 668 idx = xll_name_to_index(od); 627 filter.oif = idx;628 filter.oifmask = -1;669 G_filter.oif = idx; 670 G_filter.oifmask = -1; 629 671 } 630 672 } … … 633 675 char flushb[4096-512]; 634 676 635 if ( filter.tb == -1) {677 if (G_filter.tb == -1) { /* "flush table cache" */ 636 678 if (do_ipv6 != AF_INET6) 637 679 iproute_flush_cache(); … … 640 682 } 641 683 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; 646 688 647 689 for (;;) { 648 690 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) 652 694 return 0; 653 695 if (flush_update()) … … 656 698 } 657 699 658 if ( filter.tb != -1) {700 if (G_filter.tb != -1) { 659 701 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE); 660 702 } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { 661 bb_perror_msg_and_die("can not 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); 664 706 665 707 return 0; … … 668 710 669 711 /* Return value becomes exitcode. It's okay to not return at all */ 670 static int iproute_get( int argc,char **argv)712 static int iproute_get(char **argv) 671 713 { 672 714 struct rtnl_handle rth; … … 688 730 689 731 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; 692 736 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) { 702 746 switch (index_in_strings(options, *argv)) { 703 747 case 0: /* from */ … … 745 789 req.r.rtm_dst_len = addr.bitlen; 746 790 } 747 argc--; argv++;748 }791 } 792 argv++; 749 793 } 750 794 … … 783 827 struct rtattr * tb[RTA_MAX+1]; 784 828 785 print_route(NULL, &req.n, (void*)stdout);829 print_route(NULL, &req.n, NULL); 786 830 787 831 if (req.n.nlmsg_type != RTM_NEWROUTE) { … … 800 844 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); 801 845 } else if (!tb[RTA_SRC]) { 802 bb_error_msg_and_die(" failed toconnect the route");846 bb_error_msg_and_die("can't connect the route"); 803 847 } 804 848 if (!odev && tb[RTA_OIF]) { … … 818 862 } 819 863 } 820 print_route(NULL, &req.n, (void*)stdout);864 print_route(NULL, &req.n, NULL); 821 865 return 0; 822 866 } 823 867 824 868 /* Return value becomes exitcode. It's okay to not return at all */ 825 int do_iproute(int argc,char **argv)869 int FAST_FUNC do_iproute(char **argv) 826 870 { 827 871 static const char ip_route_commands[] ALIGN1 = … … 829 873 /*4-7*/ "delete\0""get\0""list\0""show\0" 830 874 /*8..*/ "prepend\0""replace\0""test\0""flush\0"; 831 int command_num = 6;875 int command_num; 832 876 unsigned flags = 0; 833 877 int cmd = RTM_NEWROUTE; 834 878 879 if (!*argv) 880 return iproute_list_or_flush(argv, 0); 881 835 882 /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */ 836 883 /* 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 840 886 switch (command_num) { 841 887 case 0: /* add */ … … 853 899 break; 854 900 case 5: /* get */ 855 return iproute_get(arg c-1, argv+1);901 return iproute_get(argv+1); 856 902 case 6: /* list */ 857 903 case 7: /* show */ 858 return iproute_list_or_flush(arg c-1, argv+1, 0);904 return iproute_list_or_flush(argv+1, 0); 859 905 case 8: /* prepend */ 860 906 flags = NLM_F_CREATE; 907 break; 861 908 case 9: /* replace */ 862 909 flags = NLM_F_CREATE|NLM_F_REPLACE; 910 break; 863 911 case 10: /* test */ 864 912 flags = NLM_F_EXCL; 913 break; 865 914 case 11: /* flush */ 866 return iproute_list_or_flush(arg c-1, argv+1, 1);915 return iproute_list_or_flush(argv+1, 1); 867 916 default: 868 917 bb_error_msg_and_die("unknown command %s", *argv); 869 918 } 870 919 871 return iproute_modify(cmd, flags, arg c-1, argv+1);920 return iproute_modify(cmd, flags, argv+1); 872 921 } -
branches/2.2.9/mindi-busybox/networking/libiproute/iprule.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 12 9 * 13 10 * Changes: 14 11 * 15 * Rani Assaf <rani@magic.metawire.com> 980929: 16 * initially integrated into busybox by Bernhard Fischer12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 13 * initially integrated into busybox by Bernhard Reutner-Fischer 17 14 */ 18 15 19 #include <syslog.h>20 //#include <sys/socket.h>21 16 #include <netinet/in.h> 22 17 #include <netinet/ip.h> … … 43 38 */ 44 39 45 static int print_rule(struct sockaddr_nl *who ATTRIBUTE_UNUSED, 46 struct nlmsghdr *n, void *arg) 47 { 48 FILE *fp = (FILE*)arg; 40 static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM, 41 struct nlmsghdr *n, void *arg UNUSED_PARAM) 42 { 49 43 struct rtmsg *r = NLMSG_DATA(n); 50 44 int len = n->nlmsg_len; … … 73 67 host_len = 80; 74 68 */ 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 "); 81 73 if (tb[RTA_SRC]) { 82 74 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, 85 76 RTA_DATA(tb[RTA_SRC]), 86 77 abuf, sizeof(abuf)), … … 88 79 ); 89 80 } else { 90 fp rintf(fp, "%s",format_host(r->rtm_family,81 fputs(format_host(r->rtm_family, 91 82 RTA_PAYLOAD(tb[RTA_SRC]), 92 83 RTA_DATA(tb[RTA_SRC]), 93 abuf, sizeof(abuf)) 94 ); 84 abuf, sizeof(abuf)), stdout); 95 85 } 96 86 } else if (r->rtm_src_len) { 97 fprintf(fp,"0/%d", r->rtm_src_len);87 printf("0/%d", r->rtm_src_len); 98 88 } else { 99 fprintf(fp,"all");100 } 101 fprintf(fp, " ");89 printf("all"); 90 } 91 bb_putchar(' '); 102 92 103 93 if (tb[RTA_DST]) { 104 94 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, 107 96 RTA_DATA(tb[RTA_DST]), 108 97 abuf, sizeof(abuf)), … … 110 99 ); 111 100 } else { 112 fprintf(fp,"to %s ", format_host(r->rtm_family,101 printf("to %s ", format_host(r->rtm_family, 113 102 RTA_PAYLOAD(tb[RTA_DST]), 114 103 RTA_DATA(tb[RTA_DST]), … … 116 105 } 117 106 } 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); 119 108 } 120 109 121 110 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)); 123 112 } 124 113 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])); 126 115 } 127 116 128 117 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])); 130 119 } 131 120 132 121 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)); 134 123 135 124 if (tb[RTA_FLOW]) { … … 138 127 to &= 0xFFFF; 139 128 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)); 142 131 } 143 fprintf(fp,"%s ",144 rtnl_rtrealm_n2a(to, b1 , sizeof(b1)));132 printf("%s ", 133 rtnl_rtrealm_n2a(to, b1)); 145 134 } 146 135 147 136 if (r->rtm_type == RTN_NAT) { 148 137 if (tb[RTA_GATEWAY]) { 149 fprintf(fp,"map-to %s ",138 printf("map-to %s ", 150 139 format_host(r->rtm_family, 151 140 RTA_PAYLOAD(tb[RTA_GATEWAY]), … … 153 142 abuf, sizeof(abuf))); 154 143 } else 155 fprintf(fp,"masquerade");144 printf("masquerade"); 156 145 } else if (r->rtm_type != RTN_UNICAST) 157 fp rintf(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();*/ 161 150 return 0; 162 151 } 163 152 164 153 /* Return value becomes exitcode. It's okay to not return at all */ 165 static int iprule_list( int argc,char **argv)154 static int iprule_list(char **argv) 166 155 { 167 156 struct rtnl_handle rth; … … 171 160 af = AF_INET; 172 161 173 if ( argc > 0) {162 if (*argv) { 174 163 //bb_error_msg("\"rule show\" needs no arguments"); 175 bb_warn_ignoring_args( argc);164 bb_warn_ignoring_args(*argv); 176 165 return -1; 177 166 } … … 180 169 181 170 xrtnl_wilddump_request(&rth, af, RTM_GETRULE); 182 xrtnl_dump_filter(&rth, print_rule, stdout);171 xrtnl_dump_filter(&rth, print_rule, NULL); 183 172 184 173 return 0; … … 186 175 187 176 /* Return value becomes exitcode. It's okay to not return at all */ 188 static int iprule_modify(int cmd, int argc,char **argv)177 static int iprule_modify(int cmd, char **argv) 189 178 { 190 179 static const char keywords[] ALIGN1 = … … 200 189 struct rtnl_handle rth; 201 190 struct { 202 struct nlmsghdr 203 struct rtmsg 204 char 191 struct nlmsghdr n; 192 struct rtmsg r; 193 char buf[1024]; 205 194 } req; 206 195 smalluint key; … … 222 211 } 223 212 224 while ( argc > 0) {213 while (*argv) { 225 214 key = index_in_substrings(keywords, *argv) + 1; 226 215 if (key == 0) /* no match found in keywords array, bail out. */ … … 240 229 } else if (key == ARG_preference || 241 230 key == ARG_order || 242 key == ARG_priority) { 231 key == ARG_priority 232 ) { 243 233 uint32_t pref; 244 234 NEXT_ARG(); 245 if (get_u32(&pref, *argv, 0)) 246 invarg(*argv, "preference"); 235 pref = get_u32(*argv, "preference"); 247 236 addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref); 248 237 } else if (key == ARG_tos) { … … 255 244 uint32_t fwmark; 256 245 NEXT_ARG(); 257 if (get_u32(&fwmark, *argv, 0)) 258 invarg(*argv, "fwmark"); 246 fwmark = get_u32(*argv, "fwmark"); 259 247 addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark); 260 248 } else if (key == ARG_realms) { … … 265 253 addattr32(&req.n, sizeof(req), RTA_FLOW, realm); 266 254 } else if (key == ARG_table || 267 key == ARG_lookup) { 255 key == ARG_lookup 256 ) { 268 257 uint32_t tid; 269 258 NEXT_ARG(); … … 273 262 table_ok = 1; 274 263 } else if (key == ARG_dev || 275 key == ARG_iif) { 264 key == ARG_iif 265 ) { 276 266 NEXT_ARG(); 277 267 addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1); 278 268 } else if (key == ARG_nat || 279 key == ARG_map_to) { 269 key == ARG_map_to 270 ) { 280 271 NEXT_ARG(); 281 272 addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); … … 293 284 req.r.rtm_type = type; 294 285 } 295 argc--;296 286 argv++; 297 287 } … … 312 302 313 303 /* Return value becomes exitcode. It's okay to not return at all */ 314 int do_iprule(int argc,char **argv)304 int FAST_FUNC do_iprule(char **argv) 315 305 { 316 306 static const char ip_rule_commands[] ALIGN1 = 317 307 "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 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * iptunnel.c "ip tunnel"3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 * 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> 9 6 * 10 7 * Changes: 11 8 * 12 * Rani Assaf <rani@magic.metawire.com> 980929: 13 * Rani Assaf <rani@magic.metawire.com> 980930: 14 * Phil Karn <karn@ka9q.ampr.org> 990408:"pmtudisc" flag9 * 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 15 12 */ 16 13 … … 19 16 #include <net/if_arp.h> 20 17 #include <asm/types.h> 18 21 19 #ifndef __constant_htons 22 20 #define __constant_htons htons 23 21 #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) 43 struct 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 25 64 26 65 #include "ip_common.h" /* #include "libbb.h" is inside */ … … 35 74 int fd; 36 75 37 strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name));76 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 38 77 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 39 78 xioctl(fd, SIOCGIFINDEX, &ifr); … … 48 87 int err; 49 88 50 strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name));89 strncpy_IFNAMSIZ(ifr.ifr_name, dev); 51 90 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 52 91 err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr); … … 74 113 int err; 75 114 76 strncpy (ifr.ifr_name, basedev, sizeof(ifr.ifr_name));115 strncpy_IFNAMSIZ(ifr.ifr_name, basedev); 77 116 ifr.ifr_ifru.ifru_data = (void*)p; 78 117 fd = xsocket(AF_INET, SOCK_DGRAM, 0); … … 89 128 90 129 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); 92 131 } else { 93 strncpy (ifr.ifr_name, basedev, sizeof(ifr.ifr_name));132 strncpy_IFNAMSIZ(ifr.ifr_name, basedev); 94 133 } 95 134 ifr.ifr_ifru.ifru_data = (void*)p; … … 115 154 116 155 if (p->name[0]) { 117 strncpy (ifr.ifr_name, p->name, sizeof(ifr.ifr_name));156 strncpy_IFNAMSIZ(ifr.ifr_name, p->name); 118 157 } else { 119 strncpy (ifr.ifr_name, basedev, sizeof(ifr.ifr_name));158 strncpy_IFNAMSIZ(ifr.ifr_name, basedev); 120 159 } 121 160 ifr.ifr_ifru.ifru_data = (void*)p; … … 127 166 128 167 /* Dies on error */ 129 static void parse_args( int argc,char **argv, int cmd, struct ip_tunnel_parm *p)168 static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p) 130 169 { 131 170 static const char keywords[] ALIGN1 = … … 149 188 150 189 memset(p, 0, sizeof(*p)); 151 me mset(&medium, 0, sizeof(medium));190 medium[0] = '\0'; 152 191 153 192 p->iph.version = 4; … … 158 197 p->iph.frag_off = htons(IP_DF); 159 198 160 while ( argc > 0) {199 while (*argv) { 161 200 key = index_in_strings(keywords, *argv); 162 201 if (key == ARG_mode) { … … 164 203 key = index_in_strings(keywords, *argv); 165 204 if (key == ARG_ipip || 166 key == ARG_ip_ip) { 205 key == ARG_ip_ip 206 ) { 167 207 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"); 169 209 } 170 210 p->iph.protocol = IPPROTO_IPIP; 171 211 } else if (key == ARG_gre || 172 key == ARG_gre_ip) { 212 key == ARG_gre_ip 213 ) { 173 214 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"); 175 216 } 176 217 p->iph.protocol = IPPROTO_GRE; 177 218 } else if (key == ARG_sit || 178 key == ARG_ip6_ip) { 219 key == ARG_ip6_ip 220 ) { 179 221 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"); 181 223 } 182 224 p->iph.protocol = IPPROTO_IPV6; 183 225 } else { 184 bb_error_msg_and_die(" cannot guess tunnel mode");226 bb_error_msg_and_die("%s tunnel mode", "can't guess"); 185 227 } 186 228 } else if (key == ARG_key) { … … 192 234 p->i_key = p->o_key = get_addr32(*argv); 193 235 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"); 197 237 p->i_key = p->o_key = htonl(uval); 198 238 } … … 204 244 p->o_key = get_addr32(*argv); 205 245 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"); 209 247 p->i_key = htonl(uval); 210 248 } … … 216 254 p->o_key = get_addr32(*argv); 217 255 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"); 221 257 p->o_key = htonl(uval); 222 258 } … … 251 287 } else if (key == ARG_dev) { 252 288 NEXT_ARG(); 253 strncpy (medium, *argv, IFNAMSIZ-1);289 strncpy_IFNAMSIZ(medium, *argv); 254 290 } else if (key == ARG_ttl) { 255 291 unsigned uval; … … 257 293 key = index_in_strings(keywords, *argv); 258 294 if (key != ARG_inherit) { 259 if (get_unsigned(&uval, *argv, 0)) 260 invarg(*argv, "TTL"); 295 uval = get_unsigned(*argv, "TTL"); 261 296 if (uval > 255) 262 297 invarg(*argv, "TTL must be <=255"); … … 264 299 } 265 300 } else if (key == ARG_tos || 266 key == ARG_dsfield) { 301 key == ARG_dsfield 302 ) { 267 303 uint32_t uval; 268 304 NEXT_ARG(); … … 280 316 if (p->name[0]) 281 317 duparg2("name", *argv); 282 strncpy (p->name, *argv, IFNAMSIZ);318 strncpy_IFNAMSIZ(p->name, *argv); 283 319 if (cmd == SIOCCHGTUNNEL && count == 0) { 284 320 struct ip_tunnel_parm old_p; 285 321 memset(&old_p, 0, sizeof(old_p)); 286 322 if (do_get_ioctl(*argv, &old_p)) 287 exit( 1);323 exit(EXIT_FAILURE); 288 324 *p = old_p; 289 325 } 290 326 } 291 327 count++; 292 argc--;293 328 argv++; 294 329 } … … 326 361 } 327 362 328 329 363 /* Return value becomes exitcode. It's okay to not return at all */ 330 static int do_add(int cmd, int argc,char **argv)364 static int do_add(int cmd, char **argv) 331 365 { 332 366 struct ip_tunnel_parm p; 333 367 334 parse_args(arg c, argv, cmd, &p);368 parse_args(argv, cmd, &p); 335 369 336 370 if (p.iph.ttl && p.iph.frag_off == 0) { … … 346 380 return do_add_ioctl(cmd, "sit0", &p); 347 381 default: 348 bb_error_msg_and_die("can not determine tunnel mode (ipip, gre or sit)");382 bb_error_msg_and_die("can't determine tunnel mode (ipip, gre or sit)"); 349 383 } 350 384 } 351 385 352 386 /* Return value becomes exitcode. It's okay to not return at all */ 353 static int do_del( int argc,char **argv)387 static int do_del(char **argv) 354 388 { 355 389 struct ip_tunnel_parm p; 356 390 357 parse_args(arg c, argv, SIOCDELTUNNEL, &p);391 parse_args(argv, SIOCDELTUNNEL, &p); 358 392 359 393 switch (p.iph.protocol) { … … 405 439 if (p->iph.tos & ~1) 406 440 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)); 408 442 } 409 443 if (!(p->iph.frag_off & htons(IP_DF))) … … 444 478 return; 445 479 } 446 480 /* skip headers */ 447 481 fgets(buf, sizeof(buf), fp); 448 482 fgets(buf, sizeof(buf), fp); … … 454 488 ptr = strchr(buf, ':'); 455 489 if (ptr == NULL || 456 (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { 490 (*ptr++ = 0, sscanf(buf, "%s", name) != 1) 491 ) { 457 492 bb_error_msg("wrong format of /proc/net/dev"); 458 493 return; … … 468 503 type = do_ioctl_get_iftype(name); 469 504 if (type == -1) { 470 bb_error_msg("can not get type of [%s]", name);505 bb_error_msg("can't get type of [%s]", name); 471 506 continue; 472 507 } … … 480 515 (p->iph.daddr && p1.iph.daddr != p->iph.daddr) || 481 516 (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 ) { 483 519 continue; 520 } 484 521 print_tunnel(&p1); 485 puts("");522 bb_putchar('\n'); 486 523 } 487 524 } 488 525 489 526 /* Return value becomes exitcode. It's okay to not return at all */ 490 static int do_show( int argc,char **argv)527 static int do_show(char **argv) 491 528 { 492 529 int err; 493 530 struct ip_tunnel_parm p; 494 531 495 parse_args(arg c, argv, SIOCGETTUNNEL, &p);532 parse_args(argv, SIOCGETTUNNEL, &p); 496 533 497 534 switch (p.iph.protocol) { … … 513 550 514 551 print_tunnel(&p); 515 puts("");552 bb_putchar('\n'); 516 553 return 0; 517 554 } 518 555 519 556 /* Return value becomes exitcode. It's okay to not return at all */ 520 int do_iptunnel(int argc,char **argv)557 int FAST_FUNC do_iptunnel(char **argv) 521 558 { 522 559 static const char keywords[] ALIGN1 = 523 560 "add\0""change\0""delete\0""show\0""list\0""lst\0"; 524 561 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) 530 566 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 531 --argc; 532 ++argv; 567 argv++; 533 568 if (key == ARG_add) 534 return do_add(SIOCADDTUNNEL, arg c, argv);569 return do_add(SIOCADDTUNNEL, argv); 535 570 if (key == ARG_change) 536 return do_add(SIOCCHGTUNNEL, arg c, argv);571 return do_add(SIOCCHGTUNNEL, argv); 537 572 if (key == ARG_del) 538 return do_del(arg c, argv);539 } 540 return do_show(arg c, 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 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 12 9 */ 13 10 … … 18 15 #include "libnetlink.h" 19 16 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*/) 17 void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) 26 18 { 27 19 socklen_t addr_len; 28 20 29 memset(rth, 0, sizeof(rth)); 30 21 memset(rth, 0, sizeof(*rth)); 31 22 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 32 33 memset(&rth->local, 0, sizeof(rth->local));34 23 rth->local.nl_family = AF_NETLINK; 35 24 /*rth->local.nl_groups = subscriptions;*/ … … 37 26 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)); 38 27 addr_len = sizeof(rth->local); 28 getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len); 29 30 /* too much paranoia 39 31 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) 40 bb_perror_msg_and_die(" cannotgetsockname");32 bb_perror_msg_and_die("getsockname"); 41 33 if (addr_len != sizeof(rth->local)) 42 34 bb_error_msg_and_die("wrong address length %d", addr_len); 43 35 if (rth->local.nl_family != AF_NETLINK) 44 36 bb_error_msg_and_die("wrong address family %d", rth->local.nl_family); 37 */ 45 38 rth->seq = time(NULL); 46 return 0; 47 } 48 49 int xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 39 } 40 41 int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 50 42 { 51 43 struct { … … 53 45 struct rtgenmsg g; 54 46 } req; 55 struct sockaddr_nl nladdr;56 57 memset(&nladdr, 0, sizeof(nladdr));58 nladdr.nl_family = AF_NETLINK;59 47 60 48 req.nlh.nlmsg_len = sizeof(req); … … 65 53 req.g.rtgen_family = family; 66 54 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 58 int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) 72 59 { 73 60 struct sockaddr_nl nladdr; … … 79 66 } 80 67 81 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)68 int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) 82 69 { 83 70 struct nlmsghdr nlh; … … 86 73 struct msghdr msg = { 87 74 (void*)&nladdr, sizeof(nladdr), 88 iov, 89 NULL, 75 iov, 2, 76 NULL, 0, 90 77 0 91 78 }; … … 104 91 105 92 static 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, 107 94 void *arg1/*, 108 95 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 109 96 void *arg2*/) 110 97 { 111 char buf[8192]; 98 int retval = -1; 99 char *buf = xmalloc(8*1024); /* avoid big stack buffer */ 112 100 struct sockaddr_nl nladdr; 113 struct iovec iov = { buf, sizeof(buf)};101 struct iovec iov = { buf, 8*1024 }; 114 102 115 103 while (1) { … … 119 107 struct msghdr msg = { 120 108 (void*)&nladdr, sizeof(nladdr), 121 &iov, 122 NULL, 109 &iov, 1, 110 NULL, 0, 123 111 0 124 112 }; … … 134 122 if (status == 0) { 135 123 bb_error_msg("EOF on netlink"); 136 return -1;124 goto ret; 137 125 } 138 126 if (msg.msg_namelen != sizeof(nladdr)) { … … 146 134 if (nladdr.nl_pid != 0 || 147 135 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 // } 154 145 goto skip_it; 155 146 } 156 147 157 148 if (h->nlmsg_type == NLMSG_DONE) { 158 return0;149 goto ret_0; 159 150 } 160 151 if (h->nlmsg_type == NLMSG_ERROR) { … … 166 157 bb_perror_msg("RTNETLINK answers"); 167 158 } 168 return -1;159 goto ret; 169 160 } 170 161 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: 175 168 h = NLMSG_NEXT(h, status); 176 169 } … … 182 175 bb_error_msg_and_die("remnant of size %d!", status); 183 176 } 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 185 int FAST_FUNC xrtnl_dump_filter(struct rtnl_handle *rth, 186 int (*filter)(const struct sockaddr_nl *, struct nlmsghdr *, void *) FAST_FUNC, 189 187 void *arg1) 190 188 { … … 195 193 } 196 194 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 { 195 int 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; 202 207 int status; 203 208 unsigned seq; … … 205 210 struct sockaddr_nl nladdr; 206 211 struct iovec iov = { (void*)n, n->nlmsg_len }; 207 char buf[8192];212 char *buf = xmalloc(8*1024); /* avoid big stack buffer */ 208 213 struct msghdr msg = { 209 214 (void*)&nladdr, sizeof(nladdr), 210 &iov, 211 NULL, 215 &iov, 1, 216 NULL, 0, 212 217 0 213 218 }; … … 215 220 memset(&nladdr, 0, sizeof(nladdr)); 216 221 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; 219 224 220 225 n->nlmsg_seq = seq = ++rtnl->seq; … … 225 230 226 231 if (status < 0) { 227 bb_perror_msg("can not talk to rtnetlink");228 return -1;232 bb_perror_msg("can't talk to rtnetlink"); 233 goto ret; 229 234 } 230 235 … … 232 237 233 238 while (1) { 234 iov.iov_len = sizeof(buf);239 iov.iov_len = 8*1024; 235 240 status = recvmsg(rtnl->fd, &msg, 0); 236 241 … … 244 249 if (status == 0) { 245 250 bb_error_msg("EOF on netlink"); 246 return -1;251 goto ret; 247 252 } 248 253 if (msg.msg_namelen != sizeof(nladdr)) { 249 254 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen); 250 255 } 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; 253 258 int len = h->nlmsg_len; 254 259 int l = len - sizeof(*h); 255 260 256 if (l <0 || len>status) {261 if (l < 0 || len > status) { 257 262 if (msg.msg_flags & MSG_TRUNC) { 258 263 bb_error_msg("truncated message"); 259 return -1;264 goto ret; 260 265 } 261 266 bb_error_msg_and_die("malformed message: len=%d!", len); … … 264 269 if (nladdr.nl_pid != peer || 265 270 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 // } 273 280 continue; 274 281 } … … 276 283 if (h->nlmsg_type == NLMSG_ERROR) { 277 284 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 278 if (l < sizeof(struct nlmsgerr)) {285 if (l < (int)sizeof(struct nlmsgerr)) { 279 286 bb_error_msg("ERROR truncated"); 280 287 } else { 281 errno = - err->error;288 errno = - err->error; 282 289 if (errno == 0) { 283 290 if (answer) { 284 291 memcpy(answer, h, h->nlmsg_len); 285 292 } 286 return0;293 goto ret_0; 287 294 } 288 295 bb_perror_msg("RTNETLINK answers"); 289 296 } 290 return -1;297 goto ret; 291 298 } 292 299 if (answer) { 293 300 memcpy(answer, h, h->nlmsg_len); 294 return0;301 goto ret_0; 295 302 } 296 303 … … 307 314 bb_error_msg_and_die("remnant of size %d!", status); 308 315 } 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 324 int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) 313 325 { 314 326 int len = RTA_LENGTH(4); 315 327 struct rtattr *rta; 316 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) 328 329 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) { 317 330 return -1; 331 } 318 332 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); 319 333 rta->rta_type = type; 320 334 rta->rta_len = len; 321 m emcpy(RTA_DATA(rta), &data, 4);335 move_to_unaligned32(RTA_DATA(rta), data); 322 336 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 323 337 return 0; 324 338 } 325 339 326 int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)340 int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) 327 341 { 328 342 int len = RTA_LENGTH(alen); 329 343 struct rtattr *rta; 330 344 331 if ( NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)345 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) { 332 346 return -1; 347 } 333 348 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); 334 349 rta->rta_type = type; … … 339 354 } 340 355 341 int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data)356 int FAST_FUNC rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) 342 357 { 343 358 int len = RTA_LENGTH(4); … … 350 365 subrta->rta_type = type; 351 366 subrta->rta_len = len; 352 m emcpy(RTA_DATA(subrta), &data, 4);367 move_to_unaligned32(RTA_DATA(subrta), data); 353 368 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; 354 369 return 0; 355 370 } 356 371 357 int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)372 int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) 358 373 { 359 374 struct rtattr *subrta; … … 372 387 373 388 374 intparse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)389 void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 375 390 { 376 391 while (RTA_OK(rta, len)) { … … 383 398 bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); 384 399 } 385 return 0; 386 } 400 } -
branches/2.2.9/mindi-busybox/networking/libiproute/libnetlink.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 #ifndef __LIBNETLINK_H__3 #define __LIBNETLINK_H__12 #ifndef LIBNETLINK_H 3 #define LIBNETLINK_H 1 4 4 5 5 #include <linux/types.h> … … 9 9 #include <linux/rtnetlink.h> 10 10 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; 11 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 12 13 struct rtnl_handle { 14 int fd; 15 struct sockaddr_nl local; 16 struct sockaddr_nl peer; 17 uint32_t seq; 18 uint32_t dump; 18 19 }; 19 20 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) ;21 extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC; 22 #define rtnl_close(rth) (close((rth)->fd)) 23 extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC; 24 extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC; 24 25 extern 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) 27 32 extern 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 37 extern int rtnl_send(struct rtnl_handle *rth, char *buf, int) FAST_FUNC; 32 38 33 39 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) ;40 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC; 41 extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC; 42 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) FAST_FUNC; 43 extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) FAST_FUNC; 38 44 39 extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);45 extern void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) FAST_FUNC; 40 46 41 #endif /* __LIBNETLINK_H__ */ 47 POP_SAVED_FUNCTION_VISIBILITY 48 49 #endif -
branches/2.2.9/mindi-busybox/networking/libiproute/ll_addr.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 11 9 */ 12 10 … … 18 16 19 17 20 const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen)18 const char* FAST_FUNC ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen) 21 19 { 22 20 int i; 23 21 int l; 24 22 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 ) { 27 26 return inet_ntop(AF_INET, addr, buf, blen); 28 27 } 29 28 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]); 33 32 blen -= 2; 34 33 l += 2; 35 34 } else { 36 snprintf(buf +l, blen, ":%02x", addr[i]);35 snprintf(buf + l, blen, ":%02x", addr[i]); 37 36 blen -= 3; 38 37 l += 3; … … 42 41 } 43 42 44 int ll_addr_a2n(unsigned char *lladdr, int len, char *arg)43 int FAST_FUNC ll_addr_a2n(unsigned char *lladdr, int len, char *arg) 45 44 { 45 int i; 46 46 47 if (strchr(arg, '.')) { 47 48 inet_prefix pfx; … … 55 56 memcpy(lladdr, pfx.data, 4); 56 57 return 4; 57 } else { 58 int i; 58 } 59 59 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++; 80 66 } 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; 82 76 } 77 return i+1; 83 78 } -
branches/2.2.9/mindi-busybox/networking/libiproute/ll_map.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 12 9 */ 13 10 14 #include <net/if.h> 11 #include <net/if.h> /* struct ifreq and co. */ 15 12 16 13 #include "libbb.h" … … 28 25 }; 29 26 30 static struct idxmap * idxmap[16];27 static struct idxmap **idxmap; /* treat as *idxmap[16] */ 31 28 32 29 static struct idxmap *find_by_index(int idx) … … 34 31 struct idxmap *im; 35 32 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; 39 37 return NULL; 40 38 } 41 39 42 int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 40 int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM, 41 struct nlmsghdr *n, 42 void *arg UNUSED_PARAM) 43 43 { 44 44 int h; … … 58 58 return 0; 59 59 60 if (!idxmap) 61 idxmap = xzalloc(sizeof(idxmap[0]) * 16); 62 60 63 h = ifi->ifi_index & 0xF; 61 62 64 for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next) 63 65 if (im->index == ifi->ifi_index) … … 74 76 int alen; 75 77 im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); 76 if (alen > sizeof(im->addr))78 if (alen > (int)sizeof(im->addr)) 77 79 alen = sizeof(im->addr); 78 80 memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); … … 85 87 } 86 88 87 const char *ll_idx_n2a(int idx, char *buf)89 const char FAST_FUNC *ll_idx_n2a(int idx, char *buf) 88 90 { 89 91 struct idxmap *im; … … 99 101 100 102 101 const char *ll_index_to_name(int idx)103 const char FAST_FUNC *ll_index_to_name(int idx) 102 104 { 103 105 static char nbuf[16]; … … 120 122 #endif 121 123 122 unsigned ll_index_to_flags(int idx)124 unsigned FAST_FUNC ll_index_to_flags(int idx) 123 125 { 124 126 struct idxmap *im; … … 132 134 } 133 135 134 int xll_name_to_index(const char *constname)136 int FAST_FUNC xll_name_to_index(const char *name) 135 137 { 136 138 int ret = 0; … … 151 153 goto out; 152 154 } 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 } 160 164 } 161 165 } … … 171 175 172 176 sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 173 if (sock_fd ) {177 if (sock_fd >= 0) { 174 178 struct ifreq ifr; 175 179 int tmp; 176 180 177 strncpy (ifr.ifr_name, name, IFNAMSIZ);181 strncpy_IFNAMSIZ(ifr.ifr_name, name); 178 182 ifr.ifr_ifindex = -1; 179 183 tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr); … … 187 191 /* out:*/ 188 192 if (ret <= 0) 189 bb_error_msg_and_die("can not find device \"%s\"", name);193 bb_error_msg_and_die("can't find device '%s'", name); 190 194 return ret; 191 195 } 192 196 193 int ll_init_map(struct rtnl_handle *rth)197 int FAST_FUNC ll_init_map(struct rtnl_handle *rth) 194 198 { 195 199 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); 197 201 return 0; 198 202 } -
branches/2.2.9/mindi-busybox/networking/libiproute/ll_map.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 #ifndef __LL_MAP_H__3 #define __LL_MAP_H__12 #ifndef LL_MAP_H 3 #define LL_MAP_H 1 4 4 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); 5 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 6 7 int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) FAST_FUNC; 8 int ll_init_map(struct rtnl_handle *rth) FAST_FUNC; 9 int xll_name_to_index(const char *name) FAST_FUNC; 10 const char *ll_index_to_name(int idx) FAST_FUNC; 11 const char *ll_idx_n2a(int idx, char *buf) FAST_FUNC; 10 12 /* int ll_index_to_type(int idx); */ 11 unsigned ll_index_to_flags(int idx) ;13 unsigned ll_index_to_flags(int idx) FAST_FUNC; 12 14 13 #endif /* __LL_MAP_H__ */ 15 POP_SAVED_FUNCTION_VISIBILITY 16 17 #endif -
branches/2.2.9/mindi-busybox/networking/libiproute/ll_proto.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 11 9 */ 12 10 … … 20 18 #include <linux/if_ether.h> 21 19 #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 */ 22 28 23 29 #define __PF(f,n) { ETH_P_##f, #n }, … … 91 97 92 98 93 const char *ll_proto_n2a(unsigned short id, char *buf, int len)99 const char* FAST_FUNC ll_proto_n2a(unsigned short id, char *buf, int len) 94 100 { 95 int i; 96 101 unsigned i; 97 102 id = ntohs(id); 98 99 for (i=0; i < ARRAY_SIZE(llproto_names); i++) { 103 for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { 100 104 if (llproto_names[i].id == id) 101 105 return llproto_names[i].name; … … 105 109 } 106 110 107 int ll_proto_a2n(unsigned short *id, char *buf)111 int FAST_FUNC ll_proto_a2n(unsigned short *id, char *buf) 108 112 { 109 inti;110 for (i =0; i < ARRAY_SIZE(llproto_names); i++) {113 unsigned i; 114 for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { 111 115 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; 114 118 } 115 119 } 116 if (get_u16(id, buf, 0)) 120 i = bb_strtou(buf, NULL, 0); 121 if (errno || i > 0xffff) 117 122 return -1; 118 *id = htons(*id); 123 good: 124 *id = htons(i); 119 125 return 0; 120 126 } -
branches/2.2.9/mindi-busybox/networking/libiproute/ll_types.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 11 9 */ 12 10 #include <arpa/inet.h> … … 16 14 #include "rt_names.h" 17 15 18 const char* ll_type_n2a(int type, char *buf, int len)16 const char* FAST_FUNC ll_type_n2a(int type, char *buf) 19 17 { 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 31 25 #ifdef ARPHRD_IEEE802_TR 32 __PF(IEEE802,ieee802) 26 /* ARPHRD_IEEE802, */ "ieee802" "\0" 27 /* ARPHRD_IEEE802_TR, */ "tr" "\0" 33 28 #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" 39 59 #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 43 123 #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" */ 55 156 #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" */ 61 161 #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; 114 200 } 115 s nprintf(buf, len, "[%d]", type);201 sprintf(buf, "[%d]", type); 116 202 return buf; 117 203 } -
branches/2.2.9/mindi-busybox/networking/libiproute/rt_names.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 11 9 */ 12 13 10 #include "libbb.h" 14 11 #include "rt_names.h" 15 12 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 13 typedef struct rtnl_tab_t { 14 const char *cached_str; 15 unsigned cached_result; 16 const char *tab[256]; 17 } rtnl_tab_t; 18 19 static 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 36 static 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 37 48 ) { 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; 41 53 } 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 64 static rtnl_tab_t *rtnl_rtprot_tab; 53 65 54 66 static void rtnl_rtprot_initialize(void) … … 69 81 "bird", 70 82 }; 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 s nprintf(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 91 const char* FAST_FUNC rtnl_rtprot_n2a(int id, char *buf) 92 { 93 if (id < 0 || id >= 256) { 94 sprintf(buf, "%d", id); 83 95 return buf; 84 96 } … … 86 98 rtnl_rtprot_initialize(); 87 99 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 107 int FAST_FUNC rtnl_rtprot_a2n(uint32_t *id, char *arg) 108 { 105 109 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 114 static rtnl_tab_t *rtnl_rtscope_tab; 126 115 127 116 static void rtnl_rtscope_initialize(void) 128 117 { 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 129 const char* FAST_FUNC rtnl_rtscope_n2a(int id, char *buf) 130 { 131 if (id < 0 || id >= 256) { 132 sprintf(buf, "%d", id); 145 133 return buf; 146 134 } … … 148 136 rtnl_rtscope_initialize(); 149 137 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 145 int FAST_FUNC rtnl_rtscope_a2n(uint32_t *id, char *arg) 146 { 167 147 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 152 static rtnl_tab_t *rtnl_rtrealm_tab; 188 153 189 154 static void rtnl_rtrealm_initialize(void) 190 155 { 191 156 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 162 int FAST_FUNC rtnl_rtrealm_a2n(uint32_t *id, char *arg) 163 { 210 164 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); 227 166 } 228 167 229 168 #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 s nprintf(buf, len, "%d", id);169 const char* FAST_FUNC rtnl_rtrealm_n2a(int id, char *buf) 170 { 171 if (id < 0 || id >= 256) { 172 sprintf(buf, "%d", id); 234 173 return buf; 235 174 } … … 237 176 rtnl_rtrealm_initialize(); 238 177 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); 242 182 return buf; 243 183 } … … 245 185 246 186 247 static const char **rtnl_rtdsfield_tab; /* [256] */187 static rtnl_tab_t *rtnl_rtdsfield_tab; 248 188 249 189 static void rtnl_rtdsfield_initialize(void) 250 190 { 251 191 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 197 const char* FAST_FUNC rtnl_dsfield_n2a(int id, char *buf) 198 { 199 if (id < 0 || id >= 256) { 200 sprintf(buf, "%d", id); 263 201 return buf; 264 202 } … … 266 204 rtnl_rtdsfield_initialize(); 267 205 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 213 int FAST_FUNC rtnl_dsfield_a2n(uint32_t *id, char *arg) 214 { 286 215 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); 303 217 } 304 218 305 219 306 220 #if ENABLE_FEATURE_IP_RULE 307 static const char **rtnl_rttable_tab; /* [256] */221 static rtnl_tab_t *rtnl_rttable_tab; 308 222 309 223 static void rtnl_rttable_initialize(void) 310 224 { 311 225 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 234 const char* FAST_FUNC rtnl_rttable_n2a(int id, char *buf) 235 { 236 if (id < 0 || id >= 256) { 237 sprintf(buf, "%d", id); 325 238 return buf; 326 239 } … … 328 241 rtnl_rttable_initialize(); 329 242 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 250 int FAST_FUNC rtnl_rttable_a2n(uint32_t *id, char *arg) 251 { 347 252 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); 363 254 } 364 255 -
branches/2.2.9/mindi-busybox/networking/libiproute/rt_names.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 #ifndef RT_NAMES_H _3 #define RT_NAMES_H _12 #ifndef RT_NAMES_H 3 #define RT_NAMES_H 1 4 4 5 #include <stdint.h> 5 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 6 6 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 */ 8 extern const char* rtnl_rtprot_n2a(int id, char *buf) FAST_FUNC; 9 extern const char* rtnl_rtscope_n2a(int id, char *buf) FAST_FUNC; 10 extern const char* rtnl_rtrealm_n2a(int id, char *buf) FAST_FUNC; 11 extern const char* rtnl_dsfield_n2a(int id, char *buf) FAST_FUNC; 12 extern const char* rtnl_rttable_n2a(int id, char *buf) FAST_FUNC; 13 extern int rtnl_rtprot_a2n(uint32_t *id, char *arg) FAST_FUNC; 14 extern int rtnl_rtscope_a2n(uint32_t *id, char *arg) FAST_FUNC; 15 extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg) FAST_FUNC; 16 extern int rtnl_dsfield_a2n(uint32_t *id, char *arg) FAST_FUNC; 17 extern int rtnl_rttable_a2n(uint32_t *id, char *arg) FAST_FUNC; 17 18 18 19 extern const char* ll_type_n2a(int type, char *buf, int len); 19 extern const char* ll_type_n2a(int type, char *buf) FAST_FUNC; 20 20 21 21 extern 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; 23 extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg) FAST_FUNC; 24 24 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); 25 extern const char* ll_proto_n2a(unsigned short id, char *buf, int len) FAST_FUNC; 26 extern int ll_proto_a2n(unsigned short *id, char *buf) FAST_FUNC; 27 28 POP_SAVED_FUNCTION_VISIBILITY 27 29 28 30 #endif -
branches/2.2.9/mindi-busybox/networking/libiproute/rtm_map.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 7 * 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> 12 9 */ 13 10 … … 16 13 #include "utils.h" 17 14 18 const char *rtnl_rtntype_n2a(int id, char *buf, int len)15 const char* FAST_FUNC rtnl_rtntype_n2a(int id, char *buf) 19 16 { 20 17 switch (id) { … … 44 41 return "xresolve"; 45 42 default: 46 snprintf(buf, len, "%d", id); 43 /* buf is SPRINT_BSIZE big */ 44 sprintf(buf, "%d", id); 47 45 return buf; 48 46 } … … 50 48 51 49 52 int rtnl_rtntype_a2n(int *id, char *arg)50 int FAST_FUNC rtnl_rtntype_a2n(int *id, char *arg) 53 51 { 54 52 static const char keywords[] ALIGN1 = … … 89 87 else { 90 88 res = strtoul(arg, &end, 0); 91 if ( !end ||end == arg || *end || res > 255)89 if (end == arg || *end || res > 255) 92 90 return -1; 93 91 } … … 96 94 } 97 95 98 int get_rt_realms(uint32_t *realms, char *arg)96 int FAST_FUNC get_rt_realms(uint32_t *realms, char *arg) 99 97 { 100 98 uint32_t realm = 0; -
branches/2.2.9/mindi-busybox/networking/libiproute/rtm_map.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 #ifndef __RTM_MAP_H__3 #define __RTM_MAP_H__12 #ifndef RTM_MAP_H 3 #define RTM_MAP_H 1 4 4 5 const char *rtnl_rtntype_n2a(int id, char *buf, int len); 6 int rtnl_rtntype_a2n(int *id, char *arg); 5 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 7 6 8 int get_rt_realms(uint32_t *realms, char *arg); 7 const char *rtnl_rtntype_n2a(int id, char *buf) FAST_FUNC; 8 int rtnl_rtntype_a2n(int *id, char *arg) FAST_FUNC; 9 9 10 int get_rt_realms(uint32_t *realms, char *arg) FAST_FUNC; 10 11 11 #endif /* __RTM_MAP_H__ */ 12 POP_SAVED_FUNCTION_VISIBILITY 13 14 #endif -
branches/2.2.9/mindi-busybox/networking/libiproute/utils.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * utils.c3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 4 * 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> 8 6 * 9 7 * Changes: 10 8 * 11 * Rani Assaf <rani@magic.metawire.com> 980929: 9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 12 10 */ 13 11 … … 16 14 #include "inet_common.h" 17 15 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) 16 unsigned get_unsigned(char *arg, const char *errmsg) 33 17 { 34 18 unsigned long res; 35 19 char *ptr; 36 20 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 31 uint32_t get_u32(char *arg, const char *errmsg) 47 32 { 48 33 unsigned long res; 49 34 char *ptr; 50 35 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 46 uint16_t get_u16(char *arg, const char *errmsg) 61 47 { 62 48 unsigned long res; 63 49 char *ptr; 64 50 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 61 int get_addr_1(inet_prefix *addr, char *name, int family) 62 { 122 63 memset(addr, 0, sizeof(*addr)); 123 64 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 ) { 126 69 addr->family = family; 127 70 addr->bytelen = (family == AF_INET6 ? 16 : 4); … … 144 87 if (family != AF_UNSPEC && family != AF_INET) 145 88 return -1; 89 if (inet_pton(AF_INET, name, addr->data) <= 0) 90 return -1; 146 91 addr->bytelen = 4; 147 92 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 96 static int get_prefix_1(inet_prefix *dst, char *arg, int family) 161 97 { 162 98 int err; 163 intplen;99 unsigned plen; 164 100 char *slash; 165 101 166 102 memset(dst, 0, sizeof(*dst)); 167 103 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 ) { 169 108 dst->family = family; 170 dst->bytelen = 0;171 dst->bitlen = 0;109 /*dst->bytelen = 0; - done by memset */ 110 /*dst->bitlen = 0;*/ 172 111 return 0; 173 112 } … … 178 117 err = get_addr_1(dst, arg, family); 179 118 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; 188 120 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))) 190 127 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; 192 147 } 193 dst->bitlen = plen; 194 } 195 } 196 done: 148 } 149 } 197 150 if (slash) 198 151 *slash = '/'; … … 200 153 } 201 154 202 int get_addr(inet_prefix * 155 int get_addr(inet_prefix *dst, char *arg, int family) 203 156 { 204 157 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"); 206 159 } 207 160 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 * 161 bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg); 162 } 163 return 0; 164 } 165 166 int get_prefix(inet_prefix *dst, char *arg, int family) 214 167 { 215 168 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"); 217 170 } 218 171 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); 220 173 } 221 174 return 0; … … 227 180 228 181 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); 230 183 } 231 184 return addr.data[0]; … … 252 205 } 253 206 254 int inet_addr_match(inet_prefix * a, inet_prefix *b, int bits)207 int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) 255 208 { 256 209 uint32_t *a1 = a->data; 257 210 uint32_t *a2 = b->data; 258 int words = bits >> 0x05;211 int words = bits >> 5; 259 212 260 213 bits &= 0x1f; … … 280 233 } 281 234 282 const char *rt_addr_n2a(int af, int ATTRIBUTE_UNUSED len,235 const char *rt_addr_n2a(int af, 283 236 void *addr, char *buf, int buflen) 284 237 { … … 292 245 } 293 246 294 247 #ifdef RESOLVE_HOSTNAMES 295 248 const char *format_host(int af, int len, void *addr, char *buf, int buflen) 296 249 { 297 #ifdef RESOLVE_HOSTNAMES298 250 if (resolve_hosts) { 299 251 struct hostent *h_ent; … … 318 270 } 319 271 } 272 return rt_addr_n2a(af, addr, buf, buflen); 273 } 320 274 #endif 321 return rt_addr_n2a(af, len, addr, buf, buflen);322 } -
branches/2.2.9/mindi-busybox/networking/libiproute/utils.h
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 #ifndef __UTILS_H__3 #define __UTILS_H__12 #ifndef UTILS_H 3 #define UTILS_H 1 4 4 5 5 #include "libnetlink.h" … … 7 7 #include "rtm_map.h" 8 8 9 extern int preferred_family; 9 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 10 11 extern family_t preferred_family; 10 12 extern smallint show_stats; /* UNUSED */ 11 13 extern smallint show_details; /* UNUSED */ … … 16 18 17 19 #ifndef IPPROTO_ESP 18 #define IPPROTO_ESP 20 #define IPPROTO_ESP 50 19 21 #endif 20 22 #ifndef IPPROTO_AH 21 #define IPPROTO_AH 23 #define IPPROTO_AH 51 22 24 #endif 23 25 24 26 #define SPRINT_BSIZE 64 25 #define SPRINT_BUF(x) 27 #define SPRINT_BUF(x) char x[SPRINT_BSIZE] 26 28 27 extern void incomplete_command(void) ATTRIBUTE_NORETURN;29 extern void incomplete_command(void) NORETURN; 28 30 29 #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while (0)31 #define NEXT_ARG() do { if (!*++argv) incomplete_command(); } while (0) 30 32 31 typedef struct 32 { 33 typedef struct { 33 34 uint8_t family; 34 35 uint8_t bytelen; … … 36 37 uint32_t data[4]; 37 38 } inet_prefix; 39 40 #define PREFIXLEN_SPECIFIED 1 38 41 39 42 #define DN_MAXADDL 20 … … 43 46 44 47 struct dn_naddr { 45 unsigned short 46 unsigned char a_addr[DN_MAXADDL];48 unsigned short a_len; 49 unsigned char a_addr[DN_MAXADDL]; 47 50 }; 48 51 … … 56 59 extern uint32_t get_addr32(char *name); 57 60 extern 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);*/ 59 62 extern int get_addr(inet_prefix *dst, char *arg, int family); 60 63 extern int get_prefix(inet_prefix *dst, char *arg, int family); 61 64 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); 65 extern unsigned get_unsigned(char *arg, const char *errmsg); 66 extern uint32_t get_u32(char *arg, const char *errmsg); 67 extern uint16_t get_u16(char *arg, const char *errmsg); 72 68 69 extern const char *rt_addr_n2a(int af, void *addr, char *buf, int buflen); 70 #ifdef RESOLVE_HOSTNAMES 73 71 extern 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 75 76 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;77 void invarg(const char *, const char *) NORETURN; 78 void duparg(const char *, const char *) NORETURN; 79 void duparg2(const char *, const char *) NORETURN; 79 80 int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); 80 81 … … 85 86 int ipx_pton(int af, const char *src, void *addr); 86 87 87 #endif /* __UTILS_H__ */ 88 POP_SAVED_FUNCTION_VISIBILITY 89 90 #endif -
branches/2.2.9/mindi-busybox/networking/nameif.c
r1765 r2725 5 5 * Written 2000 by Andi Kleen. 6 6 * 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> 8 9 * 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. 10 11 */ 11 12 … … 14 15 #include <net/if.h> 15 16 #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 */ 29 25 30 26 /* Octets in one Ethernet addr, from <linux/if_ether.h> */ 31 #define ETH_ALEN 27 #define ETH_ALEN 6 32 28 33 29 #ifndef ifr_newname … … 35 31 #endif 36 32 37 typedef struct mactable_s {38 struct mactable_s *next;39 struct mactable_s *prev;33 typedef struct ethtable_s { 34 struct ethtable_s *next; 35 struct ethtable_s *prev; 40 36 char *ifname; 41 37 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... */ 48 struct 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 66 static 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 56 104 } 57 105 58 int nameif_main(int argc, char **argv); 106 static 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 121 static 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 132 void delete_eth_table(ethtable_t *ch); 133 #endif 134 135 int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 59 136 int nameif_main(int argc, char **argv) 60 137 { 61 mactable_t *clist = NULL; 62 FILE *ifh; 138 ethtable_t *clist = NULL; 63 139 const char *fname = "/etc/mactab"; 64 char *line;65 140 int ctl_sk; 66 int if_index = 1; 67 mactable_t *ch; 141 ethtable_t *ch; 142 parser_t *parser; 143 char *token[2]; 68 144 69 145 if (1 & getopt32(argv, "sc:", &fname)) { 70 146 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) 75 155 bb_show_usage(); 76 156 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++); 91 161 } 92 162 } 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) 102 198 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; 120 206 } 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) 139 209 continue; 140 210 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) { 142 228 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 }; 169 232 170 233 return 0; -
branches/2.2.9/mindi-busybox/networking/nc.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* 2 /* nc: mini-netcat - built from the ground up for LRP 3 3 * 4 * 5 * 4 * Copyright (C) 1998, 1999 Charles P. Wright 5 * Copyright (C) 1998 Dave Cinege 6 6 * 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. 8 8 */ 9 9 10 10 #include "libbb.h" 11 11 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" 14 47 #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 15 94 16 95 /* Lots of small differences in features … … 18 97 */ 19 98 20 static void timeout(int signum )99 static void timeout(int signum UNUSED_PARAM) 21 100 { 22 101 bb_error_msg_and_die("timed out"); 23 102 } 24 103 25 int nc_main(int argc, char **argv) ;104 int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 26 105 int nc_main(int argc, char **argv) 27 106 { … … 30 109 int cfd = 0; 31 110 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;) 38 116 fd_set readfds, testfds; 39 117 int opt; /* must be signed (getopt returns -1) */ … … 41 119 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { 42 120 /* getopt32 is _almost_ usable: 43 ** it cannot handle "... -e prog-prog-opt" */121 ** it cannot handle "... -e PROG -prog-opt" */ 44 122 while ((opt = getopt(argc, argv, 45 "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0123 "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 46 124 ) { 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) { 55 136 /* We cannot just 'break'. We should let getopt finish. 56 137 ** Or else we won't be able to find where 57 138 ** '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( 60 141 char **p; 61 142 // +2: one for progname (optarg) and one for NULL … … 69 150 /* optind points to argv[arvc] (NULL) now. 70 151 ** FIXME: we assume that getopt will not count options 71 ** possibly present on "-e prog args" and will not152 ** possibly present on "-e PROG ARGS" and will not 72 153 ** include them into final value of optind 73 154 ** which is to be used ... */ … … 78 159 // -l and -f don't mix 79 160 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) { 82 164 if (argc) bb_show_usage(); 165 } else if (do_listen) { 166 if (argc > 1) bb_show_usage(); 83 167 } else { 84 168 if (!argc || argc > 2) bb_show_usage(); … … 97 181 if (!cfd) { 98 182 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); 107 184 xlisten(sfd, do_listen); /* can be > 1 */ 185 #if 0 /* nc-1.10 does not do this (without -v) */ 108 186 /* If we didn't specify a port number, 109 187 * query and print it after listen() */ 110 188 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); 114 193 fdprintf(2, "%d\n", ntohs(lport)); 115 194 } 116 fcntl(sfd, F_SETFD, FD_CLOEXEC); 195 #endif 196 close_on_exec_on(sfd); 117 197 accept_again: 118 198 cfd = accept(sfd, NULL, 0); … … 129 209 if (wsecs) { 130 210 alarm(0); 131 signal(SIGALRM, SIG_DFL); 211 /* Non-ignored signals revert to SIG_DFL on exec anyway */ 212 /*signal(SIGALRM, SIG_DFL);*/ 132 213 } 133 214 134 215 /* -e given? */ 135 216 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) { 139 220 /* 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); 147 224 goto accept_again; 148 225 } 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... */ 158 232 _exit(127); 159 233 } 160 234 161 / / Select loop copying stdin to cfd, and cfd to stdout.235 /* Select loop copying stdin to cfd, and cfd to stdout */ 162 236 163 237 FD_ZERO(&readfds); … … 172 246 testfds = readfds; 173 247 174 if (select( FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)248 if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0) 175 249 bb_perror_msg_and_die("select"); 176 250 177 251 #define iobuf bb_common_bufsiz1 178 for (fd = 0; fd < FD_SETSIZE; fd++) { 252 fd = STDIN_FILENO; 253 while (1) { 179 254 if (FD_ISSET(fd, &testfds)) { 180 255 nread = safe_read(fd, iobuf, sizeof(iobuf)); 181 256 if (fd == cfd) { 182 257 if (nread < 1) 183 exit( 0);258 exit(EXIT_SUCCESS); 184 259 ofd = STDOUT_FILENO; 185 260 } else { 186 if (nread <1) {187 / / Close outgoing half-connection so they get EOF, but188 // 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 */ 189 264 shutdown(cfd, 1); 190 265 FD_CLR(STDIN_FILENO, &readfds); … … 193 268 } 194 269 xwrite(ofd, iobuf, nread); 195 if (delay > 0) sleep(delay); 270 if (delay > 0) 271 sleep(delay); 196 272 } 273 if (fd == cfd) 274 break; 275 fd = cfd; 197 276 } 198 277 } -
branches/2.2.9/mindi-busybox/networking/nc_bloaty.c
r1765 r2725 2 2 * Released into public domain by the author. 3 3 * 4 * Copyright (C) 2007 Den is Vlasenko.4 * Copyright (C) 2007 Denys Vlasenko. 5 5 * 6 * Licensed under GPLv2, see file LICENSE in this tarball for details.6 * Licensed under GPLv2, see file LICENSE in this source tree. 7 7 */ 8 8 … … 37 37 * - multiple DNS checks 38 38 * Functionalty which is different from nc 1.10: 39 * - P rog in '-e prog' can have prog's parameters and options.39 * - PROG in '-e PROG' can have ARGS (and options). 40 40 * 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!) 42 44 * - numeric addresses are printed in (), not [] (IPv6 looks better), 43 45 * port numbers are inside (): (1.2.3.4:5678) … … 46 48 * - TCP connects from wrong ip/ports (if peer ip:port is specified 47 49 * on the command line, but accept() says that it came from different addr) 48 * are closed, but nc doesn't exit - continuesto listen/accept.50 * are closed, but we don't exit - we continue to listen/accept. 49 51 */ 50 52 51 53 /* 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 */ 52 91 53 92 enum { … … 78 117 unsigned wrote_net; /* total net bytes */ 79 118 #endif 80 /* ouraddr is never NULL and goes thr uthree states as we progress:119 /* ouraddr is never NULL and goes through three states as we progress: 81 120 1 - local address before bind (IP/port possibly zero) 82 121 2 - local address after bind (port is nonzero) … … 98 137 99 138 #define G (*ptr_to_globals) 100 101 139 #define wrote_out (G.wrote_out ) 102 140 #define wrote_net (G.wrote_net ) … … 116 154 #define o_interval 0 117 155 #endif 156 #define INIT_G() do { \ 157 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 158 } while (0) 159 118 160 119 161 /* Must match getopt32 call! */ … … 150 192 /* Beware: writes to stdOUT... */ 151 193 #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) 153 195 #else 154 196 #define Debug(...) do { } while (0) … … 164 206 fprintf(stderr, SENT_N_RECV_M, wrote_net, wrote_out); 165 207 fprintf(stderr, "punt!\n"); 166 exit(1);208 kill_myself_with_sig(sig); 167 209 } 168 210 … … 175 217 176 218 /* timeout and other signal handling cruft */ 177 static void tmtravel(int sig )219 static void tmtravel(int sig UNUSED_PARAM) 178 220 { 179 221 unarm(); … … 220 262 Use at your own hairy risk; if you leave shells lying around behind open 221 263 listening ports you deserve to lose!! */ 222 static int doexec(char **proggie) ATTRIBUTE_NORETURN;264 static int doexec(char **proggie) NORETURN; 223 265 static int doexec(char **proggie) 224 266 { … … 228 270 * exec'ed prog can do it yourself, if needed */ 229 271 execvp(proggie[0], proggie); 230 bb_perror_msg_and_die(" exec");272 bb_perror_msg_and_die("can't execute '%s'", proggie[0]); 231 273 } 232 274 … … 244 286 arm(o_wait); 245 287 if (setjmp(jbuf) == 0) { 246 rr = connect(fd, &themaddr-> sa, themaddr->len);288 rr = connect(fd, &themaddr->u.sa, themaddr->len); 247 289 unarm(); 248 290 } else { /* setjmp: connect failed... */ … … 276 318 if (o_verbose) { 277 319 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); 282 324 fprintf(stderr, "listening on %s ...\n", addr); 283 325 free(addr); … … 307 349 if (themaddr) { 308 350 remend = *themaddr; 309 xconnect(netfd, &themaddr-> sa, themaddr->len);351 xconnect(netfd, &themaddr->u.sa, themaddr->len); 310 352 } 311 353 /* peek first packet and remember peer addr */ … … 315 357 /* and here we block... */ 316 358 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); 318 360 if (rr < 0) 319 361 bb_perror_msg_and_die("recvfrom"); … … 324 366 our socket on it, so that our outbound packets will have correct local IP. 325 367 Unfortunately, bind() on already bound socket will fail now (EINVAL): 326 xbind(netfd, &ouraddr-> sa, ouraddr->len);368 xbind(netfd, &ouraddr->u.sa, ouraddr->len); 327 369 Need to read the packet, save data, close this socket and 328 370 create new one, and bind() it. TODO */ 329 371 if (!themaddr) 330 xconnect(netfd, &remend. sa, ouraddr->len);372 xconnect(netfd, &remend.u.sa, ouraddr->len); 331 373 } else { 332 374 /* TCP */ … … 335 377 again: 336 378 remend.len = LSA_SIZEOF_SA; 337 rr = accept(netfd, &remend. sa, &remend.len);379 rr = accept(netfd, &remend.u.sa, &remend.len); 338 380 if (rr < 0) 339 381 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# */ 347 391 } 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 } 350 405 } 351 406 unarm(); … … 357 412 offer different services via different alias addresses, such as the 358 413 "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"); 362 417 } 363 418 … … 372 427 any machines I've tested, but feel free to surprise me. */ 373 428 char optbuf[40]; 374 int x = sizeof(optbuf);429 socklen_t x = sizeof(optbuf); 375 430 376 431 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... */ 380 433 bin2hex(bigbuf_net, optbuf, x); 381 434 bigbuf_net[2*x] = '\0'; … … 394 447 In other words, we need a TCP MSG_PEEK. */ 395 448 /* 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); 399 452 fprintf(stderr, "connect to %s from %s (%s)\n", 400 453 lcladdr, remhostname, remaddr); … … 434 487 us to hang forever, and hit it */ 435 488 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); 437 490 set_nport(themaddr, htons(SLEAZE_PORT)); 438 491 connect_w_timeout(rr); … … 485 538 x = bc; 486 539 } 487 sprintf( &stage[1], " %8.8x ", obc); /* xxx: still slow? */540 sprintf((char *)&stage[1], " %8.8x ", obc); /* xxx: still slow? */ 488 541 bc -= x; /* fix current count */ 489 542 obc += x; /* fix current offset */ … … 560 613 from the net during that time, assume it's dead and close it too. */ 561 614 if (rr == 0) { 562 if (!FD_ISSET( 0, &ding1))615 if (!FD_ISSET(STDIN_FILENO, &ding1)) 563 616 netretry--; /* we actually try a coupla times. */ 564 617 if (!netretry) { … … 595 648 596 649 /* 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); 599 652 /* Considered making reads here smaller for UDP mode, but 8192-byte 600 653 mobygrams are kinda fun and exercise the reassembler. */ 601 654 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?) 604 660 } else { 605 661 rzleft = rr; … … 623 679 } 624 680 if (rnleft) { 625 rr = write( 1, np, rnleft);681 rr = write(STDOUT_FILENO, np, rnleft); 626 682 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); 629 685 np += rr; /* fix up ptrs and whatnot */ 630 686 rnleft -= rr; /* will get sanity-checked above */ … … 640 696 rr = write(netfd, zp, rr); /* one line, or the whole buffer */ 641 697 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); 644 700 zp += rr; 645 701 rzleft -= rr; … … 669 725 670 726 /* 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;)727 int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 728 int nc_main(int argc UNUSED_PARAM, char **argv) 729 { 730 char *str_p, *str_s; 731 IF_NC_EXTRA(char *str_i, *str_o;) 676 732 char *themdotted = themdotted; /* gcc */ 677 733 char **proggie; … … 679 735 unsigned o_lport = 0; 680 736 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(); 684 738 685 739 /* 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); 689 745 /* and suppress others... */ 746 bb_signals(0 690 747 #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); 694 752 695 753 proggie = argv; … … 697 755 if (strcmp(*proggie, "-e") == 0) { 698 756 *proggie = NULL; 699 argc = proggie - argv;700 757 proggie++; 701 758 goto e_found; … … 706 763 707 764 // -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_w712 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); 713 770 argv += optind; 714 771 #if ENABLE_NC_EXTRA … … 727 784 //if (option_mask32 & OPT_u) /* use UDP */ 728 785 //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 */ 732 787 //if (option_mask32 & OPT_z) /* little or no data xfer */ 733 788 … … 747 802 /* if o_lport is still 0, then we will use random port */ 748 803 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); 750 810 } else { 751 811 /* We try IPv6, then IPv4, unless addr family is 752 812 * implicitly set by way of remote addr/port spec */ 753 813 x = xsocket_type(&ouraddr, 754 USE_FEATURE_IPV6((themaddr ? themaddr->sa.sa_family : AF_UNSPEC),)814 (themaddr ? themaddr->u.sa.sa_family : AF_UNSPEC), 755 815 x); 756 816 if (o_lport) … … 761 821 if (o_udpmode) 762 822 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 } 764 829 #if 0 765 830 setsockopt(netfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf); … … 767 832 #endif 768 833 834 #ifdef BLOAT 769 835 if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) { 770 836 /* apparently UDP can listen ON "port 0", … … 773 839 bb_error_msg_and_die("UDP listen needs nonzero -p port"); 774 840 } 775 776 FD_SET(0, &ding1); /* stdin *is* initially open */ 841 #endif 842 843 FD_SET(STDIN_FILENO, &ding1); /* stdin *is* initially open */ 777 844 if (proggie) { 778 845 close(0); /* won't need stdin */ … … 793 860 /* Outbound connects. Now we're more picky about args... */ 794 861 if (!themaddr) 795 bb_ error_msg_and_die("no destination");862 bb_show_usage(); 796 863 797 864 remend = *themaddr; 798 865 if (o_verbose) 799 themdotted = xmalloc_sockaddr2dotted(&themaddr-> sa);866 themdotted = xmalloc_sockaddr2dotted(&themaddr->u.sa); 800 867 801 868 x = connect_w_timeout(netfd); -
branches/2.2.9/mindi-busybox/networking/netstat.c
r1765 r2725 9 9 * IPV6 support added by Bart Visscher <magick@linux-fan.com> 10 10 * 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. 12 15 */ 13 16 … … 15 18 #include "inet_common.h" 16 19 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 17 50 enum { 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 21 66 }; 22 # define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")23 67 24 68 #define NETSTAT_CONNECTED 0x01 … … 32 76 #define NETSTAT_ALLPROTO (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX) 33 77 34 static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;35 78 36 79 enum { … … 45 88 TCP_LAST_ACK, 46 89 TCP_LISTEN, 47 TCP_CLOSING /* now a valid state */90 TCP_CLOSING, /* now a valid state */ 48 91 }; 49 92 … … 71 114 } socket_state; 72 115 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 82 121 /* When there are IPv6 connections the IPv6 addresses will be 83 122 * truncated to none-recognition. The '-W' option makes the … … 86 125 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd 87 126 */ 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 141 struct prg_node { 142 struct prg_node *next; 143 long inode; 144 char name[PROGNAME_WIDTH]; 145 }; 146 147 #define PRG_HASH_SIZE 211 148 149 struct 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 182 static 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 201 static 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 213 static 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 228 static 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 251 static 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 269 static 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 310 static 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 93 331 94 332 … … 103 341 &in6.s6_addr32[2], &in6.s6_addr32[3]); 104 342 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); 106 344 107 345 localaddr->sin6_family = AF_INET6; … … 109 347 #endif 110 348 111 #if ENABLE_FEATURE_IPV6112 static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr)113 #else114 349 static 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; 120 353 } 121 354 … … 135 368 static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric) 136 369 { 137 enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) };138 370 char *host, *host_port; 139 371 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. */ 142 374 143 375 host = numeric ? xmalloc_sockaddr2dotted_noport(addr) … … 149 381 } 150 382 151 st atic 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;383 struct inet_params { 384 int local_port, rem_port, state, uid; 385 union { 386 struct sockaddr sa; 387 struct sockaddr_in sin; 156 388 #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 395 static 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 167 403 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, ¶m->local_port, 409 rem_addr, ¶m->rem_port, ¶m->state, 410 ¶m->txq, ¶m->rxq, 411 ¶m->uid, ¶m->inode); 412 if (num < 9) { 413 return 1; /* error */ 414 } 172 415 173 416 if (strlen(local_addr) > 8) { 174 417 #if ENABLE_FEATURE_IPV6 175 build_ipv6_addr(local_addr, & localaddr);176 build_ipv6_addr(rem_addr, & remaddr);418 build_ipv6_addr(local_addr, ¶m->localaddr.sin6); 419 build_ipv6_addr(rem_addr, ¶m->remaddr.sin6); 177 420 #endif 178 421 } 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, ¶m->localaddr.sin); 423 build_ipv4_addr(rem_addr, ¶m->remaddr.sin); 424 } 425 return 0; 426 } 427 428 static 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)) 190 433 ) { 191 434 char *l = ip_port_str( 192 (struct sockaddr *) &localaddr,local_port,193 "tcp", flags & NETSTAT_NUMERIC);435 ¶m->localaddr.sa, param->local_port, 436 proto, flags & NETSTAT_NUMERIC); 194 437 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 ¶m->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'); 199 450 free(l); 200 451 free(r); … … 202 453 } 203 454 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; 455 static int FAST_FUNC tcp_do_one(char *line) 456 { 457 struct inet_params param; 458 459 memset(¶m, 0, sizeof(param)); 460 if (scan_inet_proc_line(¶m, line)) 461 return 1; 462 463 print_inet_line(¶m, tcp_state[param.state], "tcp", param.rem_port); 464 return 0; 465 } 466 210 467 #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 ) \ 263 476 ) 264 477 #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 481 static 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(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ 488 if (scan_inet_proc_line(¶m, 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(¶m, state_str, "udp", have_remaddr); 503 return 0; 504 } 505 506 static 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(¶m, line)) 512 return 1; 513 514 have_remaddr = NOT_NULL_ADDR(param.remaddr); 515 print_inet_line(¶m, itoa(param.state), "raw", have_remaddr); 516 return 0; 517 } 518 519 static 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; 347 525 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); 360 537 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 } 367 540 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) { 368 541 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) { 369 542 if (!(flags & NETSTAT_LISTENING)) 370 return ;543 return 0; 371 544 } else { 372 545 if (!(flags & NETSTAT_CONNECTED)) 373 return ;546 return 0; 374 547 } 375 548 } … … 440 613 strcat(ss_flags, "]"); 441 614 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 633 static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) 634 { 635 int lnr; 462 636 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); 465 641 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 }471 642 return; 472 643 } 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 } 480 653 fclose(procinfo); 481 654 } 482 655 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; 656 int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 657 int netstat_main(int argc UNUSED_PARAM, char **argv) 658 { 491 659 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(); 498 662 499 663 /* Option string must match NETSTAT_xxx constants */ 500 664 opt = getopt32(argv, NETSTAT_OPTS); 501 if (opt & 0x1) { // -l665 if (opt & OPT_sock_listen) { // -l 502 666 flags &= ~NETSTAT_CONNECTED; 503 667 flags |= NETSTAT_LISTENING; 504 668 } 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 513 676 #if ENABLE_ROUTE 677 if (opt & OPT_route) { // -r 514 678 bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); 515 679 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 525 695 526 696 opt &= NETSTAT_ALLPROTO; … … 530 700 } 531 701 if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { 532 printf("Active Internet connections "); 702 printf("Active Internet connections "); /* xxx */ 533 703 534 704 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) … … 538 708 else 539 709 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); 544 718 #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); 550 724 #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); 556 730 #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 } 560 734 if (flags & NETSTAT_UNIX) { 561 735 printf("Active UNIX domain sockets "); … … 566 740 else 567 741 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(); 571 746 return 0; 572 747 } -
branches/2.2.9/mindi-busybox/networking/nslookup.c
r1765 r2725 9 9 * added by Ben Zeckel <bzeckel@hmc.edu> June 2001 10 10 * 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. 12 12 */ 13 13 … … 16 16 17 17 /* 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. 20 23 */ 21 24 … … 52 55 /* We can't use xhost2sockaddr() - we want to get ALL addresses, 53 56 * not just one */ 54 55 57 struct addrinfo *result = NULL; 56 58 int rc; … … 70 72 71 73 printf("%-10s %s\n", header, hostname); 72 // p rintf("%s\n",cur->ai_canonname); ?74 // puts(cur->ai_canonname); ? 73 75 while (cur) { 74 76 char *dotted, *revhost; … … 102 104 { 103 105 char *server; 106 struct sockaddr *sa; 104 107 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 in108 * _res._u._ext_.nsaddrs[MAXNS] (of type "struct sockaddr_in6*" each) 109 * but how to find out whether resolver uses110 * _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 112 115 print_host(server, "Server:"); 113 116 if (ENABLE_FEATURE_CLEAN_UP) 114 117 free(server); 115 puts("");118 bb_putchar('\n'); 116 119 } 117 120 118 121 /* 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(c har *server)122 an explicit dns server instead of what is in /etc/resolv.conf */ 123 static void set_default_dns(const char *server) 121 124 { 122 struct in_addr server_in_addr;125 len_and_sockaddr *lsa; 123 126 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) { 125 131 _res.nscount = 1; 126 _res.nsaddr_list[0].sin_addr = server_in_addr; 132 /* struct copy */ 133 _res.nsaddr_list[0] = lsa->u.sin; 127 134 } 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 128 150 } 129 151 130 int nslookup_main(int argc, char **argv) ;152 int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 131 153 int nslookup_main(int argc, char **argv) 132 154 { … … 136 158 * More than 3 arguments is an error to follow the pattern of the 137 159 * standard nslookup */ 138 139 if (argc < 2 || *argv[1] == '-' || argc > 3) 160 if (!argv[1] || argv[1][0] == '-' || argc > 3) 140 161 bb_show_usage(); 141 162 … … 144 165 res_init(); 145 166 /* 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") */ 147 168 /*_res.options |= RES_USE_INET6;*/ 148 169 149 if (arg c == 3)170 if (argv[2]) 150 171 set_default_dns(argv[2]); 151 172 -
branches/2.2.9/mindi-busybox/networking/ping.c
r1765 r2725 12 12 * Mike Muuss. 13 13 * 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. 15 15 */ 16 16 /* from ping6.c: … … 31 31 32 32 #if ENABLE_PING6 33 # include <netinet/icmp6.h>33 # include <netinet/icmp6.h> 34 34 /* I see RENUMBERED constants in bits/in.h - !!? 35 35 * What a fuck is going on with libc? Is it a glibc joke? */ 36 # ifdef IPV6_2292HOPLIMIT37 # undef IPV6_HOPLIMIT38 # define IPV6_HOPLIMIT IPV6_2292HOPLIMIT39 # endif36 # ifdef IPV6_2292HOPLIMIT 37 # undef IPV6_HOPLIMIT 38 # define IPV6_HOPLIMIT IPV6_2292HOPLIMIT 39 # endif 40 40 #endif 41 41 … … 44 44 MAXIPLEN = 60, 45 45 MAXICMPLEN = 76, 46 MAXPACKET = 65468,47 46 MAX_DUP_CHK = (8 * 128), 48 47 MAXWAIT = 10, … … 50 49 }; 51 50 52 /* common routines */51 /* Common routines */ 53 52 54 53 static int in_cksum(unsigned short *buf, int sz) … … 77 76 #if !ENABLE_FEATURE_FANCY_PING 78 77 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 80 struct 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 87 static void noresp(int ign UNUSED_PARAM) 88 { 89 printf("No response from %s\n", G.hostname); 86 90 exit(EXIT_FAILURE); 87 91 } … … 89 93 static void ping4(len_and_sockaddr *lsa) 90 94 { 91 struct sockaddr_in pingaddr;92 95 struct icmp *pkt; 93 96 int pingsock, c; 94 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];95 97 96 98 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)); 101 102 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); 106 106 107 107 /* listen for replies */ … … 110 110 socklen_t fromlen = sizeof(from); 111 111 112 c = recvfrom(pingsock, packet, sizeof(packet), 0,112 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0, 113 113 (struct sockaddr *) &from, &fromlen); 114 114 if (c < 0) { … … 118 118 } 119 119 if (c >= 76) { /* ip + icmp */ 120 struct iphdr *iphdr = (struct iphdr *) packet;121 122 pkt = (struct icmp *) ( packet + (iphdr->ihl << 2)); /* skip ip hdr */120 struct iphdr *iphdr = (struct iphdr *) G.packet; 121 122 pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ 123 123 if (pkt->icmp_type == ICMP_ECHOREPLY) 124 124 break; … … 132 132 static void ping6(len_and_sockaddr *lsa) 133 133 { 134 struct sockaddr_in6 pingaddr;135 134 struct icmp6_hdr *pkt; 136 135 int pingsock, c; 137 136 int sockopt; 138 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];139 137 140 138 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)); 145 142 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 146 143 … … 148 145 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 149 146 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); 152 148 153 149 /* listen for replies */ … … 156 152 socklen_t fromlen = sizeof(from); 157 153 158 c = recvfrom(pingsock, packet, sizeof(packet), 0,154 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0, 159 155 (struct sockaddr *) &from, &fromlen); 160 156 if (c < 0) { … … 163 159 continue; 164 160 } 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; 167 163 if (pkt->icmp6_type == ICMP6_ECHO_REPLY) 168 164 break; … … 174 170 #endif 175 171 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 175 static int common_ping_main(sa_family_t af, char **argv) 178 176 { 179 177 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 183 182 while ((++argv)[0] && argv[0][0] == '-') { 184 183 if (argv[0][1] == '4') { … … 196 195 #endif 197 196 198 hostname = *argv;199 if (! hostname)197 G.hostname = *argv; 198 if (!G.hostname) 200 199 bb_show_usage(); 201 200 202 201 #if ENABLE_PING6 203 lsa = xhost_and_af2sockaddr( hostname, 0, af);202 lsa = xhost_and_af2sockaddr(G.hostname, 0, af); 204 203 #else 205 lsa = xhost_and_af2sockaddr( hostname, 0, AF_INET);204 lsa = xhost_and_af2sockaddr(G.hostname, 0, AF_INET); 206 205 #endif 207 206 /* Set timer _after_ DNS resolution */ … … 210 209 211 210 #if ENABLE_PING6 212 if (lsa-> sa.sa_family == AF_INET6)211 if (lsa->u.sa.sa_family == AF_INET6) 213 212 ping6(lsa); 214 213 else 215 214 #endif 216 215 ping4(lsa); 217 printf("%s is alive!\n", hostname);216 printf("%s is alive!\n", G.hostname); 218 217 return EXIT_SUCCESS; 219 218 } … … 223 222 224 223 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")) 228 227 enum { 229 228 OPT_QUIET = 1 << 0, … … 231 230 OPT_c = 1 << 2, 232 231 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, 236 237 }; 237 238 … … 239 240 struct globals { 240 241 int pingsock; 242 int if_index; 243 char *str_I; 241 244 len_and_sockaddr *source_lsa; 242 245 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; 245 248 uint16_t myid; 246 249 unsigned tmin, tmax; /* in us */ 247 250 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] */ 248 257 const char *hostname; 249 258 const char *dotted; … … 256 265 } pingaddr; 257 266 char rcvd_tbl[MAX_DUP_CHK / 8]; 258 } ;267 } FIX_ALIASING; 259 268 #define G (*(struct globals*)&bb_common_bufsiz1) 260 269 #define pingsock (G.pingsock ) 270 #define if_index (G.if_index ) 261 271 #define source_lsa (G.source_lsa ) 272 #define str_I (G.str_I ) 262 273 #define datalen (G.datalen ) 263 #define if_index (G.if_index )264 274 #define ntransmitted (G.ntransmitted) 265 275 #define nreceived (G.nreceived ) … … 270 280 #define tmax (G.tmax ) 271 281 #define tsum (G.tsum ) 282 #define deadline (G.deadline ) 283 #define timeout (G.timeout ) 284 #define total_secs (G.total_secs ) 272 285 #define hostname (G.hostname ) 273 286 #define dotted (G.dotted ) … … 276 289 void BUG_ping_globals_too_big(void); 277 290 #define INIT_G() do { \ 278 279 291 if (sizeof(G) > COMMON_BUFSIZE) \ 292 BUG_ping_globals_too_big(); \ 280 293 pingsock = -1; \ 294 datalen = DEFDATALEN; \ 295 timeout = MAXWAIT; \ 281 296 tmin = UINT_MAX; \ 282 297 } while (0) 283 298 284 299 285 #define 286 #define 287 #define 288 #define 289 #define 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)) 290 305 291 306 /**************************************************************************/ 292 307 293 static void pingstats(int junk ATTRIBUTE_UNUSED) 308 static void print_stats_and_exit(int junk) NORETURN; 309 static void print_stats_and_exit(int junk UNUSED_PARAM) 294 310 { 295 311 signal(SIGINT, SIG_IGN); … … 310 326 tmax / 1000, tmax % 1000); 311 327 } 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)); 313 330 } 314 331 … … 326 343 bb_error_msg_and_die(bb_msg_write_error); 327 344 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 } 330 353 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 372 static 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 344 377 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 */ 347 380 pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 348 381 pkt->icmp_id = myid; 349 382 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 */ 351 386 /*if (datalen >= 4)*/ 387 /* No hton: we'll read it back on the same machine */ 352 388 *(uint32_t*)&pkt->icmp_dun = monotonic_us(); 353 389 … … 357 393 } 358 394 #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 395 static 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); 363 400 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;*/ 366 403 pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 367 404 pkt->icmp6_id = myid; … … 369 406 /*if (datalen >= 4)*/ 370 407 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 408 409 //TODO? pkt->icmp_cksum = in_cksum(...); 371 410 372 411 sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); … … 458 497 printf(" time=%u.%03u ms", triptime / 1000, triptime % 1000); 459 498 puts(dupmsg); 460 fflush (stdout);499 fflush_all(); 461 500 } 462 501 static void unpack4(char *buf, int sz, struct sockaddr_in *from) … … 494 533 } 495 534 #if ENABLE_PING6 496 static void unpack6(char *packet, int sz, struct sockaddr_in6 *from,int hoplimit)535 static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hoplimit) 497 536 { 498 537 struct icmp6_hdr *icmppkt; … … 527 566 static void ping4(len_and_sockaddr *lsa) 528 567 { 529 char packet[datalen + MAXIPLEN + MAXICMPLEN];530 568 int sockopt; 531 569 532 570 pingsock = create_icmp_socket(); 533 pingaddr.sin = lsa-> sin;571 pingaddr.sin = lsa->u.sin; 534 572 if (source_lsa) { 535 573 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF, 536 &source_lsa-> sa, source_lsa->len))574 &source_lsa->u.sa, source_lsa->len)) 537 575 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); 540 580 541 581 /* enable broadcast pings */ 542 582 setsockopt_broadcast(pingsock); 543 583 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 */ 546 587 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 547 588 548 signal(SIGINT, p ingstats);589 signal(SIGINT, print_stats_and_exit); 549 590 550 591 /* start the ping's going ... */ … … 557 598 int c; 558 599 559 c = recvfrom(pingsock, packet, sizeof(packet), 0,600 c = recvfrom(pingsock, G.rcv_packet, G.sizeof_rcv_packet, 0, 560 601 (struct sockaddr *) &from, &fromlen); 561 602 if (c < 0) { … … 564 605 continue; 565 606 } 566 unpack4( packet, c, &from);567 if (pingcount > 0&& nreceived >= pingcount)607 unpack4(G.rcv_packet, c, &from); 608 if (pingcount && nreceived >= pingcount) 568 609 break; 569 610 } … … 573 614 static void ping6(len_and_sockaddr *lsa) 574 615 { 575 char packet[datalen + MAXIPLEN + MAXICMPLEN];576 616 int sockopt; 577 617 struct msghdr msg; … … 581 621 582 622 pingsock = create_icmp6_socket(); 583 pingaddr.sin6 = lsa-> sin6;623 pingaddr.sin6 = lsa->u.sin6; 584 624 /* untested whether "-I addr" really works for IPv6: */ 585 625 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); 587 629 588 630 #ifdef ICMP6_FILTER … … 604 646 setsockopt_broadcast(pingsock); 605 647 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 */ 608 651 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 609 652 … … 619 662 pingaddr.sin6.sin6_scope_id = if_index; 620 663 621 signal(SIGINT, p ingstats);664 signal(SIGINT, print_stats_and_exit); 622 665 623 666 /* start the ping's going ... */ … … 630 673 msg.msg_iovlen = 1; 631 674 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; 634 677 while (1) { 635 678 int c; … … 650 693 /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */ 651 694 ) { 652 hoplimit = *(int*)CMSG_DATA(mp); 695 /*hoplimit = *(int*)CMSG_DATA(mp); - unaligned access */ 696 move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); 653 697 } 654 698 } 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) 657 701 break; 658 702 } … … 665 709 if (source_lsa) { 666 710 printf(" from %s", 667 xmalloc_sockaddr2dotted_noport(&source_lsa-> sa));711 xmalloc_sockaddr2dotted_noport(&source_lsa->u.sa)); 668 712 } 669 713 printf(": %d data bytes\n", datalen); 670 714 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); 673 722 ping6(lsa); 674 else 675 #endif 723 } else 724 #endif 725 { 726 G.snd_packet = xzalloc(datalen + ICMP_MINLEN + 4); 676 727 ping4(lsa); 677 }678 679 int ping_main(int argc, char **argv); 680 int ping_main(int argc, char **argv)728 } 729 } 730 731 static int common_ping_main(int opt, char **argv) 681 732 { 682 733 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; 685 735 686 736 INIT_G(); 687 737 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); 697 745 if (!if_index) { 698 746 /* 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 */ 700 749 } 701 750 } … … 703 752 hostname = argv[optind]; 704 753 #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 } 710 762 #else 711 763 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 712 764 #endif 713 765 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) 715 767 /* leaking it here... */ 716 768 source_lsa = NULL; 717 769 718 dotted = xmalloc_sockaddr2dotted_noport(&lsa-> sa);770 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); 719 771 ping(lsa); 720 p ingstats(0);721 return EXIT_SUCCESS;772 print_stats_and_exit(EXIT_SUCCESS); 773 /*return EXIT_SUCCESS;*/ 722 774 } 723 775 #endif /* FEATURE_FANCY_PING */ 724 776 725 777 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); 778 int ping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 779 int 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 789 int ping6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 790 int 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 732 797 } 733 798 #endif -
branches/2.2.9/mindi-busybox/networking/pscan.c
r1765 r2725 4 4 * Copyright 2007 Tito Ragusa <farmatito@tiscali.it> 5 5 * 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. 7 7 */ 8 8 … … 31 31 #define MONOTONIC_US() ((unsigned)monotonic_us()) 32 32 33 int pscan_main(int argc, char **argv) ;34 int pscan_main(int argc , char **argv)33 int pscan_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 34 int pscan_main(int argc UNUSED_PARAM, char **argv) 35 35 { 36 36 const char *opt_max_port = "1024"; /* -P: default max port */ … … 43 43 * will take N seconds at absolute minimum */ 44 44 const char *opt_min_rtt = "5"; /* -T: default min rtt in msec */ 45 const char *result_str; 45 46 len_and_sockaddr *lsap; 46 47 int s; 48 unsigned opt; 47 49 unsigned port, max_port, nports; 48 50 unsigned closed_ports = 0; … … 52 54 unsigned min_rtt; 53 55 unsigned rtt_4; 54 unsigned start ;56 unsigned start, diff; 55 57 56 58 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); 58 60 argv += optind; 59 61 max_port = xatou_range(opt_max_port, 1, 65535); 60 62 port = xatou_range(opt_min_port, 1, max_port); 61 63 nports = max_port - port + 1; 62 rtt_4 = timeout = xatou_range(opt_timeout, 1, INT_MAX/1000 / 4) * 1000;63 64 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; 64 68 65 69 DMSG("min_rtt %u timeout %u", min_rtt, timeout); … … 74 78 /* The SOCK_STREAM socket type is implemented on the TCP/IP protocol. */ 75 79 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); 78 81 /* We need unblocking socket so we don't need to wait for ETIMEOUT. */ 79 82 /* Nonblocking connect typically "fails" with errno == EINPROGRESS */ 80 83 ndelay_on(s); 84 81 85 DMSG("connect to port %u", port); 86 result_str = NULL; 82 87 start = MONOTONIC_US(); 83 if (connect(s, &lsap-> sa, lsap->len) == 0) {88 if (connect(s, &lsap->u.sa, lsap->len) == 0) { 84 89 /* Unlikely, for me even localhost fails :) */ 85 90 DMSG("connect succeeded"); … … 93 98 } 94 99 100 diff = 0; 95 101 while (1) { 96 102 if (errno == ECONNREFUSED) { 97 DMSG("port %u: ECONNREFUSED", port); 103 if (opt & 1) /* -c: show closed too */ 104 result_str = "closed"; 98 105 closed_ports++; 99 106 break; 100 107 } 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"; 103 113 break; 114 } 104 115 /* Can sleep (much) longer than specified delay. 105 116 * 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 (!) 107 118 * before we exceed (rather small) rtt */ 108 119 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); 110 123 if (write(s, " ", 1) >= 0) { /* We were able to write to the socket */ 111 open:112 124 open_ports++; 113 printf("%5u\ttcp\topen\t%s\n", port, port_name(port));125 result_str = "open"; 114 126 break; 115 127 } 116 128 } 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)); 118 133 119 134 /* Estimate new rtt - we don't want to wait entire timeout 120 135 * 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) 122 138 * because we don't want to accidentally miss ports. */ 123 rtt_4 = (MONOTONIC_US() - start)* 4;139 rtt_4 = diff * 4; 124 140 if (rtt_4 < min_rtt) 125 141 rtt_4 = min_rtt; … … 131 147 if (ENABLE_FEATURE_CLEAN_UP) free(lsap); 132 148 133 printf("%d closed, %d open, %d timed out ports\n",149 printf("%d closed, %d open, %d timed out (or blocked) ports\n", 134 150 closed_ports, 135 151 open_ports, -
branches/2.2.9/mindi-busybox/networking/route.c
r1765 r2725 11 11 * (derived from FvK's 'route.c 1.70 01/04/94') 12 12 * 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. 14 14 * 15 15 * … … 26 26 */ 27 27 28 #include <getopt.h>29 28 #include <net/route.h> 30 29 #include <net/if.h> … … 153 152 /* Add or delete a route, depending on action. */ 154 153 155 static void INET_setroute(int action, char **args)154 static NOINLINE void INET_setroute(int action, char **args) 156 155 { 157 156 struct rtentry rt; … … 180 179 181 180 prefix_len = xatoul_range(prefix+1, 0, 32); 182 mask_in_addr(rt) = htonl( ~ 181 mask_in_addr(rt) = htonl( ~(0xffffffffUL >> prefix_len)); 183 182 *prefix = '\0'; 184 183 #if HAVE_NEW_ADDRT … … 187 186 } else { 188 187 /* Default netmask. */ 189 netmask = bb_str_default;188 netmask = "default"; 190 189 } 191 190 /* Prefer hostname lookup is -host flag (xflag==1) was given. */ … … 304 303 /* sanity checks.. */ 305 304 if (mask_in_addr(rt)) { 306 u nsigned longmask = mask_in_addr(rt);305 uint32_t mask = mask_in_addr(rt); 307 306 308 307 mask = ~ntohl(mask); … … 315 314 } 316 315 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)) { 318 317 bb_error_msg_and_die("netmask and route address conflict"); 319 318 } … … 338 337 #if ENABLE_FEATURE_IPV6 339 338 340 static void INET6_setroute(int action, char **args)339 static NOINLINE void INET6_setroute(int action, char **args) 341 340 { 342 341 struct sockaddr_in6 sa6; … … 348 347 const char *target = *args++; 349 348 350 if (strcmp(target, bb_str_default) == 0) {349 if (strcmp(target, "default") == 0) { 351 350 prefix_len = 0; 352 351 memset(&sa6, 0, sizeof(sa6)); 353 352 } else { 354 353 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); 358 358 } else { 359 359 prefix_len = 128; … … 424 424 struct ifreq ifr; 425 425 memset(&ifr, 0, sizeof(ifr)); 426 strncpy (ifr.ifr_name, devname, sizeof(ifr.ifr_name));426 strncpy_IFNAMSIZ(ifr.ifr_name, devname); 427 427 xioctl(skfd, SIOGIFINDEX, &ifr); 428 428 rt.rtmsg_ifindex = ifr.ifr_ifindex; … … 477 477 478 478 /* also used in netstat */ 479 void bb_displayroutes(int noresolve, int netstatfmt)479 void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt) 480 480 { 481 481 char devname[64], flags[16], *sdest, *sgw; … … 485 485 struct in_addr mask; 486 486 487 FILE *fp = xfopen ("/proc/net/route", "r");487 FILE *fp = xfopen_for_read("/proc/net/route"); 488 488 489 489 printf("Kernel IP routing table\n" … … 539 539 #if ENABLE_FEATURE_IPV6 540 540 541 static void INET6_displayroutes( int noresolve)541 static void INET6_displayroutes(void) 542 542 { 543 543 char addr6[128], *naddr6; … … 553 553 struct sockaddr_in6 snaddr6; 554 554 555 FILE *fp = xfopen ("/proc/net/ipv6_route", "r");555 FILE *fp = xfopen_for_read("/proc/net/ipv6_route"); 556 556 557 557 printf("Kernel IPv6 routing table\n%-44s%-40s" … … 562 562 int r; 563 563 r = fscanf(fp, "%32s%x%*s%x%32s%x%x%x%x%s\n", 564 565 564 addr6x+14, &prefix_len, &slen, addr6x+40+7, 565 &metric, &use, &refcnt, &iflags, iface); 566 566 if (r != 9) { 567 567 if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */ … … 641 641 ; 642 642 643 int route_main(int argc, char **argv) ;644 int route_main(int argc , char **argv)643 int route_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 644 int route_main(int argc UNUSED_PARAM, char **argv) 645 645 { 646 646 unsigned opt; … … 675 675 #if ENABLE_FEATURE_IPV6 676 676 if (opt & ROUTE_OPT_INET6) 677 INET6_displayroutes( noresolve);677 INET6_displayroutes(); 678 678 else 679 679 #endif -
branches/2.2.9/mindi-busybox/networking/slattach.c
r1765 r2725 5 5 * Author: Ignacio Garcia Perez (iggarpe at gmail dot com) 6 6 * 7 * License : GPLv2 or later, see LICENSE file in this tarball.7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 8 * 9 9 * There are some differences from the standard net-tools slattach: … … 21 21 int saved_disc; 22 22 struct termios saved_state; 23 } ;23 } FIX_ALIASING; 24 24 #define G (*(struct globals*)&bb_common_bufsiz1) 25 25 #define handle (G.handle ) 26 26 #define saved_disc (G.saved_disc ) 27 27 #define saved_state (G.saved_state ) 28 #define INIT_G() do { } while (0)28 #define INIT_G() do { } while (0) 29 29 30 30 … … 44 44 } 45 45 46 static int set_termios_state_ and_warn(struct termios *state)46 static int set_termios_state_or_warn(struct termios *state) 47 47 { 48 48 int ret; … … 65 65 * as possible. 66 66 */ 67 static void restore_state_and_exit(int exitcode) ATTRIBUTE_NORETURN;67 static void restore_state_and_exit(int exitcode) NORETURN; 68 68 static void restore_state_and_exit(int exitcode) 69 69 { … … 79 79 cfsetispeed(&state, B0); 80 80 cfsetospeed(&state, B0); 81 if (set_termios_state_ and_warn(&state))81 if (set_termios_state_or_warn(&state)) 82 82 exitcode = 1; 83 83 sleep(1); 84 84 85 85 /* Restore line status */ 86 if (set_termios_state_ and_warn(&saved_state))86 if (set_termios_state_or_warn(&saved_state)) 87 87 exit(EXIT_FAILURE); 88 88 if (ENABLE_FEATURE_CLEAN_UP) … … 100 100 101 101 /* Set line status */ 102 if (set_termios_state_ and_warn(state))102 if (set_termios_state_or_warn(state)) 103 103 goto bad; 104 104 /* Set line discliple (N_SLIP always) */ … … 111 111 if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) { 112 112 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 117 static void sig_handler(int signo UNUSED_PARAM) 118 { 119 restore_state_and_exit(EXIT_SUCCESS); 120 } 121 122 int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 123 int slattach_main(int argc UNUSED_PARAM, char **argv) 124 124 { 125 125 /* Line discipline code table */ … … 135 135 struct termios state; 136 136 const char *proto = "cslip"; 137 const char *extcmd; 137 const char *extcmd; /* Command to execute after hangup */ 138 138 const char *baud_str; 139 int baud_code = -1; 139 int baud_code = -1; /* Line baud rate (system code) */ 140 140 141 141 enum { … … 176 176 /* Trap signals in order to restore tty states upon exit */ 177 177 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); 182 184 } 183 185 … … 205 207 | ((opt & OPT_L_local) ? CLOCAL : 0) 206 208 | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); 209 cfsetispeed(&state, cfgetispeed(&saved_state)); 210 cfsetospeed(&state, cfgetospeed(&saved_state)); 207 211 } 208 212 … … 238 242 239 243 /* 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 9 9 * Last modified: Fri Jun 9 14:34:24 2000 too 10 10 * 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. 12 12 * 13 13 * HISTORY … … 22 22 */ 23 23 24 #include <termios.h>25 24 #include <arpa/telnet.h> 26 25 #include <netinet/in.h> … … 44 43 UF_SGA = 0x02, 45 44 46 TS_0 = 1, 45 TS_NORMAL = 0, 46 TS_COPY = 1, 47 47 TS_IAC = 2, 48 48 TS_OPT = 3, 49 49 TS_SUB1 = 4, 50 50 TS_SUB2 = 5, 51 TS_CR = 6, 51 52 }; 52 53 53 54 typedef unsigned char byte; 54 55 56 enum { netfd = 3 }; 57 55 58 struct 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 */ 58 60 byte telstate; /* telnet negotiation state from network input */ 59 61 byte telwish; /* DO, DONT, WILL, WONT */ 60 62 byte charmode; 61 63 byte telflags; 62 byte gotsig;63 64 byte do_termios; 64 65 #if ENABLE_FEATURE_TELNET_TTYPE … … 69 70 #endif 70 71 #if ENABLE_FEATURE_AUTOWIDTH 71 intwin_width, win_height;72 unsigned win_width, win_height; 72 73 #endif 73 74 /* same buffer used both for network and console read/write */ … … 77 78 struct termios termios_def; 78 79 struct termios termios_raw; 79 } ;80 } FIX_ALIASING; 80 81 #define G (*(struct globals*)&bb_common_bufsiz1) 81 void BUG_telnet_globals_too_big(void);82 82 #define INIT_G() do { \ 83 if (sizeof(G) > COMMON_BUFSIZE)\84 BUG_telnet_globals_too_big(); \85 /* memset(&G, 0, sizeof G); - already is */\83 struct G_sizecheck { \ 84 char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ 85 }; \ 86 86 } while (0) 87 87 88 /* Function prototypes */ 88 89 89 static void rawmode(void); 90 90 static void cookmode(void); … … 92 92 static void will_charmode(void); 93 93 static void telopt(byte c); 94 static intsubneg(byte c);95 96 static void iac flush(void)97 { 98 write( G.netfd, G.iacbuf, G.iaclen);94 static void subneg(byte c); 95 96 static void iac_flush(void) 97 { 98 write(netfd, G.iacbuf, G.iaclen); 99 99 G.iaclen = 0; 100 100 } … … 102 102 #define write_str(fd, str) write(fd, str, sizeof(str) - 1) 103 103 104 static void doexit(int ev) NORETURN; 104 105 static void doexit(int ev) 105 106 { … … 108 109 } 109 110 110 static void con escape(void)111 static void con_escape(void) 111 112 { 112 113 char b; 113 114 114 if ( G.gotsig) /* came from linemode... go raw */115 if (bb_got_signal) /* came from line mode... go raw */ 115 116 rawmode(); 116 117 … … 121 122 " e exit telnet\r\n"); 122 123 123 if (read( 0, &b, 1) <= 0)124 doexit( 1);124 if (read(STDIN_FILENO, &b, 1) <= 0) 125 doexit(EXIT_FAILURE); 125 126 126 127 switch (b) { 127 128 case 'l': 128 if (! G.gotsig) {129 if (!bb_got_signal) { 129 130 do_linemode(); 130 goto r rturn;131 goto ret; 131 132 } 132 133 break; 133 134 case 'c': 134 if ( G.gotsig) {135 if (bb_got_signal) { 135 136 will_charmode(); 136 goto r rturn;137 goto ret; 137 138 } 138 139 break; … … 143 144 break; 144 145 case 'e': 145 doexit( 0);146 doexit(EXIT_SUCCESS); 146 147 } 147 148 148 149 write_str(1, "continuing...\r\n"); 149 150 150 if ( G.gotsig)151 if (bb_got_signal) 151 152 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 157 static 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 165 164 * 166 * 167 * 168 * 169 * 170 * 171 * third - whay doyyou have to make 'many write()s'?172 * 173 * So I implemented it. It's realy useful for me. I hope that174 * 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. 175 174 */ 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(); 186 183 return; 187 184 } 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 */ 193 190 } 194 191 if (j > 0) 195 write(G.netfd, outbuf, j);196 } 197 198 static void handle netinput(int len)192 full_write(netfd, outbuf, j); 193 } 194 195 static void handle_net_input(int len) 199 196 { 200 197 int i; 201 198 int cstart = 0; 202 199 203 for (i = 0; i < len; i++) 204 { 200 for (i = 0; i < len; i++) { 205 201 byte c = G.buf[i]; 206 202 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) { 211 205 cstart = i; 212 206 G.telstate = TS_IAC; 213 207 } 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; 265 279 len = cstart; 266 280 } 267 281 268 282 if (len) 269 write(1, G.buf, len);270 } 271 272 static void put iac(int c)283 full_write(STDOUT_FILENO, G.buf, len); 284 } 285 286 static void put_iac(int c) 273 287 { 274 288 G.iacbuf[G.iaclen++] = c; 275 289 } 276 290 277 static void put iac2(byte wwdd, byte c)291 static void put_iac2(byte wwdd, byte c) 278 292 { 279 293 if (G.iaclen + 3 > IACBUFSIZE) 280 iac flush();281 282 put iac(IAC);283 put iac(wwdd);284 put iac(c);294 iac_flush(); 295 296 put_iac(IAC); 297 put_iac(wwdd); 298 put_iac(c); 285 299 } 286 300 287 301 #if ENABLE_FEATURE_TELNET_TTYPE 288 static void put iac_subopt(byte c, char *str)289 { 290 int 302 static void put_iac_subopt(byte c, char *str) 303 { 304 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) 291 305 292 306 if (G.iaclen + len > IACBUFSIZE) 293 iac flush();294 295 put iac(IAC);296 put iac(SB);297 put iac(c);298 put iac(0);307 iac_flush(); 308 309 put_iac(IAC); 310 put_iac(SB); 311 put_iac(c); 312 put_iac(0); 299 313 300 314 while (*str) 301 put iac(*str++);302 303 put iac(IAC);304 put iac(SE);315 put_iac(*str++); 316 317 put_iac(IAC); 318 put_iac(SE); 305 319 } 306 320 #endif 307 321 308 322 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 309 static void put iac_subopt_autologin(void)323 static void put_iac_subopt_autologin(void) 310 324 { 311 325 int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) 312 const char * user= "USER";326 const char *p = "USER"; 313 327 314 328 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); 333 348 } 334 349 #endif 335 350 336 351 #if ENABLE_FEATURE_AUTOWIDTH 337 static void put iac_naws(byte c, int x, int y)352 static void put_iac_naws(byte c, int x, int y) 338 353 { 339 354 if (G.iaclen + 9 > IACBUFSIZE) 340 iac flush();341 342 put iac(IAC);343 put iac(SB);344 put iac(c);345 346 put iac((x >> 8) & 0xff);347 put iac(x & 0xff);348 put iac((y >> 8) & 0xff);349 put iac(y & 0xff);350 351 put iac(IAC);352 put iac(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); 353 368 } 354 369 #endif … … 379 394 setConMode(); 380 395 381 put iac2(DO, TELOPT_ECHO);382 put iac2(DO, TELOPT_SGA);383 iac flush();396 put_iac2(DO, TELOPT_ECHO); 397 put_iac2(DO, TELOPT_SGA); 398 iac_flush(); 384 399 } 385 400 … … 390 405 setConMode(); 391 406 392 put iac2(DONT, TELOPT_ECHO);393 put iac2(DONT, TELOPT_SGA);394 iac flush();407 put_iac2(DONT, TELOPT_ECHO); 408 put_iac2(DONT, TELOPT_SGA); 409 iac_flush(); 395 410 } 396 411 … … 398 413 { 399 414 if (G.telwish == WILL) 400 put iac2(DONT, c);415 put_iac2(DONT, c); 401 416 else if (G.telwish == DO) 402 put iac2(WONT, c);417 put_iac2(WONT, c); 403 418 } 404 419 … … 407 422 /* if server requests ECHO, don't agree */ 408 423 if (G.telwish == DO) { 409 put iac2(WONT, TELOPT_ECHO);424 put_iac2(WONT, TELOPT_ECHO); 410 425 return; 411 426 } … … 423 438 424 439 if (G.telflags & UF_ECHO) 425 put iac2(DO, TELOPT_ECHO);440 put_iac2(DO, TELOPT_ECHO); 426 441 else 427 put iac2(DONT, TELOPT_ECHO);442 put_iac2(DONT, TELOPT_ECHO); 428 443 429 444 setConMode(); 430 write_str(1,"\r\n"); /* sudden modec */445 full_write1_str("\r\n"); /* sudden modec */ 431 446 } 432 447 … … 441 456 return; 442 457 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); 445 461 else 446 put iac2(DONT, TELOPT_SGA);462 put_iac2(DONT, TELOPT_SGA); 447 463 } 448 464 … … 451 467 { 452 468 /* Tell server we will (or won't) do TTYPE */ 453 454 469 if (G.ttype) 455 put iac2(WILL, TELOPT_TTYPE);470 put_iac2(WILL, TELOPT_TTYPE); 456 471 else 457 put iac2(WONT, TELOPT_TTYPE);472 put_iac2(WONT, TELOPT_TTYPE); 458 473 } 459 474 #endif … … 463 478 { 464 479 /* Tell server we will (or will not) do AUTOLOGIN */ 465 466 480 if (G.autologin) 467 put iac2(WILL, TELOPT_NEW_ENVIRON);481 put_iac2(WILL, TELOPT_NEW_ENVIRON); 468 482 else 469 put iac2(WONT, TELOPT_NEW_ENVIRON);483 put_iac2(WONT, TELOPT_NEW_ENVIRON); 470 484 } 471 485 #endif … … 475 489 { 476 490 /* Tell server we will do NAWS */ 477 put iac2(WILL, TELOPT_NAWS);491 put_iac2(WILL, TELOPT_NAWS); 478 492 } 479 493 #endif … … 497 511 case TELOPT_NAWS: 498 512 to_naws(); 499 put iac_naws(c, G.win_width, G.win_height);513 put_iac_naws(c, G.win_width, G.win_height); 500 514 break; 501 515 #endif … … 507 521 508 522 /* subnegotiation -- ignore all (except TTYPE,NAWS) */ 509 static intsubneg(byte c)523 static void subneg(byte c) 510 524 { 511 525 switch (G.telstate) { … … 515 529 #if ENABLE_FEATURE_TELNET_TTYPE 516 530 else 517 if (c == TELOPT_TTYPE )518 put iac_subopt(TELOPT_TTYPE, G.ttype);531 if (c == TELOPT_TTYPE && G.ttype) 532 put_iac_subopt(TELOPT_TTYPE, G.ttype); 519 533 #endif 520 534 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 521 535 else 522 if (c == TELOPT_NEW_ENVIRON )523 put iac_subopt_autologin();536 if (c == TELOPT_NEW_ENVIRON && G.autologin) 537 put_iac_subopt_autologin(); 524 538 #endif 525 539 break; 526 540 case TS_SUB2: 527 if (c == SE) 528 return TRUE; 541 if (c == SE) { 542 G.telstate = TS_COPY; 543 return; 544 } 529 545 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 } 540 549 541 550 static void rawmode(void) … … 551 560 } 552 561 553 int telnet_main(int argc, char ** argv);554 int telnet_main(int argc , char**argv)562 int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 563 int telnet_main(int argc UNUSED_PARAM, char **argv) 555 564 { 556 565 char *host; 557 566 int port; 558 567 int len; 559 #ifdef USE_POLL560 568 struct pollfd ufds[2]; 561 #else562 fd_set readfds;563 int maxfd;564 #endif565 569 566 570 INIT_G(); … … 579 583 cfmakeraw(&G.termios_raw); 580 584 } 581 582 if (argc < 2)583 bb_show_usage();584 585 585 586 #if ENABLE_FEATURE_TELNET_AUTOLOGIN … … 597 598 bb_show_usage(); 598 599 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; 614 610 615 611 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) { 627 613 /* error, ignore and/or log something, bay go to loop */ 628 if ( G.gotsig)629 con escape();614 if (bb_got_signal) 615 con_escape(); 630 616 else 631 617 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); 646 636 } 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 4 4 * Bjorn Wesen, Axis Communications AB (bjornw@axis.com) 5 5 * 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. 7 7 * 8 8 * --------------------------------------------------------------------------- … … 12 12 * The telnetd manpage says it all: 13 13 * 14 * Telnetd operates by allocating a pseudo-terminal device (see pty(4))for15 * 16 * 17 * 18 * 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. 19 19 * 20 20 * Vladimir Oleynik <dzo@simtreas.ru> 2001 21 * 21 * Set process group corrections, initial busybox port 22 22 */ 23 24 23 #define DEBUG 0 25 24 26 25 #include "libbb.h" 26 #include <syslog.h> 27 27 28 28 #if DEBUG 29 # define TELCMDS30 # define TELOPTS29 # define TELCMDS 30 # define TELOPTS 31 31 #endif 32 32 #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 45 38 46 39 struct tsession { 47 40 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 50 46 /* 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) 52 52 int rdidx1, wridx1, size1; 53 53 int rdidx2, wridx2, size2; … … 56 56 /* Two buffers are directly after tsession in malloced memory. 57 57 * Make whole thing fit in 4k */ 58 enum { BUFSIZE = (4*1024 - sizeof(struct tsession)) / 2 }; 58 enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 }; 59 60 61 /* Globals */ 62 struct 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 59 74 60 75 /* 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 */ 93 static unsigned char * 94 remove_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 */ 174 static 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 */ 215 enum { 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 224 static struct tsession * 225 make_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 375 static void 376 free_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 431 static 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 464 int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 465 int 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. 63 543 64 544 +-------+ wridx1++ +------+ rdidx1++ +----------+ … … 70 550 +-------+ size2++ +------+ size2-- +----------+ 71 551 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. 73 558 */ 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 ignored82 and must be removed so as to not be interpreted by the terminal). Make an83 uninterrupted string of characters fit for the terminal. Do this by packing84 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 to88 the terminal.89 90 Note - If an IAC (3 byte quantity) starts before (bf + len) but extends91 past (bf + len) then that IAC will be left unprocessed and *processed will be92 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 convenience98 */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 when115 * 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 the125 buffer we were asked to process, we can't126 process this char. */127 break;128 }129 130 /*131 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE132 */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 DEBUG144 fprintf(stderr, "Ignoring IAC %s,%s\n",145 TELCMD(ptr[1]), TELOPT(ptr[2]));146 #endif147 ptr += 3;148 }149 }150 }151 152 processed = ptr - ptr0;153 num_totty = totty - ptr0;154 /* the difference between processed and num_to tty155 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 the161 buffer. */162 return memmove(ptr - num_totty, ptr0, num_totty);163 }164 165 166 static int167 getpty(char *line, int size)168 {169 int p;170 #if ENABLE_FEATURE_DEVPTS171 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 #else185 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 void214 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_STANDALONE249 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 #else254 ts->sockfd_write = 1;255 /* xzalloc: ts->sockfd_read = 0; */256 ndelay_on(0);257 ndelay_on(1);258 #endif259 /* Make the telnet client understand we will echo characters so it260 * 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 other262 * 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. Therefore289 * 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 in298 * 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_STANDALONE318 319 static void320 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 #endif361 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_STANDALONE371 #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 #else377 enum {378 IS_INETD = 1,379 master_fd = -1,380 portnbr = 23,381 };382 #endif383 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, &loginpath391 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) // -f398 //if (opt & 2) // -l399 USE_FEATURE_TELNETD_STANDALONE(400 if (opt & OPT_PORT) // -p401 portnbr = xatou16(opt_portnbr);402 //if (opt & 8) // -b403 //if (opt & 0x10) // -F404 //if (opt & 0x20) // -i405 );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_STANDALONE411 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 #else420 sessions = make_new_session();421 #endif422 423 /* We don't want to die if just one session is broken */424 signal(SIGPIPE, SIG_IGN);425 426 559 again: 427 560 FD_ZERO(&rdfdset); 428 561 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 } 429 585 if (!IS_INETD) { 430 586 FD_SET(master_fd, &rdfdset); 431 587 /* 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 */ 457 607 return 0; 608 if (count < 0) 609 goto again; /* EINTR or ENOMEM */ 458 610 459 611 #if ENABLE_FEATURE_TELNETD_STANDALONE 460 /* First check for and accept new sessions.*/612 /* Check for and accept new sessions */ 461 613 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) { 462 614 int fd; 463 615 struct tsession *new_ts; 464 616 465 fd = accept(master_fd, NULL, 0);617 fd = accept(master_fd, NULL, NULL); 466 618 if (fd < 0) 467 619 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); 470 624 if (new_ts) { 471 new_ts->next = sessions;472 sessions = new_ts;625 new_ts->next = G.sessions; 626 G.sessions = new_ts; 473 627 } else { 474 628 close(fd); … … 477 631 #endif 478 632 479 /* Then check for data tunneling .*/480 ts = sessions;633 /* Then check for data tunneling */ 634 ts = G.sessions; 481 635 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)) { 485 639 int num_totty; 486 char *ptr;487 /* Write to pty from buffer 1 .*/640 unsigned char *ptr; 641 /* Write to pty from buffer 1 */ 488 642 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; 497 648 } 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 */ 501 652 ts->wridx1 = 0; 502 653 } 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; 515 663 } 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 */ 519 667 ts->wridx2 = 0; 520 668 } 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. */ 561 676 if (ts->size1 == 0) { 562 677 ts->rdidx1 = 0; … … 567 682 ts->wridx2 = 0; 568 683 } 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: 569 719 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 571 728 goto again; 572 729 } -
branches/2.2.9/mindi-busybox/networking/tftp.c
r1765 r2725 1 1 /* 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. 6 4 * Tries to follow RFC1350. 7 5 * Only "octet" mode supported. … … 17 15 * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> 18 16 * 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 */ 22 21 #include "libbb.h" 23 22 24 25 23 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT 26 24 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 */ 30 31 31 32 /* opcodes we support */ … … 37 38 #define TFTP_OACK 6 38 39 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 */ 54 enum { 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 39 64 #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT 40 #define USE_GETPUT(...)65 #define IF_GETPUT(...) 41 66 #define CMD_GET(cmd) 1 42 67 #define CMD_PUT(cmd) 0 43 68 #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT 44 #define USE_GETPUT(...)69 #define IF_GETPUT(...) 45 70 #define CMD_GET(cmd) 0 46 71 #define CMD_PUT(cmd) 1 47 72 #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) 52 76 #endif 53 77 /* NB: in the code below … … 56 80 57 81 82 struct 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) 96 struct 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 108 static void tftp_progress_update(void) 109 { 110 bb_progress_update(&G.pmt, G.file, 0, G.pos, G.size); 111 } 112 static void tftp_progress_init(void) 113 { 114 bb_progress_init(&G.pmt); 115 tftp_progress_update(); 116 } 117 static 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 58 130 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 59 131 60 static int tftp_bl ocksize_check(int blocksize, int bufsize)132 static int tftp_blksize_check(const char *blksize_str, int maxsize) 61 133 { 62 /* Check if the bl ocksize is valid:134 /* Check if the blksize is valid: 63 135 * RFC2348 says between 8 and 65464, 64 136 * 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) 70 141 ) { 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; 76 149 } 77 150 78 static char *tftp_ option_get(char *buf, int len, const char *option)151 static char *tftp_get_option(const char *option, char *buf, int len) 79 152 { 80 153 int opt_val = 0; … … 82 155 int k; 83 156 157 /* buf points to: 158 * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */ 159 84 160 while (len > 0) { 85 /* Make sure theoptions are terminated correctly */161 /* Make sure options are terminated correctly */ 86 162 for (k = 0; k < len; k++) { 87 163 if (buf[k] == '\0') { … … 91 167 return NULL; 92 168 nul_found: 93 if (opt_val == 0) { 169 if (opt_val == 0) { /* it's "name" part */ 94 170 if (strcasecmp(buf, option) == 0) { 95 171 opt_found = 1; … … 110 186 #endif 111 187 112 static int tftp( USE_GETPUT(const int cmd,) 188 static int tftp_protocol( 189 /* NULL if tftp, !NULL if tftpd: */ 190 len_and_sockaddr *our_lsa, 113 191 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)) 116 200 { 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) 120 207 int len; 121 208 int send_len; 122 USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack= 0;)209 IF_FEATURE_TFTP_BLOCKSIZE(smallint expect_OACK = 0;) 123 210 smallint finished = 0; 124 211 uint16_t opcode; 125 uint16_t block_nr = 1;212 uint16_t block_nr; 126 213 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; 128 217 char *cp; 129 130 unsigned org_port;131 len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len);132 133 218 /* 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; 149 292 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! */ 163 303 #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) { 168 350 bb_error_msg("remote filename is too long"); 169 351 goto ret; 170 352 } 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 } 180 405 181 406 /* Using mostly goto's - continue/break will be less clear 182 407 * in where we actually jump to */ 183 184 408 while (1) { 185 409 /* Build ACK or DATA */ … … 189 413 block_nr++; 190 414 opcode = TFTP_ACK; 191 if (CMD_PUT( cmd)) {415 if (CMD_PUT(option_mask32)) { 192 416 opcode = TFTP_DATA; 193 len = full_read(local fd, cp, tftp_bufsize - 4);417 len = full_read(local_fd, cp, blksize); 194 418 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) { 199 422 finished = 1; 200 423 } … … 207 430 /* NB: send_len value is preserved in code below 208 431 * for potential resend */ 432 433 retries = TFTP_NUM_RETRIES; /* re-initialize */ 434 waittime_ms = TFTP_TIMEOUT_MS; 435 209 436 send_again: 210 #if ENABLE_ DEBUG_TFTP437 #if ENABLE_TFTP_DEBUG 211 438 fprintf(stderr, "sending %u bytes\n", send_len); 212 439 for (cp = xbuf; cp < &xbuf[send_len]; cp++) … … 214 441 fprintf(stderr, "\n"); 215 442 #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 217 451 /* Was it final ACK? then exit */ 218 452 if (finished && (opcode == TFTP_ACK)) 219 453 goto ret; 220 454 221 timeout = TFTP_NUM_RETRIES; /* re-initialize */222 455 recv_again: 223 456 /* 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 */ 230 478 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 } 235 496 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? */ 248 500 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 263 504 /* Process recv'ed packet */ 264 505 opcode = ntohs( ((uint16_t*)rbuf)[0] ); 265 506 recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); 266 267 #if ENABLE_DEBUG_TFTP 507 #if ENABLE_TFTP_DEBUG 268 508 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); 269 509 #endif 270 271 510 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"; 283 521 284 522 const char *msg = ""; 285 523 286 if ( rbuf[4] != '\0') {524 if (len > 4 && rbuf[4] != '\0') { 287 525 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); 291 529 } 292 530 bb_error_msg("server error: (%u) %s", recv_blk, msg); … … 295 533 296 534 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 297 if (want_option_ack) { 298 want_option_ack = 0; 299 535 if (expect_OACK) { 536 expect_OACK = 0; 300 537 if (opcode == TFTP_OACK) { 301 538 /* server seems to support options */ 302 539 char *res; 303 540 304 res = tftp_ option_get(&rbuf[2], len - 2, "blksize");541 res = tftp_get_option("blksize", &rbuf[2], len - 2); 305 542 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; 316 547 } 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 */ 323 563 block_nr = 0; 324 continue;325 564 } 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; 335 575 } 336 576 #endif … … 338 578 * to get / block# we are about to send next time */ 339 579 340 if (CMD_GET( cmd) && (opcode == TFTP_DATA)) {580 if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) { 341 581 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; 346 587 } 347 if ( len != (tftp_bufsize - 4)) {588 if (sz != blksize) { 348 589 finished = 1; 349 590 } 350 591 continue; /* send ACK */ 351 592 } 593 /* Disabled to cope with servers with Sorcerer's Apprentice Syndrome */ 594 #if 0 352 595 if (recv_blk == (block_nr - 1)) { 353 596 /* Server lost our TFTP_ACK. Resend it */ … … 355 598 continue; 356 599 } 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? */ 361 605 if (recv_blk == (uint16_t) (block_nr - 1)) { 362 606 if (finished) … … 376 620 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome 377 621 */ 378 } 622 } /* end of "while (1)" */ 379 623 ret: 380 624 if (ENABLE_FEATURE_CLEAN_UP) { 381 close(socketfd); 625 close(local_fd); 626 close(socket_fd); 382 627 free(xbuf); 383 628 free(rbuf); 384 629 } 385 630 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 386 642 } 387 643 388 int tftp_main(int argc, char **argv); 389 int tftp_main(int argc, char **argv) 644 #if ENABLE_TFTP 645 646 int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 647 int tftp_main(int argc UNUSED_PARAM, char **argv) 390 648 { 391 649 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; 397 657 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(); 403 661 404 662 /* -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 &local file, &remotefile412 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)); 413 671 argv += optind; 414 672 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 432 692 /* Error if filename or host is not known */ 433 if (!remote file || !argv[0])693 if (!remote_file || !argv[0]) 434 694 bb_show_usage(); 435 436 fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;437 if (!LONE_DASH(localfile)) {438 fd = xopen(localfile, flags);439 }440 695 441 696 port = bb_lookup_port(argv[1], "udp", 69); 442 697 peer_lsa = xhost2sockaddr(argv[0], port); 443 698 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); 456 718 } 457 719 return result; 458 720 } 459 721 722 #endif /* ENABLE_TFTP */ 723 724 #if ENABLE_TFTPD 725 int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 726 int 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 460 839 #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */ -
branches/2.2.9/mindi-busybox/networking/traceroute.c
r1765 r2725 23 23 */ 24 24 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 */ 27 41 28 42 /* … … 215 229 #include <netinet/ip.h> 216 230 #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 217 238 218 239 #include "libbb.h" 219 240 #include "inet_common.h" 220 241 221 222 /*223 * Definitions for internet protocol version 4.224 * Per RFC 791, September 1981.225 */226 #define IPVERSION 4227 228 242 #ifndef IPPROTO_ICMP 229 /* Grrrr.... */ 230 #define IPPROTO_ICMP 1 243 # define IPPROTO_ICMP 1 231 244 #endif 232 245 #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") 253 enum { 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 */ 245 274 }; 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 277 enum { 278 SIZEOF_ICMP_HDR = 8, 279 rcvsock = 3, /* receive (icmp) socket file descriptor */ 280 sndsock = 4, /* send (udp/icmp) socket file descriptor */ 253 281 }; 254 #define ui_next ui_i.ih_next255 #define ui_prev ui_i.ih_prev256 #define ui_x1 ui_i.ih_x1257 #define ui_pr ui_i.ih_pr258 #define ui_len ui_i.ih_len259 #define ui_src ui_i.ih_src260 #define ui_dst ui_i.ih_dst261 #define ui_sport ui_u.uh_sport262 #define ui_dport ui_u.uh_dport263 #define ui_ulen ui_u.uh_ulen264 #define ui_sum ui_u.uh_sum265 266 267 /* Host name and address list */268 struct hostinfo {269 char *name;270 int n;271 uint32_t *addrs;272 };273 282 274 283 /* Data section of the probe packet */ 275 struct outdata {284 struct outdata_t { 276 285 unsigned char seq; /* sequence number of this packet */ 277 286 unsigned char ttl; /* ttl packet left with */ 278 287 // 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 */ 280 289 }; 281 290 282 struct IFADDRLIST { 283 uint32_t addr; 284 char device[sizeof(struct ifreq)]; 291 #if ENABLE_TRACEROUTE6 292 struct outdata6_t { 293 uint32_t ident6; 294 uint32_t seq6; 295 struct timeval tv_UNUSED PACKED; /* time packet left */ 285 296 }; 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 299 struct 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) */ 312 308 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 313 staticint optlen; /* length of ip options */309 int optlen; /* length of ip options */ 314 310 #else 315 311 #define optlen 0 316 312 #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 */ 353 314 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 354 315 /* Maximum number of gateways (include room for one noop) */ … … 360 321 361 322 #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 ) 366 335 #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 */ 347 static 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 372 355 static 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; 356 wait_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; 556 371 } 557 372 … … 568 383 569 384 /* 570 * 571 * 572 * 573 * 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. 574 389 */ 575 while (nleft > 1) 390 while (nleft > 1) { 576 391 sum += *w++; 577 392 nleft -= 2; … … 582 397 sum += *(unsigned char *)w; 583 398 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 */ 587 400 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 588 401 sum += (sum >> 16); /* add carry */ … … 591 404 } 592 405 593 594 406 static void 595 407 send_probe(int seq, int ttl) 596 408 { 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; 615 411 616 412 /* 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; 619 424 // 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 658 441 /* XXX undocumented debugging hack */ 659 442 if (verbose > 1) { … … 680 463 #endif 681 464 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); 694 492 } 695 493 … … 698 496 * Convert an ICMP "type" field to a printable string. 699 497 */ 700 static inlineconst char *498 static const char * 701 499 pr_type(unsigned char t) 702 500 { … … 708 506 "Info Reply", "Mask Request", "Mask Reply" 709 507 }; 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)) 712 526 return "OUT-OF-RANGE"; 713 527 … … 716 530 #endif 717 531 532 #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE 533 #define packet4_ok(read_len, from, seq) \ 534 packet4_ok(read_len, seq) 535 #endif 718 536 static int 719 packet _ok(unsigned char *buf, int cc,struct sockaddr_in *from, int seq)720 { 721 struct icmp *icp;537 packet4_ok(int read_len, const struct sockaddr_in *from, int seq) 538 { 539 const struct icmp *icp; 722 540 unsigned char type, code; 723 541 int hlen; 724 struct ip *ip;725 726 ip = (struct ip *) buf;542 const struct ip *ip; 543 544 ip = (struct ip *) recv_pkt; 727 545 hlen = ip->ip_hl << 2; 728 if ( cc< hlen + ICMP_MINLEN) {546 if (read_len < hlen + ICMP_MINLEN) { 729 547 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 730 548 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, 732 550 inet_ntoa(from->sin_addr)); 733 551 #endif 734 552 return 0; 735 553 } 736 cc-= hlen;737 icp = (struct icmp *)( buf+ hlen);554 read_len -= hlen; 555 icp = (struct icmp *)(recv_pkt + hlen); 738 556 type = icp->icmp_type; 739 557 code = icp->icmp_code; 740 558 /* Path MTU Discovery (RFC1191) */ 741 if (code != ICMP_UNREACH_NEEDFRAG) 742 pmtu = 0; 743 else { 559 pmtu = 0; 560 if (code == ICMP_UNREACH_NEEDFRAG) 744 561 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; 750 569 751 570 hip = &icp->icmp_ip; 752 571 hlen = hip->ip_hl << 2; 753 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 754 if (useicmp) { 572 if (option_mask32 & OPT_USE_ICMP) { 755 573 struct icmp *hicmp; 756 574 757 575 /* 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 } 762 582 763 583 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 ) { 769 589 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 ) { 779 601 return (type == ICMP_TIMXCEED ? -1 : code + 1); 602 } 780 603 } 781 604 } … … 787 610 printf("\n%d bytes from %s to " 788 611 "%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)) 792 616 printf("%2d: x%8.8x\n", i, *lp++); 793 617 } … … 796 620 } 797 621 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 627 static int 628 packet_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 */ 704 static ALWAYS_INLINE int 705 packet_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 798 713 799 714 /* 800 715 * Construct an Internet address representation. 801 * If the nflag has been supplied, give716 * If the -n flag has been supplied, give 802 717 * numeric value, otherwise try for symbolic name. 803 718 */ 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 { 719 static void 720 print_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 { 813 727 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 */ 815 733 n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); 816 printf(" %s (%s)", (n ? n : ina), ina); 734 } 735 printf(" %s (%s)", (n ? n : ina), ina); 817 736 free(n); 818 737 } 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 741 static void 742 print(int read_len, const struct sockaddr *from, const struct sockaddr *to) 743 { 831 744 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 } 890 760 891 761 static void … … 893 763 { 894 764 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 */ 773 static int 774 common_traceroute_main(int op, char **argv) 775 { 776 int i; 777 int minpacket; 909 778 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; 910 785 char *tos_str; 911 char *source;912 unsigned op;913 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE914 int lsrr = 0;915 #endif916 uint16_t off = 0;917 struct IFADDRLIST *al;918 char *device;919 int max_ttl = 30;920 786 char *max_ttl_str; 921 787 char *port_str; 922 int nprobes = 3;923 788 char *nprobes_str; 924 789 char *waittime_str; 925 unsigned pausemsecs = 0;926 790 char *pausemsecs_str; 927 int first_ttl = 1;928 791 char *first_ttl_str; 929 792 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 930 793 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; 940 798 #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 948 812 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str 949 813 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str … … 952 816 #endif 953 817 ); 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) 959 822 bb_error_msg("warning: ip checksums disabled"); 960 } 823 #endif 961 824 if (op & OPT_TOS) 962 825 tos = xatou_range(tos_str, 0, 255); … … 972 835 * probe (e.g., on a multi-homed host). 973 836 */ 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); 976 839 } 977 840 if (op & OPT_WAITTIME) 978 waittime = xatou_range(waittime_str, 2, 24 * 60 * 60);841 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60); 979 842 if (op & OPT_PAUSE_MS) 980 843 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000); 981 844 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); 983 846 984 847 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 985 848 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 990 852 if (lsrr >= NGATEWAYS) 991 853 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); 993 857 ++lsrr; 994 l_sr = l_sr->link;995 free(source_route_list);996 source_route_list = l_sr;997 858 } 998 859 optlen = (lsrr + 1) * sizeof(gwlist[0]); … … 1000 861 #endif 1001 862 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_ICMP1011 if (useicmp)1012 minpacket += 8; /* XXX magic number */1013 else1014 #endif1015 minpacket += sizeof(*outudp);1016 packlen = minpacket; /* minimum sized packet */1017 1018 863 /* 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); 1040 883 1041 884 /* Ensure the socket fds won't be 0, 1 or 2 */ 1042 885 bb_sanitize_stdio(); 1043 886 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 } 1045 904 1046 905 #if TRACEROUTE_SO_DEBUG 1047 906 if (op & OPT_DEBUG) 1048 setsockopt( s, SOL_SOCKET, SO_DEBUG,907 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 1049 908 &const_int_1, sizeof(const_int_1)); 1050 909 #endif 1051 910 if (op & OPT_BYPASS_ROUTE) 1052 setsockopt( s, SOL_SOCKET, SO_DONTROUTE,911 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 1053 912 &const_int_1, sizeof(const_int_1)); 1054 913 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 } 1083 952 1084 953 #ifdef SO_SNDBUF … … 1087 956 } 1088 957 #endif 1089 #ifdef IP_HDRINCL1090 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 01091 && errno != ENOPROTOOPT1092 ) {1093 bb_perror_msg_and_die("IP_HDRINCL");1094 }1095 #else1096 958 #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) { 1098 960 bb_perror_msg_and_die("setsockopt tos %d", tos); 1099 961 } 1100 962 #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)); 1101 967 #endif 1102 968 #if TRACEROUTE_SO_DEBUG … … 1109 975 &const_int_1, sizeof(const_int_1)); 1110 976 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 1111 1041 /* Revert to non-privileged user after opening sockets */ 1112 1042 xsetgid(getgid()); 1113 1043 xsetuid(getuid()); 1114 1044 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)); 1199 1047 if (op & OPT_SOURCE) 1200 1048 printf(" from %s", source); 1201 1049 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; 1204 1055 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 */ 1207 1059 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); 1212 1063 for (probe = 0; probe < nprobes; ++probe) { 1213 int cc;1064 int read_len; 1214 1065 unsigned t1; 1215 1066 unsigned t2; 1216 1067 struct ip *ip; 1217 1068 1218 if ( sentfirst && pausemsecs > 0)1069 if (!first && pausemsecs > 0) 1219 1070 usleep(pausemsecs * 1000); 1071 fflush_all(); 1072 1220 1073 t1 = monotonic_us(); 1221 1074 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) { 1224 1078 t2 = monotonic_us(); 1225 i = packet_ok( packet, cc, from, seq);1079 i = packet_ok(read_len, from_lsa, to, seq); 1226 1080 /* Skip short packet */ 1227 1081 if (i == 0) 1228 1082 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; 1234 1090 } 1091 1235 1092 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 1245 1099 /* time exceeded in transit */ 1246 1100 if (i == -1) 1247 1101 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 1251 1109 case ICMP_UNREACH_PORT: 1252 1110 if (ip->ip_ttl <= 1) 1253 1111 printf(" !"); 1254 ++got_there;1112 got_there = 1; 1255 1113 break; 1256 1114 1257 1115 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"); 1258 1120 ++unreachable; 1259 printf(" !N"); 1260 break; 1261 1121 break; 1262 1122 case ICMP_UNREACH_HOST: 1123 #if ENABLE_TRACEROUTE6 1124 case ICMP6_DST_UNREACH_ADDR << 8: 1125 #endif 1126 printf(" !H"); 1263 1127 ++unreachable; 1264 printf(" !H"); 1265 break; 1266 1128 break; 1267 1129 case ICMP_UNREACH_PROTOCOL: 1268 ++got_there;1269 1130 printf(" !P"); 1270 break;1271 1131 got_there = 1; 1132 break; 1272 1133 case ICMP_UNREACH_NEEDFRAG: 1134 printf(" !F-%d", pmtu); 1273 1135 ++unreachable; 1274 printf(" !F-%d", pmtu); 1275 break; 1276 1136 break; 1277 1137 case ICMP_UNREACH_SRCFAIL: 1138 #if ENABLE_TRACEROUTE6 1139 case ICMP6_DST_UNREACH_ADMIN << 8: 1140 #endif 1141 printf(" !S"); 1278 1142 ++unreachable; 1279 printf(" !S"); 1280 break; 1281 1143 break; 1282 1144 case ICMP_UNREACH_FILTER_PROHIB: 1283 1145 case ICMP_UNREACH_NET_PROHIB: /* misuse */ 1146 printf(" !A"); 1284 1147 ++unreachable; 1285 printf(" !A"); 1286 break; 1287 1148 break; 1288 1149 case ICMP_UNREACH_HOST_PROHIB: 1150 printf(" !C"); 1289 1151 ++unreachable; 1152 break; 1153 case ICMP_UNREACH_HOST_PRECEDENCE: 1154 printf(" !V"); 1155 ++unreachable; 1156 break; 1157 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1290 1158 printf(" !C"); 1291 break;1292 1293 case ICMP_UNREACH_HOST_PRECEDENCE:1294 1159 ++unreachable; 1295 printf(" !V"); 1296 break; 1297 1298 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1299 ++unreachable; 1300 printf(" !C"); 1301 break; 1302 1160 break; 1303 1161 case ICMP_UNREACH_NET_UNKNOWN: 1304 1162 case ICMP_UNREACH_HOST_UNKNOWN: 1163 printf(" !U"); 1305 1164 ++unreachable; 1306 printf(" !U"); 1307 break; 1308 1165 break; 1309 1166 case ICMP_UNREACH_ISOLATED: 1167 printf(" !I"); 1310 1168 ++unreachable; 1311 printf(" !I"); 1312 break; 1313 1169 break; 1314 1170 case ICMP_UNREACH_TOSNET: 1315 1171 case ICMP_UNREACH_TOSHOST: 1172 printf(" !T"); 1316 1173 ++unreachable; 1317 printf(" !T"); 1318 break; 1319 1174 break; 1320 1175 default: 1176 printf(" !<%d>", i); 1321 1177 ++unreachable; 1322 printf(" !<%d>", code);1323 1178 break; 1324 1179 } 1325 1180 break; 1326 1181 } 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 ) { 1334 1190 break; 1335 } 1191 } 1192 } 1193 1336 1194 return 0; 1337 1195 } 1196 1197 int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1198 int traceroute_main(int argc UNUSED_PARAM, char **argv) 1199 { 1200 return common_traceroute_main(0, argv); 1201 } 1202 1203 #if ENABLE_TRACEROUTE6 1204 int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1205 int 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 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 4 5 # 5 6 6 config APP_UDHCPD 7 bool "udhcp Server (udhcpd)" 8 default n 7 8 9 config UDHCPD 10 bool "udhcp server (udhcpd)" 11 default y 12 depends on PLATFORM_LINUX 9 13 help 10 u DHCPd is a DHCP server geared primarily toward embedded systems,14 udhcpd is a DHCP server geared primarily toward embedded systems, 11 15 while striving to be fully functional and RFC compliant. 12 16 13 See http://udhcp.busybox.net for further details. 14 15 config APP_DHCPRELAY 17 config DHCPRELAY 16 18 bool "dhcprelay" 17 default n18 depends on APP_UDHCPD19 default y 20 depends on UDHCPD 19 21 help 20 22 dhcprelay listens for dhcp requests on one or more interfaces … … 22 24 server. 23 25 24 config APP_DUMPLEASES26 config DUMPLEASES 25 27 bool "Lease display utility (dumpleases)" 26 default n27 depends on APP_UDHCPD28 default y 29 depends on UDHCPD 28 30 help 29 31 dumpleases displays the leases written out by the udhcpd server. … … 31 33 by the absolute time that it expires in seconds from epoch. 32 34 33 See http://udhcp.busybox.net for further details.34 35 35 config FEATURE_UDHCPD_WRITE_LEASES_EARLY 36 36 bool "Rewrite the lease file at every new acknowledge" 37 default n38 depends on APP_UDHCPD37 default y 38 depends on UDHCPD 39 39 help 40 40 If selected, udhcpd will write a new file with leases every 41 time a new lease has been accepted, thus el eminating the need42 to send SIGUSR1 for the initial writing ,or updating. Any timed41 time a new lease has been accepted, thus eliminating the need 42 to send SIGUSR1 for the initial writing or updating. Any timed 43 43 rewriting remains undisturbed 44 44 45 config APP_UDHCPC 46 bool "udhcp Client (udhcpc)" 47 default n 45 config DHCPD_LEASES_FILE 46 string "Absolute path to lease file" 47 default "/var/lib/misc/udhcpd.leases" 48 depends on UDHCPD 48 49 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 53 config 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, 50 59 while striving to be fully functional and RFC compliant. 51 60 52 61 The udhcp client negotiates a lease with the DHCP server and 53 notifies a set of scriptswhen a lease is obtained or lost.62 runs a script when a lease is obtained or lost. 54 63 55 See http://udhcp.busybox.net for further details. 64 config 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. 56 73 57 config FEATURE_UDHCP_ DEBUG58 bool " Compile udhcp with noisy debugging messages"59 default n60 depends on APP_UDHCPD || APP_UDHCPC74 config FEATURE_UDHCP_PORT 75 bool "Enable '-P port' option for udhcpd and udhcpc" 76 default y 77 depends on UDHCPD || UDHCPC 61 78 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. 65 81 66 See http://udhcp.busybox.net for further details. 82 config 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. 67 90 68 config FEATURE_RFC3397 91 Bigger values result in bigger code. Levels above 1 92 are very verbose and useful for debugging only. 93 94 config FEATURE_UDHCP_RFC3397 69 95 bool "Support for RFC3397 domain search (experimental)" 70 default n71 depends on APP_UDHCPD || APP_UDHCPC96 default y 97 depends on UDHCPD || UDHCPC 72 98 help 73 99 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 103 config 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 112 config 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 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 4 5 # 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. 6 7 # 7 8 8 9 lib-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 13 lib-$(CONFIG_UDHCPC) += common.o packet.o signalpipe.o socket.o 14 lib-$(CONFIG_UDHCPD) += common.o packet.o signalpipe.o socket.o 15 16 lib-$(CONFIG_UDHCPC) += dhcpc.o 17 lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o files.o leases.o static_leases.o 18 lib-$(CONFIG_DUMPLEASES) += dumpleases.o 19 lib-$(CONFIG_DHCPRELAY) += dhcprelay.o 20 21 lib-$(CONFIG_FEATURE_UDHCPC_ARPING) += arpping.o 22 lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o -
branches/2.2.9/mindi-busybox/networking/udhcp/arpping.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * arpping.c4 *5 3 * Mostly stolen from: dhcpcd - DHCP client daemon 6 4 * by Yoichi Hariguchi <yoichi@fore.com> 5 * 6 * Licensed under GPLv2, see file LICENSE in this source tree. 7 7 */ 8 9 8 #include <netinet/if_ether.h> 10 9 #include <net/if_arp.h> … … 12 11 #include "common.h" 13 12 #include "dhcpd.h" 14 15 13 16 14 struct arpMsg { … … 31 29 uint8_t tInaddr[4]; /* 26 target's IP address */ 32 30 uint8_t pad[18]; /* 2a pad for min. ethernet payload (60 bytes) */ 33 } ATTRIBUTE_PACKED;31 } PACKED; 34 32 33 enum { 34 ARP_MSG_SIZE = 0x2a 35 }; 35 36 36 37 /* 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) 38 int 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) 39 43 { 40 int timeout = 2; 41 int s; /* socket */ 44 int timeout_ms; 45 struct pollfd pfd[1]; 46 #define s (pfd[0].fd) /* socket */ 42 47 int rv = 1; /* "no reply received" yet */ 43 48 struct sockaddr addr; /* for interface name */ 44 49 struct arpMsg arp; 45 fd_set fdset;46 struct timeval tm;47 unsigned prevTime;48 50 49 51 s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); … … 54 56 55 57 if (setsockopt_broadcast(s) == -1) { 56 bb_perror_msg("can not setsocketopt on raw socket");58 bb_perror_msg("can't enable bcast on raw socket"); 57 59 goto ret; 58 60 } … … 70 72 memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ 71 73 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 */ 74 76 75 77 memset(&addr, 0, sizeof(addr)); 76 78 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. 78 82 goto ret; 83 } 79 84 80 85 /* wait for arp reply, and check it */ 86 timeout_ms = 2000; 81 87 do { 88 typedef uint32_t aliased_uint32_t FIX_ALIASING; 82 89 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) 92 99 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 99 110 ) { 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"); 101 118 break; 102 119 } 103 120 } 104 timeout -= monotonic_sec() - prevTime;105 } while (timeout > 0);121 timeout_ms -= (unsigned)monotonic_ms() - prevTime; 122 } while (timeout_ms > 0); 106 123 107 124 ret: 108 125 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"); 110 127 return rv; 111 128 } -
branches/2.2.9/mindi-busybox/networking/udhcp/common.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* common.c 2 /* 3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 3 4 * 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. 5 6 */ 6 7 7 #include "common.h" 8 9 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 10 unsigned dhcp_verbose; 11 #endif 8 12 9 13 const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = { 10 14 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 11 15 }; 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 */ 21 const 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 */ 83 const 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 */ 133 const 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 153 static 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 165 unsigned 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) */ 185 uint8_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) */ 249 int 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 */ 264 void 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 */ 284 void 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 */ 308 struct 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 */ 319 int 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 */ 337 static 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 */ 354 static 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 420 int 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 1 1 /* vi: set sw=4 ts=4: */ 2 /* common.h 3 * 2 /* 4 3 * Russ Dill <Russ.Dill@asu.edu> September 2001 5 4 * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003 6 5 * 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. 8 7 */ 9 10 #ifndef _COMMON_H 11 #define _COMMON_H 8 #ifndef UDHCP_COMMON_H 9 #define UDHCP_COMMON_H 1 12 10 13 11 #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 21 12 #include <netinet/udp.h> 22 13 #include <netinet/ip.h> 23 14 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 { 15 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 16 17 extern 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 29 struct 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 54 struct ip_udp_dhcp_packet { 44 55 struct iphdr ip; 45 56 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 60 struct udp_dhcp_packet { 61 struct udphdr udp; 62 struct dhcp_packet data; 63 } PACKED; 64 65 enum { 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 */ 72 struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { 73 char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1]; 74 }; 75 76 77 /*** Options ***/ 78 79 enum { 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 173 struct dhcp_optflag { 174 uint8_t flags; 175 uint8_t code; 176 }; 177 178 struct option_set { 179 uint8_t *data; 180 struct option_set *next; 181 }; 182 183 extern const struct dhcp_optflag dhcp_optflags[]; 184 extern const char dhcp_option_strings[]; 185 extern const uint8_t dhcp_option_lengths[]; 186 187 unsigned FAST_FUNC udhcp_option_idx(const char *name); 188 189 uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; 190 int udhcp_end_option(uint8_t *optionptr) FAST_FUNC; 191 void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC; 192 void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) FAST_FUNC; 193 #if ENABLE_FEATURE_UDHCP_RFC3397 194 char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; 195 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; 196 #endif 197 struct 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 249 extern unsigned dhcp_verbose; 250 # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) 251 # if CONFIG_UDHCP_DEBUG >= 2 252 void 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*" */ 274 int FAST_FUNC udhcp_str2nip(const char *str, void *arg); 275 /* 2nd param is "struct option_set**" */ 276 int FAST_FUNC udhcp_str2optset(const char *str, void *arg); 277 278 uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; 279 280 void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; 281 282 int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; 283 284 int 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 289 int 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 293 void udhcp_sp_setup(void) FAST_FUNC; 294 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC; 295 int udhcp_sp_read(const fd_set *rfds) FAST_FUNC; 296 297 int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC; 298 299 int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC; 300 87 301 /* 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) 302 int 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 308 POP_SAVED_FUNCTION_VISIBILITY 309 94 310 #endif 95 96 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* dhcpc.c 3 * 4 * udhcp DHCP client 2 /* 3 * udhcp client 5 4 * 6 5 * Russ Dill <Russ.Dill@asu.edu> July 2001 7 6 * 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. 9 20 */ 10 11 #include <getopt.h>12 21 #include <syslog.h> 13 14 22 /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ 15 23 #define WANT_PIDFILE 1 … … 17 25 #include "dhcpd.h" 18 26 #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...) */ 44 static 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 */ 66 static 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 */ 72 static 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 */ 84 static 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 */ 233 static 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 */ 314 static 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 341 static ALWAYS_INLINE uint32_t random_xid(void) 342 { 343 return rand(); 344 } 345 346 /* Initialize the packet with the proper defaults */ 347 static 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 359 static 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. 26 424 */ 27 static unsigned timeout; 28 static uint32_t requested_ip; /* = 0 */ 29 static uint32_t server_addr; 30 static int packet_num; /* = 0 */ 425 426 static 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 */ 436 static 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 */ 465 static 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 */ 506 static 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 */ 550 static 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 */ 576 static 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 */ 596 static 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 31 668 static int sockfd = -1; 32 669 33 #define LISTEN_NONE 0670 #define LISTEN_NONE 0 34 671 #define LISTEN_KERNEL 1 35 #define LISTEN_RAW 2672 #define LISTEN_RAW 2 36 673 static smallint listen_mode; 37 674 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 38 689 static smallint state; 39 690 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"); 691 static 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 762 static 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; 48 771 if (sockfd >= 0) { 49 772 close(sockfd); 50 773 sockfd = -1; 51 774 } 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 57 782 static void perform_renew(void) 58 783 { … … 60 785 switch (state) { 61 786 case BOUND: 62 change_ mode(LISTEN_KERNEL);787 change_listen_mode(LISTEN_KERNEL); 63 788 case RENEWING: 64 789 case REBINDING: … … 69 794 case REQUESTING: 70 795 case RELEASED: 71 change_ mode(LISTEN_RAW);796 change_listen_mode(LISTEN_RAW); 72 797 state = INIT_SELECTING; 73 798 break; … … 75 800 break; 76 801 } 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 804 static void perform_release(uint32_t requested_ip, uint32_t server_addr) 88 805 { 89 806 char buffer[sizeof("255.255.255.255")]; … … 102 819 bb_info_msg("Entering released state"); 103 820 104 change_ mode(LISTEN_NONE);821 change_listen_mode(LISTEN_NONE); 105 822 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 } 129 824 130 825 static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 131 826 { 132 827 uint8_t *storage; 133 int len = strlen(str); 134 if (len > 255) len = 255; 828 int len = strnlen(str, 255); 135 829 storage = xzalloc(len + extra + OPT_DATA); 136 830 storage[OPT_CODE] = code; … … 140 834 } 141 835 142 143 int udhcpc_main(int argc, char **argv); 144 int udhcpc_main(int argc, char **argv) 836 #if BB_MMU 837 static 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 930 int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 931 int udhcpc_main(int argc UNUSED_PARAM, char **argv) 145 932 { 146 933 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; 148 944 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; 153 949 unsigned opt; 154 950 int max_fd; 155 951 int retval; 156 int len;157 952 struct timeval tv; 158 struct in_addr temp_addr; 159 struct dhcpMessage packet; 953 struct dhcp_packet packet; 160 954 fd_set rfds; 161 955 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 184 957 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") 204 980 ; 205 981 #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;) 207 1016 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; 211 1019 212 1020 /* Parse command line */ 213 opt_complementary = "c--C:C--c" // mutually exclusive214 ":hH:Hh"; // -h and -H are the same215 #if ENABLE_GETOPT_LONG216 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" 217 1025 #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 222 1043 ); 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)) 234 1045 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); 235 1046 if (opt & OPT_F) { 1047 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ 236 1048 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 */ 243 1057 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 } 255 1061 if (opt & OPT_r) 256 1062 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 267 1112 if (opt & OPT_S) { 268 openlog(applet_name, LOG_PID, LOG_ LOCAL0);1113 openlog(applet_name, LOG_PID, LOG_DAEMON); 269 1114 logmode |= LOGMODE_SYSLOG; 270 1115 } 271 272 if (read_interface(client_config.interface, &client_config.ifindex,273 NULL, client_config.arp))274 return 1;275 1116 276 1117 /* Make sure fd 0,1,2 are open */ … … 278 1119 /* Equivalent of doing a fflush after every \n */ 279 1120 setlinebuf(stdout); 280 281 1121 /* Create pidfile */ 282 1122 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 */ 299 1126 udhcp_sp_setup(); 1127 /* We want random_xid to be random... */ 1128 srand(monotonic_us()); 300 1129 301 1130 state = INIT_SELECTING; 302 1131 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 */ 307 1141 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; 310 1157 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..."); 323 1163 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 } 330 1170 /* Else: an error occured, panic! */ 331 1171 bb_perror_msg_and_die("select"); 332 1172 } 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 335 1197 switch (state) { 336 1198 case INIT_SELECTING: 337 if (packet_num < client_config.retries) {1199 if (packet_num < discover_retries) { 338 1200 if (packet_num == 0) 339 1201 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; 345 1205 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; 346 1398 } 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; 359 1405 } 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; 468 1433 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 */ 471 1436 } 472 1437 } 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; 494 1443 temp_addr.s_addr = packet.yiaddr; 495 1444 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); 525 1446 } 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 */ 528 1468 } 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; 543 1482 } 1483 continue; 1484 /* case BOUND: - ignore all packets */ 1485 /* case RELEASED: - ignore all packets */ 544 1486 } 545 } /* for (;;) */ 1487 /* back to main loop */ 1488 } /* for (;;) - main loop ends */ 1489 546 1490 ret0: 547 1491 retval = 0; 548 1492 ret: 549 /*if (client_config.pidfile) - remove_pidfile has it 's own check */1493 /*if (client_config.pidfile) - remove_pidfile has its own check */ 550 1494 remove_pidfile(client_config.pidfile); 551 1495 return retval; -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.h
r1765 r2725 1 1 /* 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 5 7 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 8 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 14 9 15 10 struct 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) */ 23 16 const char *interface; /* The name of the interface to use */ 24 17 char *pidfile; /* Optionally store the process ID */ 25 18 const char *script; /* User script to run at dhcp events */ 19 struct option_set *options; /* list of DHCP options to send to server */ 26 20 uint8_t *clientid; /* Optional client id to use */ 27 21 uint8_t *vendorclass; /* Optional vendor class-id to use */ 28 22 uint8_t *hostname; /* Optional hostname to use */ 29 23 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; 35 25 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])) 37 28 29 #if ENABLE_FEATURE_UDHCP_PORT 30 #define CLIENT_PORT (client_config.port) 31 #else 32 #define CLIENT_PORT 68 33 #endif 38 34 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 35 POP_SAVED_FUNCTION_VISIBILITY 49 36 50 37 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* dhcpd.c 3 * 4 * udhcp Server 2 /* 3 * udhcp server 5 4 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au> 6 5 * Chris Trew <ctrew@moreton.com.au> … … 8 7 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 9 8 * 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. 11 22 */ 12 13 23 #include <syslog.h> 14 24 #include "common.h" 25 #include "dhcpc.h" 15 26 #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 */ 30 static 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 */ 67 static 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 76 static 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 84 static 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 */ 101 static 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 119 static 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 */ 136 static 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 */ 207 static 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 */ 218 static 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 */ 250 static 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 } 17 276 18 277 19 278 /* globals */ 20 struct d hcpOfferedAddr *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)279 struct dyn_lease *g_leases; 280 /* struct server_config_t server_config is in bb_common_bufsiz1 */ 281 282 283 int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 284 int udhcpd_main(int argc UNUSED_PARAM, char **argv) 26 285 { 27 286 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; 33 291 unsigned timeout_end; 34 292 unsigned num_ips; 35 293 unsigned opt; 36 294 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 ); 42 312 if (!(opt & 1)) { /* no -f */ 43 313 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; 47 318 if (opt & 2) { /* -S */ 48 openlog(applet_name, LOG_PID, LOG_ LOCAL0);319 openlog(applet_name, LOG_PID, LOG_DAEMON); 49 320 logmode |= LOGMODE_SYSLOG; 50 321 } 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 52 328 /* Would rather not do read_config before daemonization - 53 329 * otherwise NOMMU machines will parse config twice */ … … 61 337 /* Create pidfile */ 62 338 write_pidfile(server_config.pidfile); 63 /* if (!..) bb_perror_msg("can not 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; 69 345 if (option) { 70 m emcpy(&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); 72 348 } 73 349 … … 80 356 } 81 357 82 leases = xzalloc(server_config.max_leases * sizeof(*leases));358 g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0])); 83 359 read_leases(server_config.lease_file); 84 360 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 ) { 87 366 retval = 1; 88 367 goto ret; … … 94 373 timeout_end = monotonic_sec() + server_config.auto_time; 95 374 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 */ 96 380 97 381 if (server_socket < 0) { 98 server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,382 server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, 99 383 server_config.interface); 100 384 } … … 116 400 } 117 401 if (retval < 0 && errno != EINTR) { 118 DEBUG("error on select");402 log1("Error on select"); 119 403 continue; 120 404 } … … 122 406 switch (udhcp_sp_read(&rfds)) { 123 407 case SIGUSR1: 124 bb_info_msg("Received aSIGUSR1");408 bb_info_msg("Received SIGUSR1"); 125 409 write_leases(); 126 410 /* why not just reset the timeout, eh */ … … 128 412 continue; 129 413 case SIGTERM: 130 bb_info_msg("Received aSIGTERM");414 bb_info_msg("Received SIGTERM"); 131 415 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); 137 423 if (bytes < 0) { 424 /* bytes can also be -2 ("bad packet data") */ 138 425 if (bytes == -1 && errno != EINTR) { 139 DEBUG("error on read,%s, reopening socket", strerror(errno));426 log1("Read error: %s, reopening socket", strerror(errno)); 140 427 close(server_socket); 141 428 server_socket = -1; … … 143 430 continue; 144 431 } 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; 163 454 } 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); 165 472 } 166 473 167 474 switch (state[0]) { 475 168 476 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 486 o 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 500 o 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 538 o 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 554 o 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); 173 587 } 174 588 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; 233 612 } 234 613 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); 240 630 } 241 631 break; 242 case DHCPRELEASE: 243 DEBUG("Received RELEASE"); 244 if (lease) 245 lease->expires = time(0); 246 break; 632 247 633 case DHCPINFORM: 248 DEBUG("Received INFORM");634 log1("Received INFORM"); 249 635 send_inform(&packet); 250 636 break; 251 default:252 bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);253 637 } 254 638 } -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.h
r1765 r2725 1 1 /* 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 5 7 6 /************************************/ 7 /* Defaults _you_ may want to tweak */ 8 /************************************/ 8 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 9 9 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 */ 15 15 #define DHCPD_CONF_FILE "/etc/udhcpd.conf" 16 16 17 struct option_set {18 uint8_t *data;19 struct option_set *next;20 };21 17 22 18 struct static_lease { 23 19 struct static_lease *next; 24 uint 8_t *mac;25 uint 32_t *ip;20 uint32_t nip; 21 uint8_t mac[6]; 26 22 }; 27 23 28 24 struct 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 */ 30 39 /* 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) */ 41 45 uint32_t auto_time; /* how long should udhcpd wait before writing a config file. 42 46 * if this is zero, it will only write one on SIGUSR1 */ … … 45 49 uint32_t conflict_time; /* how long an arp conflict offender is leased for */ 46 50 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 */ 48 52 char *lease_file; 49 53 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 */ 52 55 char *sname; /* bootp server name */ 53 56 char *boot_file; /* bootp boot file option */ 54 57 struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */ 55 } ;58 } FIX_ALIASING; 56 59 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 59 68 60 69 61 /*** leases.h ***/ 70 typedef uint32_t leasetime_t; 71 typedef int32_t signed_leasetime_t; 62 72 63 struct dhcpOfferedAddr { 64 uint8_t chaddr[16]; 65 uint32_t yiaddr; /* network order */ 66 uint32_t expires; /* host order */ 67 }; 73 struct 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; 68 90 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); 91 extern struct dyn_lease *g_leases; 92 93 struct 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; 98 int is_expired_lease(struct dyn_lease *lease) FAST_FUNC; 99 struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC; 100 struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC; 101 uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC; 74 102 75 103 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 */ 106 void add_static_lease(struct static_lease **st_lease_pp, uint8_t *mac, uint32_t nip) FAST_FUNC; 107 /* Find static lease IP by mac */ 108 uint32_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 */ 110 int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) FAST_FUNC; 85 111 /* 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 113 void 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 87 117 88 118 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); 119 void read_config(const char *file) FAST_FUNC; 120 void write_leases(void) FAST_FUNC; 121 void read_leases(const char *file) FAST_FUNC; 95 122 96 123 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 124 POP_SAVED_FUNCTION_VISIBILITY 104 125 105 126 #endif -
branches/2.2.9/mindi-busybox/networking/udhcp/dhcprelay.c
r1765 r2725 2 2 /* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com> 3 3 * 4 * Licensed under GPL v2, see file LICENSE in this tarball for details.4 * Licensed under GPLv2, see file LICENSE in this source tree. 5 5 * 6 6 * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support … … 10 10 * Upstream has GPL v2 or later 11 11 */ 12 13 12 #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) 22 20 23 21 /* This list holds information about clients. The xid_* functions manipulate this list. */ 24 static struct xid_item { 22 struct xid_item { 23 unsigned timestamp; 24 int client; 25 25 uint32_t xid; 26 26 struct sockaddr_in ip; 27 int client;28 time_t timestamp;29 27 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) 32 31 33 32 static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client) … … 42 41 item->xid = xid; 43 42 item->client = client; 44 item->timestamp = time(NULL);43 item->timestamp = monotonic_sec(); 45 44 item->next = dhcprelay_xid_list.next; 46 45 dhcprelay_xid_list.next = item; … … 53 52 struct xid_item *item = dhcprelay_xid_list.next; 54 53 struct xid_item *last = &dhcprelay_xid_list; 55 time_t current_time = time(NULL);54 unsigned current_time = monotonic_sec(); 56 55 57 56 while (item != NULL) { … … 72 71 while (item != NULL) { 73 72 if (item->xid == xid) { 74 return item;73 break; 75 74 } 76 75 item = item->next; 77 76 } 78 return NULL;77 return item; 79 78 } 80 79 … … 100 99 * returns the message type on success, -1 otherwise 101 100 */ 102 static int get_dhcp_packet_type(struct dhcp Message*p)101 static int get_dhcp_packet_type(struct dhcp_packet *p) 103 102 { 104 103 uint8_t *op; … … 108 107 return -1; 109 108 /* get message type option */ 110 op = get_option(p, DHCP_MESSAGE_TYPE);109 op = udhcp_get_option(p, DHCP_MESSAGE_TYPE); 111 110 if (op != NULL) 112 111 return op[0]; … … 115 114 116 115 /** 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 130 117 * returns array 131 118 */ 132 static char ** get_client_devices(char *dev_list, int *client_number)133 { 134 char *s, * list, **client_dev;119 static char **make_iface_list(char **client_and_server_ifaces, int *client_number) 120 { 121 char *s, **iface_list; 135 122 int i, cn; 136 123 137 /* copy list */138 list = xstrdup(dev_list);139 if (list == NULL) return NULL;140 141 124 /* 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) { 143 128 if (*s == ',') 144 129 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 } 158 132 *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 */ 157 static 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 170 static 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 } 186 181 187 182 /** 188 * pass_ on() - forwards dhcp packets from client to server183 * pass_to_server() - forwards dhcp packets from client to server 189 184 * p - packet to send 190 185 * client - number of the client 191 186 */ 192 static void pass_ on(struct dhcpMessage*p, int packet_len, int client, int *fds,187 static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, 193 188 struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) 194 189 { 195 int res, type; 196 struct xid_item *item; 190 int type; 197 191 198 192 /* check packet_type */ … … 206 200 207 201 /* 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); 217 210 } 218 211 219 212 /** 220 * pass_ back() - forwards dhcp packets from server to client213 * pass_to_client() - forwards dhcp packets from server to client 221 214 * p - packet to send 222 215 */ 223 static void pass_ back(struct dhcpMessage*p, int packet_len, int *fds)224 { 225 int res,type;216 static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) 217 { 218 int type; 226 219 struct xid_item *item; 227 220 … … 238 231 } 239 232 233 //TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! 240 234 if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) 241 235 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 */ 249 239 } 250 240 … … 253 243 } 254 244 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) { 245 int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 246 int 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 267 285 FD_ZERO(&rfds); 268 286 for (i = 0; i < num_sockets; i++) … … 271 289 tv.tv_usec = 0; 272 290 if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) { 291 int packlen; 292 struct dhcp_packet dhcp_msg; 293 273 294 /* server */ 274 295 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]); 276 297 if (packlen > 0) { 277 pass_ back(&dhcp_msg, packlen, fds);298 pass_to_client(&dhcp_msg, packlen, fds); 278 299 } 279 300 } 301 302 /* clients */ 280 303 for (i = 1; i < num_sockets; i++) { 281 /* clients */ 304 struct sockaddr_in client_addr; 305 socklen_t addr_size; 306 282 307 if (!FD_ISSET(fds[i], &rfds)) 283 308 continue; 284 addr_size = sizeof(struct sockaddr_in); 309 310 addr_size = sizeof(client_addr); 285 311 packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, 286 312 (struct sockaddr *)(&client_addr), &addr_size); 287 313 if (packlen <= 0) 288 314 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); 292 361 } 293 362 } 294 363 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 5 5 * Loosely based on the isc-dhcpd implementation by dhankins@isc.org 6 6 * 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 14 19 15 20 #define NS_MAXDNAME 1025 /* max domain name length */ … … 20 25 21 26 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"; 23 28 * returns a newly allocated string containing the space-separated domains, 24 29 * prefixed with the contents of string pre, or NULL if an error occurs. 25 30 */ 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; 31 char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre) 32 { 33 char *ret = ret; /* for compiler */ 30 34 char *dst = NULL; 31 32 if (!cstr)33 return NULL;34 35 if (pre)36 plen = strlen(pre);37 35 38 36 /* We make two passes over the cstr string. First, we compute … … 43 41 * buffer, then having to check if it's sufficiently large, etc. 44 42 */ 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; 52 48 53 49 crtpos = retpos = depth = len = 0; 54 55 50 while (crtpos < clen) { 56 51 c = cstr + crtpos; 57 52 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 */ 60 56 return NULL; 61 if (retpos == 0) 57 if (retpos == 0) /* toplevel? save return spot */ 62 58 retpos = crtpos + 2; 63 59 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 */ 67 64 return NULL; 68 65 if (dst) 69 memcpy(dst + plen +len, c + 1, *c);66 memcpy(dst + len, c + 1, *c); 70 67 len += *c + 1; 71 68 crtpos += *c + 1; 72 69 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 */ 76 75 crtpos++; 77 } else { /* return to toplevel saved spot */ 76 } else { 77 /* return to toplevel saved spot */ 78 78 crtpos = retpos; 79 79 retpos = depth = 0; 80 80 } 81 81 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 ) { 87 88 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 */ 91 93 return NULL; 92 94 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; 98 108 } 99 109 … … 104 114 static uint8_t *convert_dname(const char *src) 105 115 { 106 uint8_t c, *res, *l p, *rp;116 uint8_t c, *res, *lenptr, *dst; 107 117 int len; 108 118 109 119 res = xmalloc(strlen(src) + 2); 110 rp = lp= res;111 rp++;120 dst = lenptr = res; 121 dst++; 112 122 113 123 for (;;) { 114 124 c = (uint8_t)*src++; 115 if (c == '.' || c == '\0') { 116 len = rp - lp- 1;125 if (c == '.' || c == '\0') { /* end of label */ 126 len = dst - lenptr - 1; 117 127 /* label too long, too short, or two '.'s in a row? abort */ 118 128 if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) { … … 120 130 return NULL; 121 131 } 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 */ 125 134 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 */ 135 144 free(res); 136 145 return NULL; 137 146 } 147 148 *dst = 0; 138 149 return res; 139 150 } 140 151 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 */ 143 153 static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname) 144 154 { 145 155 const uint8_t *c, *d; 146 int off , inc;156 int off; 147 157 148 158 /* find all labels in cstr */ … … 151 161 c = cstr + off; 152 162 153 if ((*c & NS_CMPRSFLGS) != 0) {/* pointer, skip */163 if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* pointer, skip */ 154 164 off += 2; 155 } else if (*c) { /* label, try matching dname */ 156 inc = *c + 1; 165 continue; 166 } 167 if (*c) { /* label, try matching dname */ 157 168 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 */ 160 174 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++; 170 185 } 171 186 … … 173 188 } 174 189 175 /* computes string to be appended to cstr so that src would be added to190 /* Computes string to be appended to cstr so that src would be added to 176 191 * 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 rfc3011format).192 * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format). 178 193 * The computed string is returned directly; its length is returned via retlen; 179 194 * NULL and 0, respectively, are returned if an error occurs. 180 195 */ 181 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)196 uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) 182 197 { 183 198 uint8_t *d, *dname; … … 190 205 } 191 206 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; 199 218 } 200 219 … … 203 222 } 204 223 205 #endif /* ENABLE_FEATURE_RFC3397 */ 224 #ifdef DNS_COMPR_TESTING 225 /* gcc -Wall -DDNS_COMPR_TESTING domain_codec.c -o domain_codec && ./domain_codec */ 226 int 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 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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. 4 4 */ 5 #include <getopt.h>6 7 5 #include "common.h" 8 6 #include "dhcpd.h" 7 #include "unicode.h" 9 8 10 int dumpleases_main(int argc, char **argv) ;11 int dumpleases_main(int argc , char **argv)9 int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 10 int dumpleases_main(int argc UNUSED_PARAM, char **argv) 12 11 { 13 12 int fd; 14 13 int i; 15 14 unsigned opt; 16 time_t expires;15 int64_t written_at, curr, expires_abs; 17 16 const char *file = LEASES_FILE; 18 struct d hcpOfferedAddrlease;17 struct dyn_lease lease; 19 18 struct in_addr addr; 20 19 21 20 enum { 22 OPT_a = 0x1,// -a23 OPT_r = 0x2,// -r24 OPT_f = 0x4,// -f21 OPT_a = 0x1, // -a 22 OPT_r = 0x2, // -r 23 OPT_f = 0x4, // -f 25 24 }; 26 #if ENABLE_ GETOPT_LONG25 #if ENABLE_LONG_OPTS 27 26 static const char dumpleases_longopts[] ALIGN1 = 28 27 "absolute\0" No_argument "a" … … 33 32 applet_long_options = dumpleases_longopts; 34 33 #endif 34 init_unicode(); 35 35 36 opt_complementary = "=0:a--r:r--a"; 36 37 opt = getopt32(argv, "arf:", &file); … … 38 39 fd = xopen(file, O_RDONLY); 39 40 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 42 51 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"; 46 56 } 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 } 50 74 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 } 63 87 } 64 88 /* close(fd); */ -
branches/2.2.9/mindi-busybox/networking/udhcp/files.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * files.c -- DHCP server file manipulation * 3 * DHCP server config and lease file manipulation 4 * 4 5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 5 8 */ 6 7 9 #include <netinet/ether.h> 8 10 9 11 #include "common.h" 10 12 #include "dhcpd.h" 11 #include "options.h"12 13 13 14 14 /* 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) 15 static int FAST_FUNC read_str(const char *line, void *arg) 41 16 { 42 17 char **dest = arg; … … 47 22 } 48 23 49 50 static int read_u32(const char *line, void *arg) 24 static int FAST_FUNC read_u32(const char *line, void *arg) 51 25 { 52 26 *(uint32_t*)arg = bb_strtou32(line, NULL, 10); … … 54 28 } 55 29 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) 30 static int FAST_FUNC read_staticlease(const char *const_line, void *arg) 251 31 { 252 32 char *line; 253 33 char *mac_string; 254 34 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; 261 37 262 38 /* Read mac */ 263 39 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; 266 43 267 44 /* 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); 274 52 275 53 return 1; … … 279 57 struct config_keyword { 280 58 const char *keyword; 281 int (*handler)(const char *line, void *var) ;59 int (*handler)(const char *line, void *var) FAST_FUNC; 282 60 void *var; 283 61 const char *def; … … 285 63 286 64 static 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"}, 293 69 /* Avoid "max_leases value not sane" warning by setting default 294 70 * 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, ""}, 310 87 }; 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); 88 enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; 89 90 void 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); 362 107 /* reset back to the default value */ 363 k eywords[i].handler(keywords[i].def, keywords[i].var);108 k->handler(k->def, k->var); 364 109 } 365 } 366 fclose(in); 110 break; 111 } 112 } 113 } 114 config_close(parser); 367 115 368 116 server_config.start_ip = ntohl(server_config.start_ip); 369 117 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 120 void FAST_FUNC write_leases(void) 121 { 122 int fd; 378 123 unsigned i; 379 time_t curr = time(0);380 unsigned long tmp_time;381 382 f p = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);383 if (f p < 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) 384 129 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)); 386 135 387 136 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); 407 158 408 159 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 168 void 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) 424 179 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); 432 194 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 ) { 437 205 bb_error_msg("too many leases while loading %s", file); 438 206 break; 439 207 } 208 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 440 209 i++; 210 #endif 441 211 } 442 212 } 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 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * leases.c -- tools to manage DHCP leases4 3 * Russ Dill <Russ.Dill@asu.edu> July 2001 4 * 5 * Licensed under GPLv2, see file LICENSE in this source tree. 5 6 */ 6 7 7 #include "common.h" 8 8 #include "dhcpd.h" 9 9 10 11 10 /* Find the oldest expired lease, NULL if there are no expired leases */ 12 static struct d hcpOfferedAddr*oldest_expired_lease(void)11 static struct dyn_lease *oldest_expired_lease(void) 13 12 { 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); 17 15 unsigned i; 18 16 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]; 23 23 } 24 return oldest; 24 } 25 return oldest_lease; 25 26 } 26 27 28 /* Clear out all leases with matching nonzero chaddr OR yiaddr. 29 * If chaddr == NULL, this is a conflict lease. 30 */ 31 static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr) 32 { 33 unsigned i; 27 34 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) 39 38 ) { 40 memset(& (leases[i]), 0, sizeof(leases[i]));39 memset(&g_leases[i], 0, sizeof(g_leases[i])); 41 40 } 41 } 42 42 } 43 43 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 */ 47 struct 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) 47 51 { 48 struct d hcpOfferedAddr*oldest;52 struct dyn_lease *oldest; 49 53 50 54 /* clean out any old ones */ 51 clear_lease (chaddr, yiaddr);55 clear_leases(chaddr, yiaddr); 52 56 53 57 oldest = oldest_expired_lease(); 54 58 55 59 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; 59 79 } 60 80 … … 62 82 } 63 83 64 65 /* true if a lease has expired */ 66 int lease_expired(struct dhcpOfferedAddr *lease) 84 /* True if a lease has expired */ 85 int FAST_FUNC is_expired_lease(struct dyn_lease *lease) 67 86 { 68 return (lease->expires < ( unsigned long) time(0));87 return (lease->expires < (leasetime_t) time(NULL)); 69 88 } 70 89 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 */ 91 struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac) 74 92 { 75 93 unsigned i; 76 94 77 95 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]; 80 98 81 99 return NULL; 82 100 } 83 101 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 */ 103 struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip) 87 104 { 88 105 unsigned i; 89 106 90 107 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]; 93 110 94 111 return NULL; 95 112 } 96 113 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 */ 115 static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) 100 116 { 101 static const uint8_t blank_chaddr[16]; /* 16 zero bytes */102 103 117 struct in_addr temp; 104 118 int r; 105 119 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); 107 124 if (r) 108 125 return r; 109 126 110 temp.s_addr = addr;127 temp.s_addr = nip; 111 128 bb_info_msg("%s belongs to someone, reserving it for %u seconds", 112 129 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); 114 131 return 0; 115 132 } 116 133 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 */ 135 uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) 121 136 { 122 uint32_t addr , ret;123 struct d hcpOfferedAddr *lease = NULL;137 uint32_t addr; 138 struct dyn_lease *oldest_lease = NULL; 124 139 125 140 addr = server_config.start_ip; /* addr is in host order here */ 126 141 for (; addr <= server_config.end_ip; addr++) { 142 uint32_t nip; 143 struct dyn_lease *lease; 144 127 145 /* ie, 192.168.55.0 */ 128 if ( !(addr & 0xFF))146 if ((addr & 0xff) == 0) 129 147 continue; 130 148 /* ie, 192.168.55.255 */ 131 if ((addr & 0x FF) == 0xFF)149 if ((addr & 0xff) == 0xff) 132 150 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; 144 164 } 145 165 } 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 146 174 return 0; 147 175 } -
branches/2.2.9/mindi-busybox/networking/udhcp/packet.c
r1765 r2725 1 1 /* 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 */ 3 9 #include <netinet/in.h> 4 10 #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> 7 13 #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> 11 17 #endif 12 18 13 19 #include "common.h" 14 20 #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 22 void 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 */ 21 26 switch (type) { 22 case DHCPDISCOVER:23 case DHCPREQUEST:24 case DHCPRELEASE:25 case DHCPINFORM:26 packet->op = BOOTREQUEST;27 break;28 27 case DHCPOFFER: 29 28 case DHCPACK: 30 29 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; 35 34 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 41 void 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 } 49 85 #endif 86 87 /* Read a packet from socket fd, return -1 on read error, -2 on packet error */ 88 int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) 89 { 50 90 int bytes; 51 91 unsigned char *vendor; 52 92 53 93 memset(packet, 0, sizeof(*packet)); 54 bytes = read(fd, packet, sizeof(*packet));94 bytes = safe_read(fd, packet, sizeof(*packet)); 55 95 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"); 62 102 return -2; 63 103 } 64 DEBUG("Received a packet"); 104 log1("Received a packet"); 105 udhcp_dump_packet(packet); 65 106 66 107 if (packet->op == BOOTREQUEST) { 67 vendor = get_option(packet, DHCP_VENDOR);108 vendor = udhcp_get_option(packet, DHCP_VENDOR); 68 109 if (vendor) { 69 110 #if 0 111 static const char broken_vendors[][8] = { 112 "MSFT 98", 113 "" 114 }; 70 115 int i; 71 116 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 74 119 ) { 75 DEBUG("broken client (%s), forcing broadcast",120 log1("Broken client (%s), forcing broadcast replies", 76 121 broken_vendors[i]); 77 122 packet->flags |= htons(BROADCAST_FLAG); … … 79 124 } 80 125 #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) 82 127 && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 83 128 ) { 84 DEBUG("broken client (%s), forcing broadcast", "MSFT 98");129 log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); 85 130 packet->flags |= htons(BROADCAST_FLAG); 86 131 } … … 92 137 } 93 138 94 95 uint16_t udhcp_checksum(void *addr, int count) 139 uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) 96 140 { 97 141 /* Compute Internet Checksum for "count" bytes 98 * 142 * beginning at location "addr". 99 143 */ 100 144 int32_t sum = 0; … … 112 156 * with little and big endian hosts */ 113 157 uint16_t tmp = 0; 114 *(uint8_t *) (&tmp) = * (uint8_t *)source;158 *(uint8_t*)&tmp = *(uint8_t*)source; 115 159 sum += tmp; 116 160 } … … 122 166 } 123 167 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 */ 169 int 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; 131 177 int fd; 132 int result; 133 struct sockaddr_ll dest; 134 struct udp_dhcp_packet packet; 178 int result = -1; 179 const char *msg; 135 180 136 181 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 137 182 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); 155 212 156 213 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; 159 216 packet.udp.source = htons(source_port); 160 217 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 */ 162 221 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); 167 225 packet.ip.ihl = sizeof(packet.ip) >> 2; 168 226 packet.ip.version = IPVERSION; 169 227 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: 180 235 close(fd); 236 if (result < 0) { 237 ret_msg: 238 bb_perror_msg(msg, "PACKET"); 239 } 181 240 return result; 182 241 } 183 242 184 185 243 /* 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; 244 int 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 { 191 248 struct sockaddr_in client; 249 unsigned padding; 250 int fd; 251 int result = -1; 252 const char *msg; 192 253 193 254 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 } 197 259 setsockopt_reuseaddr(fd); 198 260 … … 200 262 client.sin_family = AF_INET; 201 263 client.sin_port = htons(source_port); 202 client.sin_addr.s_addr = source_ip; 203 264 client.sin_addr.s_addr = source_nip; 204 265 if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 205 close(fd);206 return -1;266 msg = "bind(%s)"; 267 goto ret_close; 207 268 } 208 269 … … 210 271 client.sin_family = AF_INET; 211 272 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: 220 285 close(fd); 286 if (result < 0) { 287 ret_msg: 288 bb_perror_msg(msg, "UDP"); 289 } 221 290 return result; 222 291 } -
branches/2.2.9/mindi-busybox/networking/udhcp/signalpipe.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* signalpipe.c 3 * 2 /* 4 3 * Signal pipe infrastructure. A reliable way of delivering signals. 5 4 * … … 20 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 20 */ 22 23 21 #include "common.h" 24 22 25 26 static int signal_pipe[2];23 /* Global variable: we access it from signal handler */ 24 static struct fd_pair signal_pipe; 27 25 28 26 static void signal_handler(int sig) 29 27 { 30 28 unsigned char ch = sig; /* use char, avoid dealing with partial writes */ 31 if (write(signal_pipe [1], &ch, 1) != 1)32 bb_perror_msg("can not send signal");29 if (write(signal_pipe.wr, &ch, 1) != 1) 30 bb_perror_msg("can't send signal"); 33 31 } 34 35 32 36 33 /* Call this before doing anything else. Sets up the socket pair 37 34 * and installs the signal handler */ 38 void udhcp_sp_setup(void)35 void FAST_FUNC udhcp_sp_setup(void) 39 36 { 40 37 /* 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); 48 47 } 49 50 48 51 49 /* Quick little function to setup the rfds. Will return the 52 50 * max_fd for use with select. Limited in that you can only pass 53 51 * one extra fd */ 54 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)52 int FAST_FUNC udhcp_sp_fd_set(fd_set *rfds, int extra_fd) 55 53 { 56 54 FD_ZERO(rfds); 57 FD_SET(signal_pipe [0], rfds);55 FD_SET(signal_pipe.rd, rfds); 58 56 if (extra_fd >= 0) { 59 fcntl(extra_fd, F_SETFD, FD_CLOEXEC);57 close_on_exec_on(extra_fd); 60 58 FD_SET(extra_fd, rfds); 61 59 } 62 return signal_pipe [0] > extra_fd ? signal_pipe[0]: extra_fd;60 return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd; 63 61 } 64 65 62 66 63 /* Read a signal from the signal pipe. Returns 0 if there is 67 64 * no signal, -1 on error (and sets errno appropriately), and 68 65 * your signal on success */ 69 int udhcp_sp_read(fd_set *rfds)66 int FAST_FUNC udhcp_sp_read(const fd_set *rfds) 70 67 { 71 68 unsigned char sig; 72 69 73 if (!FD_ISSET(signal_pipe [0], rfds))70 if (!FD_ISSET(signal_pipe.rd, rfds)) 74 71 return 0; 75 72 76 if ( read(signal_pipe[0], &sig, 1) != 1)73 if (safe_read(signal_pipe.rd, &sig, 1) != 1) 77 74 return -1; 78 75 -
branches/2.2.9/mindi-busybox/networking/udhcp/socket.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * socket.c --DHCP server client/server socket creation3 * DHCP server client/server socket creation 4 4 * 5 5 * udhcp client/server … … 23 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 24 */ 25 26 25 #include <net/if.h> 27 #include <features.h>28 26 #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> 31 29 #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> 35 33 #endif 36 34 37 35 #include "common.h" 38 36 39 40 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) 37 int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) 41 38 { 42 39 int fd; … … 48 45 49 46 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) { 52 49 if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr, 53 50 "is interface %s up and configured?", interface) … … 57 54 } 58 55 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)); 61 58 } 62 59 … … 66 63 return -1; 67 64 } 68 DEBUG("adapter index %d", ifr.ifr_ifindex);65 log1("Adapter index %d", ifr.ifr_ifindex); 69 66 *ifindex = ifr.ifr_ifindex; 70 67 } 71 68 72 if ( arp) {69 if (mac) { 73 70 if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) { 74 71 close(fd); 75 72 return -1; 76 73 } 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]); 80 77 } 81 78 … … 86 83 /* 1. None of the callers expects it to ever fail */ 87 84 /* 2. ip was always INADDR_ANY */ 88 int listen_socket(/*uint32_t ip,*/ int port, const char *inf)85 int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) 89 86 { 90 87 int fd; 91 struct ifreq interface;92 88 struct sockaddr_in addr; 93 89 94 DEBUG("Opening listen socket on *:%d %s", port, inf);90 log1("Opening listen socket on *:%d %s", port, inf); 95 91 fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 96 92 … … 99 95 bb_perror_msg_and_die("SO_BROADCAST"); 100 96 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 */ 104 100 105 101 memset(&addr, 0, sizeof(addr)); -
branches/2.2.9/mindi-busybox/networking/udhcp/static_leases.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 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 5 4 * 6 5 * Wade Berrier <wberrier@myrealbox.com> September 2004 7 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 8 */ 9 10 9 #include "common.h" 11 10 #include "dhcpd.h" 12 11 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 */ 15 void 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; 13 20 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 */ 34 uint32_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 */ 46 int 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 */ 60 void FAST_FUNC log_static_leases(struct static_lease **st_lease_pp) 18 61 { 19 62 struct static_lease *cur; 20 struct static_lease *new_static_lease;21 63 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; 27 66 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; 52 68 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 ); 96 74 cur = cur->next; 97 75 } -
branches/2.2.9/mindi-busybox/networking/vconfig.c
r1765 r2725 5 5 * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 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. 8 8 */ 9 9 … … 48 48 }; 49 49 50 #define VLAN_GROUP_ARRAY_LEN 409651 #define SIOCSIFVLAN 0x8983/* Set 802.1Q VLAN options */50 #define VLAN_GROUP_ARRAY_LEN 4096 51 #define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ 52 52 53 /* On entry, table points to the length of the current string plus54 * nul terminator plus data length for the subsequent entry. The55 * 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. */ 56 56 static const char *xfind_str(const char *table, const char *str) 57 57 { 58 58 while (strcasecmp(str, table+1) != 0) { 59 if (!*(table += table[0])) { 59 table += table[0]; 60 if (!*table) { 60 61 bb_show_usage(); 61 62 } … … 107 108 static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config"; 108 109 109 int vconfig_main(int argc, char **argv) ;110 int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 110 111 int vconfig_main(int argc, char **argv) 111 112 { … … 122 123 xopen(conf_file_name, O_RDONLY); 123 124 124 memset(&ifr, 0, sizeof( struct vlan_ioctl_args));125 memset(&ifr, 0, sizeof(ifr)); 125 126 126 127 ++argv; … … 134 135 ifr.u.name_type = *xfind_str(name_types+1, argv[1]); 135 136 } 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]); 140 138 p = argv[2]; 141 139 -
branches/2.2.9/mindi-busybox/networking/wget.c
r1765 r2725 4 4 * 5 5 * Chip Rosenthal Covad Communications <chip@laserlink.net> 6 * Licensed under GPLv2, see file LICENSE in this source tree. 6 7 * 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. 7 10 */ 8 9 /* We want libc to give us xxx64 functions also */10 /* http://www.unix.org/version2/whatsnew/lfs20mar.html */11 //#define _LARGEFILE64_SOURCE 112 13 #include <getopt.h> /* for struct option */14 11 #include "libbb.h" 15 12 … … 17 14 // May be used if we ever will want to free() all xstrdup()s... 18 15 /* char *allocated; */ 19 c har *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; 24 21 }; 25 22 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 */ 25 struct globals { 26 off_t content_len; /* Content-length of the file */ 27 off_t beg_range; /* Range at which continue begins */ 34 28 #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) 40 struct 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! */ 49 enum { 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 64 enum { 65 PROGRESS_START = -1, 66 PROGRESS_END = 0, 67 PROGRESS_BUMP = 1, 68 }; 38 69 #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 }; 70 static 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 } 44 86 #else 45 static ALWAYS_INLINE void progressmeter(int flag) {} 46 #endif 87 static 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 */ 101 static 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 } 47 126 48 127 /* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, … … 55 134 do { 56 135 clearerr(stream); 136 errno = 0; 57 137 ret = fread(p, 1, nmemb, stream); 58 138 p += ret; … … 71 151 do { 72 152 clearerr(stream); 153 errno = 0; 73 154 ret = fgets(s, size, stream); 74 155 } while (ret == NULL && ferror(stream) && errno == EINTR); … … 89 170 #endif 90 171 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); 172 static 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 181 static 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 194 static 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 } 459 202 460 203 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 } 507 220 508 221 static void parse_url(char *src_url, struct host_info *h) … … 521 234 h->is_ftp = 1; 522 235 } 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)); 524 237 525 238 // FYI: … … 539 252 p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p; 540 253 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 = ""; 544 255 } else if (*sp == '/') { 545 256 *sp = '\0'; … … 549 260 // memmove converts to: 550 261 // 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); 552 263 h->host--; 553 264 sp[-1] = '\0'; … … 555 266 } 556 267 268 // We used to set h->user to NULL here, but this interferes 269 // with handling of code 302 ("object was moved") 270 557 271 sp = strrchr(h->host, '@'); 558 h->user = NULL;559 272 if (sp != NULL) { 560 273 h->user = h->host; … … 566 279 } 567 280 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) 281 static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) 584 282 { 585 283 char *s, *hdrval; 586 284 int c; 587 285 588 *istrunc = 0;286 /* *istrunc = 0; */ 589 287 590 288 /* retrieve header line */ … … 594 292 /* see if we are at the end of the headers */ 595 293 for (s = buf; *s == '\r'; ++s) 596 ;597 if ( s[0]== '\n')294 continue; 295 if (*s == '\n') 598 296 return NULL; 599 297 600 298 /* 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 } 603 303 604 304 /* verify we are at the end of the header name */ 605 305 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)); 607 307 608 308 /* 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); 612 311 613 312 /* locate the end of header */ 614 while (*s != '\0'&& *s != '\r' && *s != '\n')313 while (*s && *s != '\r' && *s != '\n') 615 314 ++s; 616 315 617 316 /* end of header found */ 618 if (*s != '\0') {317 if (*s) { 619 318 *s = '\0'; 620 319 return hdrval; 621 320 } 622 321 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 */ 624 323 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 330 static 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 367 static 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 447 static 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 529 int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 530 int 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" 625 578 ; 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 } 657 656 #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 /* 763 Response 204 doesn't say "null file", it says "metadata 764 has changed but data didn't": 765 766 "10.2.5 204 No Content 767 The server has fulfilled the request but does not need to return 768 an entity-body, and might want to return updated metainformation. 769 The response MAY include new or updated metainformation in the form 770 of entity-headers, which if present SHOULD be associated with 771 the requested variant. 772 773 If the client is a user agent, it SHOULD NOT change its document 774 view from that which caused the request to be sent. This response 775 is primarily intended to allow input for actions to take place 776 without causing a change to the user agent's active document view, 777 although any new or updated metainformation SHOULD be applied 778 to the document currently in the user agent's active view. 779 780 The 204 response MUST NOT include a message-body, and thus 781 is always terminated by the first empty line after the header fields." 782 783 However, 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 755 857 } 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 7 7 * Copyright (C) 2004 by David Brownell 8 8 * 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. 10 10 */ 11 11 … … 24 24 // - link status monitoring (restart on link-up; stop on link-down) 25 25 26 #include <syslog.h>27 #include <poll.h>28 #include <sys/wait.h>29 26 #include <netinet/ether.h> 30 27 #include <net/ethernet.h> … … 35 32 36 33 #include "libbb.h" 34 #include <syslog.h> 37 35 38 36 /* We don't need more than 32 bits of the counter */ … … 40 38 41 39 struct arp_packet { 42 struct ether_header hdr;40 struct ether_header eth; 43 41 struct ether_arp arp; 44 } ATTRIBUTE_PACKED;42 } PACKED; 45 43 46 44 enum { … … 70 68 }; 71 69 72 #define VDBG(fmt,args...) \ 73 do { } while (0) 70 #define VDBG(...) do { } while (0) 71 72 73 enum { 74 sock_fd = 3 75 }; 76 77 struct 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 74 85 75 86 /** … … 77 88 * the first and last 256 addresses are reserved. 78 89 */ 79 static void pick(struct in_addr *ip)90 static uint32_t pick(void) 80 91 { 81 92 unsigned tmp; … … 84 95 tmp = rand() & IN_CLASSB_HOST; 85 96 } while (tmp > (IN_CLASSB_HOST - 0x0200)); 86 ip->s_addr =htonl((LINKLOCAL_ADDR + 0x0100) + tmp);97 return htonl((LINKLOCAL_ADDR + 0x0100) + tmp); 87 98 } 88 99 … … 90 101 * Broadcast an ARP packet. 91 102 */ 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) 103 static void arp( 104 /* int op, - always ARPOP_REQUEST */ 105 /* const struct ether_addr *source_eth, - always ð_addr */ 106 struct in_addr source_ip, 107 const struct ether_addr *target_eth, struct in_addr target_ip) 95 108 { 109 enum { op = ARPOP_REQUEST }; 110 #define source_eth (ð_addr) 111 96 112 struct arp_packet p; 97 113 memset(&p, 0, sizeof(p)); 98 114 99 115 // 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); 103 119 104 120 // arp request … … 108 124 p.arp.arp_pln = 4; 109 125 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); 111 127 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); 113 129 memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa)); 114 130 115 131 // 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 121 140 } 122 141 123 142 /** 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 */ 146 static int run(char *argv[3], const char *param, struct in_addr *ip) 127 147 { 128 148 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]); 131 155 132 156 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; 136 160 } 137 138 status = wait4pid(spawn(argv)); 161 bb_info_msg(fmt, argv[2], argv[0], addr); 162 163 status = spawn_and_wait(argv + 1); 139 164 if (status < 0) { 140 bb_perror_msg("%s %s ", argv[1], intf);165 bb_perror_msg("%s %s %s" + 3, argv[2], argv[0]); 141 166 return -errno; 142 167 } 143 168 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); 145 170 return status; 146 171 } … … 149 174 * Return milliseconds of random delay, up to "secs" seconds. 150 175 */ 151 static unsigned ALWAYS_INLINE ms_rdelay(unsigned secs)176 static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs) 152 177 { 153 178 return rand() % (secs * 1000); … … 157 182 * main program 158 183 */ 159 int zcip_main(int argc, char **argv) ;160 int zcip_main(int argc , char **argv)184 int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 185 int zcip_main(int argc UNUSED_PARAM, char **argv) 161 186 { 162 int state = PROBE; 163 struct ether_addr eth_addr; 164 const char *why; 165 int fd; 187 int state; 166 188 char *r_opt; 167 189 unsigned opts; 168 190 169 / * Ugly trick, but I want these zeroed in one go */191 // ugly trick, but I want these zeroed in one go 170 192 struct { 171 193 const struct in_addr null_ip; 172 194 const struct ether_addr null_addr; 173 struct sockaddr saddr;174 195 struct in_addr ip; 175 196 struct ifreq ifr; 176 char *intf;177 char *script_av[3];178 197 int timeout_ms; /* must be signed */ 179 198 unsigned conflicts; … … 185 204 #define null_ip (L.null_ip ) 186 205 #define null_addr (L.null_addr ) 187 #define saddr (L.saddr )188 206 #define ip (L.ip ) 189 207 #define ifr (L.ifr ) 190 #define intf (L.intf )191 #define script_av (L.script_av )192 208 #define timeout_ms (L.timeout_ms) 193 209 #define conflicts (L.conflicts ) … … 205 221 opt_complementary = "=2:vv:vf"; 206 222 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); 207 232 if (!FOREGROUND) { 208 / * Do it early, before all bb_xx_msg calls */233 // do it before all bb_xx_msg calls 209 234 openlog(applet_name, 0, LOG_DAEMON); 210 235 logmode |= LOGMODE_SYSLOG; … … 217 242 } 218 243 } 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); 230 254 231 255 // 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)) 234 257 return EXIT_FAILURE; 235 258 236 259 // initialize saddr 260 // saddr is: { u16 sa_family; u8 sa_data[14]; } 237 261 //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 242 265 // bind to the interface's ARP socket 243 xbind( fd, &saddr, sizeof(saddr));266 xbind(sock_fd, &saddr, sizeof(saddr)); 244 267 245 268 // get the interface's ethernet address 246 269 //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); 249 272 memcpy(ð_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 250 273 251 274 // start with some stable ip address, either a function of 252 275 // 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. 253 278 // NOTE: the sequence of addresses we try changes only 254 279 // 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 *)ð_addr + 2)); 283 srand(t); 284 } 256 285 if (ip.s_addr == 0) 257 pick(&ip);286 ip.s_addr = pick(); 258 287 259 288 // FIXME cases to handle: … … 264 293 if (!FOREGROUND) { 265 294 #if BB_MMU 266 bb_daemonize( DAEMON_CHDIR_ROOT);295 bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); 267 296 #endif 268 bb_info_msg("start, interface %s", intf);297 bb_info_msg("start, interface %s", argv_intf); 269 298 } 270 299 … … 273 302 // - start with some address we want to try 274 303 // - short random delay 275 // - arp probes to see if another host elseuses it304 // - arp probes to see if another host uses it 276 305 // - arp announcements that we're claiming it 277 306 // - use it 278 307 // - 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; 279 316 while (1) { 280 317 struct pollfd fds[1]; 281 318 unsigned deadline_us; 282 319 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; 288 324 fds[0].events = POLLIN; 289 325 fds[0].revents = 0; … … 291 327 // poll, being ready to adjust current timeout 292 328 if (!timeout_ms) { 293 timeout_ms = ms_rdelay(PROBE_WAIT);294 // FIXME setsockopt( fd, SO_ATTACH_FILTER, ...) to329 timeout_ms = random_delay_ms(PROBE_WAIT); 330 // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to 295 331 // make the kernel filter out all packets except 296 332 // ones we'd care about. … … 300 336 301 337 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; 304 345 305 346 // timeout … … 313 354 nprobes++; 314 355 VDBG("probe/%u %s@%s\n", 315 nprobes, intf, inet_ntoa(ip));316 arp( fd, &saddr, ARPOP_REQUEST,317 ð_addr,null_ip,356 nprobes, argv_intf, inet_ntoa(ip)); 357 arp(/* ARPOP_REQUEST, */ 358 /* ð_addr, */ null_ip, 318 359 &null_addr, ip); 319 360 timeout_ms = PROBE_MIN * 1000; 320 timeout_ms += ms_rdelay(PROBE_MAX - PROBE_MIN);361 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); 321 362 } 322 363 else { … … 325 366 nclaims = 0; 326 367 VDBG("announce/%u %s@%s\n", 327 nclaims, intf, inet_ntoa(ip));328 arp( fd, &saddr, ARPOP_REQUEST,329 ð_addr,ip,368 nclaims, argv_intf, inet_ntoa(ip)); 369 arp(/* ARPOP_REQUEST, */ 370 /* ð_addr, */ ip, 330 371 ð_addr, ip); 331 372 timeout_ms = ANNOUNCE_INTERVAL * 1000; … … 338 379 nclaims = 0; 339 380 VDBG("announce/%u %s@%s\n", 340 nclaims, intf, inet_ntoa(ip));341 arp( fd, &saddr, ARPOP_REQUEST,342 ð_addr,ip,381 nclaims, argv_intf, inet_ntoa(ip)); 382 arp(/* ARPOP_REQUEST, */ 383 /* ð_addr, */ ip, 343 384 ð_addr, ip); 344 385 timeout_ms = ANNOUNCE_INTERVAL * 1000; … … 350 391 nclaims++; 351 392 VDBG("announce/%u %s@%s\n", 352 nclaims, intf, inet_ntoa(ip));353 arp( fd, &saddr, ARPOP_REQUEST,354 ð_addr,ip,393 nclaims, argv_intf, inet_ntoa(ip)); 394 arp(/* ARPOP_REQUEST, */ 395 /* ð_addr, */ ip, 355 396 ð_addr, ip); 356 397 timeout_ms = ANNOUNCE_INTERVAL * 1000; … … 361 402 // link is ok to use earlier 362 403 // FIXME update filters 363 script_av[1] = (char*)"config"; 364 run(script_av, intf, &ip); 404 run(argv, "config", &ip); 365 405 ready = 1; 366 406 conflicts = 0; … … 382 422 // Invalid, should never happen. Restart the whole protocol. 383 423 state = PROBE; 384 pick(&ip);424 ip.s_addr = pick(); 385 425 timeout_ms = 0; 386 426 nprobes = 0; … … 389 429 } // switch (state) 390 430 break; // case 0 (timeout) 391 // packets arriving 431 432 // packets arriving, or link went down 392 433 case 1: 393 434 // We need to adjust the timeout in case we didn't receive … … 402 443 } else { 403 444 VDBG("adjusting timeout\n"); 404 timeout_ms = diff / 1000; 405 if (!timeout_ms) timeout_ms = 1; 445 timeout_ms = (diff / 1000) | 1; /* never 0 */ 406 446 } 407 447 } … … 411 451 // FIXME: links routinely go down; 412 452 // this shouldn't necessarily exit. 413 bb_error_msg(" %s: poll error",intf);453 bb_error_msg("iface %s is down", argv_intf); 414 454 if (ready) { 415 script_av[1] = (char*)"deconfig"; 416 run(script_av, intf, &ip); 455 run(argv, "deconfig", &ip); 417 456 } 418 457 return EXIT_FAILURE; … … 422 461 423 462 // 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); 427 465 } 428 if (p. hdr.ether_type != htons(ETHERTYPE_ARP))466 if (p.eth.ether_type != htons(ETHERTYPE_ARP)) 429 467 continue; 430 431 468 #ifdef DEBUG 432 469 { 433 struct ether_addr * 434 struct ether_addr * 435 struct in_addr * 436 struct in_addr * 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; 437 474 VDBG("%s recv arp type=%d, op=%d,\n", 438 intf, ntohs(p.hdr.ether_type),475 argv_intf, ntohs(p.eth.ether_type), 439 476 ntohs(p.arp.arp_op)); 440 477 VDBG("\tsource=%s %s\n", … … 447 484 #endif 448 485 if (p.arp.arp_op != htons(ARPOP_REQUEST) 449 486 && p.arp.arp_op != htons(ARPOP_REPLY)) 450 487 continue; 451 488 452 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 453 memcmp(ð_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, ð_addr, ETH_ALEN) != 0 494 ) { 454 495 source_ip_conflict = 1; 455 496 } 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(ð_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, ð_addr, ETH_ALEN) != 0 500 ) { 459 501 target_ip_conflict = 1; 460 502 } … … 470 512 conflicts++; 471 513 if (conflicts >= MAX_CONFLICTS) { 472 VDBG("%s ratelimit\n", intf);514 VDBG("%s ratelimit\n", argv_intf); 473 515 timeout_ms = RATE_LIMIT_INTERVAL * 1000; 474 516 state = RATE_LIMIT_PROBE; … … 476 518 477 519 // restart the whole protocol 478 pick(&ip);520 ip.s_addr = pick(); 479 521 timeout_ms = 0; 480 522 nprobes = 0; … … 488 530 state = DEFEND; 489 531 timeout_ms = DEFEND_INTERVAL * 1000; 490 arp(fd, &saddr, 491 ARPOP_REQUEST, 492 ð_addr, ip, 493 ð_addr, ip); 532 arp(/* ARPOP_REQUEST, */ 533 /* ð_addr, */ ip, 534 ð_addr, ip); 494 535 } 495 536 break; … … 500 541 VDBG("defend conflict -- starting over\n"); 501 542 ready = 0; 502 script_av[1] = (char*)"deconfig"; 503 run(script_av, intf, &ip); 543 run(argv, "deconfig", &ip); 504 544 505 545 // restart the whole protocol 506 pick(&ip);546 ip.s_addr = pick(); 507 547 timeout_ms = 0; 508 548 nprobes = 0; … … 514 554 VDBG("invalid state -- starting over\n"); 515 555 state = PROBE; 516 pick(&ip);556 ip.s_addr = pick(); 517 557 timeout_ms = 0; 518 558 nprobes = 0; … … 520 560 break; 521 561 } // switch state 522 523 562 break; // case 1 (packets arriving) 524 default:525 why = "poll";526 goto bad;527 563 } // switch poll 528 } 529 bad: 530 bb_perror_msg("%s, %s", intf, why); 531 return EXIT_FAILURE; 564 } // while (1) 565 #undef argv_intf 532 566 }
Note:
See TracChangeset
for help on using the changeset viewer.