Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/networking
- Timestamp:
- Nov 4, 2007, 3:16:40 AM (16 years ago)
- Location:
- branches/2.2.5/mindi-busybox/networking
- Files:
-
- 14 added
- 27 deleted
- 66 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.5/mindi-busybox/networking/Config.in
r821 r1765 6 6 menu "Networking Utilities" 7 7 8 config CONFIG_FEATURE_IPV68 config FEATURE_IPV6 9 9 bool "Enable IPv6 support" 10 10 default n … … 13 13 This adds IPv6 support in the networking applets. 14 14 15 config CONFIG_ARPING 15 config VERBOSE_RESOLUTION_ERRORS 16 bool "Verbose resolution errors" 17 default n 18 help 19 Enable if you are not satisfied with simplistic 20 "can't resolve 'hostname.com'" and want to know more. 21 This may increase size of your executable a bit. 22 23 config ARP 24 bool "arp" 25 default n 26 help 27 Manipulate the system ARP cache. 28 29 config ARPING 16 30 bool "arping" 17 31 default n 18 32 help 19 Ping hosts by ARP packets 20 21 config CONFIG_DNSD33 Ping hosts by ARP packets. 34 35 config DNSD 22 36 bool "dnsd" 23 37 default n 24 38 help 25 Small and static DNS server daemon. 26 27 config CONFIG_ETHER_WAKE39 Small and static DNS server daemon. 40 41 config ETHER_WAKE 28 42 bool "ether-wake" 29 43 default n … … 31 45 Send a magic packet to wake up sleeping machines. 32 46 33 config CONFIG_FAKEIDENTD47 config FAKEIDENTD 34 48 bool "fakeidentd" 35 49 default n 50 select FEATURE_SYSLOG 36 51 help 37 52 fakeidentd listens on the ident port and returns a predefined 38 53 fake value on any query. 39 54 40 config CONFIG_FTPGET55 config FTPGET 41 56 bool "ftpget" 42 57 default n … … 44 59 Retrieve a remote file via FTP. 45 60 46 config CONFIG_FTPPUT61 config FTPPUT 47 62 bool "ftpput" 48 63 default n … … 50 65 Store a remote file via FTP. 51 66 52 config CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS67 config FEATURE_FTPGETPUT_LONG_OPTIONS 53 68 bool "Enable long options in ftpget/ftpput" 54 69 default n 55 depends on CONFIG_GETOPT_LONG && (CONFIG_FTPGET || CONFIG_FTPPUT)70 depends on GETOPT_LONG && (FTPGET || FTPPUT) 56 71 help 57 72 Support long options for the ftpget/ftpput applet. 58 73 59 config CONFIG_HOSTNAME74 config HOSTNAME 60 75 bool "hostname" 61 76 default n 62 77 help 63 Show or set the system's host name 64 65 config CONFIG_HTTPD78 Show or set the system's host name. 79 80 config HTTPD 66 81 bool "httpd" 67 82 default n … … 69 84 Serve web pages via an HTTP server. 70 85 71 config CONFIG_FEATURE_HTTPD_WITHOUT_INETD72 bool " Support using httpd as a daemon (not from inetd)"73 default n 74 depends on CONFIG_HTTPD75 help 76 This option enables uid and port options for the httpd applet,77 and eliminates the need to be called from the inetd server daemon.78 79 config CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP86 config FEATURE_HTTPD_USE_SENDFILE 87 bool "Use sendfile system call" 88 default n 89 depends on HTTPD 90 help 91 When enabled, httpd will use the kernel sendfile() function 92 instead of read/write loop. 93 94 config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 80 95 bool "Support reloading the global config file using hup signal" 81 96 default n 82 depends on CONFIG_HTTPD && CONFIG_FEATURE_HTTPD_WITHOUT_INETD97 depends on HTTPD 83 98 help 84 99 This option enables processing of SIGHUP to reload cached 85 100 configuration settings. 86 101 87 config CONFIG_FEATURE_HTTPD_SETUID88 bool "Enable support-u <user> option"89 default n 90 depends on CONFIG_HTTPD && CONFIG_FEATURE_HTTPD_WITHOUT_INETD102 config FEATURE_HTTPD_SETUID 103 bool "Enable -u <user> option" 104 default n 105 depends on HTTPD 91 106 help 92 107 This option allows the server to run as a specific user … … 95 110 different user. 96 111 97 config CONFIG_FEATURE_HTTPD_BASIC_AUTH112 config FEATURE_HTTPD_BASIC_AUTH 98 113 bool "Enable Basic http Authentication" 99 114 default y 100 depends on CONFIG_HTTPD115 depends on HTTPD 101 116 help 102 117 Utilizes password settings from /etc/httpd.conf for basic 103 118 authentication on a per url basis. 104 119 105 config CONFIG_FEATURE_HTTPD_AUTH_MD5120 config FEATURE_HTTPD_AUTH_MD5 106 121 bool "Support MD5 crypted passwords for http Authentication" 107 122 default n 108 depends on CONFIG_FEATURE_HTTPD_BASIC_AUTH123 depends on FEATURE_HTTPD_BASIC_AUTH 109 124 help 110 125 Enables basic per URL authentication from /etc/httpd.conf 111 126 using md5 passwords. 112 127 113 config CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES128 config FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 114 129 bool "Support loading additional MIME types at run-time" 115 130 default n 116 depends on CONFIG_HTTPD131 depends on HTTPD 117 132 help 118 133 This option enables support for additional MIME types at 119 134 run-time to be specified in the configuration file. 120 135 121 config CONFIG_FEATURE_HTTPD_CGI136 config FEATURE_HTTPD_CGI 122 137 bool "Support Common Gateway Interface (CGI)" 123 138 default y 124 depends on CONFIG_HTTPD139 depends on HTTPD 125 140 help 126 141 This option allows scripts and executables to be invoked 127 142 when specific URLs are requested. 128 143 129 config CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR144 config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 130 145 bool "Enable support for running scripts through an interpreter" 131 146 default n 132 depends on CONFIG_FEATURE_HTTPD_CGI133 help 134 This option enables support for running scripts through an 135 interpreter. Turn this on if you want PHP scripts to work 136 properly. You need to supply an addition line in your httpd147 depends on FEATURE_HTTPD_CGI 148 help 149 This option enables support for running scripts through an 150 interpreter. Turn this on if you want PHP scripts to work 151 properly. You need to supply an additional line in your httpd 137 152 config file: 138 153 *.php:/path/to/your/php 139 154 140 config CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV155 config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 141 156 bool "Support the REMOTE_PORT environment variable for CGI" 142 157 default n 143 depends on CONFIG_FEATURE_HTTPD_CGI158 depends on FEATURE_HTTPD_CGI 144 159 help 145 160 Use of this option can assist scripts in generating 146 161 references that contain a unique port number. 147 162 148 config CONFIG_FEATURE_HTTPD_ENCODE_URL_STR163 config FEATURE_HTTPD_ENCODE_URL_STR 149 164 bool "Enable the -e option for shell script CGI simplification." 150 165 default y 151 depends on CONFIG_HTTPD166 depends on HTTPD 152 167 help 153 168 This option allows html encoding arbitrary … … 156 171 "<Hello World>". 157 172 158 config CONFIG_IFCONFIG 173 config FEATURE_HTTPD_ERROR_PAGES 174 bool "Enable support for custom error pages" 175 default n 176 depends on HTTPD 177 help 178 This option allows you to define custom error pages in 179 the configuration file instead of the default HTTP status 180 error pages. For instance, if you add the line: 181 E404:/path/e404.html 182 in the config file, the server will respond the specified 183 '/path/e404.html' file instead of the terse '404 NOT FOUND' 184 message. 185 186 config IFCONFIG 159 187 bool "ifconfig" 160 188 default n … … 162 190 Ifconfig is used to configure the kernel-resident network interfaces. 163 191 164 config CONFIG_FEATURE_IFCONFIG_STATUS192 config FEATURE_IFCONFIG_STATUS 165 193 bool "Enable status reporting output (+7k)" 166 194 default y 167 depends on CONFIG_IFCONFIG195 depends on IFCONFIG 168 196 help 169 197 If ifconfig is called with no arguments it will display the status 170 198 of the currently active interfaces. 171 199 172 config CONFIG_FEATURE_IFCONFIG_SLIP200 config FEATURE_IFCONFIG_SLIP 173 201 bool "Enable slip-specific options \"keepalive\" and \"outfill\"" 174 202 default n 175 depends on CONFIG_IFCONFIG203 depends on IFCONFIG 176 204 help 177 205 Allow "keepalive" and "outfill" support for SLIP. If you're not 178 206 planning on using serial lines, leave this unchecked. 179 207 180 config CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ208 config FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 181 209 bool "Enable options \"mem_start\", \"io_addr\", and \"irq\"" 182 210 default n 183 depends on CONFIG_IFCONFIG211 depends on IFCONFIG 184 212 help 185 213 Allow the start address for shared memory, start address for I/O, 186 214 and/or the interrupt line used by the specified device. 187 215 188 config CONFIG_FEATURE_IFCONFIG_HW216 config FEATURE_IFCONFIG_HW 189 217 bool "Enable option \"hw\" (ether only)" 190 218 default y 191 depends on CONFIG_IFCONFIG219 depends on IFCONFIG 192 220 help 193 221 Set the hardware address of this interface, if the device driver … … 195 223 class. 196 224 197 config CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS225 config FEATURE_IFCONFIG_BROADCAST_PLUS 198 226 bool "Set the broadcast automatically" 199 227 default n 200 depends on CONFIG_IFCONFIG228 depends on IFCONFIG 201 229 help 202 230 Setting this will make ifconfig attempt to find the broadcast 203 231 automatically if the value '+' is used. 204 232 205 config CONFIG_IFUPDOWN233 config IFUPDOWN 206 234 bool "ifupdown" 207 235 default n 208 select CONFIG_RUN_PARTS209 236 help 210 237 Activate or deactivate the specified interfaces. This applet makes 211 238 use of either "ifconfig" and "route" or the "ip" command to actually 212 239 configure network interfaces. Therefore, you will probably also want 213 to enable either CONFIG_IFCONFIG and CONFIG_ROUTE, or enable214 CONFIG_FEATURE_IFUPDOWN_IP and the various CONFIG_IP options. Of240 to enable either IFCONFIG and ROUTE, or enable 241 FEATURE_IFUPDOWN_IP and the various IP options. Of 215 242 course you could use non-busybox versions of these programs, so 216 243 against my better judgement (since this will surely result in plenty 217 244 of support questions on the mailing list), I do not force you to 218 245 enable these additional options. It is up to you to supply either 219 "ifconfig" and "route" or the "ip" command, either via busybox or via 220 standalone utilities. 221 222 config CONFIG_FEATURE_IFUPDOWN_IP 246 "ifconfig", "route" and "run-parts" or the "ip" command, either 247 via busybox or via standalone utilities. 248 249 config IFUPDOWN_IFSTATE_PATH 250 string "Absolute path to ifstate file" 251 default "/var/run/ifstate" 252 help 253 ifupdown keeps state information in a file called ifstate. 254 Typically it is located in /var/run/ifstate, however 255 some distributions tend to put it in other places 256 (debian, for example, uses /etc/network/run/ifstate). 257 This config option defines location of ifstate. 258 259 config FEATURE_IFUPDOWN_IP 223 260 bool "Use ip applet" 224 261 default n 225 depends on CONFIG_IFUPDOWN262 depends on IFUPDOWN 226 263 help 227 264 Use the iproute "ip" command to implement "ifup" and "ifdown", rather 228 265 than the default of using the older 'ifconfig' and 'route' utilities. 229 266 230 config CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN267 config FEATURE_IFUPDOWN_IP_BUILTIN 231 268 bool "Use busybox ip applet" 232 269 default y 233 depends on CONFIG_FEATURE_IFUPDOWN_IP234 select CONFIG_IP235 select CONFIG_FEATURE_IP_ADDRESS236 select CONFIG_FEATURE_IP_LINK237 select CONFIG_FEATURE_IP_ROUTE270 depends on FEATURE_IFUPDOWN_IP 271 select IP 272 select FEATURE_IP_ADDRESS 273 select FEATURE_IP_LINK 274 select FEATURE_IP_ROUTE 238 275 help 239 276 Use the busybox iproute "ip" applet to implement "ifupdown". 240 277 241 If le ave thisdisabled, you must install the full-blown iproute2278 If left disabled, you must install the full-blown iproute2 242 279 utility or the "ifup" and "ifdown" applets will not work. 243 280 244 config CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN281 config FEATURE_IFUPDOWN_IFCONFIG_BUILTIN 245 282 bool "Use busybox ifconfig and route applets" 246 283 default y 247 depends on CONFIG_IFUPDOWN && !CONFIG_FEATURE_IFUPDOWN_IP248 select CONFIG_IFCONFIG249 select CONFIG_ROUTE284 depends on IFUPDOWN && !FEATURE_IFUPDOWN_IP 285 select IFCONFIG 286 select ROUTE 250 287 help 251 288 Use the busybox iproute "ifconfig" and "route" applets to 252 289 implement the "ifup" and "ifdown" utilities. 253 290 254 If le ave thisdisabled, you must install the full-blown ifconfig291 If left disabled, you must install the full-blown ifconfig 255 292 and route utilities, or the "ifup" and "ifdown" applets will not 256 293 work. 257 294 258 config CONFIG_FEATURE_IFUPDOWN_IPV4295 config FEATURE_IFUPDOWN_IPV4 259 296 bool "Enable support for IPv4" 260 297 default y 261 depends on CONFIG_IFUPDOWN262 help 263 If you want busyboxto talk IPv4, leave this on.264 265 config CONFIG_FEATURE_IFUPDOWN_IPV6298 depends on IFUPDOWN 299 help 300 If you want ifup/ifdown to talk IPv4, leave this on. 301 302 config FEATURE_IFUPDOWN_IPV6 266 303 bool "Enable support for IPv6" 267 304 default n 268 depends on CONFIG_IFUPDOWN && CONFIG_FEATURE_IPV6305 depends on IFUPDOWN && FEATURE_IPV6 269 306 help 270 307 If you need support for IPv6, turn this option on. 271 308 272 config CONFIG_FEATURE_IFUPDOWN_IPX 273 bool "Enable support for IPX" 274 default n 275 depends on CONFIG_IFUPDOWN 276 help 277 If this option is selected you can use busybox to work with IPX 278 networks. 279 280 config CONFIG_FEATURE_IFUPDOWN_MAPPING 309 ### UNUSED 310 ### config FEATURE_IFUPDOWN_IPX 311 ### bool "Enable support for IPX" 312 ### default n 313 ### depends on IFUPDOWN 314 ### help 315 ### If this option is selected you can use busybox to work with IPX 316 ### networks. 317 318 config FEATURE_IFUPDOWN_MAPPING 281 319 bool "Enable mapping support" 282 320 default n 283 depends on CONFIG_IFUPDOWN321 depends on IFUPDOWN 284 322 help 285 323 This enables support for the "mapping" stanza, unless you have 286 324 a weird network setup you don't need it. 287 325 288 config CONFIG_INETD 326 config FEATURE_IFUPDOWN_EXTERNAL_DHCP 327 bool "Enable support for external dhcp clients" 328 default n 329 depends on IFUPDOWN 330 help 331 This enables support for the external dhcp clients. Clients are 332 tried in the following order: dhcpcd, dhclient, pump and udhcpc. 333 Otherwise, if udhcpc applet is enabled, it is used. 334 Otherwise, ifup/ifdown will have no support for DHCP. 335 336 config INETD 289 337 bool "inetd" 290 338 default n 339 select FEATURE_SYSLOG 291 340 help 292 341 Internet superserver daemon 293 342 294 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO343 config FEATURE_INETD_SUPPORT_BUILTIN_ECHO 295 344 bool "Support echo service" 296 345 default y 297 depends on CONFIG_INETD346 depends on INETD 298 347 help 299 348 Echo received data internal inetd service 300 349 301 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD350 config FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 302 351 bool "Support discard service" 303 352 default y 304 depends on CONFIG_INETD353 depends on INETD 305 354 help 306 355 Internet /dev/null internal inetd service 307 356 308 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME357 config FEATURE_INETD_SUPPORT_BUILTIN_TIME 309 358 bool "Support time service" 310 359 default y 311 depends on CONFIG_INETD360 depends on INETD 312 361 help 313 362 Return 32 bit time since 1900 internal inetd service 314 363 315 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME364 config FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 316 365 bool "Support daytime service" 317 366 default y 318 depends on CONFIG_INETD367 depends on INETD 319 368 help 320 369 Return human-readable time internal inetd service 321 370 322 config CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN371 config FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 323 372 bool "Support chargen service" 324 373 default y 325 depends on CONFIG_INETD374 depends on INETD 326 375 help 327 376 Familiar character generator internal inetd service 328 377 329 config CONFIG_FEATURE_INETD_RPC378 config FEATURE_INETD_RPC 330 379 bool "Support RPC services" 331 380 default n 332 depends on CONFIG_INETD333 help334 Suuport Sun-RPC based services335 336 337 config CONFIG_IP381 depends on INETD 382 select FEATURE_HAVE_RPC 383 help 384 Support Sun-RPC based services 385 386 config IP 338 387 bool "ip" 339 388 default n … … 343 392 TCP/IP. 344 393 345 config CONFIG_FEATURE_IP_ADDRESS394 config FEATURE_IP_ADDRESS 346 395 bool "ip address" 347 396 default y 348 depends on CONFIG_IP397 depends on IP 349 398 help 350 399 Address manipulation support for the "ip" applet. 351 400 352 config CONFIG_FEATURE_IP_LINK401 config FEATURE_IP_LINK 353 402 bool "ip link" 354 403 default y 355 depends on CONFIG_IP404 depends on IP 356 405 help 357 406 Configure network devices with "ip". 358 407 359 config CONFIG_FEATURE_IP_ROUTE408 config FEATURE_IP_ROUTE 360 409 bool "ip route" 361 410 default y 362 depends on CONFIG_IP411 depends on IP 363 412 help 364 413 Add support for routing table management to "ip". 365 414 366 config CONFIG_FEATURE_IP_TUNNEL415 config FEATURE_IP_TUNNEL 367 416 bool "ip tunnel" 368 417 default n 369 depends on CONFIG_IP418 depends on IP 370 419 help 371 420 Add support for tunneling commands to "ip". 372 421 373 config CONFIG_FEATURE_IP_SHORT_FORMS 422 config FEATURE_IP_RULE 423 bool "ip rule" 424 default n 425 depends on IP 426 help 427 Add support for rule commands to "ip". 428 429 config FEATURE_IP_SHORT_FORMS 374 430 bool "Support short forms of ip commands." 375 431 default n 376 depends on CONFIG_IP432 depends on IP 377 433 help 378 434 Also support short-form of ip <OBJECT> commands: … … 381 437 ip route -> iproute 382 438 ip tunnel -> iptunnel 439 ip rule -> iprule 383 440 384 441 Say N unless you desparately need the short form of the ip 385 442 object commands. 386 443 387 config CONFIG_IPADDR444 config IPADDR 388 445 bool 389 446 default y 390 depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_ADDRESS391 392 config CONFIG_IPLINK447 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_ADDRESS 448 449 config IPLINK 393 450 bool 394 451 default y 395 depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_LINK396 397 config CONFIG_IPROUTE452 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_LINK 453 454 config IPROUTE 398 455 bool 399 456 default y 400 depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_ROUTE401 402 config CONFIG_IPTUNNEL457 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_ROUTE 458 459 config IPTUNNEL 403 460 bool 404 461 default y 405 depends on CONFIG_FEATURE_IP_SHORT_FORMS && CONFIG_FEATURE_IP_TUNNEL 406 407 config CONFIG_IPCALC 462 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_TUNNEL 463 464 config IPRULE 465 bool 466 default y 467 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_RULE 468 469 config IPCALC 408 470 bool "ipcalc" 409 471 default n … … 412 474 resulting broadcast, network, and host range. 413 475 414 config CONFIG_FEATURE_IPCALC_FANCY476 config FEATURE_IPCALC_FANCY 415 477 bool "Fancy IPCALC, more options, adds 1 kbyte" 416 478 default y 417 depends on CONFIG_IPCALC479 depends on IPCALC 418 480 help 419 481 Adds the options hostname, prefix and silent to the output of "ipcalc". 420 482 421 config CONFIG_FEATURE_IPCALC_LONG_OPTIONS483 config FEATURE_IPCALC_LONG_OPTIONS 422 484 bool "Enable long options" 423 485 default n 424 depends on CONFIG_IPCALC && CONFIG_GETOPT_LONG486 depends on IPCALC && GETOPT_LONG 425 487 help 426 488 Support long options for the ipcalc applet. 427 489 428 config CONFIG_NAMEIF490 config NAMEIF 429 491 bool "nameif" 430 492 default n 493 select FEATURE_SYSLOG 431 494 help 432 495 nameif is used to rename network interface by its MAC address. … … 440 503 new_interface_name XX:XX:XX:XX:XX:XX 441 504 442 config CONFIG_NC505 config NC 443 506 bool "nc" 444 507 default n … … 447 510 connections. 448 511 449 config CONFIG_NC_GAPING_SECURITY_HOLE 450 bool "gaping security hole" 451 default n 452 depends on CONFIG_NC 453 help 454 Add support for executing a program after making or receiving a 455 successful connection (-e option). 456 457 config CONFIG_NETSTAT 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). 527 528 config NETSTAT 458 529 bool "netstat" 459 530 default n … … 461 532 netstat prints information about the Linux networking subsystem. 462 533 463 config CONFIG_NSLOOKUP 534 config FEATURE_NETSTAT_WIDE 535 bool " Enable wide netstat output" 536 default n 537 depends on NETSTAT 538 help 539 Add support for wide columns. Useful when displaying IPv6 addresses 540 (-W option). 541 542 config NSLOOKUP 464 543 bool "nslookup" 465 544 default n … … 467 546 nslookup is a tool to query Internet name servers. 468 547 469 config CONFIG_PING548 config PING 470 549 bool "ping" 471 550 default n … … 474 553 elicit an ICMP ECHO_RESPONSE from a host or gateway. 475 554 476 config CONFIG_FEATURE_FANCY_PING 555 config PING6 556 bool "ping6" 557 default n 558 depends on FEATURE_IPV6 && PING 559 help 560 This will give you a ping that can talk IPv6. 561 562 config PSCAN 563 bool "pscan" 564 default n 565 help 566 Simple network port scanner. 567 568 config FEATURE_FANCY_PING 477 569 bool "Enable fancy ping output" 478 570 default y 479 depends on CONFIG_PING571 depends on PING 480 572 help 481 573 Make the output from the ping applet include statistics, and at the 482 574 same time provide full support for ICMP packets. 483 575 484 config CONFIG_PING6 485 bool "ping6" 486 default n 487 depends on CONFIG_FEATURE_IPV6 488 help 489 This will give you a ping that can talk IPv6. 490 491 config CONFIG_FEATURE_FANCY_PING6 492 bool "Enable fancy ping6 output" 493 default y 494 depends on CONFIG_PING6 495 help 496 Make the output from the ping6 applet include statistics, and at the 497 same time provide full support for ICMP packets. 498 499 config CONFIG_ROUTE 576 config ROUTE 500 577 bool "route" 501 578 default n … … 503 580 Route displays or manipulates the kernel's IP routing tables. 504 581 505 config CONFIG_TELNET 582 config SLATTACH 583 bool "slattach" 584 default n 585 help 586 slattach is a small utility to attach network interfaces to serial lines. 587 588 config TELNET 506 589 bool "telnet" 507 590 default n … … 510 593 used to test other simple protocols. 511 594 512 config CONFIG_FEATURE_TELNET_TTYPE595 config FEATURE_TELNET_TTYPE 513 596 bool "Pass TERM type to remote host" 514 597 default y 515 depends on CONFIG_TELNET598 depends on TELNET 516 599 help 517 600 Setting this option will forward the TERM environment variable to the … … 519 602 things like ANSI colors and other control sequences behave. 520 603 521 config CONFIG_FEATURE_TELNET_AUTOLOGIN604 config FEATURE_TELNET_AUTOLOGIN 522 605 bool "Pass USER type to remote host" 523 606 default y 524 depends on CONFIG_TELNET607 depends on TELNET 525 608 help 526 609 Setting this option will forward the USER environment variable to the … … 529 612 option enables `-a' and `-l USER' arguments. 530 613 531 config CONFIG_TELNETD614 config TELNETD 532 615 bool "telnetd" 533 616 default n 617 select FEATURE_SYSLOG 534 618 help 535 619 A daemon for the TELNET protocol, allowing you to log onto the host … … 543 627 Note that for busybox telnetd to work you need several things: 544 628 First of all, your kernel needs: 545 CONFIG_UNIX98_PTYS=y546 CONFIG_DEVPTS_FS=y629 UNIX98_PTYS=y 630 DEVPTS_FS=y 547 631 548 632 Next, you need a /dev/pts directory on your root filesystem: … … 561 645 mount -t devpts devpts /dev/pts 562 646 563 You need to be sure that Busybox has CONFIG_LOGIN and564 CONFIG_FEATURE_SUID enabled. And finally, you should make647 You need to be sure that Busybox has LOGIN and 648 FEATURE_SUID enabled. And finally, you should make 565 649 certain that Busybox has been installed setuid root: 566 650 … … 571 655 572 656 573 config CONFIG_FEATURE_TELNETD_INETD 574 bool "Support call from inetd only" 575 default n 576 depends on CONFIG_TELNETD 577 help 578 Selecting this will make telnetd only callable from inetd, 579 removing the standalone support. 580 581 config CONFIG_TFTP 657 config FEATURE_TELNETD_STANDALONE 658 bool "Support standalone telnetd (not inetd only)" 659 default n 660 depends on TELNETD 661 help 662 Selecting this will make telnetd able to run standalone. 663 664 config TFTP 582 665 bool "tftp" 583 666 default n … … 587 670 for a network-enabled bootloader. 588 671 589 config CONFIG_FEATURE_TFTP_GET672 config FEATURE_TFTP_GET 590 673 bool "Enable \"get\" command" 591 674 default y 592 depends on CONFIG_TFTP675 depends on TFTP 593 676 help 594 677 Add support for the GET command within the TFTP client. This allows 595 678 a client to retrieve a file from a TFTP server. 596 679 597 config CONFIG_FEATURE_TFTP_PUT680 config FEATURE_TFTP_PUT 598 681 bool "Enable \"put\" command" 599 682 default y 600 depends on CONFIG_TFTP683 depends on TFTP 601 684 help 602 685 Add support for the PUT command within the TFTP client. This allows 603 686 a client to transfer a file to a TFTP server. 604 687 605 config CONFIG_FEATURE_TFTP_BLOCKSIZE688 config FEATURE_TFTP_BLOCKSIZE 606 689 bool "Enable \"blocksize\" command" 607 690 default n 608 depends on CONFIG_TFTP691 depends on TFTP 609 692 help 610 693 Allow the client to specify the desired block size for transfers. 611 694 612 config CONFIG_DEBUG_TFTP695 config DEBUG_TFTP 613 696 bool "Enable debug" 614 697 default n 615 depends on CONFIG_TFTP698 depends on TFTP 616 699 help 617 700 Enable debug settings for tftp. This is useful if you're running … … 619 702 you run into problems. 620 703 621 config CONFIG_TRACEROUTE704 config TRACEROUTE 622 705 bool "traceroute" 623 706 default n … … 625 708 Utility to trace the route of IP packets 626 709 627 config CONFIG_FEATURE_TRACEROUTE_VERBOSE710 config FEATURE_TRACEROUTE_VERBOSE 628 711 bool "Enable verbose output" 629 712 default n 630 depends on CONFIG_TRACEROUTE713 depends on TRACEROUTE 631 714 help 632 715 Add some verbosity to traceroute. This includes amongst other things 633 716 hostnames and ICMP response types. 634 717 635 config CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE718 config FEATURE_TRACEROUTE_SOURCE_ROUTE 636 719 bool "Enable loose source route" 637 720 default n 638 depends on CONFIG_TRACEROUTE721 depends on TRACEROUTE 639 722 help 640 723 Add option to specify a loose source route gateway 641 724 (8 maximum). 642 725 643 config CONFIG_FEATURE_TRACEROUTE_USE_ICMP726 config FEATURE_TRACEROUTE_USE_ICMP 644 727 bool "Use ICMP instead of UDP" 645 728 default n 646 depends on CONFIG_TRACEROUTE729 depends on TRACEROUTE 647 730 help 648 731 Add feature to allow for ICMP ECHO instead of UDP datagrams. … … 650 733 source networking/udhcp/Config.in 651 734 652 config CONFIG_VCONFIG735 config VCONFIG 653 736 bool "vconfig" 654 737 default n … … 656 739 Creates, removes, and configures VLAN interfaces 657 740 658 config CONFIG_WGET741 config WGET 659 742 bool "wget" 660 743 default n … … 663 746 HTTPS, and FTP servers. 664 747 665 config CONFIG_FEATURE_WGET_STATUSBAR748 config FEATURE_WGET_STATUSBAR 666 749 bool "Enable a nifty process meter (+2k)" 667 750 default y 668 depends on CONFIG_WGET751 depends on WGET 669 752 help 670 753 Enable the transfer progress bar for wget transfers. 671 754 672 config CONFIG_FEATURE_WGET_AUTHENTICATION755 config FEATURE_WGET_AUTHENTICATION 673 756 bool "Enable HTTP authentication" 674 757 default y 675 depends on CONFIG_WGET758 depends on WGET 676 759 help 677 760 Support authenticated HTTP transfers. 678 761 679 config CONFIG_FEATURE_WGET_IP6_LITERAL 680 bool "Enable IPv6 literal addresses" 681 default y 682 depends on CONFIG_WGET && CONFIG_FEATURE_IPV6 683 help 684 Support IPv6 address literal notation in URLs. 685 686 config CONFIG_FEATURE_WGET_LONG_OPTIONS 762 config FEATURE_WGET_LONG_OPTIONS 687 763 bool "Enable long options" 688 764 default n 689 depends on CONFIG_WGET && CONFIG_GETOPT_LONG765 depends on WGET && GETOPT_LONG 690 766 help 691 767 Support long options for the wget applet. 692 768 693 config CONFIG_ZCIP769 config ZCIP 694 770 bool "zcip" 695 771 default n 772 select FEATURE_SYSLOG 696 773 help 697 774 ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. -
branches/2.2.5/mindi-busybox/networking/arping.c
r821 r1765 9 9 */ 10 10 11 #include <sys/ioctl.h>12 #include <signal.h>13 14 #include <errno.h>15 #include <stdlib.h>16 #include <string.h>17 #include <unistd.h>18 19 11 #include <arpa/inet.h> 20 12 #include <net/if.h> … … 22 14 #include <netpacket/packet.h> 23 15 24 #include "busybox.h" 16 #include "libbb.h" 17 18 /* We don't expect to see 1000+ seconds delay, unsigned is enough */ 19 #define MONOTONIC_US() ((unsigned)monotonic_us()) 25 20 26 21 static struct in_addr src; … … 28 23 static struct sockaddr_ll me; 29 24 static struct sockaddr_ll he; 30 static struct timevallast;31 32 enum cfg_e{33 dad= 1,34 unsolicited= 2,35 advert= 4,36 quiet= 8,37 quit_on_reply= 16,38 broadcast_only= 32,39 unicasting= 6425 static unsigned last; 26 27 enum { 28 DAD = 1, 29 UNSOLICITED = 2, 30 ADVERT = 4, 31 QUIET = 8, 32 QUIT_ON_REPLY = 16, 33 BCAST_ONLY = 32, 34 UNICASTING = 64 40 35 }; 41 static int cfg; 42 43 static int s; 44 static int count = -1; 45 static int timeout; 46 static int sent; 47 static int brd_sent; 48 static int received; 49 static int brd_recv; 50 static int req_recv; 51 52 53 #define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \ 54 ((tv1).tv_usec-(tv2).tv_usec)/1000 ) 55 #if 0 56 static void set_signal(int signo, void (*handler) (void)) 57 { 58 struct sigaction sa; 59 60 memset(&sa, 0, sizeof(sa)); 61 sa.sa_handler = (void (*)(int)) handler; 62 sa.sa_flags = SA_RESTART; 63 sigaction(signo, &sa, NULL); 64 } 65 #endif 66 67 static int send_pack(int sock, struct in_addr *src_addr, 68 struct in_addr *dst_addr, struct sockaddr_ll *ME, 69 struct sockaddr_ll *HE) 36 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; 45 46 static int send_pack(struct in_addr *src_addr, 47 struct in_addr *dst_addr, struct sockaddr_ll *ME, 48 struct sockaddr_ll *HE) 70 49 { 71 50 int err; 72 struct timevalnow;73 RESERVE_CONFIG_UBUFFER(buf, 256);51 unsigned now; 52 unsigned char buf[256]; 74 53 struct arphdr *ah = (struct arphdr *) buf; 75 54 unsigned char *p = (unsigned char *) (ah + 1); … … 80 59 ah->ar_hln = ME->sll_halen; 81 60 ah->ar_pln = 4; 82 ah->ar_op = cfg&advert? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);61 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); 83 62 84 63 memcpy(p, &ME->sll_addr, ah->ar_hln); … … 88 67 p += 4; 89 68 90 if ( cfg&advert)69 if (option_mask32 & ADVERT) 91 70 memcpy(p, &ME->sll_addr, ah->ar_hln); 92 71 else … … 97 76 p += 4; 98 77 99 gettimeofday(&now, NULL);78 now = MONOTONIC_US(); 100 79 err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); 101 80 if (err == p - buf) { 102 81 last = now; 103 82 sent++; 104 if (!( cfg&unicasting))83 if (!(option_mask32 & UNICASTING)) 105 84 brd_sent++; 106 85 } 107 RELEASE_CONFIG_BUFFER(buf);108 86 return err; 109 87 } 110 88 89 static void finish(void) ATTRIBUTE_NORETURN; 111 90 static void finish(void) 112 91 { 113 if (!(cfg&quiet)) { 114 printf("Sent %d probes (%d broadcast(s))\n" 115 "Received %d repl%s", 92 if (!(option_mask32 & QUIET)) { 93 printf("Sent %u probe(s) (%u broadcast(s))\n" 94 "Received %u repl%s" 95 " (%u request(s), %u broadcast(s))\n", 116 96 sent, brd_sent, 117 received, (received > 1) ? "ies" : "y"); 118 if (brd_recv || req_recv) { 119 printf(" ("); 120 if (req_recv) 121 printf("%d request(s)", req_recv); 122 if (brd_recv) 123 printf("%s%d broadcast(s)", req_recv ? ", " : "", brd_recv); 124 putchar(')'); 125 } 126 putchar('\n'); 127 fflush(stdout); 128 } 129 if (cfg&dad) 97 received, (received == 1) ? "ies" : "y", 98 req_recv, brd_recv); 99 } 100 if (option_mask32 & DAD) 130 101 exit(!!received); 131 if ( cfg&unsolicited)102 if (option_mask32 & UNSOLICITED) 132 103 exit(0); 133 104 exit(!received); … … 136 107 static void catcher(void) 137 108 { 138 struct timeval tv; 139 static struct timeval start; 140 141 gettimeofday(&tv, NULL); 142 143 if (start.tv_sec == 0) 144 start = tv; 145 146 if (count-- == 0 147 || (timeout && MS_TDIFF(tv, start) > timeout * 1000 + 500)) 109 static unsigned start; 110 111 unsigned now; 112 113 now = MONOTONIC_US(); 114 if (start == 0) 115 start = now; 116 117 if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000))) 148 118 finish(); 149 119 150 if (last.tv_sec == 0 || MS_TDIFF(tv, last) > 500) { 151 send_pack(s, &src, &dst, &me, &he); 152 if (count == 0 && cfg&unsolicited) 120 count--; 121 122 if (last == 0 || (now - last) > 500000) { 123 send_pack(&src, &dst, &me, &he); 124 if (count == 0 && (option_mask32 & UNSOLICITED)) 153 125 finish(); 154 126 } … … 163 135 164 136 /* Filter out wild packets */ 165 if (FROM->sll_pkttype != PACKET_HOST &&166 FROM->sll_pkttype != PACKET_BROADCAST &&167 137 if (FROM->sll_pkttype != PACKET_HOST 138 && FROM->sll_pkttype != PACKET_BROADCAST 139 && FROM->sll_pkttype != PACKET_MULTICAST) 168 140 return 0; 169 141 … … 173 145 174 146 /* ARPHRD check and this darned FDDI hack here :-( */ 175 if (ah->ar_hrd != htons(FROM->sll_hatype) && 176 (FROM->sll_hatype != ARPHRD_FDDI 177 || ah->ar_hrd != htons(ARPHRD_ETHER))) 147 if (ah->ar_hrd != htons(FROM->sll_hatype) 148 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) 178 149 return 0; 179 150 … … 189 160 memcpy(&src_ip, p + ah->ar_hln, 4); 190 161 memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); 191 if (!( cfg&dad)) {162 if (!(option_mask32 & DAD)) { 192 163 if (src_ip.s_addr != dst.s_addr) 193 164 return 0; … … 217 188 return 0; 218 189 } 219 if (!( cfg&quiet)) {190 if (!(option_mask32 & QUIET)) { 220 191 int s_printed = 0; 221 struct timeval tv; 222 223 gettimeofday(&tv, NULL); 224 225 printf("%s %s from %s [%s]", 226 FROM->sll_pkttype == PACKET_HOST ? "Unicast" : "Broadcast", 227 ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request", 192 193 printf("%scast re%s from %s [%s]", 194 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 195 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 228 196 inet_ntoa(src_ip), 229 197 ether_ntoa((struct ether_addr *) p)); … … 236 204 printf("for "); 237 205 printf("[%s]", 238 ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); 239 } 240 241 if (last.tv_sec) { 242 long usecs = (tv.tv_sec - last.tv_sec) * 1000000 + 243 tv.tv_usec - last.tv_usec; 244 long msecs = (usecs + 500) / 1000; 245 246 usecs -= msecs * 1000 - 500; 247 printf(" %ld.%03ldms\n", msecs, usecs); 206 ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); 207 } 208 209 if (last) { 210 printf(" %u.%03ums\n", last / 1000, last % 1000); 248 211 } else { 249 212 printf(" UNSOLICITED?\n"); … … 256 219 if (ah->ar_op == htons(ARPOP_REQUEST)) 257 220 req_recv++; 258 if ( cfg&quit_on_reply)221 if (option_mask32 & QUIT_ON_REPLY) 259 222 finish(); 260 if (!( cfg&broadcast_only)) {223 if (!(option_mask32 & BCAST_ONLY)) { 261 224 memcpy(he.sll_addr, p, me.sll_halen); 262 cfg |= unicasting;225 option_mask32 |= UNICASTING; 263 226 } 264 227 return 1; 265 228 } 266 229 230 int arping_main(int argc, char **argv); 267 231 int arping_main(int argc, char **argv) 268 232 { 269 c har *device = "eth0";233 const char *device = "eth0"; 270 234 int ifindex; 271 235 char *source = NULL; 272 236 char *target; 273 274 s = socket(PF_PACKET, SOCK_DGRAM, 0); 275 ifindex = errno;237 unsigned char *packet; 238 239 sock = xsocket(PF_PACKET, SOCK_DGRAM, 0); 276 240 277 241 // Drop suid root privileges … … 279 243 280 244 { 281 unsigned longopt;282 char * _count, *_timeout, *_device;245 unsigned opt; 246 char *str_count, *str_timeout; 283 247 284 248 /* Dad also sets quit_on_reply. 285 249 * Advert also sets unsolicited. 286 250 */ 287 bb_opt_complementally = "Df:AU"; 288 opt = bb_getopt_ulflags(argc, argv, "DUAqfbc:w:i:s:", 289 &_count, &_timeout, &_device); 290 cfg |= opt & 63; /* set respective flags */ 291 if (opt & 64) /* count */ 292 count = atoi(_count); 293 if (opt & 128) /* timeout */ 294 timeout = atoi(_timeout); 295 if (opt & 256) { /* interface */ 296 if (strlen(_device) > IF_NAMESIZE) { 297 bb_error_msg_and_die("Interface name `%s' must be less than %d", 298 _device, IF_NAMESIZE); 299 } 300 device = _device; 301 } 302 if (opt & 512) /* source */ 303 source = optarg; 304 } 305 argc -= optind; 306 argv += optind; 307 308 if (argc != 1) 309 bb_show_usage(); 310 311 target = *argv; 312 313 314 if (s < 0) { 315 bb_default_error_retval = ifindex; 316 bb_perror_msg_and_die("socket"); 317 } 318 bb_default_error_retval = 2; 251 opt_complementary = "=1:Df:AU"; 252 opt = getopt32(argv, "DUAqfbc:w:I:s:", 253 &str_count, &str_timeout, &device, &source); 254 if (opt & 0x40) /* -c: count */ 255 count = xatou(str_count); 256 if (opt & 0x80) /* -w: timeout */ 257 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000; 258 //if (opt & 0x100) /* -I: interface */ 259 if (strlen(device) >= IF_NAMESIZE) { 260 bb_error_msg_and_die("interface name '%s' is too long", 261 device); 262 } 263 //if (opt & 0x200) /* -s: source */ 264 option_mask32 &= 0x3f; /* set respective flags */ 265 } 266 267 target = argv[optind]; 268 269 xfunc_error_retval = 2; 319 270 320 271 { … … 323 274 memset(&ifr, 0, sizeof(ifr)); 324 275 strncpy(ifr.ifr_name, device, IFNAMSIZ - 1); 325 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { 326 bb_error_msg_and_die("Interface %s not found", device); 327 } 276 ioctl_or_perror_and_die(sock, SIOCGIFINDEX, &ifr, "interface %s not found", device); 328 277 ifindex = ifr.ifr_ifindex; 329 278 330 if (ioctl(s, SIOCGIFFLAGS, (char *) &ifr)) { 331 bb_error_msg_and_die("SIOCGIFFLAGS"); 332 } 279 xioctl(sock, SIOCGIFFLAGS, (char *) &ifr); 280 333 281 if (!(ifr.ifr_flags & IFF_UP)) { 334 bb_error_msg_and_die(" Interface %s is down", device);282 bb_error_msg_and_die("interface %s is down", device); 335 283 } 336 284 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { 337 bb_error_msg(" Interface %s is not ARPable", device);338 exit(cfg&dad? 0 : 2);285 bb_error_msg("interface %s is not ARPable", device); 286 return (option_mask32 & DAD ? 0 : 2); 339 287 } 340 288 } 341 289 342 290 if (!inet_aton(target, &dst)) { 343 struct hostent *hp; 344 345 hp = gethostbyname2(target, AF_INET); 346 if (!hp) { 347 bb_error_msg_and_die("invalid or unknown target %s", target); 348 } 349 memcpy(&dst, hp->h_addr, 4); 291 len_and_sockaddr *lsa; 292 lsa = xhost_and_af2sockaddr(target, 0, AF_INET); 293 memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4); 294 if (ENABLE_FEATURE_CLEAN_UP) 295 free(lsa); 350 296 } 351 297 … … 354 300 } 355 301 356 if (!( cfg&dad) && cfg&unsolicited&& src.s_addr == 0)302 if (!(option_mask32 & DAD) && (option_mask32 & UNSOLICITED) && src.s_addr == 0) 357 303 src = dst; 358 304 359 if (!( cfg&dad) || src.s_addr) {305 if (!(option_mask32 & DAD) || src.s_addr) { 360 306 struct sockaddr_in saddr; 361 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0); /* maybe use bb_xsocket? */ 362 363 if (probe_fd < 0) { 364 bb_error_msg_and_die("socket"); 365 } 307 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 308 366 309 if (device) { 367 if (setsockopt 368 (probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, 369 strlen(device) + 1) == -1) 370 bb_error_msg("WARNING: interface %s is ignored", device); 310 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) 311 bb_error_msg("warning: interface %s is ignored", device); 371 312 } 372 313 memset(&saddr, 0, sizeof(saddr)); … … 374 315 if (src.s_addr) { 375 316 saddr.sin_addr = src; 376 if (bind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) { 377 bb_error_msg_and_die("bind"); 378 } 379 } else if (!(cfg&dad)) { 380 int on = 1; 317 xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 318 } else if (!(option_mask32 & DAD)) { 381 319 socklen_t alen = sizeof(saddr); 382 320 … … 384 322 saddr.sin_addr = dst; 385 323 386 if (setsockopt 387 (probe_fd, SOL_SOCKET, SO_DONTROUTE, (char *) &on, 388 sizeof(on)) == -1) 389 bb_perror_msg("WARNING: setsockopt(SO_DONTROUTE)"); 390 if (connect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)) 391 == -1) { 392 bb_error_msg_and_die("connect"); 393 } 394 if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == 395 -1) { 324 if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) 325 bb_perror_msg("warning: setsockopt(SO_DONTROUTE)"); 326 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 327 if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { 396 328 bb_error_msg_and_die("getsockname"); 397 329 } … … 399 331 } 400 332 close(probe_fd); 401 } ;333 } 402 334 403 335 me.sll_family = AF_PACKET; 404 336 me.sll_ifindex = ifindex; 405 337 me.sll_protocol = htons(ETH_P_ARP); 406 if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) { 407 bb_error_msg_and_die("bind"); 408 } 338 xbind(sock, (struct sockaddr *) &me, sizeof(me)); 409 339 410 340 { 411 341 socklen_t alen = sizeof(me); 412 342 413 if (getsockname(s , (struct sockaddr *) &me, &alen) == -1) {343 if (getsockname(sock, (struct sockaddr *) &me, &alen) == -1) { 414 344 bb_error_msg_and_die("getsockname"); 415 345 } 416 346 } 417 347 if (me.sll_halen == 0) { 418 bb_error_msg(" Interface \"%s\" is not ARPable (no ll address)", device);419 exit(cfg&dad? 0 : 2);348 bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device); 349 return (option_mask32 & DAD ? 0 : 2); 420 350 } 421 351 he = me; 422 352 memset(he.sll_addr, -1, he.sll_halen); 423 353 424 if (!( cfg&quiet)) {354 if (!(option_mask32 & QUIET)) { 425 355 printf("ARPING to %s from %s via %s\n", 426 356 inet_ntoa(dst), inet_ntoa(src), … … 428 358 } 429 359 430 if (!src.s_addr && !( cfg&dad)) {360 if (!src.s_addr && !(option_mask32 & DAD)) { 431 361 bb_error_msg_and_die("no src address in the non-DAD mode"); 432 362 } … … 447 377 catcher(); 448 378 379 packet = xmalloc(4096); 449 380 while (1) { 450 381 sigset_t sset, osset; 451 RESERVE_CONFIG_UBUFFER(packet, 4096);452 382 struct sockaddr_ll from; 453 383 socklen_t alen = sizeof(from); 454 384 int cc; 455 385 456 if ((cc = recvfrom(s, packet, 4096, 0,457 (struct sockaddr *) &from, &alen))< 0) {458 perror("recvfrom");386 cc = recvfrom(sock, packet, 4096, 0, (struct sockaddr *) &from, &alen); 387 if (cc < 0) { 388 bb_perror_msg("recvfrom"); 459 389 continue; 460 390 } … … 465 395 recv_pack(packet, cc, &from); 466 396 sigprocmask(SIG_SETMASK, &osset, NULL); 467 RELEASE_CONFIG_BUFFER(packet); 468 } 469 } 397 } 398 } -
branches/2.2.5/mindi-busybox/networking/dnsd.c
r902 r1765 18 18 */ 19 19 20 #include <unistd.h> 21 #include <string.h> 22 #include <signal.h> 23 #include <arpa/inet.h> 24 #include <sys/socket.h> 25 #include <ctype.h> 26 #include "busybox.h" 27 28 static char *fileconf = "/etc/dnsd.conf"; 29 #define LOCK_FILE "/var/run/dnsd.lock" 30 #define LOG_FILE "/var/log/dnsd.log" 31 32 #define is_daemon() (flags&16) 33 #define is_verbose() (flags&32) 34 //#define DEBUG 35 20 #include <syslog.h> 21 #include "libbb.h" 22 23 //#define DEBUG 1 24 #define DEBUG 0 36 25 37 26 enum { … … 81 70 }; 82 71 83 static struct dns_entry *dnsentry = NULL; 84 static int daemonmode = 0; 72 static struct dns_entry *dnsentry; 85 73 static uint32_t ttl = DEFAULT_TTL; 86 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 87 82 /* 88 83 * Convert host name from C-string to dns length/string. … … 91 86 { 92 87 int i = (q[0] == '.') ? 0 : 1; 93 for (; i < MAX_HOST_LEN-1 && *q; i++, q++)88 for (; i < MAX_HOST_LEN-1 && *q; i++, q++) 94 89 a[i] = tolower(*q); 95 90 a[0] = i - 1; … … 103 98 { 104 99 int i = 0, s = 0; 105 while(rip[i]) i++; 106 for(--i; i >= 0; i--) { 107 if(rip[i] == '.') { 100 while (rip[i]) 101 i++; 102 for (--i; i >= 0; i--) { 103 if (rip[i] == '.') { 108 104 rip[i] = s; 109 105 s = 0; … … 113 109 114 110 /* 115 * Append message to log file116 */117 static void log_message(char *filename, char *message)118 {119 FILE *logfile;120 if (!daemonmode)121 return;122 logfile = fopen(filename, "a");123 if (!logfile)124 return;125 fprintf(logfile, "%s\n", message);126 fclose(logfile);127 }128 129 /*130 111 * Read one line of hostname/IP from file 131 112 * Returns 0 for each valid entry read, -1 at EOF 132 113 * Assumes all host names are lower case only 133 * Hostnames with more than one label isnot handled correctly.114 * Hostnames with more than one label are not handled correctly. 134 115 * Presently the dot is copied into name without 135 116 * converting to a length/string substring for that label. 136 117 */ 137 138 static int getfileentry(FILE * fp, struct dns_entry *s, int verb) 118 static int getfileentry(FILE * fp, struct dns_entry *s) 139 119 { 140 120 unsigned int a,b,c,d; 141 char *r, *name; 142 143 restart: 144 if(!(r = bb_get_line_from_file(fp))) 121 char *line, *r, *name; 122 123 restart: 124 line = r = xmalloc_fgets(fp); 125 if (!r) 145 126 return -1; 146 while (*r == ' ' || *r == '\t') {127 while (*r == ' ' || *r == '\t') { 147 128 r++; 148 if(!*r || *r == '#' || *r == '\n') 129 if (!*r || *r == '#' || *r == '\n') { 130 free(line); 149 131 goto restart; /* skipping empty/blank and commented lines */ 132 } 150 133 } 151 134 name = r; 152 while (*r != ' ' && *r != '\t')135 while (*r != ' ' && *r != '\t') 153 136 r++; 154 *r++ = 0; 155 if(sscanf(r,"%u.%u.%u.%u",&a,&b,&c,&d) != 4) 156 goto restart; /* skipping wrong lines */ 157 158 sprintf(s->ip,"%u.%u.%u.%u",a,b,c,d); 159 sprintf(s->rip,".%u.%u.%u.%u",d,c,b,a); 137 *r++ = '\0'; 138 if (sscanf(r, ".%u.%u.%u.%u"+1, &a, &b, &c, &d) != 4) { 139 free(line); 140 goto restart; /* skipping wrong lines */ 141 } 142 143 sprintf(s->ip, ".%u.%u.%u.%u"+1, a, b, c, d); 144 sprintf(s->rip, ".%u.%u.%u.%u", d, c, b, a); 160 145 undot((uint8_t*)s->rip); 161 convname(s->name,(uint8_t*)name); 162 163 if(verb) 164 fprintf(stderr,"\tname:%s, ip:%s\n",&(s->name[1]),s->ip); 165 166 return 0; /* warningkiller */ 146 convname(s->name, (uint8_t*)name); 147 148 if (OPT_verbose) 149 fprintf(stderr, "\tname:%s, ip:%s\n", &(s->name[1]),s->ip); 150 151 free(line); 152 return 0; 167 153 } 168 154 … … 170 156 * Read hostname/IP records from file 171 157 */ 172 static void dnsentryinit( int verb)158 static void dnsentryinit(void) 173 159 { 174 160 FILE *fp; 175 161 struct dns_entry *m, *prev; 162 176 163 prev = dnsentry = NULL; 177 178 fp = bb_xfopen(fileconf, "r"); 164 fp = xfopen(fileconf, "r"); 179 165 180 166 while (1) { 181 m = xmalloc(sizeof(struct dns_entry)); 182 183 m->next = NULL; 184 if (getfileentry(fp, m, verb)) 167 m = xzalloc(sizeof(*m)); 168 /*m->next = NULL;*/ 169 if (getfileentry(fp, m)) 185 170 break; 186 171 … … 194 179 } 195 180 196 197 /*198 * Set up UDP socket199 */200 static int listen_socket(char *iface_addr, int listen_port)201 {202 struct sockaddr_in a;203 char msg[100];204 int s;205 int yes = 1;206 s = bb_xsocket(PF_INET, SOCK_DGRAM, 0);207 #ifdef SO_REUSEADDR208 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)209 bb_perror_msg_and_die("setsockopt() failed");210 #endif211 memset(&a, 0, sizeof(a));212 a.sin_port = htons(listen_port);213 a.sin_family = AF_INET;214 if (!inet_aton(iface_addr, &a.sin_addr))215 bb_perror_msg_and_die("bad iface address");216 bb_xbind(s, (struct sockaddr *)&a, sizeof(a));217 listen(s, 50); /* bb_xlisten? */218 sprintf(msg, "accepting UDP packets on addr:port %s:%d\n",219 iface_addr, (int)listen_port);220 log_message(LOG_FILE, msg);221 return s;222 }223 224 181 /* 225 182 * Look query up in dns records and return answer if found … … 231 188 struct dns_entry *d = dnsentry; 232 189 233 if(d) do { 234 #ifdef DEBUG 235 if(qs && d) { 236 char *p,*q; 237 q = (char *)&(qs[1]); 238 p = &(d->name[1]); 239 fprintf(stderr, "\n%s: %d/%d p:%s q:%s %d", 240 __FUNCTION__, strlen(p), (int)(d->name[0]), 241 p, q, strlen(q)); 242 } 190 do { 191 #if DEBUG 192 char *p,*q; 193 q = (char *)&(qs[1]); 194 p = &(d->name[1]); 195 fprintf(stderr, "\n%s: %d/%d p:%s q:%s %d", 196 __FUNCTION__, (int)strlen(p), (int)(d->name[0]), 197 p, q, (int)strlen(q)); 243 198 #endif 244 if (type == REQ_A) { 245 for (i = 1; i <= (int)(d->name[0]); i++)246 if (tolower(qs[i]) != d->name[i])199 if (type == REQ_A) { /* search by host name */ 200 for (i = 1; i <= (int)(d->name[0]); i++) 201 if (tolower(qs[i]) != d->name[i]) 247 202 break; 248 if(i > (int)(d->name[0])) { 249 #ifdef DEBUG 250 fprintf(stderr, " OK"); 251 #endif 203 if (i > (int)(d->name[0])) { 252 204 strcpy((char *)as, d->ip); 253 #if defDEBUG254 fprintf(stderr, " as:%s\n", as);205 #if DEBUG 206 fprintf(stderr, " OK as:%s\n", as); 255 207 #endif 256 208 return 0; 257 209 } 258 } else 259 if (type == REQ_PTR) { /* search by IP-address */ 210 } else if (type == REQ_PTR) { /* search by IP-address */ 260 211 if (!strncmp((char*)&d->rip[1], (char*)&qs[1], strlen(d->rip)-1)) { 261 212 strcpy((char *)as, d->name); … … 263 214 } 264 215 } 265 } while ((d = d->next) != NULL); 216 d = d->next; 217 } while (d); 266 218 return -1; 267 219 } … … 271 223 * Decode message and generate answer 272 224 */ 273 #define eret(s) do { fprintf (stderr, "%s\n", s); return -1; } while (0)274 225 static int process_packet(uint8_t * buf) 275 226 { … … 286 237 287 238 head = (struct dns_head *)buf; 288 if (head->nquer == 0) 289 eret("no queries"); 290 291 if ((head->flags & 0x8000)) 292 eret("ignoring response packet"); 239 if (head->nquer == 0) { 240 bb_error_msg("no queries"); 241 return -1; 242 } 243 244 if (head->flags & 0x8000) { 245 bb_error_msg("ignoring response packet"); 246 return -1; 247 } 293 248 294 249 from = (void *)&head[1]; // start of query string … … 317 272 318 273 // We have a standard query 319 log_message(LOG_FILE, (char *)from);274 bb_info_msg("%s", (char *)from); 320 275 lookup_result = table_lookup(type, answstr, (uint8_t*)from); 321 276 if (lookup_result != 0) { … … 331 286 memcpy(answstr, &a.s_addr, 4); // save before a disappears 332 287 outr.rlen = 4; // uint32_t IP 333 } 334 else 288 } else 335 289 outr.rlen = strlen((char *)answstr) + 1; // a host name 336 290 outr.r = answstr; // 32 bit ip or a host name … … 352 306 next += outr.rlen; 353 307 354 empty_packet: 308 empty_packet: 309 355 310 flags = ntohs(head->flags); 356 311 // clear rcode and RA, set responsebit and our new flags … … 360 315 head->nquer = htons(1); 361 316 362 packet_len = next - (void *)buf;317 packet_len = (uint8_t *)next - buf; 363 318 return packet_len; 364 319 } … … 369 324 static void interrupt(int x) 370 325 { 371 unlink(LOCK_FILE);372 write(2, "interrupt exiting\n", 18);326 /* unlink("/var/run/dnsd.lock"); */ 327 bb_error_msg("interrupt, exiting\n"); 373 328 exit(2); 374 329 } 375 330 376 331 int dnsd_main(int argc, char **argv); 377 332 int dnsd_main(int argc, char **argv) 378 333 { 334 const char *listen_interface = "0.0.0.0"; 335 char *sttl, *sport; 336 len_and_sockaddr *lsa; 379 337 int udps; 380 338 uint16_t port = 53; 381 339 uint8_t buf[MAX_PACK_LEN]; 382 unsigned long flags = 0; 383 char *listen_interface = "0.0.0.0"; 384 char *sttl=NULL, *sport=NULL; 385 386 if(argc > 1) 387 flags = bb_getopt_ulflags(argc, argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport); 388 if(sttl) 389 if(!(ttl = atol(sttl))) 390 bb_show_usage(); 391 if(sport) 392 if(!(port = atol(sport))) 393 bb_show_usage(); 394 395 if(is_verbose()) { 396 fprintf(stderr,"listen_interface: %s\n", listen_interface); 397 fprintf(stderr,"ttl: %d, port: %d\n", ttl, port); 398 fprintf(stderr,"fileconf: %s\n", fileconf); 399 } 400 401 if(is_daemon()) 402 #ifdef BB_NOMMU 403 /* reexec for vfork() do continue parent */ 404 vfork_daemon_rexec(1, 0, argc, argv, "-d"); 405 #else 406 bb_xdaemon(1, 0); 407 #endif 408 409 dnsentryinit(is_verbose()); 340 341 getopt32(argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport); 342 //if (option_mask32 & 0x1) // -i 343 //if (option_mask32 & 0x2) // -c 344 if (option_mask32 & 0x4) // -t 345 ttl = xatou_range(sttl, 1, 0xffffffff); 346 if (option_mask32 & 0x8) // -p 347 port = xatou_range(sport, 1, 0xffff); 348 349 if (OPT_verbose) { 350 bb_info_msg("listen_interface: %s", listen_interface); 351 bb_info_msg("ttl: %d, port: %d", ttl, port); 352 bb_info_msg("fileconf: %s", fileconf); 353 } 354 355 if (OPT_daemon) { 356 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); 357 openlog(applet_name, LOG_PID, LOG_DAEMON); 358 logmode = LOGMODE_SYSLOG; 359 } 360 361 dnsentryinit(); 410 362 411 363 signal(SIGINT, interrupt); 412 signal(SIGPIPE, SIG_IGN);364 /* why? signal(SIGPIPE, SIG_IGN); */ 413 365 signal(SIGHUP, SIG_IGN); 414 366 #ifdef SIGTSTP … … 419 371 #endif 420 372 421 udps = listen_socket(listen_interface, port); 422 if (udps < 0) 423 exit(1); 373 lsa = xdotted2sockaddr(listen_interface, port); 374 udps = xsocket(lsa->sa.sa_family, SOCK_DGRAM, 0); 375 xbind(udps, &lsa->sa, lsa->len); 376 /* xlisten(udps, 50); - ?!! DGRAM sockets are never listened on I think? */ 377 bb_info_msg("Accepting UDP packets on %s", 378 xmalloc_sockaddr2dotted(&lsa->sa)); 424 379 425 380 while (1) { 426 fd_set fdset;427 381 int r; 428 429 FD_ZERO(&fdset); 430 FD_SET(udps, &fdset); 431 // Block until a message arrives 432 if((r = select(udps + 1, &fdset, NULL, NULL, NULL)) < 0) 433 bb_perror_msg_and_die("select error"); 434 else 435 if(r == 0) 436 bb_perror_msg_and_die("select spurious return"); 437 438 /* Can this test ever be false? */ 439 if (FD_ISSET(udps, &fdset)) { 440 struct sockaddr_in from; 441 int fromlen = sizeof(from); 442 r = recvfrom(udps, buf, sizeof(buf), 0, 443 (struct sockaddr *)&from, 444 (void *)&fromlen); 445 if(is_verbose()) 446 fprintf(stderr, "\n--- Got UDP size=%d ", r); 447 log_message(LOG_FILE, "\n--- Got UDP "); 448 449 if (r < 12 || r > 512) { 450 bb_error_msg("invalid packet size"); 451 continue; 452 } 453 if (r > 0) { 454 r = process_packet(buf); 455 if (r > 0) 456 sendto(udps, buf, 457 r, 0, (struct sockaddr *)&from, 458 fromlen); 459 } 460 } // end if 461 } // end while 382 socklen_t fromlen = lsa->len; 383 // FIXME: need to get *DEST* address (to which of our addresses 384 // this query was directed), and reply from the same address. 385 // Or else we can exhibit usual UDP ugliness: 386 // [ip1.multihomed.ip2] <= query to ip1 <= peer 387 // [ip1.multihomed.ip2] => reply from ip2 => peer (confused) 388 r = recvfrom(udps, buf, sizeof(buf), 0, &lsa->sa, &fromlen); 389 if (OPT_verbose) 390 bb_info_msg("Got UDP packet"); 391 if (r < 12 || r > 512) { 392 bb_error_msg("invalid packet size"); 393 continue; 394 } 395 r = process_packet(buf); 396 if (r <= 0) 397 continue; 398 sendto(udps, buf, r, 0, &lsa->sa, fromlen); 399 } 462 400 return 0; 463 401 } 464 465 -
branches/2.2.5/mindi-busybox/networking/ether-wake.c
r821 r1765 66 66 67 67 68 #include <unistd.h>69 #include <stdlib.h>70 #include <stdio.h>71 #include <errno.h>72 #include <ctype.h>73 #include <string.h>74 75 #include <sys/socket.h>76 #include <sys/types.h>77 #include <sys/ioctl.h>78 #include <features.h>79 68 #include <netpacket/packet.h> 80 69 #include <net/ethernet.h> 81 #include <netdb.h>82 70 #include <netinet/ether.h> 83 84 #ifdef __linux__85 71 #include <linux/if.h> 86 #endif 87 88 #include "busybox.h" 72 73 #include "libbb.h" 89 74 90 75 /* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to … … 94 79 #ifdef PF_PACKET 95 80 # define whereto_t sockaddr_ll 96 # define make_socket() bb_xsocket(PF_PACKET, SOCK_RAW, 0)81 # define make_socket() xsocket(PF_PACKET, SOCK_RAW, 0) 97 82 #else 98 83 # define whereto_t sockaddr 99 # define make_socket() bb_xsocket(AF_INET, SOCK_PACKET, SOCK_PACKET)84 # define make_socket() xsocket(AF_INET, SOCK_PACKET, SOCK_PACKET) 100 85 #endif 101 86 … … 108 93 for (i = 0; i < pktsize; ++i) { 109 94 printf("%2.2x ", outpack[i]); 110 if (i % 20 == 19) p rintf("\n");95 if (i % 20 == 19) puts(""); 111 96 } 112 97 printf("\n\n"); 113 98 } 114 99 #else 115 # define bb_debug_msg(fmt, args...) 116 # define bb_debug_dump_packet(outpack, pktsize) 117 #endif 118 119 static inline void get_dest_addr(const char *arg, struct ether_addr *eaddr); 120 static inline int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast); 121 static inline int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd); 122 123 int etherwake_main(int argc, char *argv[]) 124 { 125 char *ifname = "eth0", *pass = NULL; 126 unsigned long flags; 100 # define bb_debug_msg(fmt, args...) ((void)0) 101 # define bb_debug_dump_packet(outpack, pktsize) ((void)0) 102 #endif 103 104 /* Convert the host ID string to a MAC address. 105 * The string may be a: 106 * Host name 107 * IP address string 108 * MAC address string 109 */ 110 static void get_dest_addr(const char *hostid, struct ether_addr *eaddr) 111 { 112 struct ether_addr *eap; 113 114 eap = ether_aton(hostid); 115 if (eap) { 116 *eaddr = *eap; 117 bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr)); 118 #if !defined(__UCLIBC__) 119 } else if (ether_hostton(hostid, eaddr) == 0) { 120 bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr)); 121 #endif 122 } else 123 bb_show_usage(); 124 } 125 126 static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast) 127 { 128 int i; 129 unsigned char *station_addr = eaddr->ether_addr_octet; 130 131 memset(pkt, 0xff, 6); 132 if (!broadcast) 133 memcpy(pkt, station_addr, 6); 134 pkt += 6; 135 136 memcpy(pkt, station_addr, 6); /* 6 */ 137 pkt += 6; 138 139 *pkt++ = 0x08; /* 12 */ /* Or 0x0806 for ARP, 0x8035 for RARP */ 140 *pkt++ = 0x42; /* 13 */ 141 142 memset(pkt, 0xff, 6); /* 14 */ 143 144 for (i = 0; i < 16; ++i) { 145 pkt += 6; 146 memcpy(pkt, station_addr, 6); /* 20,26,32,... */ 147 } 148 149 return 20 + 16*6; /* length of packet */ 150 } 151 152 static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd) 153 { 154 unsigned passwd[6]; 155 int byte_cnt, i; 156 157 /* handle MAC format */ 158 byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x", 159 &passwd[0], &passwd[1], &passwd[2], 160 &passwd[3], &passwd[4], &passwd[5]); 161 /* handle IP format */ 162 // FIXME: why < 4?? should it be < 6? 163 if (byte_cnt < 4) 164 byte_cnt = sscanf(ethoptarg, "%u.%u.%u.%u", 165 &passwd[0], &passwd[1], &passwd[2], &passwd[3]); 166 if (byte_cnt < 4) { 167 bb_error_msg("cannot read Wake-On-LAN pass"); 168 return 0; 169 } 170 // TODO: check invalid numbers >255?? 171 for (i = 0; i < byte_cnt; ++i) 172 wol_passwd[i] = passwd[i]; 173 174 bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n", 175 wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3], 176 byte_cnt); 177 178 return byte_cnt; 179 } 180 181 int ether_wake_main(int argc, char **argv); 182 int ether_wake_main(int argc, char **argv) 183 { 184 const char *ifname = "eth0"; 185 char *pass; 186 unsigned flags; 127 187 unsigned char wol_passwd[6]; 128 188 int wol_passwd_sz = 0; 129 130 189 int s; /* Raw socket */ 131 190 int pktsize; … … 136 195 137 196 /* handle misc user options */ 138 flags = bb_getopt_ulflags(argc, argv, "bi:p:", &ifname, &pass); 139 if (optind == argc) 140 bb_show_usage(); 141 if (pass) 197 opt_complementary = "=1"; 198 flags = getopt32(argv, "bi:p:", &ifname, &pass); 199 if (flags & 4) /* -p */ 142 200 wol_passwd_sz = get_wol_pw(pass, wol_passwd); 201 flags &= 1; /* we further interested only in -b [bcast] flag */ 143 202 144 203 /* create the raw socket */ … … 146 205 147 206 /* now that we have a raw socket we can drop root */ 148 xsetuid(getuid());207 /* xsetuid(getuid()); - but save on code size... */ 149 208 150 209 /* look up the dest mac address */ … … 152 211 153 212 /* fill out the header of the packet */ 154 pktsize = get_fill(outpack, &eaddr, flags /* & 1 [OPT_BROADCAST]*/);213 pktsize = get_fill(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */); 155 214 156 215 bb_debug_dump_packet(outpack, pktsize); … … 161 220 struct ifreq if_hwaddr; 162 221 163 strcpy(if_hwaddr.ifr_name, ifname); 164 if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0) 165 bb_perror_msg_and_die("SIOCGIFHWADDR on %s failed", ifname); 222 strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name)); 223 ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname); 166 224 167 225 memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6); … … 190 248 191 249 /* This is necessary for broadcasts to work */ 192 if (flags /*& 1 [OPT_BROADCAST]*/) { 193 int one = 1; 194 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(one)) < 0) 250 if (flags /* & 1 OPT_BROADCAST */) { 251 if (setsockopt_broadcast(s) != 0) 195 252 bb_perror_msg("SO_BROADCAST"); 196 253 } … … 200 257 struct ifreq ifr; 201 258 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 202 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) 203 bb_perror_msg_and_die("SIOCGIFINDEX"); 259 xioctl(s, SIOCGIFINDEX, &ifr); 204 260 memset(&whereto, 0, sizeof(whereto)); 205 261 whereto.sll_family = AF_PACKET; … … 214 270 strcpy(whereto.sa_data, ifname); 215 271 #endif 216 217 if (sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto, sizeof(whereto)) < 0) 218 bb_perror_msg(bb_msg_write_error); 219 220 close(s); 221 272 xsendto(s, outpack, pktsize, (struct sockaddr *)&whereto, sizeof(whereto)); 273 if (ENABLE_FEATURE_CLEAN_UP) 274 close(s); 222 275 return EXIT_SUCCESS; 223 276 } 224 225 /* Convert the host ID string to a MAC address.226 * The string may be a:227 * Host name228 * IP address string229 * MAC address string230 */231 static inline void get_dest_addr(const char *hostid, struct ether_addr *eaddr)232 {233 struct ether_addr *eap;234 235 eap = ether_aton(hostid);236 if (eap) {237 *eaddr = *eap;238 bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr));239 #if !defined(__UCLIBC__)240 } else if (ether_hostton(hostid, eaddr) == 0) {241 bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));242 #else243 # warning Need to implement ether_hostton() for uClibc244 #endif245 } else246 bb_show_usage();247 }248 249 static inline int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)250 {251 int offset, i;252 unsigned char *station_addr = eaddr->ether_addr_octet;253 254 if (broadcast)255 memset(pkt+0, 0xff, 6);256 else257 memcpy(pkt, station_addr, 6);258 memcpy(pkt+6, station_addr, 6);259 pkt[12] = 0x08; /* Or 0x0806 for ARP, 0x8035 for RARP */260 pkt[13] = 0x42;261 offset = 14;262 263 memset(pkt+offset, 0xff, 6);264 offset += 6;265 266 for (i = 0; i < 16; ++i) {267 memcpy(pkt+offset, station_addr, 6);268 offset += 6;269 }270 271 return offset;272 }273 274 static inline int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)275 {276 int passwd[6];277 int byte_cnt, i;278 279 /* handle MAC format */280 byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x",281 &passwd[0], &passwd[1], &passwd[2],282 &passwd[3], &passwd[4], &passwd[5]);283 /* handle IP format */284 if (byte_cnt < 4)285 byte_cnt = sscanf(ethoptarg, "%d.%d.%d.%d",286 &passwd[0], &passwd[1], &passwd[2], &passwd[3]);287 if (byte_cnt < 4) {288 bb_error_msg("Unable to read the Wake-On-LAN pass");289 return 0;290 }291 292 for (i = 0; i < byte_cnt; ++i)293 wol_passwd[i] = passwd[i];294 295 bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n",296 wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3],297 byte_cnt);298 299 return byte_cnt;300 } -
branches/2.2.5/mindi-busybox/networking/ftpgetput.c
r821 r1765 14 14 */ 15 15 16 #include <sys/ioctl.h>17 18 #include <ctype.h>19 #include <errno.h>20 #include <fcntl.h>21 16 #include <getopt.h> 22 #include <signal.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include <sys/socket.h> 27 28 #include "busybox.h" 17 #include "libbb.h" 29 18 30 19 typedef struct ftp_host_info_s { 31 c har *user;32 c har *password;33 struct sockaddr_in *s_in;20 const char *user; 21 const char *password; 22 struct len_and_sockaddr *lsa; 34 23 } ftp_host_info_t; 35 24 36 static char verbose_flag = 0; 37 static char do_continue = 0; 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 { 31 /* Guard against garbage from remote server */ 32 const char *cp = remote; 33 while (*cp >= ' ' && *cp < '\x7f') cp++; 34 bb_error_msg_and_die("unexpected server response%s%s: %.*s", 35 msg ? " to " : "", msg ? msg : "", 36 (int)(cp - remote), remote); 37 } 38 38 39 39 40 static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf) 40 41 { 42 unsigned n; 41 43 if (verbose_flag) { 42 bb_error_msg("cmd %s %s", s1, s2);44 bb_error_msg("cmd %s %s", s1, s2); 43 45 } 44 46 45 47 if (s1) { 46 48 if (s2) { 47 fprintf(stream, "%s %s\r\n", s1, s2);49 fprintf(stream, "%s %s\r\n", s1, s2); 48 50 } else { 49 51 fprintf(stream, "%s\r\n", s1); … … 54 56 55 57 if (fgets(buf, 510, stream) == NULL) { 56 bb_perror_msg_and_die("fgets ()");58 bb_perror_msg_and_die("fgets"); 57 59 } 58 60 buf_ptr = strstr(buf, "\r\n"); … … 60 62 *buf_ptr = '\0'; 61 63 } 62 } while (! isdigit(buf[0]) || buf[3] != ' '); 63 64 return atoi(buf); 65 } 66 67 static int xconnect_ftpdata(ftp_host_info_t *server, const char *buf) 64 } while (!isdigit(buf[0]) || buf[3] != ' '); 65 66 buf[3] = '\0'; 67 n = xatou(buf); 68 buf[3] = ' '; 69 return n; 70 } 71 72 static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) 68 73 { 69 74 char *buf_ptr; 70 75 unsigned short port_num; 71 76 77 /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] 78 * Server's IP is N1.N2.N3.N4 (we ignore it) 79 * Server's port for data connection is P1*256+P2 */ 80 buf_ptr = strrchr(buf, ')'); 81 if (buf_ptr) *buf_ptr = '\0'; 82 72 83 buf_ptr = strrchr(buf, ','); 73 84 *buf_ptr = '\0'; 74 port_num = atoi(buf_ptr + 1);85 port_num = xatoul_range(buf_ptr + 1, 0, 255); 75 86 76 87 buf_ptr = strrchr(buf, ','); 77 88 *buf_ptr = '\0'; 78 port_num += atoi(buf_ptr + 1) * 256;79 80 se rver->s_in->sin_port=htons(port_num);81 return (xconnect(server->s_in));89 port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; 90 91 set_nport(server->lsa, htons(port_num)); 92 return xconnect_stream(server->lsa); 82 93 } 83 94 … … 88 99 89 100 /* Connect to the command socket */ 90 control_stream = fdopen(xconnect (server->s_in), "r+");101 control_stream = fdopen(xconnect_stream(server->lsa), "r+"); 91 102 if (control_stream == NULL) { 92 bb_perror_msg_and_die("Couldnt open control stream"); 103 /* fdopen failed - extremely unlikely */ 104 bb_perror_nomsg_and_die(); 93 105 } 94 106 95 107 if (ftpcmd(NULL, NULL, control_stream, buf) != 220) { 96 bb_error_msg_and_die("%s", buf + 4);108 ftp_die(NULL, buf); 97 109 } 98 110 99 111 /* Login to the server */ 100 switch (ftpcmd("USER 112 switch (ftpcmd("USER", server->user, control_stream, buf)) { 101 113 case 230: 102 114 break; 103 115 case 331: 104 if (ftpcmd("PASS 105 bb_error_msg_and_die("PASS error: %s", buf + 4);116 if (ftpcmd("PASS", server->password, control_stream, buf) != 230) { 117 ftp_die("PASS", buf); 106 118 } 107 119 break; 108 120 default: 109 bb_error_msg_and_die("USER error: %s", buf + 4);121 ftp_die("USER", buf); 110 122 } 111 123 112 124 ftpcmd("TYPE I", NULL, control_stream, buf); 113 125 114 return (control_stream);126 return control_stream; 115 127 } 116 128 117 129 #if !ENABLE_FTPGET 118 #define ftp_receive 0 130 int ftp_receive(ftp_host_info_t *server, FILE *control_stream, 131 const char *local_path, char *server_path); 119 132 #else 120 static int ftp_receive(ftp_host_info_t *server, FILE *control_stream, 133 static 134 int ftp_receive(ftp_host_info_t *server, FILE *control_stream, 121 135 const char *local_path, char *server_path) 122 136 { 123 137 char buf[512]; 124 off_t filesize = 0; 138 /* I think 'filesize' usage here is bogus. Let's see... */ 139 //off_t filesize = -1; 140 #define filesize ((off_t)-1) 125 141 int fd_data; 126 142 int fd_local = -1; … … 129 145 /* Connect to the data socket */ 130 146 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { 131 bb_error_msg_and_die("PASV error: %s", buf + 4);147 ftp_die("PASV", buf); 132 148 } 133 149 fd_data = xconnect_ftpdata(server, buf); 134 150 135 if (ftpcmd("SIZE ", server_path, control_stream, buf) == 213) { 136 unsigned long value=filesize; 137 if (safe_strtoul(buf + 4, &value)) 138 bb_error_msg_and_die("SIZE error: %s", buf + 4); 139 filesize = value; 151 if (ftpcmd("SIZE", server_path, control_stream, buf) == 213) { 152 //filesize = BB_STRTOOFF(buf + 4, NULL, 10); 153 //if (errno || filesize < 0) 154 // ftp_die("SIZE", buf); 140 155 } else { 141 filesize = -1;142 156 do_continue = 0; 143 157 } 144 158 145 if ( (local_path[0] == '-') && (local_path[1] == '\0')) {159 if (LONE_DASH(local_path)) { 146 160 fd_local = STDOUT_FILENO; 147 161 do_continue = 0; … … 151 165 struct stat sbuf; 152 166 if (lstat(local_path, &sbuf) < 0) { 153 bb_perror_msg_and_die(" fstat()");167 bb_perror_msg_and_die("lstat"); 154 168 } 155 169 if (sbuf.st_size > 0) { … … 161 175 162 176 if (do_continue) { 163 sprintf(buf, "REST % ld", (long)beg_range);177 sprintf(buf, "REST %"OFF_FMT"d", beg_range); 164 178 if (ftpcmd(buf, NULL, control_stream, buf) != 350) { 165 179 do_continue = 0; 166 180 } else { 167 filesize -= beg_range; 168 } 169 } 170 171 if (ftpcmd("RETR ", server_path, control_stream, buf) > 150) { 172 bb_error_msg_and_die("RETR error: %s", buf + 4); 181 //if (filesize != -1) 182 // filesize -= beg_range; 183 } 184 } 185 186 if (ftpcmd("RETR", server_path, control_stream, buf) > 150) { 187 ftp_die("RETR", buf); 173 188 } 174 189 … … 176 191 if (fd_local == -1) { 177 192 if (do_continue) { 178 fd_local = bb_xopen(local_path, O_APPEND | O_WRONLY);193 fd_local = xopen(local_path, O_APPEND | O_WRONLY); 179 194 } else { 180 fd_local = bb_xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY);195 fd_local = xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY); 181 196 } 182 197 } … … 184 199 /* Copy the file */ 185 200 if (filesize != -1) { 186 if ( -1 == bb_copyfd_size(fd_data, fd_local, filesize))187 exit(EXIT_FAILURE);201 if (bb_copyfd_size(fd_data, fd_local, filesize) == -1) 202 return EXIT_FAILURE; 188 203 } else { 189 if ( -1 == bb_copyfd_eof(fd_data, fd_local))190 exit(EXIT_FAILURE);204 if (bb_copyfd_eof(fd_data, fd_local) == -1) 205 return EXIT_FAILURE; 191 206 } 192 207 … … 194 209 close(fd_data); 195 210 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) { 196 bb_error_msg_and_die("ftp error: %s", buf + 4);211 ftp_die(NULL, buf); 197 212 } 198 213 ftpcmd("QUIT", NULL, control_stream, buf); 199 214 200 return (EXIT_SUCCESS);215 return EXIT_SUCCESS; 201 216 } 202 217 #endif 203 218 204 219 #if !ENABLE_FTPPUT 205 #define ftp_send 0 220 int ftp_send(ftp_host_info_t *server, FILE *control_stream, 221 const char *server_path, char *local_path); 206 222 #else 207 static int ftp_send(ftp_host_info_t *server, FILE *control_stream, 223 static 224 int ftp_send(ftp_host_info_t *server, FILE *control_stream, 208 225 const char *server_path, char *local_path) 209 226 { … … 216 233 /* Connect to the data socket */ 217 234 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { 218 bb_error_msg_and_die("PASV error: %s", buf + 4);235 ftp_die("PASV", buf); 219 236 } 220 237 fd_data = xconnect_ftpdata(server, buf); 221 238 222 239 /* get the local file */ 223 if ((local_path[0] == '-') && (local_path[1] == '\0')) { 224 fd_local = STDIN_FILENO; 225 } else { 226 fd_local = bb_xopen(local_path, O_RDONLY); 240 fd_local = STDIN_FILENO; 241 if (NOT_LONE_DASH(local_path)) { 242 fd_local = xopen(local_path, O_RDONLY); 227 243 fstat(fd_local, &sbuf); 228 244 229 sprintf(buf, "ALLO % lu", (unsigned long)sbuf.st_size);245 sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size); 230 246 response = ftpcmd(buf, NULL, control_stream, buf); 231 247 switch (response) { … … 235 251 default: 236 252 close(fd_local); 237 bb_error_msg_and_die("ALLO error: %s", buf + 4);253 ftp_die("ALLO", buf); 238 254 break; 239 255 } 240 256 } 241 response = ftpcmd("STOR 257 response = ftpcmd("STOR", server_path, control_stream, buf); 242 258 switch (response) { 243 259 case 125: … … 246 262 default: 247 263 close(fd_local); 248 bb_error_msg_and_die("STOR error: %s", buf + 4);264 ftp_die("STOR", buf); 249 265 } 250 266 … … 257 273 close(fd_data); 258 274 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) { 259 bb_error_msg_and_die("error: %s", buf + 4);275 ftp_die("close", buf); 260 276 } 261 277 ftpcmd("QUIT", NULL, control_stream, buf); 262 278 263 return (EXIT_SUCCESS);279 return EXIT_SUCCESS; 264 280 } 265 281 #endif … … 272 288 273 289 #if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS 274 static const struct option ftpgetput_long_options[] = { 275 {"continue", 1, NULL, 'c'}, 276 {"verbose", 0, NULL, 'v'}, 277 {"username", 1, NULL, 'u'}, 278 {"password", 1, NULL, 'p'}, 279 {"port", 1, NULL, 'P'}, 280 {0, 0, 0, 0} 281 }; 282 #else 283 #define ftpgetput_long_options 0 284 #endif 285 290 static const char ftpgetput_longopts[] ALIGN1 = 291 "continue\0" Required_argument "c" 292 "verbose\0" No_argument "v" 293 "username\0" Required_argument "u" 294 "password\0" Required_argument "p" 295 "port\0" Required_argument "P" 296 ; 297 #endif 298 299 int ftpgetput_main(int argc, char **argv); 286 300 int ftpgetput_main(int argc, char **argv) 287 301 { 288 302 /* content-length of the file */ 289 unsigned long opt; 290 char *port = "ftp"; 291 303 unsigned opt; 304 const char *port = "ftp"; 292 305 /* socket to ftp server */ 293 306 FILE *control_stream; 294 struct sockaddr_in s_in; 295 296 /* continue a prev transfer (-c) */ 307 /* continue previous transfer (-c) */ 297 308 ftp_host_info_t *server; 298 309 299 int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = NULL; 300 310 #if ENABLE_FTPPUT && !ENABLE_FTPGET 311 # define ftp_action ftp_send 312 #elif ENABLE_FTPGET && !ENABLE_FTPPUT 313 # define ftp_action ftp_receive 314 #else 315 int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = ftp_send; 301 316 /* Check to see if the command is ftpget or ftput */ 302 if (ENABLE_FTPPUT && (!ENABLE_FTPGET || bb_applet_name[3] == 'p')) { 303 ftp_action = ftp_send; 304 } 305 if (ENABLE_FTPGET && (!ENABLE_FTPPUT || bb_applet_name[3] == 'g')) { 317 if (applet_name[3] == 'g') { 306 318 ftp_action = ftp_receive; 307 319 } 320 #endif 308 321 309 322 /* Set default values */ 310 server = xmalloc(sizeof( ftp_host_info_t));323 server = xmalloc(sizeof(*server)); 311 324 server->user = "anonymous"; 312 325 server->password = "busybox@"; 313 verbose_flag = 0;314 326 315 327 /* 316 328 * Decipher the command line 317 329 */ 318 if (ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS) 319 bb_applet_long_options = ftpgetput_long_options; 320 321 opt = bb_getopt_ulflags(argc, argv, "cvu:p:P:", &server->user, &server->password, &port); 330 #if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS 331 applet_long_options = ftpgetput_longopts; 332 #endif 333 opt_complementary = "=3"; /* must have 3 params */ 334 opt = getopt32(argv, "cvu:p:P:", &server->user, &server->password, &port); 335 argv += optind; 322 336 323 337 /* Process the non-option command line arguments */ 324 if (argc - optind != 3) {325 bb_show_usage();326 }327 328 338 if (opt & FTPGETPUT_OPT_CONTINUE) { 329 339 do_continue = 1; … … 336 346 * sites (i.e. ftp.us.debian.org) use round-robin DNS 337 347 * and we want to connect to only one IP... */ 338 server->s_in = &s_in; 339 bb_lookup_host(&s_in, argv[optind]); 340 s_in.sin_port = bb_lookup_port(port, "tcp", 21); 348 server->lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21)); 341 349 if (verbose_flag) { 342 printf("Connecting to %s [%s]:%d\n",343 argv[optind], inet_ntoa(s_in.sin_addr), ntohs(s_in.sin_port));350 printf("Connecting to %s (%s)\n", argv[0], 351 xmalloc_sockaddr2dotted(&server->lsa->sa)); 344 352 } 345 353 … … 347 355 control_stream = ftp_login(server); 348 356 349 return (ftp_action(server, control_stream, argv[optind + 1], argv[optind + 2]));350 } 357 return ftp_action(server, control_stream, argv[1], argv[2]); 358 } -
branches/2.2.5/mindi-busybox/networking/hostname.c
r821 r1765 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * $Id: hostname.c,v 1.36 2003/07/14 21:21:01 andersen Exp $4 3 * Mini hostname implementation for busybox 5 4 * … … 9 8 * use of long options and GNU getopt. Improved the usage info. 10 9 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 10 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 11 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 12 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 24 13 */ 25 14 26 #include <errno.h> 27 #include <arpa/inet.h> 28 #include <netdb.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <getopt.h> 34 #include "busybox.h" 35 36 extern char *optarg; /* in unistd.h */ 37 extern int optind, opterr, optopt; /* in unistd.h */ 15 #include "libbb.h" 38 16 39 17 static void do_sethostname(char *s, int isfile) 40 18 { 41 19 FILE *f; 42 char buf[255];43 20 44 21 if (!s) … … 47 24 if (sethostname(s, strlen(s)) < 0) { 48 25 if (errno == EPERM) 49 bb_error_msg_and_die( "you must be root to change the hostname");26 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 50 27 else 51 28 bb_perror_msg_and_die("sethostname"); 52 29 } 53 30 } else { 54 f = bb_xfopen(s, "r"); 55 while (fgets(buf, 255, f) != NULL) { 56 if (buf[0] =='#') { 31 f = xfopen(s, "r"); 32 #define strbuf bb_common_bufsiz1 33 while (fgets(strbuf, sizeof(strbuf), f) != NULL) { 34 if (strbuf[0] == '#') { 57 35 continue; 58 36 } 59 chomp( buf);60 do_sethostname( buf, 0);37 chomp(strbuf); 38 do_sethostname(strbuf, 0); 61 39 } 62 #ifdef CONFIG_FEATURE_CLEAN_UP 63 fclose(f); 64 #endif 40 if (ENABLE_FEATURE_CLEAN_UP) 41 fclose(f); 65 42 } 66 43 } 67 44 45 int hostname_main(int argc, char **argv); 68 46 int hostname_main(int argc, char **argv) 69 47 { 70 int opt; 71 int type = 0; 72 struct hostent *hp; 73 char *filename = NULL; 74 char buf[255]; 75 char *p = NULL; 48 enum { 49 OPT_d = 0x1, 50 OPT_f = 0x2, 51 OPT_i = 0x4, 52 OPT_s = 0x8, 53 OPT_F = 0x10, 54 OPT_dfis = 0xf, 55 }; 56 57 char buf[256]; 58 char *hostname_str; 76 59 77 60 if (argc < 1) 78 61 bb_show_usage(); 79 62 80 while ((opt = getopt(argc, argv, "dfisF:")) > 0) { 81 switch (opt) { 82 case 'd': 83 case 'f': 84 case 'i': 85 case 's': 86 type = opt; 87 break; 88 case 'F': 89 filename = optarg; 90 break; 91 default: 92 bb_show_usage(); 93 } 94 } 63 getopt32(argv, "dfisF:", &hostname_str); 95 64 96 65 /* Output in desired format */ 97 if (type != 0) { 98 gethostname(buf, 255); 66 if (option_mask32 & OPT_dfis) { 67 struct hostent *hp; 68 char *p; 69 gethostname(buf, sizeof(buf)); 99 70 hp = xgethostbyname(buf); 100 71 p = strchr(hp->h_name, '.'); 101 if ( type == 'f') {72 if (option_mask32 & OPT_f) { 102 73 puts(hp->h_name); 103 } else if ( type == 's') {74 } else if (option_mask32 & OPT_s) { 104 75 if (p != NULL) { 105 *p = 0;76 *p = '\0'; 106 77 } 107 78 puts(hp->h_name); 108 } else if (type == 'd') { 109 if (p) puts(p + 1); 110 } else if (type == 'i') { 79 } else if (option_mask32 & OPT_d) { 80 if (p) 81 puts(p + 1); 82 } else if (option_mask32 & OPT_i) { 111 83 while (hp->h_addr_list[0]) { 112 84 printf("%s ", inet_ntoa(*(struct in_addr *) (*hp->h_addr_list++))); 113 85 } 114 p rintf("\n");86 puts(""); 115 87 } 116 88 } 117 89 /* Set the hostname */ 118 else if ( filename != NULL) {119 do_sethostname( filename, 1);90 else if (option_mask32 & OPT_F) { 91 do_sethostname(hostname_str, 1); 120 92 } else if (optind < argc) { 121 93 do_sethostname(argv[optind], 0); … … 123 95 /* Or if all else fails, 124 96 * just print the current hostname */ 125 126 gethostname(buf, 255);97 else { 98 gethostname(buf, sizeof(buf)); 127 99 puts(buf); 128 100 } 129 return (0);101 return 0; 130 102 } -
branches/2.2.5/mindi-busybox/networking/httpd.c
r902 r1765 21 21 * 22 22 * 23 * When a url contains "cgi-bin" it is assumed to be a cgi script. The23 * When a url starts by "/cgi-bin/" it is assumed to be a cgi script. The 24 24 * server changes directory to the location of the script and executes it 25 25 * after setting QUERY_STRING and other environment variables. 26 * 27 * Doc: 28 * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html 26 29 * 27 30 * The server can also be invoked as a url arg decoder and html text encoder … … 40 43 * A:127.0.0.1 # Allow local loopback connections 41 44 * D:* # Deny from other IP connections 45 * E404:/path/e404.html # /path/e404.html is the 404 (not found) error page 42 46 * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ 43 47 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ … … 82 86 * result, the subdir settings only have a lifetime of a single request. 83 87 * 88 * Custom error pages can contain an absolute path or be relative to 89 * 'home_httpd'. Error pages are to be static files (no CGI or script). Error 90 * page can only be defined in the root configuration file and are not taken 91 * into account in local (directories) config files. 84 92 * 85 93 * If -c is not set, an attempt will be made to open the default … … 87 95 * server exits with an error. 88 96 * 89 */ 90 91 92 #include <stdio.h> 93 #include <ctype.h> /* for isspace */ 94 #include <string.h> 95 #include <stdlib.h> /* for malloc */ 96 #include <time.h> 97 #include <unistd.h> /* for close */ 98 #include <signal.h> 99 #include <sys/types.h> 100 #include <sys/socket.h> /* for connect and socket*/ 101 #include <netinet/in.h> /* for sockaddr_in */ 102 #include <sys/stat.h> 103 #include <sys/wait.h> 104 #include <fcntl.h> /* for open modes */ 105 #include "busybox.h" 106 107 108 static const char httpdVersion[] = "busybox httpd/1.35 6-Oct-2004"; 109 static const char default_path_httpd_conf[] = "/etc"; 110 static const char httpd_conf[] = "httpd.conf"; 111 static const char home[] = "./"; 112 113 #ifdef CONFIG_LFS 114 # define cont_l_fmt "%lld" 115 # define cont_l_type (long long) 116 #else 117 # define cont_l_fmt "%ld" 118 # define cont_l_type (long) 119 #endif 120 121 #define TIMEOUT 60 122 123 // Note: busybox xfuncs are not used because we want the server to keep running 124 // if something bad happens due to a malformed user request. 125 // As a result, all memory allocation after daemonize 126 // is checked rigorously 97 */ 98 99 #include "libbb.h" 100 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE 101 #include <sys/sendfile.h> 102 #endif 127 103 128 104 //#define DEBUG 1 129 130 #ifndef DEBUG 131 # define DEBUG 0 132 #endif 133 134 #define MAX_MEMORY_BUFF 8192 /* IO buffer */ 135 136 typedef struct HT_ACCESS { 105 #define DEBUG 0 106 107 /* amount of buffering in a pipe */ 108 #ifndef PIPE_BUF 109 # define PIPE_BUF 4096 110 #endif 111 112 #define IOBUF_SIZE 8192 /* IO buffer */ 113 114 #define HEADER_READ_TIMEOUT 60 115 116 static const char default_path_httpd_conf[] ALIGN1 = "/etc"; 117 static const char httpd_conf[] ALIGN1 = "httpd.conf"; 118 static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; 119 120 typedef struct has_next_ptr { 121 struct has_next_ptr *next; 122 } has_next_ptr; 123 124 /* Must have "next" as a first member */ 125 typedef struct Htaccess { 126 struct Htaccess *next; 137 127 char *after_colon; 138 struct HT_ACCESS *next; 139 char before_colon[1]; /* really bigger, must last */ 128 char before_colon[1]; /* really bigger, must be last */ 140 129 } Htaccess; 141 130 142 typedef struct HT_ACCESS_IP { 143 unsigned int ip; 144 unsigned int mask; 131 /* Must have "next" as a first member */ 132 typedef struct Htaccess_IP { 133 struct Htaccess_IP *next; 134 unsigned ip; 135 unsigned mask; 145 136 int allow_deny; 146 struct HT_ACCESS_IP *next;147 137 } Htaccess_IP; 148 138 149 typedef struct 150 { 151 char buf[MAX_MEMORY_BUFF]; 152 153 USE_FEATURE_HTTPD_BASIC_AUTH(const char *realm;) 154 USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) 155 156 const char *query; 157 158 USE_FEATURE_HTTPD_CGI(char *referer;) 159 160 const char *configFile; 161 162 unsigned int rmt_ip; 163 #if defined(CONFIG_FEATURE_HTTPD_CGI) || DEBUG 164 char rmt_ip_str[16]; /* for set env REMOTE_ADDR */ 165 #endif 166 unsigned port; /* server initial port and for 167 set env REMOTE_PORT */ 168 union HTTPD_FOUND { 139 enum { 140 HTTP_OK = 200, 141 HTTP_MOVED_TEMPORARILY = 302, 142 HTTP_BAD_REQUEST = 400, /* malformed syntax */ 143 HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */ 144 HTTP_NOT_FOUND = 404, 145 HTTP_FORBIDDEN = 403, 146 HTTP_REQUEST_TIMEOUT = 408, 147 HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */ 148 HTTP_INTERNAL_SERVER_ERROR = 500, 149 HTTP_CONTINUE = 100, 150 #if 0 /* future use */ 151 HTTP_SWITCHING_PROTOCOLS = 101, 152 HTTP_CREATED = 201, 153 HTTP_ACCEPTED = 202, 154 HTTP_NON_AUTHORITATIVE_INFO = 203, 155 HTTP_NO_CONTENT = 204, 156 HTTP_MULTIPLE_CHOICES = 300, 157 HTTP_MOVED_PERMANENTLY = 301, 158 HTTP_NOT_MODIFIED = 304, 159 HTTP_PAYMENT_REQUIRED = 402, 160 HTTP_BAD_GATEWAY = 502, 161 HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */ 162 HTTP_RESPONSE_SETSIZE = 0xffffffff 163 #endif 164 }; 165 166 static const uint16_t http_response_type[] ALIGN2 = { 167 HTTP_OK, 168 HTTP_MOVED_TEMPORARILY, 169 HTTP_REQUEST_TIMEOUT, 170 HTTP_NOT_IMPLEMENTED, 171 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 172 HTTP_UNAUTHORIZED, 173 #endif 174 HTTP_NOT_FOUND, 175 HTTP_BAD_REQUEST, 176 HTTP_FORBIDDEN, 177 HTTP_INTERNAL_SERVER_ERROR, 178 #if 0 /* not implemented */ 179 HTTP_CREATED, 180 HTTP_ACCEPTED, 181 HTTP_NO_CONTENT, 182 HTTP_MULTIPLE_CHOICES, 183 HTTP_MOVED_PERMANENTLY, 184 HTTP_NOT_MODIFIED, 185 HTTP_BAD_GATEWAY, 186 HTTP_SERVICE_UNAVAILABLE, 187 #endif 188 }; 189 190 static const struct { 191 const char *name; 192 const char *info; 193 } http_response[ARRAY_SIZE(http_response_type)] = { 194 { "OK", NULL }, 195 { "Found", "Directories must end with a slash" }, /* ?? */ 196 { "Request Timeout", "No request appeared within 60 seconds" }, 197 { "Not Implemented", "The requested method is not recognized" }, 198 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 199 { "Unauthorized", "" }, 200 #endif 201 { "Not Found", "The requested URL was not found" }, 202 { "Bad Request", "Unsupported method" }, 203 { "Forbidden", "" }, 204 { "Internal Server Error", "Internal Server Error" }, 205 #if 0 /* not implemented */ 206 { "Created" }, 207 { "Accepted" }, 208 { "No Content" }, 209 { "Multiple Choices" }, 210 { "Moved Permanently" }, 211 { "Not Modified" }, 212 { "Bad Gateway", "" }, 213 { "Service Unavailable", "" }, 214 #endif 215 }; 216 217 struct globals { 218 int verbose; /* must be int (used by getopt32) */ 219 smallint flg_deny_all; 220 221 unsigned rmt_ip; /* used for IP-based allow/deny rules */ 222 time_t last_mod; 223 off_t ContentLength; /* -1 - unknown */ 224 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ 225 const char *bind_addr_or_port; 226 227 const char *g_query; 228 const char *configFile; 229 const char *home_httpd; 230 169 231 const char *found_mime_type; 170 232 const char *found_moved_temporarily; 171 } httpd_found; 172 173 off_t ContentLength; /* -1 - unknown */ 174 time_t last_mod; 175 176 Htaccess_IP *ip_a_d; /* config allow/deny lines */ 177 int flg_deny_all; 178 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 179 Htaccess *auth; /* config user:password lines */ 180 #endif 181 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 182 Htaccess *mime_a; /* config mime types */ 183 #endif 184 185 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 186 int accepted_socket; 187 # define a_c_r config->accepted_socket 188 # define a_c_w config->accepted_socket 189 #else 190 # define a_c_r 0 191 # define a_c_w 1 192 #endif 193 volatile int alarm_signaled; 194 195 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 196 Htaccess *script_i; /* config script interpreters */ 197 #endif 198 } HttpdConfig; 199 200 static HttpdConfig *config; 201 202 static const char request_GET[] = "GET"; /* size algorithmic optimize */ 203 204 static const char* const suffixTable [] = { 205 /* Warning: shorted equivalent suffix in one line must be first */ 206 ".htm.html", "text/html", 207 ".jpg.jpeg", "image/jpeg", 208 ".gif", "image/gif", 209 ".png", "image/png", 210 ".txt.h.c.cc.cpp", "text/plain", 211 ".css", "text/css", 212 ".wav", "audio/wav", 213 ".avi", "video/x-msvideo", 214 ".qt.mov", "video/quicktime", 215 ".mpe.mpeg", "video/mpeg", 216 ".mid.midi", "audio/midi", 217 ".mp3", "audio/mpeg", 218 #if 0 /* unpopular */ 219 ".au", "audio/basic", 220 ".pac", "application/x-ns-proxy-autoconfig", 221 ".vrml.wrl", "model/vrml", 222 #endif 223 0, "application/octet-stream" /* default */ 224 }; 225 226 typedef enum 227 { 228 HTTP_OK = 200, 229 HTTP_MOVED_TEMPORARILY = 302, 230 HTTP_BAD_REQUEST = 400, /* malformed syntax */ 231 HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */ 232 HTTP_NOT_FOUND = 404, 233 HTTP_FORBIDDEN = 403, 234 HTTP_REQUEST_TIMEOUT = 408, 235 HTTP_NOT_IMPLEMENTED = 501, /* used for unrecognized requests */ 236 HTTP_INTERNAL_SERVER_ERROR = 500, 237 #if 0 /* future use */ 238 HTTP_CONTINUE = 100, 239 HTTP_SWITCHING_PROTOCOLS = 101, 240 HTTP_CREATED = 201, 241 HTTP_ACCEPTED = 202, 242 HTTP_NON_AUTHORITATIVE_INFO = 203, 243 HTTP_NO_CONTENT = 204, 244 HTTP_MULTIPLE_CHOICES = 300, 245 HTTP_MOVED_PERMANENTLY = 301, 246 HTTP_NOT_MODIFIED = 304, 247 HTTP_PAYMENT_REQUIRED = 402, 248 HTTP_BAD_GATEWAY = 502, 249 HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */ 250 HTTP_RESPONSE_SETSIZE=0xffffffff 251 #endif 252 } HttpResponseNum; 253 254 typedef struct 255 { 256 HttpResponseNum type; 257 const char *name; 258 const char *info; 259 } HttpEnumString; 260 261 static const HttpEnumString httpResponseNames[] = { 262 { HTTP_OK, "OK", NULL }, 263 { HTTP_MOVED_TEMPORARILY, "Found", "Directories must end with a slash." }, 264 { HTTP_REQUEST_TIMEOUT, "Request Timeout", 265 "No request appeared within a reasonable time period." }, 266 { HTTP_NOT_IMPLEMENTED, "Not Implemented", 267 "The requested method is not recognized by this server." }, 268 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 269 { HTTP_UNAUTHORIZED, "Unauthorized", "" }, 270 #endif 271 { HTTP_NOT_FOUND, "Not Found", 272 "The requested URL was not found on this server." }, 273 { HTTP_BAD_REQUEST, "Bad Request", "Unsupported method." }, 274 { HTTP_FORBIDDEN, "Forbidden", "" }, 275 { HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error", 276 "Internal Server Error" }, 277 #if 0 /* not implemented */ 278 { HTTP_CREATED, "Created" }, 279 { HTTP_ACCEPTED, "Accepted" }, 280 { HTTP_NO_CONTENT, "No Content" }, 281 { HTTP_MULTIPLE_CHOICES, "Multiple Choices" }, 282 { HTTP_MOVED_PERMANENTLY, "Moved Permanently" }, 283 { HTTP_NOT_MODIFIED, "Not Modified" }, 284 { HTTP_BAD_GATEWAY, "Bad Gateway", "" }, 285 { HTTP_SERVICE_UNAVAILABLE, "Service Unavailable", "" }, 233 Htaccess_IP *ip_a_d; /* config allow/deny lines */ 234 235 USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;) 236 USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) 237 USE_FEATURE_HTTPD_CGI(char *referer;) 238 USE_FEATURE_HTTPD_CGI(char *user_agent;) 239 240 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 241 Htaccess *g_auth; /* config user:password lines */ 242 #endif 243 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 244 Htaccess *mime_a; /* config mime types */ 245 #endif 246 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 247 Htaccess *script_i; /* config script interpreters */ 248 #endif 249 char *iobuf; /* [IOBUF_SIZE] */ 250 #define hdr_buf bb_common_bufsiz1 251 char *hdr_ptr; 252 int hdr_cnt; 253 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 254 const char *http_error_page[ARRAY_SIZE(http_response_type)]; 286 255 #endif 287 256 }; 288 289 290 static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT"; 291 static const char Content_length[] = "Content-length:"; 292 293 294 static int 295 scan_ip (const char **ep, unsigned int *ip, unsigned char endc) 296 { 297 const char *p = *ep; 298 int auto_mask = 8; 299 int j; 300 301 *ip = 0; 302 for (j = 0; j < 4; j++) { 303 unsigned int octet; 304 305 if ((*p < '0' || *p > '9') && (*p != '/' || j == 0) && *p != 0) 306 return -auto_mask; 307 octet = 0; 308 while (*p >= '0' && *p <= '9') { 309 octet *= 10; 310 octet += *p - '0'; 311 if (octet > 255) 257 #define G (*ptr_to_globals) 258 #define verbose (G.verbose ) 259 #define flg_deny_all (G.flg_deny_all ) 260 #define rmt_ip (G.rmt_ip ) 261 #define bind_addr_or_port (G.bind_addr_or_port) 262 #define g_query (G.g_query ) 263 #define configFile (G.configFile ) 264 #define home_httpd (G.home_httpd ) 265 #define found_mime_type (G.found_mime_type ) 266 #define found_moved_temporarily (G.found_moved_temporarily) 267 #define ContentLength (G.ContentLength ) 268 #define last_mod (G.last_mod ) 269 #define ip_a_d (G.ip_a_d ) 270 #define g_realm (G.g_realm ) 271 #define remoteuser (G.remoteuser ) 272 #define referer (G.referer ) 273 #define user_agent (G.user_agent ) 274 #define rmt_ip_str (G.rmt_ip_str ) 275 #define g_auth (G.g_auth ) 276 #define mime_a (G.mime_a ) 277 #define script_i (G.script_i ) 278 #define iobuf (G.iobuf ) 279 #define hdr_ptr (G.hdr_ptr ) 280 #define hdr_cnt (G.hdr_cnt ) 281 #define http_error_page (G.http_error_page ) 282 #define INIT_G() do { \ 283 PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ 284 USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ 285 bind_addr_or_port = "80"; \ 286 ContentLength = -1; \ 287 } while (0) 288 289 290 #define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) 291 292 /* Prototypes */ 293 static void send_file_and_exit(const char *url, int headers) ATTRIBUTE_NORETURN; 294 295 static void free_llist(has_next_ptr **pptr) 296 { 297 has_next_ptr *cur = *pptr; 298 while (cur) { 299 has_next_ptr *t = cur; 300 cur = cur->next; 301 free(t); 302 } 303 *pptr = NULL; 304 } 305 306 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ 307 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ 308 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 309 static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr) 310 { 311 free_llist((has_next_ptr**)pptr); 312 } 313 #endif 314 315 static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr) 316 { 317 free_llist((has_next_ptr**)pptr); 318 } 319 320 /* Returns presumed mask width in bits or < 0 on error. 321 * Updates strp, stores IP at provided pointer */ 322 static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc) 323 { 324 const char *p = *strp; 325 int auto_mask = 8; 326 unsigned ip = 0; 327 int j; 328 329 if (*p == '/') 312 330 return -auto_mask; 313 p++; 314 } 315 if (*p == '.') 316 p++; 317 if (*p != '/' && *p != 0) 318 auto_mask += 8; 319 *ip = ((*ip) << 8) | octet; 320 } 321 if (*p != 0) { 322 if (*p != endc) 323 return -auto_mask; 324 p++; 325 if(*p == 0) 326 return -auto_mask; 327 } 328 *ep = p; 329 return auto_mask; 330 } 331 332 static int 333 scan_ip_mask (const char *ipm, unsigned int *ip, unsigned int *mask) 334 { 335 int i; 336 unsigned int msk; 337 338 i = scan_ip(&ipm, ip, '/'); 339 if(i < 0) 340 return i; 341 if(*ipm) { 342 const char *p = ipm; 343 344 i = 0; 345 while (*p) { 346 if (*p < '0' || *p > '9') { 347 if (*p == '.') { 348 i = scan_ip (&ipm, mask, 0); 349 return i != 32; 350 } 331 332 for (j = 0; j < 4; j++) { 333 unsigned octet; 334 335 if ((*p < '0' || *p > '9') && *p != '/' && *p) 336 return -auto_mask; 337 octet = 0; 338 while (*p >= '0' && *p <= '9') { 339 octet *= 10; 340 octet += *p - '0'; 341 if (octet > 255) 342 return -auto_mask; 343 p++; 344 } 345 if (*p == '.') 346 p++; 347 if (*p != '/' && *p) 348 auto_mask += 8; 349 ip = (ip << 8) | octet; 350 } 351 if (*p) { 352 if (*p != endc) 353 return -auto_mask; 354 p++; 355 if (*p == '\0') 356 return -auto_mask; 357 } 358 *ipp = ip; 359 *strp = p; 360 return auto_mask; 361 } 362 363 /* Returns 0 on success. Stores IP and mask at provided pointers */ 364 static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp) 365 { 366 int i; 367 unsigned mask; 368 char *p; 369 370 i = scan_ip(&str, ipp, '/'); 371 if (i < 0) 372 return i; 373 374 if (*str) { 375 /* there is /xxx after dotted-IP address */ 376 i = bb_strtou(str, &p, 10); 377 if (*p == '.') { 378 /* 'xxx' itself is dotted-IP mask, parse it */ 379 /* (return 0 (success) only if it has N.N.N.N form) */ 380 return scan_ip(&str, maskp, '\0') - 32; 381 } 382 if (*p) 351 383 return -1; 352 } 353 i *= 10; 354 i += *p - '0'; 355 p++; 356 } 357 } 358 if (i > 32 || i < 0) 359 return -1; 360 msk = 0x80000000; 361 *mask = 0; 362 while (i > 0) { 363 *mask |= msk; 364 msk >>= 1; 365 i--; 366 } 367 return 0; 368 } 369 370 #if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES) 371 static void free_config_lines(Htaccess **pprev) 372 { 373 Htaccess *prev = *pprev; 374 375 while( prev ) { 376 Htaccess *cur = prev; 377 378 prev = cur->next; 379 free(cur); 380 } 381 *pprev = NULL; 382 } 383 #endif 384 384 } 385 386 if (i > 32) 387 return -1; 388 389 if (sizeof(unsigned) == 4 && i == 32) { 390 /* mask >>= 32 below may not work */ 391 mask = 0; 392 } else { 393 mask = 0xffffffff; 394 mask >>= i; 395 } 396 /* i == 0 -> *maskp = 0x00000000 397 * i == 1 -> *maskp = 0x80000000 398 * i == 4 -> *maskp = 0xf0000000 399 * i == 31 -> *maskp = 0xfffffffe 400 * i == 32 -> *maskp = 0xffffffff */ 401 *maskp = (uint32_t)(~mask); 402 return 0; 403 } 404 405 /* 406 * Parse configuration file into in-memory linked list. 407 * 408 * The first non-white character is examined to determine if the config line 409 * is one of the following: 410 * .ext:mime/type # new mime type not compiled into httpd 411 * [adAD]:from # ip address allow/deny, * for wildcard 412 * /path:user:pass # username/password 413 * Ennn:error.html # error page for status nnn 414 * 415 * Any previous IP rules are discarded. 416 * If the flag argument is not SUBDIR_PARSE then all /path and mime rules 417 * are also discarded. That is, previous settings are retained if flag is 418 * SUBDIR_PARSE. 419 * Error pages are only parsed on the main config file. 420 * 421 * path Path where to look for httpd.conf (without filename). 422 * flag Type of the parse request. 423 */ 385 424 /* flag */ 386 425 #define FIRST_PARSE 0 … … 388 427 #define SIGNALED_PARSE 2 389 428 #define FIND_FROM_HTTPD_ROOT 3 390 /****************************************************************************391 *392 > $Function: parse_conf()393 *394 * $Description: parse configuration file into in-memory linked list.395 *396 * The first non-white character is examined to determine if the config line397 * is one of the following:398 * .ext:mime/type # new mime type not compiled into httpd399 * [adAD]:from # ip address allow/deny, * for wildcard400 * /path:user:pass # username/password401 *402 * Any previous IP rules are discarded.403 * If the flag argument is not SUBDIR_PARSE then all /path and mime rules404 * are also discarded. That is, previous settings are retained if flag is405 * SUBDIR_PARSE.406 *407 * $Parameters:408 * (const char *) path . . null for ip address checks, path for password409 * checks.410 * (int) flag . . . . . . the source of the parse request.411 *412 * $Return: (None)413 *414 ****************************************************************************/415 429 static void parse_conf(const char *path, int flag) 416 430 { 417 FILE *f; 418 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 419 Htaccess *prev, *cur; 420 #elif CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 421 Htaccess *cur; 422 #endif 423 424 const char *cf = config->configFile; 425 char buf[160]; 426 char *p0 = NULL; 427 char *c, *p; 428 429 /* free previous ip setup if present */ 430 Htaccess_IP *pip = config->ip_a_d; 431 432 while( pip ) { 433 Htaccess_IP *cur_ipl = pip; 434 435 pip = cur_ipl->next; 436 free(cur_ipl); 437 } 438 config->ip_a_d = NULL; 439 440 config->flg_deny_all = 0; 441 442 #if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR) 443 /* retain previous auth and mime config only for subdir parse */ 444 if(flag != SUBDIR_PARSE) { 445 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 446 free_config_lines(&config->auth); 447 #endif 448 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 449 free_config_lines(&config->mime_a); 450 #endif 451 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 452 free_config_lines(&config->script_i); 453 #endif 454 } 455 #endif 456 457 if(flag == SUBDIR_PARSE || cf == NULL) { 458 cf = alloca(strlen(path) + sizeof(httpd_conf) + 2); 459 if(cf == NULL) { 460 if(flag == FIRST_PARSE) 461 bb_error_msg_and_die(bb_msg_memory_exhausted); 462 return; 463 } 464 sprintf((char *)cf, "%s/%s", path, httpd_conf); 465 } 466 467 while((f = fopen(cf, "r")) == NULL) { 468 if(flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) { 469 /* config file not found, no changes to config */ 470 return; 471 } 472 if(config->configFile && flag == FIRST_PARSE) /* if -c option given */ 473 bb_perror_msg_and_die("%s", cf); 474 flag = FIND_FROM_HTTPD_ROOT; 475 cf = httpd_conf; 476 } 477 478 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 479 prev = config->auth; 480 #endif 481 /* This could stand some work */ 482 while ( (p0 = fgets(buf, sizeof(buf), f)) != NULL) { 483 c = NULL; 484 for(p = p0; *p0 != 0 && *p0 != '#'; p0++) { 485 if(!isspace(*p0)) { 486 *p++ = *p0; 487 if(*p0 == ':' && c == NULL) 488 c = p; 489 } 490 } 491 *p = 0; 492 493 /* test for empty or strange line */ 494 if (c == NULL || *c == 0) 495 continue; 496 p0 = buf; 497 if(*p0 == 'd') 498 *p0 = 'D'; 499 if(*c == '*') { 500 if(*p0 == 'D') { 501 /* memorize deny all */ 502 config->flg_deny_all++; 503 } 504 /* skip default other "word:*" config lines */ 505 continue; 506 } 507 508 if(*p0 == 'a') 509 *p0 = 'A'; 510 else if(*p0 != 'D' && *p0 != 'A' 511 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 512 && *p0 != '/' 513 #endif 514 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 515 && *p0 != '.' 516 #endif 517 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 518 && *p0 != '*' 519 #endif 520 ) 521 continue; 522 if(*p0 == 'A' || *p0 == 'D') { 523 /* storing current config IP line */ 524 pip = calloc(1, sizeof(Htaccess_IP)); 525 if(pip) { 526 if(scan_ip_mask (c, &(pip->ip), &(pip->mask))) { 527 /* syntax IP{/mask} error detected, protect all */ 431 FILE *f; 432 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 433 Htaccess *prev; 434 #endif 435 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ 436 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ 437 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 438 Htaccess *cur; 439 #endif 440 const char *cf = configFile; 441 char buf[160]; 442 char *p0 = NULL; 443 char *c, *p; 444 Htaccess_IP *pip; 445 446 /* discard old rules */ 447 free_Htaccess_IP_list(&ip_a_d); 448 flg_deny_all = 0; 449 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ 450 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ 451 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 452 /* retain previous auth and mime config only for subdir parse */ 453 if (flag != SUBDIR_PARSE) { 454 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 455 free_Htaccess_list(&g_auth); 456 #endif 457 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 458 free_Htaccess_list(&mime_a); 459 #endif 460 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 461 free_Htaccess_list(&script_i); 462 #endif 463 } 464 #endif 465 466 if (flag == SUBDIR_PARSE || cf == NULL) { 467 cf = alloca(strlen(path) + sizeof(httpd_conf) + 2); 468 sprintf((char *)cf, "%s/%s", path, httpd_conf); 469 } 470 471 while ((f = fopen(cf, "r")) == NULL) { 472 if (flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) { 473 /* config file not found, no changes to config */ 474 return; 475 } 476 if (configFile && flag == FIRST_PARSE) /* if -c option given */ 477 bb_perror_msg_and_die("%s", cf); 478 flag = FIND_FROM_HTTPD_ROOT; 479 cf = httpd_conf; 480 } 481 482 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 483 prev = g_auth; 484 #endif 485 /* This could stand some work */ 486 while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) { 487 c = NULL; 488 for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) { 489 if (!isspace(*p0)) { 490 *p++ = *p0; 491 if (*p0 == ':' && c == NULL) 492 c = p; 493 } 494 } 495 *p = '\0'; 496 497 /* test for empty or strange line */ 498 if (c == NULL || *c == '\0') 499 continue; 500 p0 = buf; 501 if (*p0 == 'd') 528 502 *p0 = 'D'; 529 pip->mask = 0; 530 } 531 pip->allow_deny = *p0; 532 if(*p0 == 'D') { 533 /* Deny:form_IP move top */ 534 pip->next = config->ip_a_d; 535 config->ip_a_d = pip; 536 } else { 537 /* add to bottom A:form_IP config line */ 538 Htaccess_IP *prev_IP = config->ip_a_d; 539 540 if(prev_IP == NULL) { 541 config->ip_a_d = pip; 542 } else { 543 while(prev_IP->next) 544 prev_IP = prev_IP->next; 545 prev_IP->next = pip; 546 } 547 } 548 } 549 continue; 550 } 551 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 552 if(*p0 == '/') { 553 /* make full path from httpd root / curent_path / config_line_path */ 554 cf = flag == SUBDIR_PARSE ? path : ""; 555 p0 = malloc(strlen(cf) + (c - buf) + 2 + strlen(c)); 556 if(p0 == NULL) 557 continue; 558 c[-1] = 0; 559 sprintf(p0, "/%s%s", cf, buf); 560 561 /* another call bb_simplify_path */ 562 cf = p = p0; 563 564 do { 565 if (*p == '/') { 566 if (*cf == '/') { /* skip duplicate (or initial) slash */ 567 continue; 568 } else if (*cf == '.') { 569 if (cf[1] == '/' || cf[1] == 0) { /* remove extra '.' */ 503 if (*c == '*') { 504 if (*p0 == 'D') { 505 /* memorize deny all */ 506 flg_deny_all = 1; 507 } 508 /* skip default other "word:*" config lines */ 509 continue; 510 } 511 512 if (*p0 == 'a') 513 *p0 = 'A'; 514 if (*p0 == 'A' || *p0 == 'D') { 515 /* storing current config IP line */ 516 pip = xzalloc(sizeof(Htaccess_IP)); 517 if (pip) { 518 if (scan_ip_mask(c, &(pip->ip), &(pip->mask))) { 519 /* syntax IP{/mask} error detected, protect all */ 520 *p0 = 'D'; 521 pip->mask = 0; 522 } 523 pip->allow_deny = *p0; 524 if (*p0 == 'D') { 525 /* Deny:from_IP move top */ 526 pip->next = ip_a_d; 527 ip_a_d = pip; 528 } else { 529 /* add to bottom A:form_IP config line */ 530 Htaccess_IP *prev_IP = ip_a_d; 531 532 if (prev_IP == NULL) { 533 ip_a_d = pip; 534 } else { 535 while (prev_IP->next) 536 prev_IP = prev_IP->next; 537 prev_IP->next = pip; 538 } 539 } 540 } 541 continue; 542 } 543 544 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 545 if (flag == FIRST_PARSE && *p0 == 'E') { 546 int i; 547 /* error status code */ 548 int status = atoi(++p0); 549 /* c already points at the character following ':' in parse loop */ 550 /* c = strchr(p0, ':'); c++; */ 551 if (status < HTTP_CONTINUE) { 552 bb_error_msg("config error '%s' in '%s'", buf, cf); 570 553 continue; 571 } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == 0)) { 572 ++cf; 573 if (p > p0) { 574 while (*--p != '/'); /* omit previous dir */ 575 } 576 continue; 577 } 578 } 579 } 580 *++p = *cf; 581 } while (*++cf); 582 583 if ((p == p0) || (*p != '/')) { /* not a trailing slash */ 584 ++p; /* so keep last character */ 585 } 586 *p = 0; 587 sprintf(p0, "%s:%s", p0, c); 588 } 589 #endif 590 591 #if defined(CONFIG_FEATURE_HTTPD_BASIC_AUTH) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES) || defined(CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR) 592 /* storing current config line */ 593 cur = calloc(1, sizeof(Htaccess) + strlen(p0)); 594 if(cur) { 595 cf = strcpy(cur->before_colon, p0); 596 c = strchr(cf, ':'); 597 *c++ = 0; 598 cur->after_colon = c; 599 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 600 if(*cf == '.') { 601 /* config .mime line move top for overwrite previous */ 602 cur->next = config->mime_a; 603 config->mime_a = cur; 604 continue; 605 } 606 #endif 607 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 608 if(*cf == '*' && cf[1] == '.') { 609 /* config script interpreter line move top for overwrite previous */ 610 cur->next = config->script_i; 611 config->script_i = cur; 612 continue; 613 } 614 #endif 615 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 616 free(p0); 617 if(prev == NULL) { 618 /* first line */ 619 config->auth = prev = cur; 620 } else { 621 /* sort path, if current lenght eq or bigger then move up */ 622 Htaccess *prev_hti = config->auth; 623 size_t l = strlen(cf); 624 Htaccess *hti; 625 626 for(hti = prev_hti; hti; hti = hti->next) { 627 if(l >= strlen(hti->before_colon)) { 628 /* insert before hti */ 629 cur->next = hti; 630 if(prev_hti != hti) { 631 prev_hti->next = cur; 632 } else { 633 /* insert as top */ 634 config->auth = cur; 635 } 636 break; 637 } 638 if(prev_hti != hti) 639 prev_hti = prev_hti->next; 640 } 641 if(!hti) { /* not inserted, add to bottom */ 642 prev->next = cur; 643 prev = cur; 644 } 645 } 646 #endif 647 } 648 #endif 649 } 650 fclose(f); 651 } 652 653 #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR 654 /**************************************************************************** 655 * 656 > $Function: encodeString() 657 * 658 * $Description: Given a string, html encode special characters. 659 * This is used for the -e command line option to provide an easy way 660 * for scripts to encode result data without confusing browsers. The 661 * returned string pointer is memory allocated by malloc(). 662 * 663 * $Parameters: 664 * (const char *) string . . The first string to encode. 665 * 666 * $Return: (char *) . . . .. . . A pointer to the encoded string. 667 * 668 * $Errors: Returns a null string ("") if memory is not available. 669 * 670 ****************************************************************************/ 671 static char *encodeString(const char *string) 672 { 673 /* take the simple route and encode everything */ 674 /* could possibly scan once to get length. */ 675 int len = strlen(string); 676 char *out = malloc(len * 6 + 1); 677 char *p=out; 678 char ch; 679 680 if (!out) return ""; 681 while ((ch = *string++)) { 682 // very simple check for what to encode 683 if (isalnum(ch)) *p++ = ch; 684 else p += sprintf(p, "&#%d;", (unsigned char) ch); 685 } 686 *p=0; 687 return out; 688 } 689 #endif /* CONFIG_FEATURE_HTTPD_ENCODE_URL_STR */ 690 691 /**************************************************************************** 692 * 693 > $Function: decodeString() 694 * 695 * $Description: Given a URL encoded string, convert it to plain ascii. 696 * Since decoding always makes strings smaller, the decode is done in-place. 697 * Thus, callers should strdup() the argument if they do not want the 698 * argument modified. The return is the original pointer, allowing this 699 * function to be easily used as arguments to other functions. 700 * 701 * $Parameters: 702 * (char *) string . . . The first string to decode. 703 * (int) flag . . . 1 if require decode '+' as ' ' for CGI 704 * 705 * $Return: (char *) . . . . A pointer to the decoded string (same as input). 706 * 707 * $Errors: None 708 * 709 ****************************************************************************/ 710 static char *decodeString(char *orig, int flag_plus_to_space) 711 { 712 /* note that decoded string is always shorter than original */ 713 char *string = orig; 714 char *ptr = string; 715 716 while (*ptr) 717 { 718 if (*ptr == '+' && flag_plus_to_space) { *string++ = ' '; ptr++; } 719 else if (*ptr != '%') *string++ = *ptr++; 720 else { 721 unsigned int value1, value2; 722 723 ptr++; 724 if(sscanf(ptr, "%1X", &value1) != 1 || 725 sscanf(ptr+1, "%1X", &value2) != 1) { 726 if(!flag_plus_to_space) 727 return NULL; 728 *string++ = '%'; 729 } else { 730 value1 = value1 * 16 + value2; 731 if(value1 == '/' || value1 == 0) 732 return orig+1; 733 *string++ = value1; 734 ptr += 2; 735 } 736 } 737 } 738 *string = '\0'; 739 return orig; 740 } 741 742 743 #ifdef CONFIG_FEATURE_HTTPD_CGI 744 /**************************************************************************** 745 * 746 > $Function: addEnv() 747 * 748 * $Description: Add an environment variable setting to the global list. 749 * A NAME=VALUE string is allocated, filled, and added to the list of 750 * environment settings passed to the cgi execution script. 751 * 752 * $Parameters: 753 * (char *) name_before_underline - The first part environment variable name. 754 * (char *) name_after_underline - The second part environment variable name. 755 * (char *) value . . The value to which the env variable is set. 756 * 757 * $Return: (void) 758 * 759 * $Errors: Silently returns if the env runs out of space to hold the new item 760 * 761 ****************************************************************************/ 762 static void addEnv(const char *name_before_underline, 763 const char *name_after_underline, const char *value) 764 { 765 char *s = NULL; 766 const char *underline; 767 768 if (!value) 769 value = ""; 770 underline = *name_after_underline ? "_" : ""; 771 asprintf(&s, "%s%s%s=%s", name_before_underline, underline, 772 name_after_underline, value); 773 if(s) { 774 putenv(s); 775 } 776 } 777 778 #if defined(CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV) || defined(CONFIG_FEATURE_HTTPD_WITHOUT_INETD) 779 /* set environs SERVER_PORT and REMOTE_PORT */ 780 static void addEnvPort(const char *port_name) 781 { 782 char buf[16]; 783 784 sprintf(buf, "%u", config->port); 785 addEnv(port_name, "PORT", buf); 786 } 787 #endif 788 #endif /* CONFIG_FEATURE_HTTPD_CGI */ 789 790 791 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 792 /**************************************************************************** 793 * 794 > $Function: decodeBase64() 795 * 796 > $Description: Decode a base 64 data stream as per rfc1521. 797 * Note that the rfc states that none base64 chars are to be ignored. 798 * Since the decode always results in a shorter size than the input, it is 799 * OK to pass the input arg as an output arg. 800 * 801 * $Parameter: 802 * (char *) Data . . . . A pointer to a base64 encoded string. 803 * Where to place the decoded data. 804 * 805 * $Return: void 806 * 807 * $Errors: None 808 * 809 ****************************************************************************/ 810 static void decodeBase64(char *Data) 811 { 812 813 const unsigned char *in = (const unsigned char *)Data; 814 // The decoded size will be at most 3/4 the size of the encoded 815 unsigned long ch = 0; 816 int i = 0; 817 818 while (*in) { 819 int t = *in++; 820 821 if(t >= '0' && t <= '9') 822 t = t - '0' + 52; 823 else if(t >= 'A' && t <= 'Z') 824 t = t - 'A'; 825 else if(t >= 'a' && t <= 'z') 826 t = t - 'a' + 26; 827 else if(t == '+') 828 t = 62; 829 else if(t == '/') 830 t = 63; 831 else if(t == '=') 832 t = 0; 833 else 834 continue; 835 836 ch = (ch << 6) | t; 837 i++; 838 if (i == 4) { 839 *Data++ = (char) (ch >> 16); 840 *Data++ = (char) (ch >> 8); 841 *Data++ = (char) ch; 842 i = 0; 843 } 844 } 845 *Data = 0; 846 } 847 #endif 848 849 850 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 851 /**************************************************************************** 852 * 853 > $Function: openServer() 854 * 855 * $Description: create a listen server socket on the designated port. 856 * 857 * $Return: (int) . . . A connection socket. -1 for errors. 858 * 859 * $Errors: None 860 * 861 ****************************************************************************/ 862 static int openServer(void) 863 { 864 struct sockaddr_in lsocket; 865 int fd; 866 int on = 1; 867 868 /* create the socket right now */ 869 /* inet_addr() returns a value that is already in network order */ 870 memset(&lsocket, 0, sizeof(lsocket)); 871 lsocket.sin_family = AF_INET; 872 lsocket.sin_addr.s_addr = INADDR_ANY; 873 lsocket.sin_port = htons(config->port); 874 fd = bb_xsocket(AF_INET, SOCK_STREAM, 0); 875 /* tell the OS it's OK to reuse a previous address even though */ 876 /* it may still be in a close down state. Allows bind to succeed. */ 877 #ifdef SO_REUSEPORT 878 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on)) ; 879 #else 880 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) ; 881 #endif 882 bb_xbind(fd, (struct sockaddr *)&lsocket, sizeof(lsocket)); 883 listen(fd, 9); /* bb_xlisten? */ 884 signal(SIGCHLD, SIG_IGN); /* prevent zombie (defunct) processes */ 885 return fd; 886 } 887 #endif /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */ 888 889 /**************************************************************************** 890 * 891 > $Function: sendHeaders() 892 * 893 * $Description: Create and send HTTP response headers. 894 * The arguments are combined and sent as one write operation. Note that 895 * IE will puke big-time if the headers are not sent in one packet and the 896 * second packet is delayed for any reason. 897 * 898 * $Parameter: 899 * (HttpResponseNum) responseNum . . . The result code to send. 900 * 901 * $Return: (int) . . . . writing errors 902 * 903 ****************************************************************************/ 904 static int sendHeaders(HttpResponseNum responseNum) 905 { 906 char *buf = config->buf; 907 const char *responseString = ""; 908 const char *infoString = 0; 909 const char *mime_type; 910 unsigned int i; 911 time_t timer = time(0); 912 char timeStr[80]; 913 int len; 914 915 for (i = 0; 916 i < (sizeof(httpResponseNames)/sizeof(httpResponseNames[0])); i++) { 917 if (httpResponseNames[i].type == responseNum) { 918 responseString = httpResponseNames[i].name; 919 infoString = httpResponseNames[i].info; 920 break; 921 } 922 } 923 /* error message is HTML */ 924 mime_type = responseNum == HTTP_OK ? 925 config->httpd_found.found_mime_type : "text/html"; 926 927 /* emit the current date */ 928 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer)); 929 len = sprintf(buf, 930 "HTTP/1.0 %d %s\r\nContent-type: %s\r\n" 931 "Date: %s\r\nConnection: close\r\n", 932 responseNum, responseString, mime_type, timeStr); 933 934 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 935 if (responseNum == HTTP_UNAUTHORIZED) { 936 len += sprintf(buf+len, "WWW-Authenticate: Basic realm=\"%s\"\r\n", 937 config->realm); 938 } 939 #endif 940 if(responseNum == HTTP_MOVED_TEMPORARILY) { 941 len += sprintf(buf+len, "Location: %s/%s%s\r\n", 942 config->httpd_found.found_moved_temporarily, 943 (config->query ? "?" : ""), 944 (config->query ? config->query : "")); 945 } 946 947 if (config->ContentLength != -1) { /* file */ 948 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod)); 949 len += sprintf(buf+len, "Last-Modified: %s\r\n%s " cont_l_fmt "\r\n", 950 timeStr, Content_length, cont_l_type config->ContentLength); 951 } 952 strcat(buf, "\r\n"); 953 len += 2; 954 if (infoString) { 955 len += sprintf(buf+len, 956 "<HEAD><TITLE>%d %s</TITLE></HEAD>\n" 957 "<BODY><H1>%d %s</H1>\n%s\n</BODY>\n", 958 responseNum, responseString, 959 responseNum, responseString, infoString); 960 } 961 #if DEBUG 962 fprintf(stderr, "Headers: '%s'", buf); 963 #endif 964 return bb_full_write(a_c_w, buf, len); 965 } 966 967 /**************************************************************************** 968 * 969 > $Function: getLine() 970 * 971 * $Description: Read from the socket until an end of line char found. 972 * 973 * Characters are read one at a time until an eol sequence is found. 974 * 975 * $Return: (int) . . . . number of characters read. -1 if error. 976 * 977 ****************************************************************************/ 978 static int getLine(void) 979 { 980 int count = 0; 981 char *buf = config->buf; 982 983 while (read(a_c_r, buf + count, 1) == 1) { 984 if (buf[count] == '\r') continue; 985 if (buf[count] == '\n') { 986 buf[count] = 0; 987 return count; 988 } 989 if(count < (MAX_MEMORY_BUFF-1)) /* check owerflow */ 990 count++; 991 } 992 if (count) return count; 993 else return -1; 994 } 995 996 #ifdef CONFIG_FEATURE_HTTPD_CGI 997 /**************************************************************************** 998 * 999 > $Function: sendCgi() 1000 * 1001 * $Description: Execute a CGI script and send it's stdout back 1002 * 1003 * Environment variables are set up and the script is invoked with pipes 1004 * for stdin/stdout. If a post is being done the script is fed the POST 1005 * data in addition to setting the QUERY_STRING variable (for GETs or POSTs). 1006 * 1007 * $Parameters: 1008 * (const char *) url . . . . . . The requested URL (with leading /). 1009 * (int bodyLen) . . . . . . . . Length of the post body. 1010 * (const char *cookie) . . . . . For set HTTP_COOKIE. 1011 * (const char *content_type) . . For set CONTENT_TYPE. 1012 1013 * 1014 * $Return: (char *) . . . . A pointer to the decoded string (same as input). 1015 * 1016 * $Errors: None 1017 * 1018 ****************************************************************************/ 1019 static int sendCgi(const char *url, 1020 const char *request, int bodyLen, const char *cookie, 1021 const char *content_type) 1022 { 1023 int fromCgi[2]; /* pipe for reading data from CGI */ 1024 int toCgi[2]; /* pipe for sending data to CGI */ 1025 1026 static char * argp[] = { 0, 0 }; 1027 int pid = 0; 1028 int inFd; 1029 int outFd; 1030 int firstLine = 1; 1031 1032 do { 1033 if (pipe(fromCgi) != 0) { 1034 break; 1035 } 1036 if (pipe(toCgi) != 0) { 1037 break; 1038 } 1039 1040 pid = fork(); 1041 if (pid < 0) { 1042 pid = 0; 1043 break; 1044 } 1045 1046 if (!pid) { 1047 /* child process */ 1048 char *script; 1049 char *purl = strdup( url ); 1050 char realpath_buff[MAXPATHLEN]; 1051 1052 if(purl == NULL) 1053 _exit(242); 1054 1055 inFd = toCgi[0]; 1056 outFd = fromCgi[1]; 1057 1058 dup2(inFd, 0); // replace stdin with the pipe 1059 dup2(outFd, 1); // replace stdout with the pipe 1060 if(!DEBUG) 1061 dup2(outFd, 2); // replace stderr with the pipe 1062 1063 close(toCgi[0]); 1064 close(toCgi[1]); 1065 close(fromCgi[0]); 1066 close(fromCgi[1]); 1067 1068 /* 1069 * Find PATH_INFO. 1070 */ 1071 script = purl; 1072 while((script = strchr( script + 1, '/' )) != NULL) { 1073 /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */ 1074 struct stat sb; 1075 1076 *script = '\0'; 1077 if(is_directory(purl + 1, 1, &sb) == 0) { 1078 /* not directory, found script.cgi/PATH_INFO */ 1079 *script = '/'; 1080 break; 1081 } 1082 *script = '/'; /* is directory, find next '/' */ 1083 } 1084 addEnv("PATH", "INFO", script); /* set /PATH_INFO or NULL */ 1085 addEnv("PATH", "", getenv("PATH")); 1086 addEnv("REQUEST", "METHOD", request); 1087 if(config->query) { 1088 char *uri = alloca(strlen(purl) + 2 + strlen(config->query)); 1089 if(uri) 1090 sprintf(uri, "%s?%s", purl, config->query); 1091 addEnv("REQUEST", "URI", uri); 1092 } else { 1093 addEnv("REQUEST", "URI", purl); 1094 } 1095 if(script != NULL) 1096 *script = '\0'; /* reduce /PATH_INFO */ 1097 /* SCRIPT_FILENAME required by PHP in CGI mode */ 1098 if(realpath(purl + 1, realpath_buff)) 1099 addEnv("SCRIPT", "FILENAME", realpath_buff); 1100 else 1101 *realpath_buff = 0; 1102 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ 1103 addEnv("SCRIPT_NAME", "", purl); 1104 addEnv("QUERY_STRING", "", config->query); 1105 addEnv("SERVER", "SOFTWARE", httpdVersion); 1106 addEnv("SERVER", "PROTOCOL", "HTTP/1.0"); 1107 addEnv("GATEWAY_INTERFACE", "", "CGI/1.1"); 1108 addEnv("REMOTE", "ADDR", config->rmt_ip_str); 1109 #ifdef CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 1110 addEnvPort("REMOTE"); 1111 #endif 1112 if(bodyLen) { 1113 char sbl[32]; 1114 1115 sprintf(sbl, "%d", bodyLen); 1116 addEnv("CONTENT", "LENGTH", sbl); 1117 } 1118 if(cookie) 1119 addEnv("HTTP", "COOKIE", cookie); 1120 if(content_type) 1121 addEnv("CONTENT", "TYPE", content_type); 1122 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1123 if(config->remoteuser) { 1124 addEnv("REMOTE", "USER", config->remoteuser); 1125 addEnv("AUTH_TYPE", "", "Basic"); 1126 } 1127 #endif 1128 if(config->referer) 1129 addEnv("HTTP", "REFERER", config->referer); 1130 1131 /* set execve argp[0] without path */ 1132 argp[0] = strrchr( purl, '/' ) + 1; 1133 /* but script argp[0] must have absolute path and chdiring to this */ 1134 if(*realpath_buff) { 1135 script = strrchr(realpath_buff, '/'); 1136 if(script) { 1137 *script = '\0'; 1138 if(chdir(realpath_buff) == 0) { 1139 // now run the program. If it fails, 1140 // use _exit() so no destructors 1141 // get called and make a mess. 1142 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1143 char *interpr = NULL; 1144 char *suffix = strrchr(purl, '.'); 1145 1146 if(suffix) { 1147 Htaccess * cur; 1148 for (cur = config->script_i; cur; cur = cur->next) 1149 if(strcmp(cur->before_colon + 1, suffix) == 0) { 1150 interpr = cur->after_colon; 554 } 555 556 /* then error page; find matching status */ 557 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { 558 if (http_response_type[i] == status) { 559 http_error_page[i] = concat_path_file((*c == '/') ? NULL : home_httpd, c); 1151 560 break; 1152 561 } 1153 } 1154 #endif 1155 *script = '/'; 1156 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1157 if (interpr) 1158 execv(interpr, argp); 1159 else 1160 #endif 1161 execv(realpath_buff, argp); 1162 } 1163 } 1164 } 1165 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1166 config->accepted_socket = 1; /* send to stdout */ 1167 #endif 1168 sendHeaders(HTTP_NOT_FOUND); 1169 _exit(242); 1170 } /* end child */ 1171 1172 } while (0); 1173 1174 if (pid) { 1175 /* parent process */ 1176 int status; 1177 size_t post_readed_size = 0, post_readed_idx = 0; 1178 1179 inFd = fromCgi[0]; 1180 outFd = toCgi[1]; 1181 close(fromCgi[1]); 1182 close(toCgi[0]); 1183 signal(SIGPIPE, SIG_IGN); 1184 1185 while (1) { 1186 fd_set readSet; 1187 fd_set writeSet; 1188 char wbuf[128]; 1189 int nfound; 1190 int count; 1191 1192 FD_ZERO(&readSet); 1193 FD_ZERO(&writeSet); 1194 FD_SET(inFd, &readSet); 1195 if(bodyLen > 0 || post_readed_size > 0) { 1196 FD_SET(outFd, &writeSet); 1197 nfound = outFd > inFd ? outFd : inFd; 1198 if(post_readed_size == 0) { 1199 FD_SET(a_c_r, &readSet); 1200 if(nfound < a_c_r) 1201 nfound = a_c_r; 1202 } 1203 /* Now wait on the set of sockets! */ 1204 nfound = select(nfound + 1, &readSet, &writeSet, 0, NULL); 1205 } else { 1206 if(!bodyLen) { 1207 close(outFd); 1208 bodyLen = -1; 1209 } 1210 nfound = select(inFd + 1, &readSet, 0, 0, NULL); 1211 } 1212 1213 if (nfound <= 0) { 1214 if (waitpid(pid, &status, WNOHANG) > 0) { 1215 close(inFd); 562 } 563 continue; 564 } 565 #endif 566 567 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 568 if (*p0 == '/') { 569 /* make full path from httpd root / current_path / config_line_path */ 570 cf = (flag == SUBDIR_PARSE ? path : ""); 571 p0 = xmalloc(strlen(cf) + (c - buf) + 2 + strlen(c)); 572 c[-1] = '\0'; 573 sprintf(p0, "/%s%s", cf, buf); 574 575 /* another call bb_simplify_path */ 576 cf = p = p0; 577 578 do { 579 if (*p == '/') { 580 if (*cf == '/') { /* skip duplicate (or initial) slash */ 581 continue; 582 } else if (*cf == '.') { 583 if (cf[1] == '/' || cf[1] == '\0') { /* remove extra '.' */ 584 continue; 585 } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == '\0')) { 586 ++cf; 587 if (p > p0) { 588 while (*--p != '/') /* omit previous dir */; 589 } 590 continue; 591 } 592 } 593 } 594 *++p = *cf; 595 } while (*++cf); 596 597 if ((p == p0) || (*p != '/')) { /* not a trailing slash */ 598 ++p; /* so keep last character */ 599 } 600 *p = '\0'; 601 sprintf(p0 + strlen(p0), ":%s", c); 602 } 603 #endif 604 605 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH \ 606 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES \ 607 || ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 608 /* storing current config line */ 609 cur = xzalloc(sizeof(Htaccess) + strlen(p0)); 610 if (cur) { 611 cf = strcpy(cur->before_colon, p0); 612 c = strchr(cf, ':'); 613 *c++ = 0; 614 cur->after_colon = c; 615 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 616 if (*cf == '.') { 617 /* config .mime line move top for overwrite previous */ 618 cur->next = mime_a; 619 mime_a = cur; 620 continue; 621 } 622 #endif 623 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 624 if (*cf == '*' && cf[1] == '.') { 625 /* config script interpreter line move top for overwrite previous */ 626 cur->next = script_i; 627 script_i = cur; 628 continue; 629 } 630 #endif 631 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 632 free(p0); 633 if (prev == NULL) { 634 /* first line */ 635 g_auth = prev = cur; 636 } else { 637 /* sort path, if current lenght eq or bigger then move up */ 638 Htaccess *prev_hti = g_auth; 639 size_t l = strlen(cf); 640 Htaccess *hti; 641 642 for (hti = prev_hti; hti; hti = hti->next) { 643 if (l >= strlen(hti->before_colon)) { 644 /* insert before hti */ 645 cur->next = hti; 646 if (prev_hti != hti) { 647 prev_hti->next = cur; 648 } else { 649 /* insert as top */ 650 g_auth = cur; 651 } 652 break; 653 } 654 if (prev_hti != hti) 655 prev_hti = prev_hti->next; 656 } 657 if (!hti) { /* not inserted, add to bottom */ 658 prev->next = cur; 659 prev = cur; 660 } 661 } 662 #endif 663 } 664 #endif 665 } 666 fclose(f); 667 } 668 669 #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR 670 /* 671 * Given a string, html-encode special characters. 672 * This is used for the -e command line option to provide an easy way 673 * for scripts to encode result data without confusing browsers. The 674 * returned string pointer is memory allocated by malloc(). 675 * 676 * Returns a pointer to the encoded string (malloced). 677 */ 678 static char *encodeString(const char *string) 679 { 680 /* take the simple route and encode everything */ 681 /* could possibly scan once to get length. */ 682 int len = strlen(string); 683 char *out = xmalloc(len * 6 + 1); 684 char *p = out; 685 char ch; 686 687 while ((ch = *string++)) { 688 /* very simple check for what to encode */ 689 if (isalnum(ch)) 690 *p++ = ch; 691 else 692 p += sprintf(p, "&#%d;", (unsigned char) ch); 693 } 694 *p = '\0'; 695 return out; 696 } 697 #endif /* FEATURE_HTTPD_ENCODE_URL_STR */ 698 699 /* 700 * Given a URL encoded string, convert it to plain ascii. 701 * Since decoding always makes strings smaller, the decode is done in-place. 702 * Thus, callers should strdup() the argument if they do not want the 703 * argument modified. The return is the original pointer, allowing this 704 * function to be easily used as arguments to other functions. 705 * 706 * string The first string to decode. 707 * option_d 1 if called for httpd -d 708 * 709 * Returns a pointer to the decoded string (same as input). 710 */ 711 static unsigned hex_to_bin(unsigned char c) 712 { 713 unsigned v; 714 715 v = c - '0'; 716 if (v <= 9) 717 return v; 718 /* c | 0x20: letters to lower case, non-letters 719 * to (potentially different) non-letters */ 720 v = (unsigned)(c | 0x20) - 'a'; 721 if (v <= 5) 722 return v + 10; 723 return ~0; 724 } 725 /* For testing: 726 void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } 727 int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); 728 t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } 729 */ 730 static char *decodeString(char *orig, int option_d) 731 { 732 /* note that decoded string is always shorter than original */ 733 char *string = orig; 734 char *ptr = string; 735 char c; 736 737 while ((c = *ptr++) != '\0') { 738 unsigned v; 739 740 if (option_d && c == '+') { 741 *string++ = ' '; 742 continue; 743 } 744 if (c != '%') { 745 *string++ = c; 746 continue; 747 } 748 v = hex_to_bin(ptr[0]); 749 if (v > 15) { 750 bad_hex: 751 if (!option_d) 752 return NULL; 753 *string++ = '%'; 754 continue; 755 } 756 v = (v * 16) | hex_to_bin(ptr[1]); 757 if (v > 255) 758 goto bad_hex; 759 if (!option_d && (v == '/' || v == '\0')) { 760 /* caller takes it as indication of invalid 761 * (dangerous wrt exploits) chars */ 762 return orig + 1; 763 } 764 *string++ = v; 765 ptr += 2; 766 } 767 *string = '\0'; 768 return orig; 769 } 770 771 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 772 /* 773 * Decode a base64 data stream as per rfc1521. 774 * Note that the rfc states that non base64 chars are to be ignored. 775 * Since the decode always results in a shorter size than the input, 776 * it is OK to pass the input arg as an output arg. 777 * Parameter: a pointer to a base64 encoded string. 778 * Decoded data is stored in-place. 779 */ 780 static void decodeBase64(char *Data) 781 { 782 const unsigned char *in = (const unsigned char *)Data; 783 /* The decoded size will be at most 3/4 the size of the encoded */ 784 unsigned ch = 0; 785 int i = 0; 786 787 while (*in) { 788 int t = *in++; 789 790 if (t >= '0' && t <= '9') 791 t = t - '0' + 52; 792 else if (t >= 'A' && t <= 'Z') 793 t = t - 'A'; 794 else if (t >= 'a' && t <= 'z') 795 t = t - 'a' + 26; 796 else if (t == '+') 797 t = 62; 798 else if (t == '/') 799 t = 63; 800 else if (t == '=') 801 t = 0; 802 else 803 continue; 804 805 ch = (ch << 6) | t; 806 i++; 807 if (i == 4) { 808 *Data++ = (char) (ch >> 16); 809 *Data++ = (char) (ch >> 8); 810 *Data++ = (char) ch; 811 i = 0; 812 } 813 } 814 *Data = '\0'; 815 } 816 #endif 817 818 /* 819 * Create a listen server socket on the designated port. 820 */ 821 static int openServer(void) 822 { 823 int n = bb_strtou(bind_addr_or_port, NULL, 10); 824 if (!errno && n && n <= 0xffff) 825 n = create_and_bind_stream_or_die(NULL, n); 826 else 827 n = create_and_bind_stream_or_die(bind_addr_or_port, 80); 828 xlisten(n, 9); 829 return n; 830 } 831 832 /* 833 * Log the connection closure and exit. 834 */ 835 static void log_and_exit(void) ATTRIBUTE_NORETURN; 836 static void log_and_exit(void) 837 { 838 /* Paranoia. IE said to be buggy. It may send some extra data 839 * or be confused by us just exiting without SHUT_WR. Oh well. */ 840 shutdown(1, SHUT_WR); 841 ndelay_on(0); 842 while (read(0, iobuf, IOBUF_SIZE) > 0) 843 continue; 844 845 if (verbose > 2) 846 bb_error_msg("closed"); 847 _exit(xfunc_error_retval); 848 } 849 850 /* 851 * Create and send HTTP response headers. 852 * The arguments are combined and sent as one write operation. Note that 853 * IE will puke big-time if the headers are not sent in one packet and the 854 * second packet is delayed for any reason. 855 * responseNum - the result code to send. 856 */ 857 static void send_headers(int responseNum) 858 { 859 static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT"; 860 861 const char *responseString = ""; 862 const char *infoString = NULL; 863 const char *mime_type; 864 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 865 const char *error_page = 0; 866 #endif 867 unsigned i; 868 time_t timer = time(0); 869 char tmp_str[80]; 870 int len; 871 872 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { 873 if (http_response_type[i] == responseNum) { 874 responseString = http_response[i].name; 875 infoString = http_response[i].info; 876 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 877 error_page = http_error_page[i]; 878 #endif 879 break; 880 } 881 } 882 /* error message is HTML */ 883 mime_type = responseNum == HTTP_OK ? 884 found_mime_type : "text/html"; 885 886 if (verbose) 887 bb_error_msg("response:%u", responseNum); 888 889 /* emit the current date */ 890 strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&timer)); 891 len = sprintf(iobuf, 892 "HTTP/1.0 %d %s\r\nContent-type: %s\r\n" 893 "Date: %s\r\nConnection: close\r\n", 894 responseNum, responseString, mime_type, tmp_str); 895 896 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 897 if (responseNum == HTTP_UNAUTHORIZED) { 898 len += sprintf(iobuf + len, 899 "WWW-Authenticate: Basic realm=\"%s\"\r\n", 900 g_realm); 901 } 902 #endif 903 if (responseNum == HTTP_MOVED_TEMPORARILY) { 904 len += sprintf(iobuf + len, "Location: %s/%s%s\r\n", 905 found_moved_temporarily, 906 (g_query ? "?" : ""), 907 (g_query ? g_query : "")); 908 } 909 910 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES 911 if (error_page && !access(error_page, R_OK)) { 912 strcat(iobuf, "\r\n"); 913 len += 2; 914 915 if (DEBUG) 916 fprintf(stderr, "headers: '%s'\n", iobuf); 917 full_write(1, iobuf, len); 918 if (DEBUG) 919 fprintf(stderr, "writing error page: '%s'\n", error_page); 920 return send_file_and_exit(error_page, FALSE); 921 } 922 #endif 923 924 if (ContentLength != -1) { /* file */ 925 strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&last_mod)); 926 len += sprintf(iobuf + len, "Last-Modified: %s\r\n%s %"OFF_FMT"d\r\n", 927 tmp_str, "Content-length:", ContentLength); 928 } 929 iobuf[len++] = '\r'; 930 iobuf[len++] = '\n'; 931 if (infoString) { 932 len += sprintf(iobuf + len, 933 "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n" 934 "<BODY><H1>%d %s</H1>\n%s\n</BODY></HTML>\n", 935 responseNum, responseString, 936 responseNum, responseString, infoString); 937 } 938 if (DEBUG) 939 fprintf(stderr, "headers: '%s'\n", iobuf); 940 if (full_write(1, iobuf, len) != len) { 941 if (verbose > 1) 942 bb_perror_msg("error"); 943 log_and_exit(); 944 } 945 } 946 947 static void send_headers_and_exit(int responseNum) ATTRIBUTE_NORETURN; 948 static void send_headers_and_exit(int responseNum) 949 { 950 send_headers(responseNum); 951 log_and_exit(); 952 } 953 954 /* 955 * Read from the socket until '\n' or EOF. '\r' chars are removed. 956 * '\n' is replaced with NUL. 957 * Return number of characters read or 0 if nothing is read 958 * ('\r' and '\n' are not counted). 959 * Data is returned in iobuf. 960 */ 961 static int get_line(void) 962 { 963 int count = 0; 964 char c; 965 966 while (1) { 967 if (hdr_cnt <= 0) { 968 hdr_cnt = safe_read(0, hdr_buf, sizeof(hdr_buf)); 969 if (hdr_cnt <= 0) 970 break; 971 hdr_ptr = hdr_buf; 972 } 973 iobuf[count] = c = *hdr_ptr++; 974 hdr_cnt--; 975 976 if (c == '\r') 977 continue; 978 if (c == '\n') { 979 iobuf[count] = '\0'; 980 return count; 981 } 982 if (count < (IOBUF_SIZE - 1)) /* check overflow */ 983 count++; 984 } 985 return count; 986 } 987 988 #if ENABLE_FEATURE_HTTPD_CGI 989 static void setenv1(const char *name, const char *value) 990 { 991 setenv(name, value ? value : "", 1); 992 } 993 994 /* 995 * Spawn CGI script, forward CGI's stdin/out <=> network 996 * 997 * Environment variables are set up and the script is invoked with pipes 998 * for stdin/stdout. If a post is being done the script is fed the POST 999 * data in addition to setting the QUERY_STRING variable (for GETs or POSTs). 1000 * 1001 * Parameters: 1002 * const char *url The requested URL (with leading /). 1003 * int bodyLen Length of the post body. 1004 * const char *cookie For set HTTP_COOKIE. 1005 * const char *content_type For set CONTENT_TYPE. 1006 */ 1007 static void send_cgi_and_exit( 1008 const char *url, 1009 const char *request, 1010 int bodyLen, 1011 const char *cookie, 1012 const char *content_type) ATTRIBUTE_NORETURN; 1013 static void send_cgi_and_exit( 1014 const char *url, 1015 const char *request, 1016 int bodyLen, 1017 const char *cookie, 1018 const char *content_type) 1019 { 1020 struct { int rd; int wr; } fromCgi; /* CGI -> httpd pipe */ 1021 struct { int rd; int wr; } toCgi; /* httpd -> CGI pipe */ 1022 char *fullpath; 1023 char *script; 1024 char *purl; 1025 int buf_count; 1026 int status; 1027 int pid = 0; 1028 1029 /* 1030 * We are mucking with environment _first_ and then vfork/exec, 1031 * this allows us to use vfork safely. Parent don't care about 1032 * these environment changes anyway. 1033 */ 1034 1035 /* 1036 * Find PATH_INFO. 1037 */ 1038 purl = xstrdup(url); 1039 script = purl; 1040 while ((script = strchr(script + 1, '/')) != NULL) { 1041 /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */ 1042 struct stat sb; 1043 1044 *script = '\0'; 1045 if (!is_directory(purl + 1, 1, &sb)) { 1046 /* not directory, found script.cgi/PATH_INFO */ 1047 *script = '/'; 1048 break; 1049 } 1050 *script = '/'; /* is directory, find next '/' */ 1051 } 1052 setenv1("PATH_INFO", script); /* set /PATH_INFO or "" */ 1053 setenv1("REQUEST_METHOD", request); 1054 if (g_query) { 1055 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", purl, g_query)); 1056 } else { 1057 setenv1("REQUEST_URI", purl); 1058 } 1059 if (script != NULL) 1060 *script = '\0'; /* cut off /PATH_INFO */ 1061 1062 /* SCRIPT_FILENAME required by PHP in CGI mode */ 1063 fullpath = concat_path_file(home_httpd, purl); 1064 setenv1("SCRIPT_FILENAME", fullpath); 1065 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ 1066 setenv1("SCRIPT_NAME", purl); 1067 /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html: 1068 * QUERY_STRING: The information which follows the ? in the URL 1069 * which referenced this script. This is the query information. 1070 * It should not be decoded in any fashion. This variable 1071 * should always be set when there is query information, 1072 * regardless of command line decoding. */ 1073 /* (Older versions of bbox seem to do some decoding) */ 1074 setenv1("QUERY_STRING", g_query); 1075 putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER); 1076 putenv((char*)"SERVER_PROTOCOL=HTTP/1.0"); 1077 putenv((char*)"GATEWAY_INTERFACE=CGI/1.1"); 1078 /* Having _separate_ variables for IP and port defeats 1079 * the purpose of having socket abstraction. Which "port" 1080 * are you using on Unix domain socket? 1081 * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense. 1082 * Oh well... */ 1083 { 1084 char *p = rmt_ip_str ? rmt_ip_str : (char*)""; 1085 char *cp = strrchr(p, ':'); 1086 if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']')) 1087 cp = NULL; 1088 if (cp) *cp = '\0'; /* delete :PORT */ 1089 setenv1("REMOTE_ADDR", p); 1090 if (cp) { 1091 *cp = ':'; 1092 #if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 1093 setenv1("REMOTE_PORT", cp + 1); 1094 #endif 1095 } 1096 } 1097 setenv1("HTTP_USER_AGENT", user_agent); 1098 if (bodyLen) 1099 putenv(xasprintf("CONTENT_LENGTH=%d", bodyLen)); 1100 if (cookie) 1101 setenv1("HTTP_COOKIE", cookie); 1102 if (content_type) 1103 setenv1("CONTENT_TYPE", content_type); 1104 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1105 if (remoteuser) { 1106 setenv1("REMOTE_USER", remoteuser); 1107 putenv((char*)"AUTH_TYPE=Basic"); 1108 } 1109 #endif 1110 if (referer) 1111 setenv1("HTTP_REFERER", referer); 1112 1113 xpipe(&fromCgi.rd); 1114 xpipe(&toCgi.rd); 1115 1116 pid = vfork(); 1117 if (pid < 0) { 1118 /* TODO: log perror? */ 1119 log_and_exit(); 1120 } 1121 1122 if (!pid) { 1123 /* Child process */ 1124 xfunc_error_retval = 242; 1125 1126 xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */ 1127 xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */ 1128 close(fromCgi.rd); 1129 close(toCgi.wr); 1130 /* User seeing stderr output can be a security problem. 1131 * If CGI really wants that, it can always do dup itself. */ 1132 /* dup2(1, 2); */ 1133 1134 /* script must have absolute path */ 1135 script = strrchr(fullpath, '/'); 1136 if (!script) 1137 goto error_execing_cgi; 1138 *script = '\0'; 1139 /* chdiring to script's dir */ 1140 if (chdir(fullpath) == 0) { 1141 char *argv[2]; 1142 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1143 char *interpr = NULL; 1144 char *suffix = strrchr(purl, '.'); 1145 1146 if (suffix) { 1147 Htaccess *cur; 1148 for (cur = script_i; cur; cur = cur->next) { 1149 if (strcmp(cur->before_colon + 1, suffix) == 0) { 1150 interpr = cur->after_colon; 1151 break; 1152 } 1153 } 1154 } 1155 #endif 1156 *script = '/'; 1157 /* set argv[0] to name without path */ 1158 argv[0] = (char*)bb_basename(purl); 1159 argv[1] = NULL; 1160 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1161 if (interpr) 1162 execv(interpr, argv); 1163 else 1164 #endif 1165 execv(fullpath, argv); 1166 } 1167 error_execing_cgi: 1168 /* send to stdout 1169 * (we are CGI here, our stdout is pumped to the net) */ 1170 send_headers_and_exit(HTTP_NOT_FOUND); 1171 } /* end child */ 1172 1173 /* Parent process */ 1174 1175 /* First, restore variables possibly changed by child */ 1176 xfunc_error_retval = 0; 1177 1178 /* Prepare for pumping data. 1179 * iobuf is used for CGI -> network data, 1180 * hdr_buf is for network -> CGI data (POSTDATA) */ 1181 buf_count = 0; 1182 close(fromCgi.wr); 1183 close(toCgi.rd); 1184 1185 /* If CGI dies, we still want to correctly finish reading its output 1186 * and send it to the peer. So please no SIGPIPEs! */ 1187 signal(SIGPIPE, SIG_IGN); 1188 1189 /* This loop still looks messy. What is an exit criteria? 1190 * "CGI's output closed"? Or "CGI has exited"? 1191 * What to do if CGI has closed both input and output, but 1192 * didn't exit? etc... */ 1193 1194 /* NB: breaking out of this loop jumps to log_and_exit() */ 1195 while (1) { 1196 fd_set readSet; 1197 fd_set writeSet; 1198 int nfound; 1199 int count; 1200 1201 FD_ZERO(&readSet); 1202 FD_ZERO(&writeSet); 1203 FD_SET(fromCgi.rd, &readSet); 1204 if (bodyLen > 0 || hdr_cnt > 0) { 1205 FD_SET(toCgi.wr, &writeSet); 1206 nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd; 1207 if (hdr_cnt <= 0) 1208 FD_SET(0, &readSet); 1209 /* Now wait on the set of sockets! */ 1210 nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL); 1211 } else { 1212 if (!bodyLen) { 1213 close(toCgi.wr); /* no more POST data to CGI */ 1214 bodyLen = -1; 1215 } 1216 nfound = select(fromCgi.rd + 1, &readSet, NULL, NULL, NULL); 1217 } 1218 1219 if (nfound <= 0) { 1220 if (waitpid(pid, &status, WNOHANG) <= 0) { 1221 /* Weird. CGI didn't exit and no fd's 1222 * are ready, yet select returned?! */ 1223 continue; 1224 } 1225 close(fromCgi.rd); 1226 if (DEBUG && WIFEXITED(status)) 1227 bb_error_msg("CGI exited, status=%d", WEXITSTATUS(status)); 1228 if (DEBUG && WIFSIGNALED(status)) 1229 bb_error_msg("CGI killed, signal=%d", WTERMSIG(status)); 1230 break; 1231 } 1232 1233 if (hdr_cnt > 0 && FD_ISSET(toCgi.wr, &writeSet)) { 1234 /* Have data from peer and can write to CGI */ 1235 count = safe_write(toCgi.wr, hdr_ptr, hdr_cnt); 1236 /* Doesn't happen, we dont use nonblocking IO here 1237 *if (count < 0 && errno == EAGAIN) { 1238 * ... 1239 *} else */ 1240 if (count > 0) { 1241 hdr_ptr += count; 1242 hdr_cnt -= count; 1243 } else { 1244 hdr_cnt = bodyLen = 0; /* EOF/broken pipe to CGI */ 1245 } 1246 } else if (bodyLen > 0 && hdr_cnt == 0 1247 && FD_ISSET(0, &readSet) 1248 ) { 1249 /* We expect data, prev data portion is eaten by CGI 1250 * and there *is* data to read from the peer 1251 * (POSTDATA?) */ 1252 count = bodyLen > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : bodyLen; 1253 count = safe_read(0, hdr_buf, count); 1254 if (count > 0) { 1255 hdr_cnt = count; 1256 hdr_ptr = hdr_buf; 1257 bodyLen -= count; 1258 } else { 1259 bodyLen = 0; /* closed */ 1260 } 1261 } 1262 1263 #define PIPESIZE PIPE_BUF 1264 #if PIPESIZE >= IOBUF_SIZE 1265 # error "PIPESIZE >= IOBUF_SIZE" 1266 #endif 1267 if (FD_ISSET(fromCgi.rd, &readSet)) { 1268 /* There is something to read from CGI */ 1269 char *rbuf = iobuf; 1270 1271 /* Are we still buffering CGI output? */ 1272 if (buf_count >= 0) { 1273 /* HTTP_200[] has single "\r\n" at the end. 1274 * According to http://hoohoo.ncsa.uiuc.edu/cgi/out.html, 1275 * CGI scripts MUST send their own header terminated by 1276 * empty line, then data. That's why we have only one 1277 * <cr><lf> pair here. We will output "200 OK" line 1278 * if needed, but CGI still has to provide blank line 1279 * between header and body */ 1280 1281 /* Must use safe_read, not full_read, because 1282 * CGI may output a few first bytes and then wait 1283 * for POSTDATA without closing stdout. 1284 * With full_read we may wait here forever. */ 1285 count = safe_read(fromCgi.rd, rbuf + buf_count, PIPESIZE - 8); 1286 if (count <= 0) { 1287 /* eof (or error) and there was no "HTTP", 1288 * so write it, then write received data */ 1289 if (buf_count) { 1290 full_write(1, HTTP_200, sizeof(HTTP_200)-1); 1291 full_write(1, rbuf, buf_count); 1292 } 1293 break; /* CGI stdout is closed, exiting */ 1294 } 1295 buf_count += count; 1296 count = 0; 1297 /* "Status" header format is: "Status: 302 Redirected\r\n" */ 1298 if (buf_count >= 8 && memcmp(rbuf, "Status: ", 8) == 0) { 1299 /* send "HTTP/1.0 " */ 1300 if (full_write(1, HTTP_200, 9) != 9) 1301 break; 1302 rbuf += 8; /* skip "Status: " */ 1303 count = buf_count - 8; 1304 buf_count = -1; /* buffering off */ 1305 } else if (buf_count >= 4) { 1306 /* Did CGI add "HTTP"? */ 1307 if (memcmp(rbuf, HTTP_200, 4) != 0) { 1308 /* there is no "HTTP", do it ourself */ 1309 if (full_write(1, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1) 1310 break; 1311 } 1312 /* Commented out: 1313 if (!strstr(rbuf, "ontent-")) { 1314 full_write(s, "Content-type: text/plain\r\n\r\n", 28); 1315 } 1316 * Counter-example of valid CGI without Content-type: 1317 * echo -en "HTTP/1.0 302 Found\r\n" 1318 * echo -en "Location: http://www.busybox.net\r\n" 1319 * echo -en "\r\n" 1320 */ 1321 count = buf_count; 1322 buf_count = -1; /* buffering off */ 1323 } 1324 } else { 1325 count = safe_read(fromCgi.rd, rbuf, PIPESIZE); 1326 if (count <= 0) 1327 break; /* eof (or error) */ 1328 } 1329 if (full_write(1, rbuf, count) != count) 1330 break; 1331 if (DEBUG) 1332 fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf); 1333 } /* if (FD_ISSET(fromCgi.rd)) */ 1334 } /* while (1) */ 1335 log_and_exit(); 1336 } 1337 #endif /* FEATURE_HTTPD_CGI */ 1338 1339 /* 1340 * Send a file response to a HTTP request, and exit 1341 * 1342 * Parameters: 1343 * const char *url The requested URL (with leading /). 1344 * headers Don't send headers before if FALSE. 1345 */ 1346 static void send_file_and_exit(const char *url, int headers) 1347 { 1348 static const char *const suffixTable[] = { 1349 /* Warning: shorter equivalent suffix in one line must be first */ 1350 ".htm.html", "text/html", 1351 ".jpg.jpeg", "image/jpeg", 1352 ".gif", "image/gif", 1353 ".png", "image/png", 1354 ".txt.h.c.cc.cpp", "text/plain", 1355 ".css", "text/css", 1356 ".wav", "audio/wav", 1357 ".avi", "video/x-msvideo", 1358 ".qt.mov", "video/quicktime", 1359 ".mpe.mpeg", "video/mpeg", 1360 ".mid.midi", "audio/midi", 1361 ".mp3", "audio/mpeg", 1362 #if 0 /* unpopular */ 1363 ".au", "audio/basic", 1364 ".pac", "application/x-ns-proxy-autoconfig", 1365 ".vrml.wrl", "model/vrml", 1366 #endif 1367 NULL 1368 }; 1369 1370 char *suffix; 1371 int f; 1372 const char *const *table; 1373 const char *try_suffix; 1374 ssize_t count; 1375 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1376 off_t offset = 0; 1377 #endif 1378 1379 suffix = strrchr(url, '.'); 1380 1381 /* If not found, set default as "application/octet-stream"; */ 1382 found_mime_type = "application/octet-stream"; 1383 if (suffix) { 1384 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 1385 Htaccess *cur; 1386 #endif 1387 for (table = suffixTable; *table; table += 2) { 1388 try_suffix = strstr(table[0], suffix); 1389 if (try_suffix) { 1390 try_suffix += strlen(suffix); 1391 if (*try_suffix == '\0' || *try_suffix == '.') { 1392 found_mime_type = table[1]; 1393 break; 1394 } 1395 } 1396 } 1397 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 1398 for (cur = mime_a; cur; cur = cur->next) { 1399 if (strcmp(cur->before_colon, suffix) == 0) { 1400 found_mime_type = cur->after_colon; 1401 break; 1402 } 1403 } 1404 #endif 1405 } 1406 1407 if (DEBUG) 1408 bb_error_msg("sending file '%s' content-type: %s", 1409 url, found_mime_type); 1410 1411 f = open(url, O_RDONLY); 1412 if (f < 0) { 1413 if (DEBUG) 1414 bb_perror_msg("cannot open '%s'", url); 1415 if (headers) 1416 send_headers_and_exit(HTTP_NOT_FOUND); 1417 } 1418 1419 if (headers) 1420 send_headers(HTTP_OK); 1421 1422 /* If you want to know about EPIPE below 1423 * (happens if you abort downloads from local httpd): */ 1424 signal(SIGPIPE, SIG_IGN); 1425 1426 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1427 do { 1428 /* byte count (3rd arg) is rounded down to 64k */ 1429 count = sendfile(1, f, &offset, MAXINT(ssize_t) - 0xffff); 1430 if (count < 0) { 1431 if (offset == 0) 1432 goto fallback; 1433 goto fin; 1434 } 1435 } while (count > 0); 1436 log_and_exit(); 1437 1438 fallback: 1439 #endif 1440 while ((count = safe_read(f, iobuf, IOBUF_SIZE)) > 0) { 1441 ssize_t n = count; 1442 count = full_write(1, iobuf, count); 1443 if (count != n) 1444 break; 1445 } 1446 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1447 fin: 1448 #endif 1449 if (count < 0 && verbose > 1) 1450 bb_perror_msg("error"); 1451 log_and_exit(); 1452 } 1453 1454 static int checkPermIP(void) 1455 { 1456 Htaccess_IP *cur; 1457 1458 /* This could stand some work */ 1459 for (cur = ip_a_d; cur; cur = cur->next) { 1216 1460 #if DEBUG 1217 if (WIFEXITED(status)) 1218 bb_error_msg("piped has exited with status=%d", WEXITSTATUS(status)); 1219 if (WIFSIGNALED(status)) 1220 bb_error_msg("piped has exited with signal=%d", WTERMSIG(status)); 1221 #endif 1222 break; 1223 } 1224 } else if(post_readed_size > 0 && FD_ISSET(outFd, &writeSet)) { 1225 count = bb_full_write(outFd, wbuf + post_readed_idx, post_readed_size); 1226 if(count > 0) { 1227 post_readed_size -= count; 1228 post_readed_idx += count; 1229 if(post_readed_size == 0) 1230 post_readed_idx = 0; 1231 } else { 1232 post_readed_size = post_readed_idx = bodyLen = 0; /* broken pipe to CGI */ 1233 } 1234 } else if(bodyLen > 0 && post_readed_size == 0 && FD_ISSET(a_c_r, &readSet)) { 1235 count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen; 1236 count = safe_read(a_c_r, wbuf, count); 1237 if(count > 0) { 1238 post_readed_size += count; 1239 bodyLen -= count; 1240 } else { 1241 bodyLen = 0; /* closed */ 1242 } 1243 } 1244 if(FD_ISSET(inFd, &readSet)) { 1245 int s = a_c_w; 1246 char *rbuf = config->buf; 1247 1248 #ifndef PIPE_BUF 1249 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 1461 fprintf(stderr, 1462 "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n", 1463 rmt_ip_str, 1464 (unsigned char)(cur->ip >> 24), 1465 (unsigned char)(cur->ip >> 16), 1466 (unsigned char)(cur->ip >> 8), 1467 (unsigned char)(cur->ip), 1468 (unsigned char)(cur->mask >> 24), 1469 (unsigned char)(cur->mask >> 16), 1470 (unsigned char)(cur->mask >> 8), 1471 (unsigned char)(cur->mask) 1472 ); 1473 #endif 1474 if ((rmt_ip & cur->mask) == cur->ip) 1475 return cur->allow_deny == 'A'; /* Allow/Deny */ 1476 } 1477 1478 /* if unconfigured, return 1 - access from all */ 1479 return !flg_deny_all; 1480 } 1481 1482 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1483 /* 1484 * Check the permission file for access password protected. 1485 * 1486 * If config file isn't present, everything is allowed. 1487 * Entries are of the form you can see example from header source 1488 * 1489 * path The file path. 1490 * request User information to validate. 1491 * 1492 * Returns 1 if request is OK. 1493 */ 1494 static int checkPerm(const char *path, const char *request) 1495 { 1496 Htaccess *cur; 1497 const char *p; 1498 const char *p0; 1499 1500 const char *prev = NULL; 1501 1502 /* This could stand some work */ 1503 for (cur = g_auth; cur; cur = cur->next) { 1504 size_t l; 1505 1506 p0 = cur->before_colon; 1507 if (prev != NULL && strcmp(prev, p0) != 0) 1508 continue; /* find next identical */ 1509 p = cur->after_colon; 1510 if (DEBUG) 1511 fprintf(stderr, "checkPerm: '%s' ? '%s'\n", p0, request); 1512 1513 l = strlen(p0); 1514 if (strncmp(p0, path, l) == 0 1515 && (l == 1 || path[l] == '/' || path[l] == '\0') 1516 ) { 1517 char *u; 1518 /* path match found. Check request */ 1519 /* for check next /path:user:password */ 1520 prev = p0; 1521 u = strchr(request, ':'); 1522 if (u == NULL) { 1523 /* bad request, ':' required */ 1524 break; 1525 } 1526 1527 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { 1528 char *cipher; 1529 char *pp; 1530 1531 if (strncmp(p, request, u - request) != 0) { 1532 /* user doesn't match */ 1533 continue; 1534 } 1535 pp = strchr(p, ':'); 1536 if (pp && pp[1] == '$' && pp[2] == '1' 1537 && pp[3] == '$' && pp[4] 1538 ) { 1539 pp++; 1540 cipher = pw_encrypt(u+1, pp); 1541 if (strcmp(cipher, pp) == 0) 1542 goto set_remoteuser_var; /* Ok */ 1543 /* unauthorized */ 1544 continue; 1545 } 1546 } 1547 1548 if (strcmp(p, request) == 0) { 1549 set_remoteuser_var: 1550 remoteuser = strdup(request); 1551 if (remoteuser) 1552 remoteuser[u - request] = '\0'; 1553 return 1; /* Ok */ 1554 } 1555 /* unauthorized */ 1556 } 1557 } /* for */ 1558 1559 return prev == NULL; 1560 } 1561 #endif /* FEATURE_HTTPD_BASIC_AUTH */ 1562 1563 /* 1564 * Handle timeouts 1565 */ 1566 static void exit_on_signal(int sig) ATTRIBUTE_NORETURN; 1567 static void exit_on_signal(int sig) 1568 { 1569 send_headers_and_exit(HTTP_REQUEST_TIMEOUT); 1570 } 1571 1572 /* 1573 * Handle an incoming http request and exit. 1574 */ 1575 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) ATTRIBUTE_NORETURN; 1576 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) 1577 { 1578 static const char request_GET[] ALIGN1 = "GET"; 1579 1580 struct stat sb; 1581 char *urlcopy; 1582 char *urlp; 1583 char *tptr; 1584 int http_major_version; 1585 int ip_allowed; 1586 #if ENABLE_FEATURE_HTTPD_CGI 1587 const char *prequest; 1588 unsigned long length = 0; 1589 char *cookie = 0; 1590 char *content_type = 0; 1591 #endif 1592 struct sigaction sa; 1593 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1594 int credentials = -1; /* if not required this is Ok */ 1595 #endif 1596 1597 /* Allocation of iobuf is postponed until now 1598 * (IOW, server process doesn't need to waste 8k) */ 1599 iobuf = xmalloc(IOBUF_SIZE); 1600 1601 rmt_ip = 0; 1602 if (fromAddr->sa.sa_family == AF_INET) { 1603 rmt_ip = ntohl(fromAddr->sin.sin_addr.s_addr); 1604 } 1605 #if ENABLE_FEATURE_IPV6 1606 if (fromAddr->sa.sa_family == AF_INET6 1607 && fromAddr->sin6.sin6_addr.s6_addr32[0] == 0 1608 && fromAddr->sin6.sin6_addr.s6_addr32[1] == 0 1609 && ntohl(fromAddr->sin6.sin6_addr.s6_addr32[2]) == 0xffff) 1610 rmt_ip = ntohl(fromAddr->sin6.sin6_addr.s6_addr32[3]); 1611 #endif 1612 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { 1613 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->sa); 1614 } 1615 if (verbose) { 1616 /* this trick makes -v logging much simpler */ 1617 applet_name = rmt_ip_str; 1618 if (verbose > 2) 1619 bb_error_msg("connected"); 1620 } 1621 1622 /* Install timeout handler */ 1623 memset(&sa, 0, sizeof(sa)); 1624 sa.sa_handler = exit_on_signal; 1625 /* sigemptyset(&sa.sa_mask); - memset should be enough */ 1626 /*sa.sa_flags = 0; - no SA_RESTART */ 1627 sigaction(SIGALRM, &sa, NULL); 1628 alarm(HEADER_READ_TIMEOUT); 1629 1630 if (!get_line()) /* EOF or error or empty line */ 1631 send_headers_and_exit(HTTP_BAD_REQUEST); 1632 1633 /* Determine type of request (GET/POST) */ 1634 urlp = strpbrk(iobuf, " \t"); 1635 if (urlp == NULL) 1636 send_headers_and_exit(HTTP_BAD_REQUEST); 1637 *urlp++ = '\0'; 1638 #if ENABLE_FEATURE_HTTPD_CGI 1639 prequest = request_GET; 1640 if (strcasecmp(iobuf, prequest) != 0) { 1641 prequest = "POST"; 1642 if (strcasecmp(iobuf, prequest) != 0) 1643 send_headers_and_exit(HTTP_NOT_IMPLEMENTED); 1644 } 1250 1645 #else 1251 # define PIPESIZE PIPE_BUF 1252 #endif 1253 #if PIPESIZE >= MAX_MEMORY_BUFF 1254 # error "PIPESIZE >= MAX_MEMORY_BUFF" 1255 #endif 1256 1257 // There is something to read 1258 count = safe_read(inFd, rbuf, PIPESIZE); 1259 if (count == 0) 1260 break; /* closed */ 1261 if (count > 0) { 1262 if (firstLine) { 1263 rbuf[count] = 0; 1264 /* check to see if the user script added headers */ 1265 if(strncmp(rbuf, "HTTP/1.0 200 OK\r\n", 4) != 0) { 1266 bb_full_write(s, "HTTP/1.0 200 OK\r\n", 17); 1267 } 1268 if (strstr(rbuf, "ontent-") == 0) { 1269 bb_full_write(s, "Content-type: text/plain\r\n\r\n", 28); 1270 } 1271 firstLine = 0; 1272 } 1273 if (bb_full_write(s, rbuf, count) != count) 1274 break; 1275 1276 #if DEBUG 1277 fprintf(stderr, "cgi read %d bytes\n", count); 1278 #endif 1279 } 1280 } 1281 } 1282 } 1283 return 0; 1284 } 1285 #endif /* CONFIG_FEATURE_HTTPD_CGI */ 1286 1287 /**************************************************************************** 1288 * 1289 > $Function: sendFile() 1290 * 1291 * $Description: Send a file response to an HTTP request 1292 * 1293 * $Parameter: 1294 * (const char *) url . . The URL requested. 1295 * 1296 * $Return: (int) . . . . . . Always 0. 1297 * 1298 ****************************************************************************/ 1299 static int sendFile(const char *url) 1300 { 1301 char * suffix; 1302 int f; 1303 const char * const * table; 1304 const char * try_suffix; 1305 1306 suffix = strrchr(url, '.'); 1307 1308 for (table = suffixTable; *table; table += 2) 1309 if(suffix != NULL && (try_suffix = strstr(*table, suffix)) != 0) { 1310 try_suffix += strlen(suffix); 1311 if(*try_suffix == 0 || *try_suffix == '.') 1312 break; 1313 } 1314 /* also, if not found, set default as "application/octet-stream"; */ 1315 config->httpd_found.found_mime_type = *(table+1); 1316 #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES 1317 if (suffix) { 1318 Htaccess * cur; 1319 1320 for (cur = config->mime_a; cur; cur = cur->next) { 1321 if(strcmp(cur->before_colon, suffix) == 0) { 1322 config->httpd_found.found_mime_type = cur->after_colon; 1323 break; 1324 } 1325 } 1326 } 1327 #endif /* CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES */ 1328 1329 #if DEBUG 1330 fprintf(stderr, "Sending file '%s' Content-type: %s\n", 1331 url, config->httpd_found.found_mime_type); 1332 #endif 1333 1334 f = open(url, O_RDONLY); 1335 if (f >= 0) { 1336 int count; 1337 char *buf = config->buf; 1338 1339 sendHeaders(HTTP_OK); 1340 while ((count = bb_full_read(f, buf, MAX_MEMORY_BUFF)) > 0) { 1341 if (bb_full_write(a_c_w, buf, count) != count) 1342 break; 1343 } 1344 close(f); 1345 } else { 1346 #if DEBUG 1347 bb_perror_msg("Unable to open '%s'", url); 1348 #endif 1349 sendHeaders(HTTP_NOT_FOUND); 1350 } 1351 1352 return 0; 1353 } 1354 1355 static int checkPermIP(void) 1356 { 1357 Htaccess_IP * cur; 1358 1359 /* This could stand some work */ 1360 for (cur = config->ip_a_d; cur; cur = cur->next) { 1361 #if DEBUG 1362 fprintf(stderr, "checkPermIP: '%s' ? ", config->rmt_ip_str); 1363 fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n", 1364 (unsigned char)(cur->ip >> 24), 1365 (unsigned char)(cur->ip >> 16), 1366 (unsigned char)(cur->ip >> 8), 1367 cur->ip & 0xff, 1368 (unsigned char)(cur->mask >> 24), 1369 (unsigned char)(cur->mask >> 16), 1370 (unsigned char)(cur->mask >> 8), 1371 cur->mask & 0xff); 1372 #endif 1373 if((config->rmt_ip & cur->mask) == cur->ip) 1374 return cur->allow_deny == 'A'; /* Allow/Deny */ 1375 } 1376 1377 /* if unconfigured, return 1 - access from all */ 1378 return !config->flg_deny_all; 1379 } 1380 1381 /**************************************************************************** 1382 * 1383 > $Function: checkPerm() 1384 * 1385 * $Description: Check the permission file for access password protected. 1386 * 1387 * If config file isn't present, everything is allowed. 1388 * Entries are of the form you can see example from header source 1389 * 1390 * $Parameters: 1391 * (const char *) path . . . . The file path. 1392 * (const char *) request . . . User information to validate. 1393 * 1394 * $Return: (int) . . . . . . . . . 1 if request OK, 0 otherwise. 1395 * 1396 ****************************************************************************/ 1397 1398 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1399 static int checkPerm(const char *path, const char *request) 1400 { 1401 Htaccess * cur; 1402 const char *p; 1403 const char *p0; 1404 1405 const char *prev = NULL; 1406 1407 /* This could stand some work */ 1408 for (cur = config->auth; cur; cur = cur->next) { 1409 p0 = cur->before_colon; 1410 if(prev != NULL && strcmp(prev, p0) != 0) 1411 continue; /* find next identical */ 1412 p = cur->after_colon; 1413 #if DEBUG 1414 fprintf(stderr,"checkPerm: '%s' ? '%s'\n", p0, request); 1415 #endif 1646 if (strcasecmp(iobuf, request_GET) != 0) 1647 send_headers_and_exit(HTTP_NOT_IMPLEMENTED); 1648 #endif 1649 urlp = skip_whitespace(urlp); 1650 if (urlp[0] != '/') 1651 send_headers_and_exit(HTTP_BAD_REQUEST); 1652 1653 /* Find end of URL and parse HTTP version, if any */ 1654 http_major_version = -1; 1655 tptr = strchrnul(urlp, ' '); 1656 /* Is it " HTTP/"? */ 1657 if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0) 1658 http_major_version = (tptr[6] - '0'); 1659 *tptr = '\0'; 1660 1661 /* Copy URL from after "GET "/"POST " to stack-allocated char[] */ 1662 urlcopy = alloca((tptr - urlp) + sizeof("/index.html")); 1663 /*if (urlcopy == NULL) 1664 * send_headers_and_exit(HTTP_INTERNAL_SERVER_ERROR);*/ 1665 strcpy(urlcopy, urlp); 1666 /* NB: urlcopy ptr is never changed after this */ 1667 1668 /* Extract url args if present */ 1669 tptr = strchr(urlcopy, '?'); 1670 g_query = NULL; 1671 if (tptr) { 1672 *tptr++ = '\0'; 1673 g_query = tptr; 1674 } 1675 1676 /* Decode URL escape sequences */ 1677 tptr = decodeString(urlcopy, 0); 1678 if (tptr == NULL) 1679 send_headers_and_exit(HTTP_BAD_REQUEST); 1680 if (tptr == urlcopy + 1) { 1681 /* '/' or NUL is encoded */ 1682 send_headers_and_exit(HTTP_NOT_FOUND); 1683 } 1684 1685 /* Canonicalize path */ 1686 /* Algorithm stolen from libbb bb_simplify_path(), 1687 * but don't strdup and reducing trailing slash and protect out root */ 1688 urlp = tptr = urlcopy; 1689 do { 1690 if (*urlp == '/') { 1691 /* skip duplicate (or initial) slash */ 1692 if (*tptr == '/') { 1693 continue; 1694 } 1695 if (*tptr == '.') { 1696 /* skip extra '.' */ 1697 if (tptr[1] == '/' || !tptr[1]) { 1698 continue; 1699 } 1700 /* '..': be careful */ 1701 if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) { 1702 ++tptr; 1703 if (urlp == urlcopy) /* protect root */ 1704 send_headers_and_exit(HTTP_BAD_REQUEST); 1705 while (*--urlp != '/') /* omit previous dir */; 1706 continue; 1707 } 1708 } 1709 } 1710 *++urlp = *tptr; 1711 } while (*++tptr); 1712 *++urlp = '\0'; /* so keep last character */ 1713 tptr = urlp; /* end ptr */ 1714 1715 /* If URL is a directory, add '/' */ 1716 if (tptr[-1] != '/') { 1717 if (is_directory(urlcopy + 1, 1, &sb)) { 1718 found_moved_temporarily = urlcopy; 1719 } 1720 } 1721 1722 /* Log it */ 1723 if (verbose > 1) 1724 bb_error_msg("url:%s", urlcopy); 1725 1726 tptr = urlcopy; 1727 ip_allowed = checkPermIP(); 1728 while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) { 1729 /* have path1/path2 */ 1730 *tptr = '\0'; 1731 if (is_directory(urlcopy + 1, 1, &sb)) { 1732 /* may be having subdir config */ 1733 parse_conf(urlcopy + 1, SUBDIR_PARSE); 1734 ip_allowed = checkPermIP(); 1735 } 1736 *tptr = '/'; 1737 } 1738 if (http_major_version >= 0) { 1739 /* Request was with "... HTTP/nXXX", and n >= 0 */ 1740 1741 /* Read until blank line for HTTP version specified, else parse immediate */ 1742 while (1) { 1743 alarm(HEADER_READ_TIMEOUT); 1744 if (!get_line()) 1745 break; /* EOF or error or empty line */ 1746 if (DEBUG) 1747 bb_error_msg("header: '%s'", iobuf); 1748 1749 #if ENABLE_FEATURE_HTTPD_CGI 1750 /* try and do our best to parse more lines */ 1751 if ((STRNCASECMP(iobuf, "Content-length:") == 0)) { 1752 /* extra read only for POST */ 1753 if (prequest != request_GET) { 1754 tptr = iobuf + sizeof("Content-length:") - 1; 1755 if (!tptr[0]) 1756 send_headers_and_exit(HTTP_BAD_REQUEST); 1757 errno = 0; 1758 /* not using strtoul: it ignores leading minus! */ 1759 length = strtol(tptr, &tptr, 10); 1760 /* length is "ulong", but we need to pass it to int later */ 1761 /* so we check for negative or too large values in one go: */ 1762 /* (long -> ulong conv caused negatives to be seen as > INT_MAX) */ 1763 if (tptr[0] || errno || length > INT_MAX) 1764 send_headers_and_exit(HTTP_BAD_REQUEST); 1765 } 1766 } else if (STRNCASECMP(iobuf, "Cookie:") == 0) { 1767 cookie = strdup(skip_whitespace(iobuf + sizeof("Cookie:")-1)); 1768 } else if (STRNCASECMP(iobuf, "Content-Type:") == 0) { 1769 content_type = strdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1)); 1770 } else if (STRNCASECMP(iobuf, "Referer:") == 0) { 1771 referer = strdup(skip_whitespace(iobuf + sizeof("Referer:")-1)); 1772 } else if (STRNCASECMP(iobuf, "User-Agent:") == 0) { 1773 user_agent = strdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1)); 1774 } 1775 #endif 1776 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1777 if (STRNCASECMP(iobuf, "Authorization:") == 0) { 1778 /* We only allow Basic credentials. 1779 * It shows up as "Authorization: Basic <userid:password>" where 1780 * the userid:password is base64 encoded. 1781 */ 1782 tptr = skip_whitespace(iobuf + sizeof("Authorization:")-1); 1783 if (STRNCASECMP(tptr, "Basic") != 0) 1784 continue; 1785 tptr += sizeof("Basic")-1; 1786 /* decodeBase64() skips whitespace itself */ 1787 decodeBase64(tptr); 1788 credentials = checkPerm(urlcopy, tptr); 1789 } 1790 #endif /* FEATURE_HTTPD_BASIC_AUTH */ 1791 } /* while extra header reading */ 1792 } 1793 1794 /* We read headers, disable peer timeout */ 1795 alarm(0); 1796 1797 if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || ip_allowed == 0) { 1798 /* protect listing [/path]/httpd_conf or IP deny */ 1799 send_headers_and_exit(HTTP_FORBIDDEN); 1800 } 1801 1802 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1803 if (credentials <= 0 && checkPerm(urlcopy, ":") == 0) { 1804 send_headers_and_exit(HTTP_UNAUTHORIZED); 1805 } 1806 #endif 1807 1808 if (found_moved_temporarily) { 1809 send_headers_and_exit(HTTP_MOVED_TEMPORARILY); 1810 } 1811 1812 tptr = urlcopy + 1; /* skip first '/' */ 1813 1814 #if ENABLE_FEATURE_HTTPD_CGI 1815 if (strncmp(tptr, "cgi-bin/", 8) == 0) { 1816 if (tptr[8] == '\0') { 1817 /* protect listing "cgi-bin/" */ 1818 send_headers_and_exit(HTTP_FORBIDDEN); 1819 } 1820 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); 1821 } 1822 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1416 1823 { 1417 size_t l = strlen(p0); 1418 1419 if(strncmp(p0, path, l) == 0 && 1420 (l == 1 || path[l] == '/' || path[l] == 0)) { 1421 char *u; 1422 /* path match found. Check request */ 1423 /* for check next /path:user:password */ 1424 prev = p0; 1425 u = strchr(request, ':'); 1426 if(u == NULL) { 1427 /* bad request, ':' required */ 1428 break; 1429 } 1430 1431 #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5 1432 { 1433 char *cipher; 1434 char *pp; 1435 1436 if(strncmp(p, request, u-request) != 0) { 1437 /* user uncompared */ 1438 continue; 1439 } 1440 pp = strchr(p, ':'); 1441 if(pp && pp[1] == '$' && pp[2] == '1' && 1442 pp[3] == '$' && pp[4]) { 1443 pp++; 1444 cipher = pw_encrypt(u+1, pp); 1445 if (strcmp(cipher, pp) == 0) 1446 goto set_remoteuser_var; /* Ok */ 1447 /* unauthorized */ 1448 continue; 1449 } 1450 } 1451 #endif 1452 if (strcmp(p, request) == 0) { 1453 #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5 1454 set_remoteuser_var: 1455 #endif 1456 config->remoteuser = strdup(request); 1457 if(config->remoteuser) 1458 config->remoteuser[(u - request)] = 0; 1459 return 1; /* Ok */ 1460 } 1461 /* unauthorized */ 1462 } 1463 } 1464 } /* for */ 1465 1466 return prev == NULL; 1467 } 1468 1469 #endif /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */ 1470 1471 /**************************************************************************** 1472 * 1473 > $Function: handle_sigalrm() 1474 * 1475 * $Description: Handle timeouts 1476 * 1477 ****************************************************************************/ 1478 1479 static void 1480 handle_sigalrm( int sig ) 1481 { 1482 sendHeaders(HTTP_REQUEST_TIMEOUT); 1483 config->alarm_signaled = sig; 1484 } 1485 1486 /**************************************************************************** 1487 * 1488 > $Function: handleIncoming() 1489 * 1490 * $Description: Handle an incoming http request. 1491 * 1492 ****************************************************************************/ 1493 static void handleIncoming(void) 1494 { 1495 char *buf = config->buf; 1496 char *url; 1497 char *purl; 1498 int blank = -1; 1499 char *test; 1500 struct stat sb; 1501 int ip_allowed; 1502 #ifdef CONFIG_FEATURE_HTTPD_CGI 1503 const char *prequest = request_GET; 1504 long length=0; 1505 char *cookie = 0; 1506 char *content_type = 0; 1507 #endif 1508 fd_set s_fd; 1509 struct timeval tv; 1510 int retval; 1511 struct sigaction sa; 1512 1513 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1514 int credentials = -1; /* if not requred this is Ok */ 1515 #endif 1516 1517 sa.sa_handler = handle_sigalrm; 1518 sigemptyset(&sa.sa_mask); 1519 sa.sa_flags = 0; /* no SA_RESTART */ 1520 sigaction(SIGALRM, &sa, NULL); 1521 1522 do { 1523 int count; 1524 1525 (void) alarm( TIMEOUT ); 1526 if (getLine() <= 0) 1527 break; /* closed */ 1528 1529 purl = strpbrk(buf, " \t"); 1530 if(purl == NULL) { 1531 BAD_REQUEST: 1532 sendHeaders(HTTP_BAD_REQUEST); 1533 break; 1534 } 1535 *purl = 0; 1536 #ifdef CONFIG_FEATURE_HTTPD_CGI 1537 if(strcasecmp(buf, prequest) != 0) { 1538 prequest = "POST"; 1539 if(strcasecmp(buf, prequest) != 0) { 1540 sendHeaders(HTTP_NOT_IMPLEMENTED); 1541 break; 1542 } 1543 } 1824 char *suffix = strrchr(tptr, '.'); 1825 if (suffix) { 1826 Htaccess *cur; 1827 for (cur = script_i; cur; cur = cur->next) { 1828 if (strcmp(cur->before_colon + 1, suffix) == 0) { 1829 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); 1830 } 1831 } 1832 } 1833 } 1834 #endif 1835 if (prequest != request_GET) { 1836 send_headers_and_exit(HTTP_NOT_IMPLEMENTED); 1837 } 1838 #endif /* FEATURE_HTTPD_CGI */ 1839 1840 if (urlp[-1] == '/') 1841 strcpy(urlp, "index.html"); 1842 if (stat(tptr, &sb) == 0) { 1843 /* It's a dir URL and there is index.html */ 1844 ContentLength = sb.st_size; 1845 last_mod = sb.st_mtime; 1846 } 1847 #if ENABLE_FEATURE_HTTPD_CGI 1848 else if (urlp[-1] == '/') { 1849 /* It's a dir URL and there is no index.html 1850 * Try cgi-bin/index.cgi */ 1851 if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { 1852 urlp[0] = '\0'; 1853 g_query = urlcopy; 1854 send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type); 1855 } 1856 } 1857 #endif 1858 /* else { 1859 * fall through to send_file, it errors out if open fails 1860 * } 1861 */ 1862 1863 send_file_and_exit(tptr, TRUE); 1864 } 1865 1866 /* 1867 * The main http server function. 1868 * Given a socket, listen for new connections and farm out 1869 * the processing as a [v]forked process. 1870 * Never returns. 1871 */ 1872 #if BB_MMU 1873 static void mini_httpd(int server_socket) ATTRIBUTE_NORETURN; 1874 static void mini_httpd(int server_socket) 1875 { 1876 /* NB: it's best to not use xfuncs in this loop before fork(). 1877 * Otherwise server may die on transient errors (temporary 1878 * out-of-memory condition, etc), which is Bad(tm). 1879 * Try to do any dangerous calls after fork. 1880 */ 1881 while (1) { 1882 int n; 1883 len_and_sockaddr fromAddr; 1884 1885 /* Wait for connections... */ 1886 fromAddr.len = LSA_SIZEOF_SA; 1887 n = accept(server_socket, &fromAddr.sa, &fromAddr.len); 1888 1889 if (n < 0) 1890 continue; 1891 /* set the KEEPALIVE option to cull dead connections */ 1892 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 1893 1894 if (fork() == 0) { 1895 /* child */ 1896 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 1897 /* Do not reload config on HUP */ 1898 signal(SIGHUP, SIG_IGN); 1899 #endif 1900 close(server_socket); 1901 xmove_fd(n, 0); 1902 xdup2(0, 1); 1903 1904 handle_incoming_and_exit(&fromAddr); 1905 } 1906 /* parent, or fork failed */ 1907 close(n); 1908 } /* while (1) */ 1909 /* never reached */ 1910 } 1544 1911 #else 1545 if(strcasecmp(buf, request_GET) != 0) { 1546 sendHeaders(HTTP_NOT_IMPLEMENTED); 1547 break; 1548 } 1549 #endif 1550 *purl = ' '; 1551 count = sscanf(purl, " %[^ ] HTTP/%d.%*d", buf, &blank); 1552 1553 if (count < 1 || buf[0] != '/') { 1554 /* Garbled request/URL */ 1555 goto BAD_REQUEST; 1556 } 1557 url = alloca(strlen(buf) + 12); /* + sizeof("/index.html\0") */ 1558 if(url == NULL) { 1559 sendHeaders(HTTP_INTERNAL_SERVER_ERROR); 1560 break; 1561 } 1562 strcpy(url, buf); 1563 /* extract url args if present */ 1564 test = strchr(url, '?'); 1565 if (test) { 1566 *test++ = 0; 1567 config->query = test; 1568 } 1569 1570 test = decodeString(url, 0); 1571 if(test == NULL) 1572 goto BAD_REQUEST; 1573 if(test == (buf+1)) { 1574 sendHeaders(HTTP_NOT_FOUND); 1575 break; 1576 } 1577 /* algorithm stolen from libbb bb_simplify_path(), 1578 but don`t strdup and reducing trailing slash and protect out root */ 1579 purl = test = url; 1580 1581 do { 1582 if (*purl == '/') { 1583 if (*test == '/') { /* skip duplicate (or initial) slash */ 1584 continue; 1585 } else if (*test == '.') { 1586 if (test[1] == '/' || test[1] == 0) { /* skip extra '.' */ 1587 continue; 1588 } else if ((test[1] == '.') && (test[2] == '/' || test[2] == 0)) { 1589 ++test; 1590 if (purl == url) { 1591 /* protect out root */ 1592 goto BAD_REQUEST; 1593 } 1594 while (*--purl != '/'); /* omit previous dir */ 1595 continue; 1596 } 1597 } 1598 } 1599 *++purl = *test; 1600 } while (*++test); 1601 1602 *++purl = 0; /* so keep last character */ 1603 test = purl; /* end ptr */ 1604 1605 /* If URL is directory, adding '/' */ 1606 if(test[-1] != '/') { 1607 if ( is_directory(url + 1, 1, &sb) ) { 1608 config->httpd_found.found_moved_temporarily = url; 1609 } 1610 } 1611 #if DEBUG 1612 fprintf(stderr, "url='%s', args=%s\n", url, config->query); 1613 #endif 1614 1615 test = url; 1616 ip_allowed = checkPermIP(); 1617 while(ip_allowed && (test = strchr( test + 1, '/' )) != NULL) { 1618 /* have path1/path2 */ 1619 *test = '\0'; 1620 if( is_directory(url + 1, 1, &sb) ) { 1621 /* may be having subdir config */ 1622 parse_conf(url + 1, SUBDIR_PARSE); 1623 ip_allowed = checkPermIP(); 1624 } 1625 *test = '/'; 1626 } 1627 if(blank >= 0) { 1628 // read until blank line for HTTP version specified, else parse immediate 1629 while(1) { 1630 alarm(TIMEOUT); 1631 count = getLine(); 1632 if(count <= 0) 1633 break; 1634 1635 #if DEBUG 1636 fprintf(stderr, "Header: '%s'\n", buf); 1637 #endif 1638 1639 #ifdef CONFIG_FEATURE_HTTPD_CGI 1640 /* try and do our best to parse more lines */ 1641 if ((strncasecmp(buf, Content_length, 15) == 0)) { 1642 if(prequest != request_GET) 1643 length = strtol(buf + 15, 0, 0); // extra read only for POST 1644 } else if ((strncasecmp(buf, "Cookie:", 7) == 0)) { 1645 for(test = buf + 7; isspace(*test); test++) 1646 ; 1647 cookie = strdup(test); 1648 } else if ((strncasecmp(buf, "Content-Type:", 13) == 0)) { 1649 for(test = buf + 13; isspace(*test); test++) 1650 ; 1651 content_type = strdup(test); 1652 } else if ((strncasecmp(buf, "Referer:", 8) == 0)) { 1653 for(test = buf + 8; isspace(*test); test++) 1654 ; 1655 config->referer = strdup(test); 1656 } 1657 #endif 1658 1659 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1660 if (strncasecmp(buf, "Authorization:", 14) == 0) { 1661 /* We only allow Basic credentials. 1662 * It shows up as "Authorization: Basic <userid:password>" where 1663 * the userid:password is base64 encoded. 1664 */ 1665 for(test = buf + 14; isspace(*test); test++) 1666 ; 1667 if (strncasecmp(test, "Basic", 5) != 0) 1668 continue; 1669 1670 test += 5; /* decodeBase64() skiping space self */ 1671 decodeBase64(test); 1672 credentials = checkPerm(url, test); 1673 } 1674 #endif /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */ 1675 1676 } /* while extra header reading */ 1677 } 1678 (void) alarm( 0 ); 1679 if(config->alarm_signaled) 1680 break; 1681 1682 if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) { 1683 /* protect listing [/path]/httpd_conf or IP deny */ 1684 #ifdef CONFIG_FEATURE_HTTPD_CGI 1685 FORBIDDEN: /* protect listing /cgi-bin */ 1686 #endif 1687 sendHeaders(HTTP_FORBIDDEN); 1688 break; 1689 } 1690 1691 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1692 if (credentials <= 0 && checkPerm(url, ":") == 0) { 1693 sendHeaders(HTTP_UNAUTHORIZED); 1694 break; 1695 } 1696 #endif 1697 1698 if(config->httpd_found.found_moved_temporarily) { 1699 sendHeaders(HTTP_MOVED_TEMPORARILY); 1700 #if DEBUG 1701 /* clear unforked memory flag */ 1702 config->httpd_found.found_moved_temporarily = NULL; 1703 #endif 1704 break; 1705 } 1706 1707 test = url + 1; /* skip first '/' */ 1708 1709 #ifdef CONFIG_FEATURE_HTTPD_CGI 1710 /* if strange Content-Length */ 1711 if (length < 0) 1712 break; 1713 1714 if (strncmp(test, "cgi-bin", 7) == 0) { 1715 if(test[7] == '/' && test[8] == 0) 1716 goto FORBIDDEN; // protect listing cgi-bin/ 1717 sendCgi(url, prequest, length, cookie, content_type); 1718 } else { 1719 if (prequest != request_GET) 1720 sendHeaders(HTTP_NOT_IMPLEMENTED); 1721 else { 1722 #endif /* CONFIG_FEATURE_HTTPD_CGI */ 1723 if(purl[-1] == '/') 1724 strcpy(purl, "index.html"); 1725 if ( stat(test, &sb ) == 0 ) { 1726 config->ContentLength = sb.st_size; 1727 config->last_mod = sb.st_mtime; 1728 } 1729 sendFile(test); 1730 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1731 /* unset if non inetd looped */ 1732 config->ContentLength = -1; 1733 #endif 1734 1735 #ifdef CONFIG_FEATURE_HTTPD_CGI 1736 } 1737 } 1738 #endif 1739 1740 } while (0); 1741 1742 1743 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1744 /* from inetd don`t looping: freeing, closing automatic from exit always */ 1745 # if DEBUG 1746 fprintf(stderr, "closing socket\n"); 1747 # endif 1748 # ifdef CONFIG_FEATURE_HTTPD_CGI 1749 free(cookie); 1750 free(content_type); 1751 free(config->referer); 1752 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1753 free(config->remoteuser); 1754 #endif 1755 # endif 1756 #endif /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */ 1757 shutdown(a_c_w, SHUT_WR); 1758 1759 /* Properly wait for remote to closed */ 1760 FD_ZERO (&s_fd) ; 1761 FD_SET (a_c_r, &s_fd) ; 1762 1763 do { 1764 tv.tv_sec = 2 ; 1765 tv.tv_usec = 0 ; 1766 retval = select (a_c_r + 1, &s_fd, NULL, NULL, &tv); 1767 } while (retval > 0 && (read (a_c_r, buf, sizeof (config->buf)) > 0)); 1768 1769 shutdown(a_c_r, SHUT_RD); 1770 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1771 close(config->accepted_socket); 1772 #endif /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */ 1773 } 1774 1775 /**************************************************************************** 1776 * 1777 > $Function: miniHttpd() 1778 * 1779 * $Description: The main http server function. 1780 * 1781 * Given an open socket fildes, listen for new connections and farm out 1782 * the processing as a forked process. 1783 * 1784 * $Parameters: 1785 * (int) server. . . The server socket fildes. 1786 * 1787 * $Return: (int) . . . . Always 0. 1788 * 1789 ****************************************************************************/ 1790 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1791 static int miniHttpd(int server) 1792 { 1793 fd_set readfd, portfd; 1794 1795 FD_ZERO(&portfd); 1796 FD_SET(server, &portfd); 1797 1798 /* copy the ports we are watching to the readfd set */ 1799 while (1) { 1800 readfd = portfd; 1801 1802 /* Now wait INDEFINITELY on the set of sockets! */ 1803 if (select(server + 1, &readfd, 0, 0, 0) > 0) { 1804 if (FD_ISSET(server, &readfd)) { 1805 int on; 1806 struct sockaddr_in fromAddr; 1807 1808 socklen_t fromAddrLen = sizeof(fromAddr); 1809 int s = accept(server, 1810 (struct sockaddr *)&fromAddr, &fromAddrLen); 1811 1812 if (s < 0) { 1813 continue; 1814 } 1815 config->accepted_socket = s; 1816 config->rmt_ip = ntohl(fromAddr.sin_addr.s_addr); 1817 #if defined(CONFIG_FEATURE_HTTPD_CGI) || DEBUG 1818 sprintf(config->rmt_ip_str, "%u.%u.%u.%u", 1819 (unsigned char)(config->rmt_ip >> 24), 1820 (unsigned char)(config->rmt_ip >> 16), 1821 (unsigned char)(config->rmt_ip >> 8), 1822 config->rmt_ip & 0xff); 1823 config->port = ntohs(fromAddr.sin_port); 1824 #if DEBUG 1825 bb_error_msg("connection from IP=%s, port %u\n", 1826 config->rmt_ip_str, config->port); 1827 #endif 1828 #endif /* CONFIG_FEATURE_HTTPD_CGI */ 1829 1830 /* set the KEEPALIVE option to cull dead connections */ 1831 on = 1; 1832 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof (on)); 1833 1834 #if !DEBUG 1835 if (fork() == 0) 1836 #endif 1837 { 1838 /* This is the spawned thread */ 1839 #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 1840 /* protect reload config, may be confuse checking */ 1841 signal(SIGHUP, SIG_IGN); 1842 #endif 1843 handleIncoming(); 1844 #if !DEBUG 1845 exit(0); 1846 #endif 1847 } 1848 close(s); 1849 } 1850 } 1851 } // while (1) 1852 return 0; 1853 } 1854 1855 #else 1856 /* from inetd */ 1857 1858 static int miniHttpd(void) 1859 { 1860 struct sockaddr_in fromAddrLen; 1861 socklen_t sinlen = sizeof (struct sockaddr_in); 1862 1863 getpeername (0, (struct sockaddr *)&fromAddrLen, &sinlen); 1864 config->rmt_ip = ntohl(fromAddrLen.sin_addr.s_addr); 1865 #ifdef CONFIG_FEATURE_HTTPD_CGI 1866 sprintf(config->rmt_ip_str, "%u.%u.%u.%u", 1867 (unsigned char)(config->rmt_ip >> 24), 1868 (unsigned char)(config->rmt_ip >> 16), 1869 (unsigned char)(config->rmt_ip >> 8), 1870 config->rmt_ip & 0xff); 1871 #endif 1872 config->port = ntohs(fromAddrLen.sin_port); 1873 handleIncoming(); 1874 return 0; 1875 } 1876 #endif /* CONFIG_FEATURE_HTTPD_WITHOUT_INETD */ 1877 1878 #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 1912 static void mini_httpd_nommu(int server_socket, int argc, char **argv) ATTRIBUTE_NORETURN; 1913 static void mini_httpd_nommu(int server_socket, int argc, char **argv) 1914 { 1915 char *argv_copy[argc + 2]; 1916 1917 argv_copy[0] = argv[0]; 1918 argv_copy[1] = (char*)"-i"; 1919 memcpy(&argv_copy[2], &argv[1], argc * sizeof(argv[0])); 1920 1921 /* NB: it's best to not use xfuncs in this loop before vfork(). 1922 * Otherwise server may die on transient errors (temporary 1923 * out-of-memory condition, etc), which is Bad(tm). 1924 * Try to do any dangerous calls after fork. 1925 */ 1926 while (1) { 1927 int n; 1928 len_and_sockaddr fromAddr; 1929 1930 /* Wait for connections... */ 1931 fromAddr.len = LSA_SIZEOF_SA; 1932 n = accept(server_socket, &fromAddr.sa, &fromAddr.len); 1933 1934 if (n < 0) 1935 continue; 1936 /* set the KEEPALIVE option to cull dead connections */ 1937 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 1938 1939 if (vfork() == 0) { 1940 /* child */ 1941 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 1942 /* Do not reload config on HUP */ 1943 signal(SIGHUP, SIG_IGN); 1944 #endif 1945 close(server_socket); 1946 xmove_fd(n, 0); 1947 xdup2(0, 1); 1948 1949 /* Run a copy of ourself in inetd mode */ 1950 re_exec(argv_copy); 1951 } 1952 /* parent, or vfork failed */ 1953 close(n); 1954 } /* while (1) */ 1955 /* never reached */ 1956 } 1957 #endif 1958 1959 /* 1960 * Process a HTTP connection on stdin/out. 1961 * Never returns. 1962 */ 1963 static void mini_httpd_inetd(void) ATTRIBUTE_NORETURN; 1964 static void mini_httpd_inetd(void) 1965 { 1966 len_and_sockaddr fromAddr; 1967 1968 fromAddr.len = LSA_SIZEOF_SA; 1969 getpeername(0, &fromAddr.sa, &fromAddr.len); 1970 handle_incoming_and_exit(&fromAddr); 1971 } 1972 1973 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 1879 1974 static void sighup_handler(int sig) 1880 1975 { 1881 /* set and reset */1882 1976 struct sigaction sa; 1883 1977 1884 parse_conf(default_path_httpd_conf, 1885 sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE); 1978 parse_conf(default_path_httpd_conf, sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE); 1979 1980 memset(&sa, 0, sizeof(sa)); 1886 1981 sa.sa_handler = sighup_handler; 1887 sigemptyset(&sa.sa_mask);1982 /*sigemptyset(&sa.sa_mask); - memset should be enough */ 1888 1983 sa.sa_flags = SA_RESTART; 1889 1984 sigaction(SIGHUP, &sa, NULL); … … 1891 1986 #endif 1892 1987 1893 enum httpd_opts_nums{1988 enum { 1894 1989 c_opt_config_file = 0, 1895 1990 d_opt_decode_url, 1896 1991 h_opt_home_httpd, 1897 1992 USE_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,) 1898 USE_FEATURE_HTTPD_BASIC_AUTH(r_opt_realm,) 1899 USE_FEATURE_HTTPD_AUTH_MD5(m_opt_md5,) 1900 USE_FEATURE_HTTPD_SETUID(u_opt_setuid,) 1901 USE_FEATURE_HTTPD_WITHOUT_INETD(p_opt_port,) 1993 USE_FEATURE_HTTPD_BASIC_AUTH( r_opt_realm ,) 1994 USE_FEATURE_HTTPD_AUTH_MD5( m_opt_md5 ,) 1995 USE_FEATURE_HTTPD_SETUID( u_opt_setuid ,) 1996 p_opt_port , 1997 p_opt_inetd , 1998 p_opt_foreground, 1999 p_opt_verbose , 2000 OPT_CONFIG_FILE = 1 << c_opt_config_file, 2001 OPT_DECODE_URL = 1 << d_opt_decode_url, 2002 OPT_HOME_HTTPD = 1 << h_opt_home_httpd, 2003 OPT_ENCODE_URL = USE_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0, 2004 OPT_REALM = USE_FEATURE_HTTPD_BASIC_AUTH( (1 << r_opt_realm )) + 0, 2005 OPT_MD5 = USE_FEATURE_HTTPD_AUTH_MD5( (1 << m_opt_md5 )) + 0, 2006 OPT_SETUID = USE_FEATURE_HTTPD_SETUID( (1 << u_opt_setuid )) + 0, 2007 OPT_PORT = 1 << p_opt_port, 2008 OPT_INETD = 1 << p_opt_inetd, 2009 OPT_FOREGROUND = 1 << p_opt_foreground, 2010 OPT_VERBOSE = 1 << p_opt_verbose, 1902 2011 }; 1903 2012 1904 static const char httpd_opts[]="c:d:h:" 1905 USE_FEATURE_HTTPD_ENCODE_URL_STR("e:") 1906 USE_FEATURE_HTTPD_BASIC_AUTH("r:") 1907 USE_FEATURE_HTTPD_AUTH_MD5("m:") 1908 USE_FEATURE_HTTPD_SETUID("u:") 1909 USE_FEATURE_HTTPD_WITHOUT_INETD("p:"); 1910 1911 #define OPT_CONFIG_FILE (1<<c_opt_config_file) 1912 #define OPT_DECODE_URL (1<<d_opt_decode_url) 1913 #define OPT_HOME_HTTPD (1<<h_opt_home_httpd) 1914 1915 #define OPT_ENCODE_URL USE_FEATURE_HTTPD_ENCODE_URL_STR((1<<e_opt_encode_url)) \ 1916 SKIP_FEATURE_HTTPD_ENCODE_URL_STR(0) 1917 1918 #define OPT_REALM USE_FEATURE_HTTPD_BASIC_AUTH((1<<r_opt_realm)) \ 1919 SKIP_FEATURE_HTTPD_BASIC_AUTH(0) 1920 1921 #define OPT_MD5 USE_FEATURE_HTTPD_AUTH_MD5((1<<m_opt_md5)) \ 1922 SKIP_FEATURE_HTTPD_AUTH_MD5(0) 1923 1924 #define OPT_SETUID USE_FEATURE_HTTPD_SETUID((1<<u_opt_setuid)) \ 1925 SKIP_FEATURE_HTTPD_SETUID(0) 1926 1927 #define OPT_PORT USE_FEATURE_HTTPD_WITHOUT_INETD((1<<p_opt_port)) \ 1928 SKIP_FEATURE_HTTPD_WITHOUT_INETD(0) 1929 1930 1931 int httpd_main(int argc, char *argv[]) 1932 { 1933 unsigned long opt; 1934 const char *home_httpd = home; 1935 char *url_for_decode; 1936 USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;) 1937 USE_FEATURE_HTTPD_WITHOUT_INETD(const char *s_port;) 1938 USE_FEATURE_HTTPD_WITHOUT_INETD(int server;) 1939 1940 USE_FEATURE_HTTPD_SETUID(const char *s_uid;) 1941 USE_FEATURE_HTTPD_SETUID(long uid = -1;) 1942 1943 USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;) 1944 1945 config = xcalloc(1, sizeof(*config)); 1946 #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH 1947 config->realm = "Web Server Authentication"; 1948 #endif 1949 1950 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1951 config->port = 80; 1952 #endif 1953 1954 config->ContentLength = -1; 1955 1956 opt = bb_getopt_ulflags(argc, argv, httpd_opts, 1957 &(config->configFile), &url_for_decode, &home_httpd 2013 2014 int httpd_main(int argc, char **argv); 2015 int httpd_main(int argc, char **argv) 2016 { 2017 int server_socket = server_socket; /* for gcc */ 2018 unsigned opt; 2019 char *url_for_decode; 2020 USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;) 2021 USE_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) 2022 USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) 2023 USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;) 2024 2025 INIT_G(); 2026 2027 #if ENABLE_LOCALE_SUPPORT 2028 /* Undo busybox.c: we want to speak English in http (dates etc) */ 2029 setlocale(LC_TIME, "C"); 2030 #endif 2031 2032 home_httpd = xrealloc_getcwd_or_warn(NULL); 2033 /* -v counts, -i implies -f */ 2034 opt_complementary = "vv:if"; 2035 /* We do not "absolutize" path given by -h (home) opt. 2036 * If user gives relative path in -h, $SCRIPT_FILENAME can end up 2037 * relative too. */ 2038 opt = getopt32(argv, "c:d:h:" 2039 USE_FEATURE_HTTPD_ENCODE_URL_STR("e:") 2040 USE_FEATURE_HTTPD_BASIC_AUTH("r:") 2041 USE_FEATURE_HTTPD_AUTH_MD5("m:") 2042 USE_FEATURE_HTTPD_SETUID("u:") 2043 "p:ifv", 2044 &configFile, &url_for_decode, &home_httpd 1958 2045 USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) 1959 USE_FEATURE_HTTPD_BASIC_AUTH(, & (config->realm))2046 USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) 1960 2047 USE_FEATURE_HTTPD_AUTH_MD5(, &pass) 1961 USE_FEATURE_HTTPD_SETUID(, &s_uid) 1962 USE_FEATURE_HTTPD_WITHOUT_INETD(, &s_port) 1963 ); 1964 1965 if(opt & OPT_DECODE_URL) { 1966 printf("%s", decodeString(url_for_decode, 1)); 1967 return 0; 1968 } 1969 #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR 1970 if(opt & OPT_ENCODE_URL) { 1971 printf("%s", encodeString(url_for_encode)); 1972 return 0; 1973 } 1974 #endif 1975 #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5 1976 if(opt & OPT_MD5) { 1977 printf("%s\n", pw_encrypt(pass, "$1$")); 1978 return 0; 1979 } 1980 #endif 1981 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1982 if(opt & OPT_PORT) 1983 config->port = bb_xgetlarg(s_port, 10, 1, 0xffff); 1984 #ifdef CONFIG_FEATURE_HTTPD_SETUID 1985 if(opt & OPT_SETUID) { 1986 char *e; 1987 1988 uid = strtol(s_uid, &e, 0); 1989 if(*e != '\0') { 1990 /* not integer */ 1991 uid = bb_xgetpwnam(s_uid); 1992 } 1993 } 1994 #endif 1995 #endif 1996 1997 bb_xchdir(home_httpd); 1998 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 1999 server = openServer(); 2000 # ifdef CONFIG_FEATURE_HTTPD_SETUID 2001 /* drop privileges */ 2002 if(uid > 0) 2003 setuid(uid); 2004 # endif 2005 #endif 2006 2007 #ifdef CONFIG_FEATURE_HTTPD_CGI 2008 { 2009 char *p = getenv("PATH"); 2010 if(p) { 2011 p = bb_xstrdup(p); 2012 } 2013 clearenv(); 2014 if(p) 2015 setenv("PATH", p, 1); 2016 # ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 2017 addEnvPort("SERVER"); 2018 # endif 2019 } 2020 #endif 2021 2022 #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 2023 sighup_handler(0); 2048 USE_FEATURE_HTTPD_SETUID(, &s_ugid) 2049 , &bind_addr_or_port 2050 , &verbose 2051 ); 2052 if (opt & OPT_DECODE_URL) { 2053 fputs(decodeString(url_for_decode, 1), stdout); 2054 return 0; 2055 } 2056 #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR 2057 if (opt & OPT_ENCODE_URL) { 2058 fputs(encodeString(url_for_encode), stdout); 2059 return 0; 2060 } 2061 #endif 2062 #if ENABLE_FEATURE_HTTPD_AUTH_MD5 2063 if (opt & OPT_MD5) { 2064 puts(pw_encrypt(pass, "$1$")); 2065 return 0; 2066 } 2067 #endif 2068 #if ENABLE_FEATURE_HTTPD_SETUID 2069 if (opt & OPT_SETUID) { 2070 if (!get_uidgid(&ugid, s_ugid, 1)) 2071 bb_error_msg_and_die("unrecognized user[:group] " 2072 "name '%s'", s_ugid); 2073 } 2074 #endif 2075 2076 #if !BB_MMU 2077 if (!(opt & OPT_FOREGROUND)) { 2078 bb_daemonize_or_rexec(0, argv); /* don't change current directory */ 2079 } 2080 #endif 2081 2082 xchdir(home_httpd); 2083 if (!(opt & OPT_INETD)) { 2084 signal(SIGCHLD, SIG_IGN); 2085 server_socket = openServer(); 2086 #if ENABLE_FEATURE_HTTPD_SETUID 2087 /* drop privileges */ 2088 if (opt & OPT_SETUID) { 2089 if (ugid.gid != (gid_t)-1) { 2090 if (setgroups(1, &ugid.gid) == -1) 2091 bb_perror_msg_and_die("setgroups"); 2092 xsetgid(ugid.gid); 2093 } 2094 xsetuid(ugid.uid); 2095 } 2096 #endif 2097 } 2098 2099 #if ENABLE_FEATURE_HTTPD_CGI 2100 { 2101 char *p = getenv("PATH"); 2102 /* env strings themself are not freed, no need to strdup(p): */ 2103 clearenv(); 2104 if (p) 2105 putenv(p - 5); 2106 // if (!(opt & OPT_INETD)) 2107 // setenv_long("SERVER_PORT", ???); 2108 } 2109 #endif 2110 2111 #if ENABLE_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 2112 if (!(opt & OPT_INETD)) 2113 sighup_handler(0); 2114 else /* do not install HUP handler in inetd mode */ 2115 #endif 2116 parse_conf(default_path_httpd_conf, FIRST_PARSE); 2117 2118 xfunc_error_retval = 0; 2119 if (opt & OPT_INETD) 2120 mini_httpd_inetd(); 2121 #if BB_MMU 2122 if (!(opt & OPT_FOREGROUND)) 2123 bb_daemonize(0); /* don't change current directory */ 2124 mini_httpd(server_socket); /* never returns */ 2024 2125 #else 2025 parse_conf(default_path_httpd_conf, FIRST_PARSE); 2026 #endif 2027 2028 #ifdef CONFIG_FEATURE_HTTPD_WITHOUT_INETD 2029 # if !DEBUG 2030 bb_xdaemon(1, 0); /* don`t change curent directory */ 2031 # endif 2032 return miniHttpd(server); 2033 #else 2034 return miniHttpd(); 2035 #endif 2036 } 2126 mini_httpd_nommu(server_socket, argc, argv); /* never returns */ 2127 #endif 2128 /* return 0; */ 2129 } -
branches/2.2.5/mindi-busybox/networking/ifconfig.c
r821 r1765 27 27 */ 28 28 29 #include <stdio.h>30 #include <stdlib.h>31 #include <string.h> /* strcmp and friends */32 #include <ctype.h> /* isdigit and friends */33 #include <stddef.h> /* offsetof */34 #include <unistd.h>35 #include <netdb.h>36 #include <sys/ioctl.h>37 29 #include <net/if.h> 38 30 #include <net/if_arp.h> 39 31 #include <netinet/in.h> 40 #if __GLIBC__ >=2 && __GLIBC_MINOR>= 132 #if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 41 33 #include <netpacket/packet.h> 42 34 #include <net/ethernet.h> … … 46 38 #endif 47 39 #include "inet_common.h" 48 #include " busybox.h"49 50 #if def CONFIG_FEATURE_IFCONFIG_SLIP40 #include "libbb.h" 41 42 #if ENABLE_FEATURE_IFCONFIG_SLIP 51 43 # include <net/if_slip.h> 52 44 #endif … … 71 63 #endif 72 64 73 #if def CONFIG_FEATURE_IPV665 #if ENABLE_FEATURE_IPV6 74 66 struct in6_ifreq { 75 67 struct in6_addr ifr6_addr; … … 122 114 #define A_SET_AFTER 0x40 /* Set a flag at the end. */ 123 115 #define A_COLON_CHK 0x80 /* Is this needed? See below. */ 124 #if def CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS116 #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 125 117 #define A_HOSTNAME 0x100 /* Set if it is ip addr. */ 126 118 #define A_BROADCAST 0x200 /* Set if it is broadcast addr. */ … … 179 171 struct options { 180 172 const char *name; 181 #if def CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS173 #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 182 174 const unsigned int flags:6; 183 175 const unsigned int arg_flags:10; … … 198 190 {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)}, 199 191 {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)}, 200 #if def CONFIG_FEATURE_IFCONFIG_HW192 #if ENABLE_FEATURE_IFCONFIG_HW 201 193 {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)}, 202 194 #endif … … 208 200 {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)}, 209 201 #endif 210 #if def CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ202 #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 211 203 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)}, 212 204 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)}, … … 214 206 #endif 215 207 /* Last entry if for unmatched (possibly hostname) arg. */ 216 #if def CONFIG_FEATURE_IPV6208 #if ENABLE_FEATURE_IPV6 217 209 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */ 218 210 {"SIOCDIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */ … … 228 220 {"netmask", N_ARG, ARG_NETMASK, 0}, 229 221 {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST}, 230 #if def CONFIG_FEATURE_IFCONFIG_HW222 #if ENABLE_FEATURE_IFCONFIG_HW 231 223 {"hw", N_ARG, ARG_HW, 0}, 232 224 #endif … … 238 230 {"outfill", N_ARG, ARG_OUTFILL, 0}, 239 231 #endif 240 #if def CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ232 #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 241 233 {"mem_start", N_ARG, ARG_MEM_START, 0}, 242 234 {"io_addr", N_ARG, ARG_IO_ADDR, 0}, 243 235 {"irq", N_ARG, ARG_IRQ, 0}, 244 236 #endif 245 #if def CONFIG_FEATURE_IPV6237 #if ENABLE_FEATURE_IPV6 246 238 {"add", N_ARG, ARG_ADD_DEL, 0}, 247 239 {"del", N_ARG, ARG_ADD_DEL, 0}, … … 262 254 */ 263 255 264 #ifdef CONFIG_FEATURE_IFCONFIG_HW 265 static int in_ether(char *bufp, struct sockaddr *sap); 266 #endif 267 268 #ifdef CONFIG_FEATURE_IFCONFIG_STATUS 269 extern int interface_opt_a; 270 extern int display_interfaces(char *ifname); 256 #if ENABLE_FEATURE_IFCONFIG_HW 257 static int in_ether(const char *bufp, struct sockaddr *sap); 271 258 #endif 272 259 … … 275 262 */ 276 263 264 int ifconfig_main(int argc, char **argv); 277 265 int ifconfig_main(int argc, char **argv) 278 266 { 279 267 struct ifreq ifr; 280 268 struct sockaddr_in sai; 281 #ifdef CONFIG_FEATURE_IPV6 282 struct sockaddr_in6 sai6; 283 #endif 284 #ifdef CONFIG_FEATURE_IFCONFIG_HW 269 #if ENABLE_FEATURE_IFCONFIG_HW 285 270 struct sockaddr sa; 286 271 #endif … … 288 273 const struct options *op; 289 274 int sockfd; /* socket fd we use to manipulate stuff with */ 290 int goterr;291 275 int selector; 292 #if def CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS276 #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 293 277 unsigned int mask; 294 278 unsigned int did_flags; … … 299 283 #endif 300 284 char *p; 301 char host[128];302 303 goterr = 0; 285 /*char host[128];*/ 286 const char *host = NULL; /* make gcc happy */ 287 304 288 did_flags = 0; 305 #if def CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS289 #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 306 290 sai_hostname = 0; 307 291 sai_netmask = 0; … … 312 296 --argc; 313 297 314 #if def CONFIG_FEATURE_IFCONFIG_STATUS315 if ( (argc > 0) && (((*argv)[0] == '-') && ((*argv)[1] == 'a') && !(*argv)[2])) {298 #if ENABLE_FEATURE_IFCONFIG_STATUS 299 if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { 316 300 interface_opt_a = 1; 317 301 --argc; … … 321 305 322 306 if (argc <= 1) { 323 #if def CONFIG_FEATURE_IFCONFIG_STATUS307 #if ENABLE_FEATURE_IFCONFIG_STATUS 324 308 return display_interfaces(argc ? *argv : NULL); 325 309 #else 326 bb_error_msg_and_die 327 ("ifconfig was not compiled with interface status display support."); 310 bb_error_msg_and_die("no support for status display"); 328 311 #endif 329 312 } 330 313 331 314 /* Create a channel to the NET kernel. */ 332 sockfd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);315 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); 333 316 334 317 /* get interface name */ … … 345 328 for (op = OptArray; op->name; op++) { /* Find table entry. */ 346 329 if (strcmp(p, op->name) == 0) { /* If name matches... */ 347 if ((mask &= op->flags)) { /* set the mask and go. */ 330 mask &= op->flags; 331 if (mask) /* set the mask and go. */ 348 332 goto FOUND_ARG; 349 }350 333 /* If we get here, there was a valid arg with an */ 351 334 /* invalid '-' prefix. */ 352 ++goterr; 353 goto LOOP; 335 bb_error_msg_and_die("bad: '%s'", p-1); 354 336 } 355 337 } 356 338 357 339 /* We fell through, so treat as possible hostname. */ 358 a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;340 a1op = Arg1Opt + ARRAY_SIZE(Arg1Opt) - 1; 359 341 mask = op->arg_flags; 360 342 goto HOSTNAME; 361 343 362 344 FOUND_ARG: 363 345 if (mask & ARG_MASK) { 364 346 mask = op->arg_flags; 365 347 a1op = Arg1Opt + (op - OptArray); 366 if (mask & A_NETMASK & did_flags) {348 if (mask & A_NETMASK & did_flags) 367 349 bb_show_usage(); 368 }369 350 if (*++argv == NULL) { 370 if (mask & A_ARG_REQ) {351 if (mask & A_ARG_REQ) 371 352 bb_show_usage(); 372 } else { 373 --argv; 374 mask &= A_SET_AFTER; /* just for broadcast */ 375 } 353 --argv; 354 mask &= A_SET_AFTER; /* just for broadcast */ 376 355 } else { /* got an arg so process it */ 377 356 HOSTNAME: 378 357 did_flags |= (mask & (A_NETMASK|A_HOSTNAME)); 379 358 if (mask & A_CAST_HOST_COPY) { 380 #if def CONFIG_FEATURE_IFCONFIG_HW359 #if ENABLE_FEATURE_IFCONFIG_HW 381 360 if (mask & A_CAST_RESOLVE) { 382 361 #endif 383 #if def CONFIG_FEATURE_IPV6362 #if ENABLE_FEATURE_IPV6 384 363 char *prefix; 385 364 int prefix_len = 0; 386 365 #endif 387 388 safe_strncpy(host, *argv, (sizeof host)); 389 #ifdef CONFIG_FEATURE_IPV6 390 if ((prefix = strchr(host, '/'))) { 391 if (safe_strtoi(prefix + 1, &prefix_len) || 392 (prefix_len < 0) || (prefix_len > 128)) 393 { 394 ++goterr; 395 goto LOOP; 396 } 397 *prefix = 0; 366 /*safe_strncpy(host, *argv, (sizeof host));*/ 367 host = *argv; 368 #if ENABLE_FEATURE_IPV6 369 prefix = strchr(host, '/'); 370 if (prefix) { 371 prefix_len = xatou_range(prefix + 1, 0, 128); 372 *prefix = '\0'; 398 373 } 399 374 #endif 400 401 375 sai.sin_family = AF_INET; 402 376 sai.sin_port = 0; 403 if (!strcmp(host, bb_ INET_default)) {377 if (!strcmp(host, bb_str_default)) { 404 378 /* Default is special, meaning 0.0.0.0. */ 405 379 sai.sin_addr.s_addr = INADDR_ANY; 406 #ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS 407 } else if (((host[0] == '+') && !host[1]) && (mask & A_BROADCAST) && 408 (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)) { 380 } 381 #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 382 else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST) 383 && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME) 384 ) { 409 385 /* + is special, meaning broadcast is derived. */ 410 386 sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask); 411 #endif 412 #ifdef CONFIG_FEATURE_IPV6 413 } else if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) { 414 int sockfd6; 415 struct in6_ifreq ifr6; 416 417 memcpy((char *) &ifr6.ifr6_addr, 418 (char *) &sai6.sin6_addr, 419 sizeof(struct in6_addr)); 420 421 /* Create a channel to the NET kernel. */ 422 if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 423 bb_perror_msg_and_die("socket6"); 424 } 425 if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) { 426 perror("SIOGIFINDEX"); 427 ++goterr; 387 } 388 #endif 389 else { 390 len_and_sockaddr *lsa; 391 if (strcmp(host, "inet") == 0) 392 continue; /* compat stuff */ 393 lsa = xhost2sockaddr(host, 0); 394 #if ENABLE_FEATURE_IPV6 395 if (lsa->sa.sa_family == AF_INET6) { 396 int sockfd6; 397 struct in6_ifreq ifr6; 398 399 memcpy((char *) &ifr6.ifr6_addr, 400 (char *) &(lsa->sin6.sin6_addr), 401 sizeof(struct in6_addr)); 402 403 /* Create a channel to the NET kernel. */ 404 sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); 405 xioctl(sockfd6, SIOGIFINDEX, &ifr); 406 ifr6.ifr6_ifindex = ifr.ifr_ifindex; 407 ifr6.ifr6_prefixlen = prefix_len; 408 ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "%s", a1op->name); 409 if (ENABLE_FEATURE_CLEAN_UP) 410 free(lsa); 428 411 continue; 429 412 } 430 ifr6.ifr6_ifindex = ifr.ifr_ifindex; 431 ifr6.ifr6_prefixlen = prefix_len; 432 if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) { 433 perror(a1op->name); 434 ++goterr; 435 } 436 continue; 437 #endif 438 } else if (inet_aton(host, &sai.sin_addr) == 0) { 439 /* It's not a dotted quad. */ 440 struct hostent *hp; 441 if ((hp = gethostbyname(host)) == (struct hostent *)NULL) { 442 ++goterr; 443 continue; 444 } 445 memcpy((char *) &sai.sin_addr, (char *) hp->h_addr_list[0], 446 sizeof(struct in_addr)); 413 #endif 414 sai.sin_addr = lsa->sin.sin_addr; 415 if (ENABLE_FEATURE_CLEAN_UP) 416 free(lsa); 447 417 } 448 #if def CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS449 if (mask & A_HOSTNAME) {418 #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS 419 if (mask & A_HOSTNAME) 450 420 sai_hostname = sai.sin_addr.s_addr; 451 } 452 if (mask & A_NETMASK) { 421 if (mask & A_NETMASK) 453 422 sai_netmask = sai.sin_addr.s_addr; 454 }455 423 #endif 456 424 p = (char *) &sai; 457 #if def CONFIG_FEATURE_IFCONFIG_HW425 #if ENABLE_FEATURE_IFCONFIG_HW 458 426 } else { /* A_CAST_HOST_COPY_IN_ETHER */ 459 427 /* This is the "hw" arg case. */ 460 if (strcmp("ether", *argv) || (*++argv == NULL)) {428 if (strcmp("ether", *argv) || !*++argv) 461 429 bb_show_usage(); 462 } 463 safe_strncpy(host, *argv, (sizeof host)); 464 if (in_ether(host, &sa)) { 465 bb_error_msg("invalid hw-addr %s", host); 466 ++goterr; 467 continue; 468 } 430 /*safe_strncpy(host, *argv, sizeof(host));*/ 431 host = *argv; 432 if (in_ether(host, &sa)) 433 bb_error_msg_and_die("invalid hw-addr %s", host); 469 434 p = (char *) &sa; 470 435 } 471 436 #endif 472 memcpy( (((char *) (&ifr)) + a1op->ifr_offset),437 memcpy( (((char *)&ifr) + a1op->ifr_offset), 473 438 p, sizeof(struct sockaddr)); 474 439 } else { 440 /* FIXME: error check?? */ 475 441 unsigned long i = strtoul(*argv, NULL, 0); 476 477 p = ((char *) (&ifr)) + a1op->ifr_offset; 478 #ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 442 p = ((char *)&ifr) + a1op->ifr_offset; 443 #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ 479 444 if (mask & A_MAP_TYPE) { 480 if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) { 481 ++goterr; 482 continue; 483 } 484 if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) { 445 xioctl(sockfd, SIOCGIFMAP, &ifr); 446 if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) 485 447 *((unsigned char *) p) = i; 486 } else if (mask & A_MAP_USHORT) {448 else if (mask & A_MAP_USHORT) 487 449 *((unsigned short *) p) = i; 488 } else {450 else 489 451 *((unsigned long *) p) = i; 490 }491 452 } else 492 453 #endif 493 if (mask & A_CAST_CHAR_PTR) {454 if (mask & A_CAST_CHAR_PTR) 494 455 *((caddr_t *) p) = (caddr_t) i; 495 } else {/* A_CAST_INT */456 else /* A_CAST_INT */ 496 457 *((int *) p) = i; 497 }498 458 } 499 459 500 if (ioctl(sockfd, a1op->selector, &ifr) < 0) { 501 perror(a1op->name); 502 ++goterr; 503 continue; 504 } 460 ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "%s", a1op->name); 505 461 #ifdef QUESTIONABLE_ALIAS_CASE 506 462 if (mask & A_COLON_CHK) { 507 463 /* 508 464 * Don't do the set_flag() if the address is an alias with 509 * a -at the end, since it's deleted already! - Roman465 * a '-' at the end, since it's deleted already! - Roman 510 466 * 511 467 * Should really use regex.h here, not sure though how well … … 514 470 char *ptr; 515 471 short int found_colon = 0; 516 517 for (ptr = ifr.ifr_name; *ptr; ptr++) { 518 if (*ptr == ':') { 472 for (ptr = ifr.ifr_name; *ptr; ptr++) 473 if (*ptr == ':') 519 474 found_colon++; 520 } 521 } 522 523 if (found_colon && *(ptr - 1) == '-') { 475 if (found_colon && ptr[-1] == '-') 524 476 continue; 525 }526 477 } 527 478 #endif 528 479 } 529 if (!(mask & A_SET_AFTER)) {480 if (!(mask & A_SET_AFTER)) 530 481 continue; 531 }532 482 mask = N_SET; 533 483 } 534 484 535 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 536 perror("SIOCGIFFLAGS"); 537 ++goterr; 538 } else { 539 selector = op->selector; 540 if (mask & SET_MASK) { 541 ifr.ifr_flags |= selector; 542 } else { 543 ifr.ifr_flags &= ~selector; 544 } 545 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { 546 perror("SIOCSIFFLAGS"); 547 ++goterr; 548 } 549 } 550 LOOP: 551 continue; 552 } /* end of while-loop */ 553 554 if (ENABLE_FEATURE_CLEAN_UP) close(sockfd); 555 return goterr; 485 xioctl(sockfd, SIOCGIFFLAGS, &ifr); 486 selector = op->selector; 487 if (mask & SET_MASK) 488 ifr.ifr_flags |= selector; 489 else 490 ifr.ifr_flags &= ~selector; 491 xioctl(sockfd, SIOCSIFFLAGS, &ifr); 492 } /* while () */ 493 494 if (ENABLE_FEATURE_CLEAN_UP) 495 close(sockfd); 496 return 0; 556 497 } 557 498 558 #if def CONFIG_FEATURE_IFCONFIG_HW499 #if ENABLE_FEATURE_IFCONFIG_HW 559 500 /* Input an Ethernet address and convert to binary. */ 560 static int in_ether(c har *bufp, struct sockaddr *sap)501 static int in_ether(const char *bufp, struct sockaddr *sap) 561 502 { 562 503 char *ptr; … … 595 536 } while (++i < ETH_ALEN); 596 537 597 return (int) (*bufp);/* Error if we don't end at end of string. */538 return *bufp; /* Error if we don't end at end of string. */ 598 539 } 599 540 #endif -
branches/2.2.5/mindi-busybox/networking/ifupdown.c
r821 r1765 11 11 * Remove checks for kernel version, assume kernel version 2.2.0 or better. 12 12 * Lines in the interfaces file cannot wrap. 13 * To adhere to the FHS, the default state file is /var/run/ifstate. 13 * To adhere to the FHS, the default state file is /var/run/ifstate 14 * (defined via CONFIG_IFUPDOWN_IFSTATE_PATH) and can be overridden by build 15 * configuration. 14 16 * 15 17 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 16 18 */ 17 19 18 /* TODO: standardise execute() return codes to return 0 for success and 1 for failure */19 20 #include <sys/stat.h>21 20 #include <sys/utsname.h> 22 #include <sys/wait.h>23 24 #include <ctype.h>25 #include <errno.h>26 #include <fcntl.h>27 21 #include <fnmatch.h> 28 22 #include <getopt.h> 29 #include <stdarg.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "busybox.h" 23 24 #include "libbb.h" 36 25 37 26 #define MAX_OPT_DEPTH 10 … … 40 29 #define EUNBALPER 10000 41 30 42 #if def CONFIG_FEATURE_IFUPDOWN_MAPPING31 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 43 32 #define MAX_INTERFACE_LENGTH 10 44 33 #endif 45 34 46 #if 0 47 #define debug_noise(fmt, args...) printf(fmt, ## args) 48 #else 49 #define debug_noise(fmt, args...) 50 #endif 35 #define debug_noise(args...) /*fprintf(stderr, args)*/ 51 36 52 37 /* Forward declaration */ 53 38 struct interface_defn_t; 54 39 55 typedef int (execfn)(char *command); 56 57 struct method_t 58 { 59 char *name; 40 typedef int execfn(char *command); 41 42 struct method_t { 43 const char *name; 60 44 int (*up)(struct interface_defn_t *ifd, execfn *e); 61 45 int (*down)(struct interface_defn_t *ifd, execfn *e); 62 46 }; 63 47 64 struct address_family_t 65 { 66 char *name; 48 struct address_family_t { 49 const char *name; 67 50 int n_methods; 68 struct method_t *method;51 const struct method_t *method; 69 52 }; 70 53 71 struct mapping_defn_t 72 { 54 struct mapping_defn_t { 73 55 struct mapping_defn_t *next; 74 56 … … 84 66 }; 85 67 86 struct variable_t 87 { 68 struct variable_t { 88 69 char *name; 89 70 char *value; 90 71 }; 91 72 92 struct interface_defn_t 93 { 94 struct address_family_t *address_family; 95 struct method_t *method; 73 struct interface_defn_t { 74 const struct address_family_t *address_family; 75 const struct method_t *method; 96 76 97 77 char *iface; … … 101 81 }; 102 82 103 struct interfaces_file_t 104 { 83 struct interfaces_file_t { 105 84 llist_t *autointerfaces; 106 85 llist_t *ifaces; … … 108 87 }; 109 88 110 static char no_act = 0; 111 static char verbose = 0; 112 static char **__myenviron = NULL; 89 #define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:" 90 enum { 91 OPT_do_all = 0x1, 92 OPT_no_act = 0x2, 93 OPT_verbose = 0x4, 94 OPT_force = 0x8, 95 OPT_no_mappings = 0x10, 96 }; 97 #define DO_ALL (option_mask32 & OPT_do_all) 98 #define NO_ACT (option_mask32 & OPT_no_act) 99 #define VERBOSE (option_mask32 & OPT_verbose) 100 #define FORCE (option_mask32 & OPT_force) 101 #define NO_MAPPINGS (option_mask32 & OPT_no_mappings) 102 103 static char **my_environ; 104 105 static const char *startup_PATH; 113 106 114 107 #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 115 108 116 #ifdef CONFIG_FEATURE_IFUPDOWN_IP 117 118 static unsigned int count_bits(unsigned int a) 119 { 120 unsigned int result; 121 result = (a & 0x55) + ((a >> 1) & 0x55); 122 result = (result & 0x33) + ((result >> 2) & 0x33); 123 return((result & 0x0F) + ((result >> 4) & 0x0F)); 124 } 125 126 static int count_netmask_bits(char *dotted_quad) 127 { 128 unsigned int result, a, b, c, d; 129 /* Found a netmask... Check if it is dotted quad */ 130 if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) 131 return -1; 132 result = count_bits(a); 133 result += count_bits(b); 134 result += count_bits(c); 135 result += count_bits(d); 136 return ((int)result); 137 } 138 #endif 139 140 static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length) 141 { 142 if (*pos + str_length >= *len) { 143 char *newbuf; 144 145 newbuf = xrealloc(*buf, *len * 2 + str_length + 1); 146 *buf = newbuf; 147 *len = *len * 2 + str_length + 1; 148 } 149 150 while (str_length-- >= 1) { 151 (*buf)[(*pos)++] = *str; 152 str++; 153 } 154 (*buf)[*pos] = '\0'; 155 } 156 157 static int strncmpz(char *l, char *r, size_t llen) 109 static void addstr(char **bufp, const char *str, size_t str_length) 110 { 111 /* xasprintf trick will be smaller, but we are often 112 * called with str_length == 1 - don't want to have 113 * THAT much of malloc/freeing! */ 114 char *buf = *bufp; 115 int len = (buf ? strlen(buf) : 0); 116 str_length++; 117 buf = xrealloc(buf, len + str_length); 118 /* copies at most str_length-1 chars! */ 119 safe_strncpy(buf + len, str, str_length); 120 *bufp = buf; 121 } 122 123 static int strncmpz(const char *l, const char *r, size_t llen) 158 124 { 159 125 int i = strncmp(l, r, llen); 160 126 161 if (i == 0) { 162 return(-r[llen]); 163 } else { 164 return(i); 165 } 166 } 167 168 static char *get_var(char *id, size_t idlen, struct interface_defn_t *ifd) 127 if (i == 0) 128 return -r[llen]; 129 return i; 130 } 131 132 static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd) 169 133 { 170 134 int i; … … 173 137 char *result; 174 138 static char label_buf[20]; 175 strncpy(label_buf, ifd->iface, 19); 176 label_buf[19]=0; 139 safe_strncpy(label_buf, ifd->iface, sizeof(label_buf)); 177 140 result = strchr(label_buf, ':'); 178 141 if (result) { 179 *result=0; 180 } 181 return( label_buf); 182 } else if (strncmpz(id, "label", idlen) == 0) { 183 return (ifd->iface); 184 } else { 185 for (i = 0; i < ifd->n_options; i++) { 186 if (strncmpz(id, ifd->option[i].name, idlen) == 0) { 187 return (ifd->option[i].value); 188 } 189 } 190 } 191 192 return(NULL); 193 } 194 195 static char *parse(char *command, struct interface_defn_t *ifd) 196 { 197 198 char *result = NULL; 199 size_t pos = 0, len = 0; 142 *result = '\0'; 143 } 144 return label_buf; 145 } 146 if (strncmpz(id, "label", idlen) == 0) { 147 return ifd->iface; 148 } 149 for (i = 0; i < ifd->n_options; i++) { 150 if (strncmpz(id, ifd->option[i].name, idlen) == 0) { 151 return ifd->option[i].value; 152 } 153 } 154 return NULL; 155 } 156 157 #if ENABLE_FEATURE_IFUPDOWN_IP 158 static int count_netmask_bits(const char *dotted_quad) 159 { 160 // int result; 161 // unsigned a, b, c, d; 162 // /* Found a netmask... Check if it is dotted quad */ 163 // if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) 164 // return -1; 165 // if ((a|b|c|d) >> 8) 166 // return -1; /* one of numbers is >= 256 */ 167 // d |= (a << 24) | (b << 16) | (c << 8); /* IP */ 168 // d = ~d; /* 11110000 -> 00001111 */ 169 170 /* Shorter version */ 171 int result; 172 struct in_addr ip; 173 unsigned d; 174 175 if (inet_aton(dotted_quad, &ip) == 0) 176 return -1; /* malformed dotted IP */ 177 d = ntohl(ip.s_addr); /* IP in host order */ 178 d = ~d; /* 11110000 -> 00001111 */ 179 if (d & (d+1)) /* check that it is in 00001111 form */ 180 return -1; /* no it is not */ 181 result = 32; 182 while (d) { 183 d >>= 1; 184 result--; 185 } 186 return result; 187 } 188 #endif 189 190 static char *parse(const char *command, struct interface_defn_t *ifd) 191 { 200 192 size_t old_pos[MAX_OPT_DEPTH] = { 0 }; 201 193 int okay[MAX_OPT_DEPTH] = { 1 }; 202 194 int opt_depth = 1; 195 char *result = NULL; 203 196 204 197 while (*command) { 205 198 switch (*command) { 206 207 default: 208 addstr(&result, &len, &pos, command, 1); 199 default: 200 addstr(&result, command, 1); 201 command++; 202 break; 203 case '\\': 204 if (command[1]) { 205 addstr(&result, command + 1, 1); 206 command += 2; 207 } else { 208 addstr(&result, command, 1); 209 209 command++; 210 break; 211 case '\\': 212 if (command[1]) { 213 addstr(&result, &len, &pos, command + 1, 1); 214 command += 2; 210 } 211 break; 212 case '[': 213 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) { 214 old_pos[opt_depth] = result ? strlen(result) : 0; 215 okay[opt_depth] = 1; 216 opt_depth++; 217 command += 2; 218 } else { 219 addstr(&result, "[", 1); 220 command++; 221 } 222 break; 223 case ']': 224 if (command[1] == ']' && opt_depth > 1) { 225 opt_depth--; 226 if (!okay[opt_depth]) { 227 result[old_pos[opt_depth]] = '\0'; 228 } 229 command += 2; 230 } else { 231 addstr(&result, "]", 1); 232 command++; 233 } 234 break; 235 case '%': 236 { 237 char *nextpercent; 238 char *varvalue; 239 240 command++; 241 nextpercent = strchr(command, '%'); 242 if (!nextpercent) { 243 errno = EUNBALPER; 244 free(result); 245 return NULL; 246 } 247 248 varvalue = get_var(command, nextpercent - command, ifd); 249 250 if (varvalue) { 251 addstr(&result, varvalue, strlen(varvalue)); 215 252 } else { 216 addstr(&result, &len, &pos, command, 1); 217 command++; 218 } 219 break; 220 case '[': 221 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) { 222 old_pos[opt_depth] = pos; 223 okay[opt_depth] = 1; 224 opt_depth++; 225 command += 2; 226 } else { 227 addstr(&result, &len, &pos, "[", 1); 228 command++; 229 } 230 break; 231 case ']': 232 if (command[1] == ']' && opt_depth > 1) { 233 opt_depth--; 234 if (!okay[opt_depth]) { 235 pos = old_pos[opt_depth]; 236 result[pos] = '\0'; 237 } 238 command += 2; 239 } else { 240 addstr(&result, &len, &pos, "]", 1); 241 command++; 242 } 243 break; 244 case '%': 245 { 246 char *nextpercent; 247 char *varvalue; 248 249 command++; 250 nextpercent = strchr(command, '%'); 251 if (!nextpercent) { 252 errno = EUNBALPER; 253 free(result); 254 return (NULL); 255 } 256 257 varvalue = get_var(command, nextpercent - command, ifd); 258 259 if (varvalue) { 260 addstr(&result, &len, &pos, varvalue, strlen(varvalue)); 261 } else { 262 #ifdef CONFIG_FEATURE_IFUPDOWN_IP 263 /* Sigh... Add a special case for 'ip' to convert from 264 * dotted quad to bit count style netmasks. */ 265 if (strncmp(command, "bnmask", 6)==0) { 266 int res; 267 varvalue = get_var("netmask", 7, ifd); 268 if (varvalue && (res=count_netmask_bits(varvalue)) > 0) { 269 char argument[255]; 270 sprintf(argument, "%d", res); 271 addstr(&result, &len, &pos, argument, strlen(argument)); 253 #if ENABLE_FEATURE_IFUPDOWN_IP 254 /* Sigh... Add a special case for 'ip' to convert from 255 * dotted quad to bit count style netmasks. */ 256 if (strncmp(command, "bnmask", 6) == 0) { 257 unsigned res; 258 varvalue = get_var("netmask", 7, ifd); 259 if (varvalue) { 260 res = count_netmask_bits(varvalue); 261 if (res > 0) { 262 const char *argument = utoa(res); 263 addstr(&result, argument, strlen(argument)); 272 264 command = nextpercent + 1; 273 265 break; 274 266 } 275 267 } 276 #endif277 okay[opt_depth - 1] = 0;278 268 } 279 280 command = nextpercent + 1; 281 } 282 break; 269 #endif 270 okay[opt_depth - 1] = 0; 271 } 272 273 command = nextpercent + 1; 274 } 275 break; 283 276 } 284 277 } … … 287 280 errno = EUNBALBRACK; 288 281 free(result); 289 return (NULL);282 return NULL; 290 283 } 291 284 … … 293 286 errno = EUNDEFVAR; 294 287 free(result); 295 return(NULL); 296 } 297 298 return(result); 299 } 300 301 static int execute(char *command, struct interface_defn_t *ifd, execfn *exec) 288 return NULL; 289 } 290 291 return result; 292 } 293 294 /* execute() returns 1 for success and 0 for failure */ 295 static int execute(const char *command, struct interface_defn_t *ifd, execfn *exec) 302 296 { 303 297 char *out; … … 306 300 out = parse(command, ifd); 307 301 if (!out) { 308 return(0); 309 } 310 ret = (*exec) (out); 302 /* parse error? */ 303 return 0; 304 } 305 /* out == "": parsed ok but not all needed variables known, skip */ 306 ret = out[0] ? (*exec)(out) : 1; 311 307 312 308 free(out); 313 309 if (ret != 1) { 314 return (0);315 } 316 return (1);317 } 318 #endif 319 320 #if def CONFIG_FEATURE_IFUPDOWN_IPV6310 return 0; 311 } 312 return 1; 313 } 314 #endif 315 316 #if ENABLE_FEATURE_IFUPDOWN_IPV6 321 317 static int loopback_up6(struct interface_defn_t *ifd, execfn *exec) 322 318 { 323 #if def CONFIG_FEATURE_IFUPDOWN_IP319 #if ENABLE_FEATURE_IFUPDOWN_IP 324 320 int result; 325 result = execute("ip addr add ::1 dev %iface%", ifd, exec);321 result = execute("ip addr add ::1 dev %iface%", ifd, exec); 326 322 result += execute("ip link set %iface% up", ifd, exec); 327 323 return ((result == 2) ? 2 : 0); 328 324 #else 329 return ( execute("ifconfig %iface% add ::1", ifd, exec));325 return execute("ifconfig %iface% add ::1", ifd, exec); 330 326 #endif 331 327 } … … 333 329 static int loopback_down6(struct interface_defn_t *ifd, execfn *exec) 334 330 { 335 #if def CONFIG_FEATURE_IFUPDOWN_IP336 return (execute("ip link set %iface% down", ifd, exec));331 #if ENABLE_FEATURE_IFUPDOWN_IP 332 return execute("ip link set %iface% down", ifd, exec); 337 333 #else 338 return (execute("ifconfig %iface% del ::1", ifd, exec));334 return execute("ifconfig %iface% del ::1", ifd, exec); 339 335 #endif 340 336 } … … 343 339 { 344 340 int result; 345 #ifdef CONFIG_FEATURE_IFUPDOWN_IP 346 result = execute("ip addr add %address%/%netmask% dev %iface% [[label %label%]]", ifd, exec); 347 result += execute("ip link set [[mtu %mtu%]] [[address %hwaddress%]] %iface% up", ifd, exec); 348 result += execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec); 341 #if ENABLE_FEATURE_IFUPDOWN_IP 342 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); 343 result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec); 344 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ 345 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); 349 346 #else 350 result = execute("ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up", ifd, exec);347 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); 351 348 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); 352 result += execute("[[ route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);349 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); 353 350 #endif 354 351 return ((result == 3) ? 3 : 0); … … 357 354 static int static_down6(struct interface_defn_t *ifd, execfn *exec) 358 355 { 359 #if def CONFIG_FEATURE_IFUPDOWN_IP360 return (execute("ip link set %iface% down", ifd, exec));356 #if ENABLE_FEATURE_IFUPDOWN_IP 357 return execute("ip link set %iface% down", ifd, exec); 361 358 #else 362 return (execute("ifconfig %iface% down", ifd, exec));363 #endif 364 } 365 366 #if def CONFIG_FEATURE_IFUPDOWN_IP359 return execute("ifconfig %iface% down", ifd, exec); 360 #endif 361 } 362 363 #if ENABLE_FEATURE_IFUPDOWN_IP 367 364 static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec) 368 365 { 369 366 int result; 370 367 result = execute("ip tunnel add %iface% mode sit remote " 371 "%endpoint% [[local %local%]] [[ttl %ttl%]]", ifd, exec);368 "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd, exec); 372 369 result += execute("ip link set %iface% up", ifd, exec); 373 370 result += execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec); 374 result += execute("[[ ip route add ::/0 via %gateway%]]", ifd, exec);371 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); 375 372 return ((result == 4) ? 4 : 0); 376 373 } … … 378 375 static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec) 379 376 { 380 return ( execute("ip tunnel del %iface%", ifd, exec));381 } 382 #endif 383 384 static struct method_t methods6[] = {385 #if def CONFIG_FEATURE_IFUPDOWN_IP377 return execute("ip tunnel del %iface%", ifd, exec); 378 } 379 #endif 380 381 static const struct method_t methods6[] = { 382 #if ENABLE_FEATURE_IFUPDOWN_IP 386 383 { "v4tunnel", v4tunnel_up, v4tunnel_down, }, 387 384 #endif … … 390 387 }; 391 388 392 static struct address_family_t addr_inet6 = {389 static const struct address_family_t addr_inet6 = { 393 390 "inet6", 394 sizeof(methods6) / sizeof(struct method_t),391 ARRAY_SIZE(methods6), 395 392 methods6 396 393 }; 397 #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */398 399 #if def CONFIG_FEATURE_IFUPDOWN_IPV4394 #endif /* FEATURE_IFUPDOWN_IPV6 */ 395 396 #if ENABLE_FEATURE_IFUPDOWN_IPV4 400 397 static int loopback_up(struct interface_defn_t *ifd, execfn *exec) 401 398 { 402 #if def CONFIG_FEATURE_IFUPDOWN_IP399 #if ENABLE_FEATURE_IFUPDOWN_IP 403 400 int result; 404 401 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec); … … 406 403 return ((result == 2) ? 2 : 0); 407 404 #else 408 return ( execute("ifconfig %iface% 127.0.0.1 up", ifd, exec));405 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec); 409 406 #endif 410 407 } … … 412 409 static int loopback_down(struct interface_defn_t *ifd, execfn *exec) 413 410 { 414 #if def CONFIG_FEATURE_IFUPDOWN_IP411 #if ENABLE_FEATURE_IFUPDOWN_IP 415 412 int result; 416 413 result = execute("ip addr flush dev %iface%", ifd, exec); … … 418 415 return ((result == 2) ? 2 : 0); 419 416 #else 420 return ( execute("ifconfig %iface% 127.0.0.1 down", ifd, exec));417 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec); 421 418 #endif 422 419 } … … 425 422 { 426 423 int result; 427 #if def CONFIG_FEATURE_IFUPDOWN_IP428 result = execute("ip addr add %address%/%bnmask% [[broadcast %broadcast%]] "429 "dev %iface% [[peer %pointopoint%]] [[label %label%]]", ifd, exec);430 result += execute("ip link set [[mtu %mtu%]] [[address %hwaddress%]] %iface% up", ifd, exec);431 result += execute("[[ ip route add default via %gateway% dev %iface%]]", ifd, exec);424 #if ENABLE_FEATURE_IFUPDOWN_IP 425 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " 426 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); 427 result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec); 428 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); 432 429 return ((result == 3) ? 3 : 0); 433 430 #else 434 result = execute("ifconfig %iface% %address% netmask %netmask% "435 "[[broadcast %broadcast%]] [[pointopoint %pointopoint%]] "436 "[[media %media%]] [[mtu %mtu%]] [[hw %hwaddress%]] up",431 /* ifconfig said to set iface up before it processes hw %hwaddress%, 432 * which then of course fails. Thus we run two separate ifconfig */ 433 result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up", 437 434 ifd, exec); 438 result += execute("[[ route add default gw %gateway% %iface% ]]", ifd, exec); 439 return ((result == 2) ? 2 : 0); 435 result += execute("ifconfig %iface% %address% netmask %netmask%" 436 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ", 437 ifd, exec); 438 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); 439 return ((result == 3) ? 3 : 0); 440 440 #endif 441 441 } … … 444 444 { 445 445 int result; 446 #if def CONFIG_FEATURE_IFUPDOWN_IP446 #if ENABLE_FEATURE_IFUPDOWN_IP 447 447 result = execute("ip addr flush dev %iface%", ifd, exec); 448 448 result += execute("ip link set %iface% down", ifd, exec); 449 449 #else 450 result = execute("[[ route del default gw %gateway% %iface%]]", ifd, exec);450 result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); 451 451 result += execute("ifconfig %iface% down", ifd, exec); 452 452 #endif … … 454 454 } 455 455 456 static int execable(char *program) 457 { 458 struct stat buf; 459 if (0 == stat(program, &buf)) { 460 if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) { 461 return(1); 462 } 463 } 464 return(0); 465 } 456 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 457 struct dhcp_client_t 458 { 459 const char *name; 460 const char *startcmd; 461 const char *stopcmd; 462 }; 463 464 static const struct dhcp_client_t ext_dhcp_clients[] = { 465 { "dhcpcd", 466 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%", 467 "dhcpcd -k %iface%", 468 }, 469 { "dhclient", 470 "dhclient -pf /var/run/dhclient.%iface%.pid %iface%", 471 "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null", 472 }, 473 { "pump", 474 "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]", 475 "pump -i %iface% -k", 476 }, 477 { "udhcpc", 478 "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]", 479 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", 480 }, 481 }; 482 #endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ 466 483 467 484 static int dhcp_up(struct interface_defn_t *ifd, execfn *exec) 468 485 { 469 if (execable("/sbin/udhcpc")) { 470 return( execute("udhcpc -n -p /var/run/udhcpc.%iface%.pid -i " 471 "%iface% [[-H %hostname%]] [[-c %clientid%]]", ifd, exec)); 472 } else if (execable("/sbin/pump")) { 473 return( execute("pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]]", ifd, exec)); 474 } else if (execable("/sbin/dhclient")) { 475 return( execute("dhclient -pf /var/run/dhclient.%iface%.pid %iface%", ifd, exec)); 476 } else if (execable("/sbin/dhcpcd")) { 477 return( execute("dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] " 478 "[[-l %leasetime%]] %iface%", ifd, exec)); 479 } 480 return(0); 486 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 487 int i; 488 #if ENABLE_FEATURE_IFUPDOWN_IP 489 /* ip doesn't up iface when it configures it (unlike ifconfig) */ 490 if (!execute("ip link set %iface% up", ifd, exec)) 491 return 0; 492 #endif 493 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { 494 if (exists_execable(ext_dhcp_clients[i].name)) 495 return execute(ext_dhcp_clients[i].startcmd, ifd, exec); 496 } 497 bb_error_msg("no dhcp clients found"); 498 return 0; 499 #elif ENABLE_APP_UDHCPC 500 #if ENABLE_FEATURE_IFUPDOWN_IP 501 /* ip doesn't up iface when it configures it (unlike ifconfig) */ 502 if (!execute("ip link set %iface% up", ifd, exec)) 503 return 0; 504 #endif 505 return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid " 506 "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]", 507 ifd, exec); 508 #else 509 return 0; /* no dhcp support */ 510 #endif 481 511 } 482 512 483 513 static int dhcp_down(struct interface_defn_t *ifd, execfn *exec) 484 514 { 485 int result = 0; 486 if (execable("/sbin/udhcpc")) { 487 /* SIGUSR2 forces udhcpc to release the current lease and go inactive, 488 * and SIGTERM causes udhcpc to exit. Signals are queued and processed 489 * sequentially so we don't need to sleep */ 490 result = execute("kill -USR2 `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec); 491 result += execute("kill -TERM `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec); 492 } else if (execable("/sbin/pump")) { 493 result = execute("pump -i %iface% -k", ifd, exec); 494 } else if (execable("/sbin/dhclient")) { 495 result = execute("kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null", ifd, exec); 496 } else if (execable("/sbin/dhcpcd")) { 497 result = execute("dhcpcd -k %iface%", ifd, exec); 498 } 499 return (result || static_down(ifd, exec)); 515 #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 516 int i; 517 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { 518 if (exists_execable(ext_dhcp_clients[i].name)) 519 return execute(ext_dhcp_clients[i].stopcmd, ifd, exec); 520 } 521 bb_error_msg("no dhcp clients found, using static interface shutdown"); 522 return static_down(ifd, exec); 523 #elif ENABLE_APP_UDHCPC 524 return execute("kill " 525 "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec); 526 #else 527 return 0; /* no dhcp support */ 528 #endif 529 } 530 531 static int manual_up_down(struct interface_defn_t *ifd, execfn *exec) 532 { 533 return 1; 500 534 } 501 535 502 536 static int bootp_up(struct interface_defn_t *ifd, execfn *exec) 503 537 { 504 return ( execute("bootpc [[--bootfile %bootfile%]] --dev %iface%"505 "[[--server %server%]] [[--hwaddr %hwaddr%]]"506 "--returniffail --serverbcast", ifd, exec));538 return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%" 539 "[[ --server %server%]][[ --hwaddr %hwaddr%]]" 540 " --returniffail --serverbcast", ifd, exec); 507 541 } 508 542 509 543 static int ppp_up(struct interface_defn_t *ifd, execfn *exec) 510 544 { 511 return ( execute("pon [[%provider%]]", ifd, exec));545 return execute("pon[[ %provider%]]", ifd, exec); 512 546 } 513 547 514 548 static int ppp_down(struct interface_defn_t *ifd, execfn *exec) 515 549 { 516 return ( execute("poff [[%provider%]]", ifd, exec));550 return execute("poff[[ %provider%]]", ifd, exec); 517 551 } 518 552 519 553 static int wvdial_up(struct interface_defn_t *ifd, execfn *exec) 520 554 { 521 return ( execute("/sbin/start-stop-daemon --start -x /usr/bin/wvdial "522 "-p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]", ifd, exec));555 return execute("start-stop-daemon --start -x wvdial " 556 "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd, exec); 523 557 } 524 558 525 559 static int wvdial_down(struct interface_defn_t *ifd, execfn *exec) 526 560 { 527 return ( execute("/sbin/start-stop-daemon --stop -x /usr/bin/wvdial "528 "-p /var/run/wvdial.%iface% -s 2", ifd, exec));529 } 530 531 static struct method_t methods[] =532 { 561 return execute("start-stop-daemon --stop -x wvdial " 562 "-p /var/run/wvdial.%iface% -s 2", ifd, exec); 563 } 564 565 static const struct method_t methods[] = { 566 { "manual", manual_up_down, manual_up_down, }, 533 567 { "wvdial", wvdial_up, wvdial_down, }, 534 568 { "ppp", ppp_up, ppp_down, }, … … 539 573 }; 540 574 541 static struct address_family_t addr_inet = 542 { 575 static const struct address_family_t addr_inet = { 543 576 "inet", 544 sizeof(methods) / sizeof(struct method_t),577 ARRAY_SIZE(methods), 545 578 methods 546 579 }; 547 580 548 #endif /* if def CONFIG_FEATURE_IFUPDOWN_IPV4 */581 #endif /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */ 549 582 550 583 static char *next_word(char **buf) … … 553 586 char *word; 554 587 555 if ( (buf == NULL) || (*buf == NULL) || (**buf == '\0')) {588 if (!buf || !*buf || !**buf) { 556 589 return NULL; 557 590 } 558 591 559 592 /* Skip over leading whitespace */ 560 word = *buf; 561 while (isspace(*word)) { 562 ++word; 563 } 593 word = skip_whitespace(*buf); 564 594 565 595 /* Skip over comments */ 566 596 if (*word == '#') { 567 return (NULL);597 return NULL; 568 598 } 569 599 … … 571 601 length = strcspn(word, " \t\n"); 572 602 if (length == 0) { 573 return (NULL);603 return NULL; 574 604 } 575 605 *buf = word + length; … … 583 613 } 584 614 585 static struct address_family_t *get_address_family(struct address_family_t *af[], char *name)615 static const struct address_family_t *get_address_family(const struct address_family_t *const af[], char *name) 586 616 { 587 617 int i; 618 619 if (!name) 620 return NULL; 588 621 589 622 for (i = 0; af[i]; i++) { … … 595 628 } 596 629 597 static struct method_t *get_method(struct address_family_t *af, char *name)630 static const struct method_t *get_method(const struct address_family_t *af, char *name) 598 631 { 599 632 int i; 633 634 if (!name) 635 return NULL; 600 636 601 637 for (i = 0; i < af->n_methods; i++) { … … 604 640 } 605 641 } 606 return (NULL);642 return NULL; 607 643 } 608 644 609 645 static const llist_t *find_list_string(const llist_t *list, const char *string) 610 646 { 647 if (string == NULL) 648 return NULL; 649 611 650 while (list) { 612 651 if (strcmp(list->data, string) == 0) { 613 return (list);652 return list; 614 653 } 615 654 list = list->link; 616 655 } 617 return (NULL);656 return NULL; 618 657 } 619 658 620 659 static struct interfaces_file_t *read_interfaces(const char *filename) 621 660 { 622 #if def CONFIG_FEATURE_IFUPDOWN_MAPPING661 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 623 662 struct mapping_defn_t *currmap = NULL; 624 663 #endif … … 633 672 defn = xzalloc(sizeof(struct interfaces_file_t)); 634 673 635 f = bb_xfopen(filename, "r");636 637 while ((buf = bb_get_chomped_line_from_file(f)) != NULL) {674 f = xfopen(filename, "r"); 675 676 while ((buf = xmalloc_getline(f)) != NULL) { 638 677 char *buf_ptr = buf; 639 678 … … 645 684 646 685 if (strcmp(firstword, "mapping") == 0) { 647 #if def CONFIG_FEATURE_IFUPDOWN_MAPPING686 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 648 687 currmap = xzalloc(sizeof(struct mapping_defn_t)); 649 688 … … 654 693 } 655 694 656 currmap->match[currmap->n_matches++] = bb_xstrdup(firstword);695 currmap->match[currmap->n_matches++] = xstrdup(firstword); 657 696 } 658 697 currmap->max_mappings = 0; … … 672 711 currently_processing = MAPPING; 673 712 } else if (strcmp(firstword, "iface") == 0) { 674 { 675 char *iface_name; 676 char *address_family_name; 677 char *method_name; 678 struct address_family_t *addr_fams[] = { 679 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4 680 &addr_inet, 681 #endif 682 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6 683 &addr_inet6, 684 #endif 685 NULL 686 }; 687 688 currif = xzalloc(sizeof(struct interface_defn_t)); 689 iface_name = next_word(&buf_ptr); 690 address_family_name = next_word(&buf_ptr); 691 method_name = next_word(&buf_ptr); 692 693 if (buf_ptr == NULL) { 694 bb_error_msg("too few parameters for line \"%s\"", buf); 713 static const struct address_family_t *const addr_fams[] = { 714 #if ENABLE_FEATURE_IFUPDOWN_IPV4 715 &addr_inet, 716 #endif 717 #if ENABLE_FEATURE_IFUPDOWN_IPV6 718 &addr_inet6, 719 #endif 720 NULL 721 }; 722 723 char *iface_name; 724 char *address_family_name; 725 char *method_name; 726 llist_t *iface_list; 727 728 currif = xzalloc(sizeof(struct interface_defn_t)); 729 iface_name = next_word(&buf_ptr); 730 address_family_name = next_word(&buf_ptr); 731 method_name = next_word(&buf_ptr); 732 733 if (buf_ptr == NULL) { 734 bb_error_msg("too few parameters for line \"%s\"", buf); 735 return NULL; 736 } 737 738 /* ship any trailing whitespace */ 739 buf_ptr = skip_whitespace(buf_ptr); 740 741 if (buf_ptr[0] != '\0') { 742 bb_error_msg("too many parameters \"%s\"", buf); 743 return NULL; 744 } 745 746 currif->iface = xstrdup(iface_name); 747 748 currif->address_family = get_address_family(addr_fams, address_family_name); 749 if (!currif->address_family) { 750 bb_error_msg("unknown address type \"%s\"", address_family_name); 751 return NULL; 752 } 753 754 currif->method = get_method(currif->address_family, method_name); 755 if (!currif->method) { 756 bb_error_msg("unknown method \"%s\"", method_name); 757 return NULL; 758 } 759 760 for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) { 761 struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data; 762 if ((strcmp(tmp->iface, currif->iface) == 0) && 763 (tmp->address_family == currif->address_family)) { 764 bb_error_msg("duplicate interface \"%s\"", tmp->iface); 695 765 return NULL; 696 766 } 697 698 /* ship any trailing whitespace */ 699 while (isspace(*buf_ptr)) { 700 ++buf_ptr; 701 } 702 703 if (buf_ptr[0] != '\0') { 704 bb_error_msg("too many parameters \"%s\"", buf); 705 return NULL; 706 } 707 708 currif->iface = bb_xstrdup(iface_name); 709 710 currif->address_family = get_address_family(addr_fams, address_family_name); 711 if (!currif->address_family) { 712 bb_error_msg("unknown address type \"%s\"", address_family_name); 713 return NULL; 714 } 715 716 currif->method = get_method(currif->address_family, method_name); 717 if (!currif->method) { 718 bb_error_msg("unknown method \"%s\"", method_name); 719 return NULL; 720 } 721 722 723 { 724 llist_t *iface_list; 725 for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) { 726 struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data; 727 if ((strcmp(tmp->iface, currif->iface) == 0) && 728 (tmp->address_family == currif->address_family)) { 729 bb_error_msg("duplicate interface \"%s\"", tmp->iface); 730 return NULL; 731 } 732 } 733 734 llist_add_to_end(&(defn->ifaces), (char*)currif); 735 } 736 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name); 737 } 767 } 768 llist_add_to_end(&(defn->ifaces), (char*)currif); 769 770 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name); 738 771 currently_processing = IFACE; 739 772 } else if (strcmp(firstword, "auto") == 0) { … … 746 779 747 780 /* Add the interface to the list */ 748 llist_add_to_end(&(defn->autointerfaces), bb_xstrdup(firstword));781 llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword)); 749 782 debug_noise("\nauto %s\n", firstword); 750 783 } … … 752 785 } else { 753 786 switch (currently_processing) { 754 case IFACE: 755 { 756 int i; 757 758 if (strlen(buf_ptr) == 0) { 759 bb_error_msg("option with empty value \"%s\"", buf); 760 return NULL; 761 } 762 763 if (strcmp(firstword, "up") != 0 764 && strcmp(firstword, "down") != 0 765 && strcmp(firstword, "pre-up") != 0 766 && strcmp(firstword, "post-down") != 0) { 767 for (i = 0; i < currif->n_options; i++) { 768 if (strcmp(currif->option[i].name, firstword) == 0) { 769 bb_error_msg("duplicate option \"%s\"", buf); 770 return NULL; 771 } 787 case IFACE: 788 { 789 int i; 790 791 if (strlen(buf_ptr) == 0) { 792 bb_error_msg("option with empty value \"%s\"", buf); 793 return NULL; 794 } 795 796 if (strcmp(firstword, "up") != 0 797 && strcmp(firstword, "down") != 0 798 && strcmp(firstword, "pre-up") != 0 799 && strcmp(firstword, "post-down") != 0) { 800 for (i = 0; i < currif->n_options; i++) { 801 if (strcmp(currif->option[i].name, firstword) == 0) { 802 bb_error_msg("duplicate option \"%s\"", buf); 803 return NULL; 772 804 } 773 805 } 774 806 } 775 if (currif->n_options >= currif->max_options) { 776 struct variable_t *opt; 777 778 currif->max_options = currif->max_options + 10; 779 opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options); 780 currif->option = opt; 807 } 808 if (currif->n_options >= currif->max_options) { 809 struct variable_t *opt; 810 811 currif->max_options = currif->max_options + 10; 812 opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options); 813 currif->option = opt; 814 } 815 currif->option[currif->n_options].name = xstrdup(firstword); 816 currif->option[currif->n_options].value = xstrdup(buf_ptr); 817 if (!currif->option[currif->n_options].name) { 818 perror(filename); 819 return NULL; 820 } 821 if (!currif->option[currif->n_options].value) { 822 perror(filename); 823 return NULL; 824 } 825 debug_noise("\t%s=%s\n", currif->option[currif->n_options].name, 826 currif->option[currif->n_options].value); 827 currif->n_options++; 828 break; 829 case MAPPING: 830 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 831 if (strcmp(firstword, "script") == 0) { 832 if (currmap->script != NULL) { 833 bb_error_msg("duplicate script in mapping \"%s\"", buf); 834 return NULL; 835 } else { 836 currmap->script = xstrdup(next_word(&buf_ptr)); 781 837 } 782 currif->option[currif->n_options].name = bb_xstrdup(firstword); 783 currif->option[currif->n_options].value = bb_xstrdup(buf_ptr); 784 if (!currif->option[currif->n_options].name) { 785 perror(filename); 786 return NULL; 838 } else if (strcmp(firstword, "map") == 0) { 839 if (currmap->max_mappings == currmap->n_mappings) { 840 currmap->max_mappings = currmap->max_mappings * 2 + 1; 841 currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings); 787 842 } 788 if (!currif->option[currif->n_options].value) { 789 perror(filename); 790 return NULL; 791 } 792 debug_noise("\t%s=%s\n", currif->option[currif->n_options].name, 793 currif->option[currif->n_options].value); 794 currif->n_options++; 795 break; 796 case MAPPING: 797 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING 798 if (strcmp(firstword, "script") == 0) { 799 if (currmap->script != NULL) { 800 bb_error_msg("duplicate script in mapping \"%s\"", buf); 801 return NULL; 802 } else { 803 currmap->script = bb_xstrdup(next_word(&buf_ptr)); 804 } 805 } else if (strcmp(firstword, "map") == 0) { 806 if (currmap->max_mappings == currmap->n_mappings) { 807 currmap->max_mappings = currmap->max_mappings * 2 + 1; 808 currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings); 809 } 810 currmap->mapping[currmap->n_mappings] = bb_xstrdup(next_word(&buf_ptr)); 811 currmap->n_mappings++; 812 } else { 813 bb_error_msg("misplaced option \"%s\"", buf); 814 return NULL; 815 } 816 #endif 817 break; 818 case NONE: 819 default: 843 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr)); 844 currmap->n_mappings++; 845 } else { 820 846 bb_error_msg("misplaced option \"%s\"", buf); 821 847 return NULL; 848 } 849 #endif 850 break; 851 case NONE: 852 default: 853 bb_error_msg("misplaced option \"%s\"", buf); 854 return NULL; 822 855 } 823 856 } … … 825 858 } 826 859 if (ferror(f) != 0) { 827 bb_perror_msg_and_die("%s", filename); 860 /* ferror does NOT set errno! */ 861 bb_error_msg_and_die("%s: I/O error", filename); 828 862 } 829 863 fclose(f); … … 832 866 } 833 867 834 static char *setlocalenv(c har *format, const char *name, const char *value)868 static char *setlocalenv(const char *format, const char *name, const char *value) 835 869 { 836 870 char *result; … … 838 872 char *there; 839 873 840 result = bb_xasprintf(format, name, value);874 result = xasprintf(format, name, value); 841 875 842 876 for (here = there = result; *there != '=' && *there; there++) { … … 863 897 char **ppch; 864 898 865 if ( __myenviron != NULL) {866 for (ppch = __myenviron; *ppch; ppch++) {899 if (my_environ != NULL) { 900 for (ppch = my_environ; *ppch; ppch++) { 867 901 free(*ppch); 868 902 *ppch = NULL; 869 903 } 870 free( __myenviron);871 } 872 __myenviron = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));873 environend = __myenviron;904 free(my_environ); 905 } 906 my_environ = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ )); 907 environend = my_environ; 874 908 875 909 for (i = 0; i < iface->n_options; i++) { 876 910 if (strcmp(iface->option[i].name, "up") == 0 877 || strcmp(iface->option[i].name, "down") == 0 878 || strcmp(iface->option[i].name, "pre-up") == 0 879 || strcmp(iface->option[i].name, "post-down") == 0) { 911 || strcmp(iface->option[i].name, "down") == 0 912 || strcmp(iface->option[i].name, "pre-up") == 0 913 || strcmp(iface->option[i].name, "post-down") == 0 914 ) { 880 915 continue; 881 916 } … … 887 922 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name); 888 923 *(environend++) = setlocalenv("%s=%s", "MODE", mode); 889 *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");924 *(environend++) = setlocalenv("%s=%s", "PATH", startup_PATH); 890 925 } 891 926 892 927 static int doit(char *str) 893 928 { 894 if ( verbose || no_act) {895 p rintf("%s\n",str);896 } 897 if (! no_act) {929 if (option_mask32 & (OPT_no_act|OPT_verbose)) { 930 puts(str); 931 } 932 if (!(option_mask32 & OPT_no_act)) { 898 933 pid_t child; 899 934 int status; 900 935 901 936 fflush(NULL); 902 switch (child = fork()) { 903 case -1: /* failure */ 904 return 0; 905 case 0: /* child */ 906 execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, __myenviron); 907 exit(127); 937 child = fork(); 938 switch (child) { 939 case -1: /* failure */ 940 return 0; 941 case 0: /* child */ 942 execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ); 943 exit(127); 908 944 } 909 945 waitpid(child, &status, 0); … … 912 948 } 913 949 } 914 return (1);950 return 1; 915 951 } 916 952 … … 927 963 } 928 964 929 buf = bb_xasprintf("run-parts /etc/network/if-%s.d", opt); 930 if (doit(buf) != 1) { 931 return 0; 932 } 933 return 1; 934 } 935 936 static int check(char *str) { 965 buf = xasprintf("run-parts /etc/network/if-%s.d", opt); 966 /* heh, we don't bother free'ing it */ 967 return doit(buf); 968 } 969 970 static int check(char *str) 971 { 937 972 return str != NULL; 938 973 } … … 940 975 static int iface_up(struct interface_defn_t *iface) 941 976 { 942 if (!iface->method->up(iface, check)) return -1;977 if (!iface->method->up(iface, check)) return -1; 943 978 set_environ(iface, "start"); 944 979 if (!execute_all(iface, "pre-up")) return 0; … … 958 993 } 959 994 960 #if def CONFIG_FEATURE_IFUPDOWN_MAPPING995 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 961 996 static int popen2(FILE **in, FILE **out, char *command, ...) 962 997 { … … 987 1022 fflush(NULL); 988 1023 switch (pid = fork()) { 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 execvp(command, argv);1003 1004 1005 1006 1007 1008 1009 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; 1010 1045 } 1011 1046 /* unreached */ … … 1018 1053 pid_t pid; 1019 1054 1020 char *logical = bb_xstrdup(physical);1055 char *logical = xstrdup(physical); 1021 1056 1022 1057 /* Run the mapping script. */ … … 1038 1073 * grab a line of output and use that as the name of the 1039 1074 * logical interface. */ 1040 char *new_logical = (char *)xmalloc(MAX_INTERFACE_LENGTH);1075 char *new_logical = xmalloc(MAX_INTERFACE_LENGTH); 1041 1076 1042 1077 if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) { … … 1062 1097 return logical; 1063 1098 } 1064 #endif /* CONFIG_FEATURE_IFUPDOWN_MAPPING */1099 #endif /* FEATURE_IFUPDOWN_MAPPING */ 1065 1100 1066 1101 static llist_t *find_iface_state(llist_t *state_list, const char *iface) … … 1070 1105 1071 1106 while (search) { 1072 if ((strncmp(search->data, iface, iface_len) == 0) &&1073 1074 return (search);1107 if ((strncmp(search->data, iface, iface_len) == 0) 1108 && (search->data[iface_len] == '=')) { 1109 return search; 1075 1110 } 1076 1111 search = search->link; 1077 1112 } 1078 return(NULL); 1079 } 1080 1113 return NULL; 1114 } 1115 1116 /* read the previous state from the state file */ 1117 static llist_t *read_iface_state(void) 1118 { 1119 llist_t *state_list = NULL; 1120 FILE *state_fp = fopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "r"); 1121 1122 if (state_fp) { 1123 char *start, *end_ptr; 1124 while ((start = xmalloc_fgets(state_fp)) != NULL) { 1125 /* We should only need to check for a single character */ 1126 end_ptr = start + strcspn(start, " \t\n"); 1127 *end_ptr = '\0'; 1128 llist_add_to(&state_list, start); 1129 } 1130 fclose(state_fp); 1131 } 1132 return state_list; 1133 } 1134 1135 1136 int ifupdown_main(int argc, char **argv); 1081 1137 int ifupdown_main(int argc, char **argv) 1082 1138 { 1083 int (*cmds) 1139 int (*cmds)(struct interface_defn_t *) = NULL; 1084 1140 struct interfaces_file_t *defn; 1085 llist_t *state_list = NULL;1086 1141 llist_t *target_list = NULL; 1087 1142 const char *interfaces = "/etc/network/interfaces"; 1088 const char *statefile = "/var/run/ifstate"; 1089 1090 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING 1091 int run_mappings = 1; 1092 #endif 1093 int do_all = 0; 1094 int force = 0; 1095 int any_failures = 0; 1096 int i; 1097 1098 if (bb_applet_name[2] == 'u') { 1143 bool any_failures = 0; 1144 1145 cmds = iface_down; 1146 if (applet_name[2] == 'u') { 1099 1147 /* ifup command */ 1100 1148 cmds = iface_up; 1149 } 1150 1151 getopt32(argv, OPTION_STR, &interfaces); 1152 if (argc - optind > 0) { 1153 if (DO_ALL) bb_show_usage(); 1101 1154 } else { 1102 /* ifdown command */ 1103 cmds = iface_down; 1104 } 1105 1106 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING 1107 while ((i = getopt(argc, argv, "i:hvnamf")) != -1) 1108 #else 1109 while ((i = getopt(argc, argv, "i:hvnaf")) != -1) 1110 #endif 1111 { 1112 switch (i) { 1113 case 'i': /* interfaces */ 1114 interfaces = optarg; 1115 break; 1116 case 'v': /* verbose */ 1117 verbose = 1; 1118 break; 1119 case 'a': /* all */ 1120 do_all = 1; 1121 break; 1122 case 'n': /* no-act */ 1123 no_act = 1; 1124 break; 1125 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING 1126 case 'm': /* no-mappings */ 1127 run_mappings = 0; 1128 break; 1129 #endif 1130 case 'f': /* force */ 1131 force = 1; 1132 break; 1133 default: 1134 bb_show_usage(); 1135 break; 1136 } 1137 } 1138 1139 if (argc - optind > 0) { 1140 if (do_all) { 1141 bb_show_usage(); 1142 } 1143 } else { 1144 if (!do_all) { 1145 bb_show_usage(); 1146 } 1155 if (!DO_ALL) bb_show_usage(); 1147 1156 } 1148 1157 … … 1152 1161 1153 1162 if (!defn) { 1154 exit(EXIT_FAILURE); 1155 } 1163 return EXIT_FAILURE; 1164 } 1165 1166 startup_PATH = getenv("PATH"); 1167 if (!startup_PATH) startup_PATH = ""; 1156 1168 1157 1169 /* Create a list of interfaces to work on */ 1158 if (do_all) { 1159 if (cmds == iface_up) { 1160 target_list = defn->autointerfaces; 1161 } else { 1162 /* iface_down */ 1163 const llist_t *list = state_list; 1164 while (list) { 1165 llist_add_to_end(&target_list, bb_xstrdup(list->data)); 1166 list = list->link; 1167 } 1168 target_list = defn->autointerfaces; 1169 } 1170 if (DO_ALL) { 1171 target_list = defn->autointerfaces; 1170 1172 } else { 1171 1173 llist_add_to_end(&target_list, argv[optind]); 1172 1174 } 1173 1174 1175 1175 1176 /* Update the interfaces */ … … 1180 1181 char *liface; 1181 1182 char *pch; 1182 intokay = 0;1183 intcmds_ret;1184 1185 iface = bb_xstrdup(target_list->data);1183 bool okay = 0; 1184 unsigned cmds_ret; 1185 1186 iface = xstrdup(target_list->data); 1186 1187 target_list = target_list->link; 1187 1188 … … 1189 1190 if (pch) { 1190 1191 *pch = '\0'; 1191 liface = bb_xstrdup(pch + 1);1192 liface = xstrdup(pch + 1); 1192 1193 } else { 1193 liface = bb_xstrdup(iface); 1194 } 1195 1196 if (!force) { 1194 liface = xstrdup(iface); 1195 } 1196 1197 if (!FORCE) { 1198 llist_t *state_list = read_iface_state(); 1197 1199 const llist_t *iface_state = find_iface_state(state_list, iface); 1198 1200 … … 1205 1207 } else { 1206 1208 /* ifdown */ 1207 if ( iface_state) {1209 if (!iface_state) { 1208 1210 bb_error_msg("interface %s not configured", iface); 1209 1211 continue; 1210 1212 } 1211 1213 } 1212 } 1213 1214 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING 1215 if ((cmds == iface_up) && run_mappings) { 1214 llist_free(state_list, free); 1215 } 1216 1217 #if ENABLE_FEATURE_IFUPDOWN_MAPPING 1218 if ((cmds == iface_up) && !NO_MAPPINGS) { 1216 1219 struct mapping_defn_t *currmap; 1217 1220 1218 1221 for (currmap = defn->mappings; currmap; currmap = currmap->next) { 1219 1222 int i; 1220 1223 for (i = 0; i < currmap->n_matches; i++) { 1221 1224 if (fnmatch(currmap->match[i], liface, 0) != 0) 1222 1225 continue; 1223 if ( verbose) {1226 if (VERBOSE) { 1224 1227 printf("Running mapping script %s on %s\n", currmap->script, liface); 1225 1228 } … … 1230 1233 } 1231 1234 #endif 1232 1233 1235 1234 1236 iface_list = defn->ifaces; … … 1246 1248 cmds_ret = cmds(currif); 1247 1249 if (cmds_ret == -1) { 1248 bb_error_msg(" Don't seem to have all the variables for %s/%s.",1250 bb_error_msg("don't seem to have all the variables for %s/%s", 1249 1251 liface, currif->address_family->name); 1250 any_failures += 1;1252 any_failures = 1; 1251 1253 } else if (cmds_ret == 0) { 1252 any_failures += 1;1254 any_failures = 1; 1253 1255 } 1254 1256 … … 1257 1259 iface_list = iface_list->link; 1258 1260 } 1259 if (verbose) { 1260 printf("\n"); 1261 } 1262 1263 if (!okay && !force) { 1264 bb_error_msg("Ignoring unknown interface %s", liface); 1265 any_failures += 1; 1266 } else { 1261 if (VERBOSE) { 1262 puts(""); 1263 } 1264 1265 if (!okay && !FORCE) { 1266 bb_error_msg("ignoring unknown interface %s", liface); 1267 any_failures = 1; 1268 } else if (!NO_ACT) { 1269 /* update the state file */ 1270 FILE *state_fp; 1271 llist_t *state; 1272 llist_t *state_list = read_iface_state(); 1267 1273 llist_t *iface_state = find_iface_state(state_list, iface); 1268 1274 1269 1275 if (cmds == iface_up) { 1270 char * newiface = bb_xasprintf("%s=%s", iface, liface);1276 char * const newiface = xasprintf("%s=%s", iface, liface); 1271 1277 if (iface_state == NULL) { 1272 1278 llist_add_to_end(&state_list, newiface); … … 1276 1282 } 1277 1283 } else { 1278 /* Remove an interface from the linked list */ 1284 /* Remove an interface from state_list */ 1285 llist_unlink(&state_list, iface_state); 1279 1286 free(llist_pop(&iface_state)); 1280 1287 } 1281 } 1282 } 1283 1284 /* Actually write the new state */ 1285 if (!no_act) { 1286 FILE *state_fp = NULL; 1287 1288 state_fp = bb_xfopen(statefile, "w"); 1289 while (state_list) { 1290 if (state_list->data) { 1291 fputs(state_list->data, state_fp); 1292 fputc('\n', state_fp); 1293 } 1294 state_list = state_list->link; 1295 } 1296 fclose(state_fp); 1297 } 1298 1299 if (any_failures) 1300 return 1; 1301 return 0; 1302 } 1288 1289 /* Actually write the new state */ 1290 state_fp = xfopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "w"); 1291 state = state_list; 1292 while (state) { 1293 if (state->data) { 1294 fprintf(state_fp, "%s\n", state->data); 1295 } 1296 state = state->link; 1297 } 1298 fclose(state_fp); 1299 llist_free(state_list, free); 1300 } 1301 } 1302 1303 return any_failures; 1304 } -
branches/2.2.5/mindi-busybox/networking/inetd.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $ */ 2 3 /* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */ … … 23 24 * without specific prior written permission. 24 25 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''AND26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND 26 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE … … 36 37 */ 37 38 38 /* 39 * Inetd - Internet super-server 39 /* Inetd - Internet super-server 40 40 * 41 41 * This program invokes all internet services as needed. … … 50 50 * on file descriptor 0. Datagram servers may either connect 51 51 * to their peer, freeing up the original socket for inetd 52 * to receive further messages on, or ``take over the socket'',52 * to receive further messages on, or "take over the socket", 53 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''.54 * out. The first type of server is said to be "multi-threaded"; 55 * the second type of server "single-threaded". 56 56 * 57 57 * Inetd uses a configuration file which is read at startup 58 58 * and, possibly, at some later time in response to a hangup signal. 59 * The configuration file is ``free format''with fields given in the59 * The configuration file is "free format" with fields given in the 60 60 * order shown below. Continuation lines for an entry must begin with 61 61 * a space or tab. All fields must be present in each entry. … … 105 105 */ 106 106 107 /* 108 * Here's the scoop concerning the user[.:]group feature: 107 /* inetd rules for passing file descriptors to children 108 * (http://www.freebsd.org/cgi/man.cgi?query=inetd): 109 * 110 * The wait/nowait entry specifies whether the server that is invoked by 111 * inetd will take over the socket associated with the service access point, 112 * and thus whether inetd should wait for the server to exit before listen- 113 * ing for new service requests. Datagram servers must use "wait", as 114 * they are always invoked with the original datagram socket bound to the 115 * specified service address. These servers must read at least one datagram 116 * from the socket before exiting. If a datagram server connects to its 117 * peer, freeing the socket so inetd can receive further messages on the 118 * socket, it is said to be a "multi-threaded" server; it should read one 119 * datagram from the socket and create a new socket connected to the peer. 120 * It should fork, and the parent should then exit to allow inetd to check 121 * for new service requests to spawn new servers. Datagram servers which 122 * process all incoming datagrams on a socket and eventually time out are 123 * said to be "single-threaded". The comsat(8), (biff(1)) and talkd(8) 124 * utilities are both examples of the latter type of datagram server. The 125 * tftpd(8) utility is an example of a multi-threaded datagram server. 126 * 127 * Servers using stream sockets generally are multi-threaded and use the 128 * "nowait" entry. Connection requests for these services are accepted by 129 * inetd, and the server is given only the newly-accepted socket connected 130 * to a client of the service. Most stream-based services operate in this 131 * manner. Stream-based servers that use "wait" are started with the lis- 132 * tening service socket, and must accept at least one connection request 133 * before exiting. Such a server would normally accept and process incoming 134 * connection requests until a timeout. 135 */ 136 137 /* Here's the scoop concerning the user[.:]group feature: 109 138 * 110 139 * 1) set-group-option off. … … 125 154 * initgroups(name, specified group) 126 155 * setuid() 127 *128 156 */ 129 157 130 #include <sys/param.h> 131 #include <sys/stat.h> 132 #include <sys/ioctl.h> 133 #include <sys/socket.h> 158 #include "libbb.h" 159 #include <syslog.h> 134 160 #include <sys/un.h> 135 #include <sys/file.h> 136 #include <sys/wait.h> 137 #include <sys/resource.h> 138 139 140 #include <netinet/in.h> 141 #include <arpa/inet.h> 142 143 #include <errno.h> 144 #include <signal.h> 145 #include <netdb.h> 146 #include <syslog.h> 147 #include <stdio.h> 148 #include <stdlib.h> 149 #include <unistd.h> 150 #include <string.h> 151 #include <ctype.h> 152 #include <time.h> 153 154 #include "busybox.h" 155 156 //#define CONFIG_FEATURE_INETD_RPC 157 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 158 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 159 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME 160 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 161 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 162 //#define CONFIG_FEATURE_IPV6 163 164 #ifdef CONFIG_FEATURE_INETD_RPC 161 162 //#define ENABLE_FEATURE_INETD_RPC 1 163 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1 164 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1 165 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1 166 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1 167 //#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1 168 //#define ENABLE_FEATURE_IPV6 1 169 170 #if ENABLE_FEATURE_INETD_RPC 165 171 #include <rpc/rpc.h> 166 172 #include <rpc/pmap_clnt.h> 167 173 #endif 168 174 169 #define _PATH_INETDCONF "/etc/inetd.conf" 175 extern char **environ; 176 177 170 178 #define _PATH_INETDPID "/var/run/inetd.pid" 171 172 173 #define TOOMANY 0 /* don't start more than TOOMANY */174 179 175 180 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ … … 185 190 186 191 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ 187 #define FD_MARGIN (8)192 #define FD_MARGIN 8 188 193 static rlim_t rlim_ofile_cur = OPEN_MAX; 189 194 static struct rlimit rlim_ofile; … … 191 196 192 197 /* Check unsupporting builtin */ 193 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \194 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \195 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \196 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \197 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN198 #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 198 203 # define INETD_FEATURE_ENABLED 199 204 #endif 200 205 201 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \202 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \203 defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN206 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \ 207 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \ 208 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 204 209 # define INETD_SETPROCTITLE 205 210 #endif 206 211 207 typedef struct servtab 208 { 209 char *se_hostaddr; /* host address to listen on */ 210 char *se_service; /* name of service */ 211 int se_socktype; /* type of socket to use */ 212 int se_family; /* address family */ 213 char *se_proto; /* protocol used */ 214 #ifdef CONFIG_FEATURE_INETD_RPC 215 int se_rpcprog; /* rpc program number */ 216 int se_rpcversl; /* rpc program lowest version */ 217 int se_rpcversh; /* rpc program highest version */ 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 */ 218 #if ENABLE_FEATURE_INETD_RPC 219 int se_rpcprog; /* rpc program number */ 220 int se_rpcversl; /* rpc program lowest version */ 221 int se_rpcversh; /* rpc program highest version */ 218 222 #define isrpcservice(sep) ((sep)->se_rpcversl != 0) 219 223 #else 220 224 #define isrpcservice(sep) 0 221 225 #endif 222 223 224 225 226 pid_t se_wait; /* single threaded server */ 227 short se_checked; /* looked at during merge */ 228 char *se_user; /* user name to run as */ 229 char *se_group; /* group name to run as */ 226 230 #ifdef INETD_FEATURE_ENABLED 227 const struct builtin *se_bi;/* if built-in, description */228 #endif 229 231 const struct builtin *se_bi; /* if built-in, description */ 232 #endif 233 char *se_server; /* server program */ 230 234 #define MAXARGV 20 231 char *se_argv[MAXARGV + 1]; /* program arguments */ 232 int se_fd; /* open descriptor */ 233 union 234 { 235 struct sockaddr se_un_ctrladdr; 236 struct sockaddr_in se_un_ctrladdr_in; 237 #ifdef CONFIG_FEATURE_IPV6 238 struct sockaddr_in6 se_un_ctrladdr_in6; 239 #endif 240 struct sockaddr_un se_un_ctrladdr_un; 241 } se_un; /* bound address */ 235 char *se_argv[MAXARGV + 1]; /* program arguments */ 236 int se_fd; /* open descriptor */ 237 union { 238 struct sockaddr se_un_ctrladdr; 239 struct sockaddr_in se_un_ctrladdr_in; 240 #if ENABLE_FEATURE_IPV6 241 struct sockaddr_in6 se_un_ctrladdr_in6; 242 #endif 243 struct sockaddr_un se_un_ctrladdr_un; 244 } se_un; /* bound address */ 242 245 #define se_ctrladdr se_un.se_un_ctrladdr 243 246 #define se_ctrladdr_in se_un.se_un_ctrladdr_in 244 247 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6 245 248 #define se_ctrladdr_un se_un.se_un_ctrladdr_un 246 247 248 249 250 249 int se_ctrladdr_size; 250 int se_max; /* max # of instances of this service */ 251 int se_count; /* number started since se_time */ 252 struct timeval se_time; /* start of se_count */ 253 struct servtab *se_next; 251 254 } servtab_t; 252 255 … … 254 257 255 258 #ifdef INETD_FEATURE_ENABLED 256 struct builtin 257 { 258 const char *bi_service; /* internally provided service name */ 259 int bi_socktype; /* type of socket supported */ 260 short bi_fork; /* 1 if should fork before call */ 261 short bi_wait; /* 1 if should wait for child */ 262 void (*bi_fn) (int, servtab_t *); 259 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 *); 263 265 }; 264 266 267 /* Echo received data */ 268 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 269 static void echo_stream(int, servtab_t *); 270 static void echo_dg(int, servtab_t *); 271 #endif 272 /* Internet /dev/null */ 273 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 274 static void discard_stream(int, servtab_t *); 275 static void discard_dg(int, servtab_t *); 276 #endif 277 /* Return 32 bit time since 1900 */ 278 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 279 static void machtime_stream(int, servtab_t *); 280 static void machtime_dg(int, servtab_t *); 281 #endif 282 /* Return human-readable time */ 283 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 284 static void daytime_stream(int, servtab_t *); 285 static void daytime_dg(int, servtab_t *); 286 #endif 287 /* Familiar character generator */ 288 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 289 static void chargen_stream(int, servtab_t *); 290 static void chargen_dg(int, servtab_t *); 291 #endif 292 293 static const struct builtin builtins[] = { 294 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 265 295 /* Echo received data */ 266 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 267 static void echo_stream (int, servtab_t *); 268 static void echo_dg (int, servtab_t *); 269 # endif296 {"echo", SOCK_STREAM, 1, 0, echo_stream,}, 297 {"echo", SOCK_DGRAM, 0, 0, echo_dg,}, 298 #endif 299 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 270 300 /* Internet /dev/null */ 271 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 272 static void discard_stream (int, servtab_t *); 273 static void discard_dg (int, servtab_t *); 274 # endif301 {"discard", SOCK_STREAM, 1, 0, discard_stream,}, 302 {"discard", SOCK_DGRAM, 0, 0, discard_dg,}, 303 #endif 304 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 275 305 /* Return 32 bit time since 1900 */ 276 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME 277 static void machtime_stream (int, servtab_t *); 278 static void machtime_dg (int, servtab_t *); 279 # endif306 {"time", SOCK_STREAM, 0, 0, machtime_stream,}, 307 {"time", SOCK_DGRAM, 0, 0, machtime_dg,}, 308 #endif 309 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 280 310 /* Return human-readable time */ 281 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 282 static void daytime_stream (int, servtab_t *); 283 static void daytime_dg (int, servtab_t *); 284 # endif311 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,}, 312 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,}, 313 #endif 314 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 285 315 /* Familiar character generator */ 286 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 287 static void chargen_stream (int, servtab_t *); 288 static void chargen_dg (int, servtab_t *); 289 #endif 290 291 static const struct builtin builtins[] = { 292 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 293 /* Echo received data */ 294 {"echo", SOCK_STREAM, 1, 0, echo_stream,}, 295 {"echo", SOCK_DGRAM, 0, 0, echo_dg,}, 296 #endif 297 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 298 /* Internet /dev/null */ 299 {"discard", SOCK_STREAM, 1, 0, discard_stream,}, 300 {"discard", SOCK_DGRAM, 0, 0, discard_dg,}, 301 #endif 302 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME 303 /* Return 32 bit time since 1900 */ 304 {"time", SOCK_STREAM, 0, 0, machtime_stream,}, 305 {"time", SOCK_DGRAM, 0, 0, machtime_dg,}, 306 #endif 307 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 308 /* Return human-readable time */ 309 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,}, 310 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,}, 311 #endif 312 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 313 /* Familiar character generator */ 314 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,}, 315 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,}, 316 #endif 317 {NULL, 0, 0, 0, NULL} 316 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,}, 317 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,}, 318 #endif 319 {NULL, 0, 0, 0, NULL} 318 320 }; 319 321 #endif /* INETD_FEATURE_ENABLED */ … … 322 324 static int nsock, maxsock; 323 325 static fd_set allsock; 324 static int toomany = TOOMANY;326 static int toomany; 325 327 static int timingout; 326 328 static struct servent *sp; 327 329 static uid_t uid; 328 330 329 static c har *CONFIG = _PATH_INETDCONF;331 static const char *config_filename = "/etc/inetd.conf"; 330 332 331 333 static FILE *fconfig; 332 static char line[1024];333 334 static char *defhost; 334 335 335 static char *newstr (char *cp) 336 { 337 if ((cp = strdup (cp ? cp : ""))) 338 return (cp); 339 syslog (LOG_ERR, "strdup: %m"); 340 exit (1); 341 } 342 343 static int setconfig (void) 344 { 345 free (defhost); 346 defhost = newstr ("*"); 347 if (fconfig != NULL) { 348 fseek (fconfig, 0L, SEEK_SET); 349 return (1); 350 } 351 fconfig = fopen (CONFIG, "r"); 352 return (fconfig != NULL); 353 } 354 355 static void endconfig (void) 356 { 357 if (fconfig) { 358 (void) fclose (fconfig); 359 fconfig = NULL; 360 } 361 free (defhost); 362 defhost = 0; 363 } 364 365 #ifdef CONFIG_FEATURE_INETD_RPC 366 static void register_rpc (servtab_t *sep) 367 { 368 int n; 369 struct sockaddr_in ir_sin; 370 struct protoent *pp; 371 socklen_t size; 372 373 if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) { 374 syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto); 375 return; 376 } 377 size = sizeof ir_sin; 378 if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 379 syslog (LOG_ERR, "%s/%s: getsockname: %m", 380 sep->se_service, sep->se_proto); 381 return; 382 } 383 384 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 385 (void) pmap_unset (sep->se_rpcprog, n); 386 if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port))) 387 syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m", 388 sep->se_service, sep->se_proto, 389 sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)); 390 } 391 } 392 393 static void unregister_rpc (servtab_t *sep) 394 { 395 int n; 396 397 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 398 if (!pmap_unset (sep->se_rpcprog, n)) 399 syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n); 400 } 401 } 402 #endif /* CONFIG_FEATURE_INETD_RPC */ 403 404 static void freeconfig (servtab_t *cp) 405 { 406 int i; 407 408 free (cp->se_hostaddr); 409 free (cp->se_service); 410 free (cp->se_proto); 411 free (cp->se_user); 412 free (cp->se_group); 413 free (cp->se_server); 414 for (i = 0; i < MAXARGV; i++) 415 free (cp->se_argv[i]); 416 } 417 418 static int bump_nofile (void) 336 /* xstrdup(NULL) returns NULL, but this one 337 * will return newly-allocated "" if called with NULL arg 338 * TODO: audit whether this makes any real difference 339 */ 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; 365 } 366 367 #if ENABLE_FEATURE_INETD_RPC 368 static void register_rpc(servtab_t *sep) 369 { 370 int n; 371 struct sockaddr_in ir_sin; 372 struct protoent *pp; 373 socklen_t size; 374 375 if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) { 376 bb_perror_msg("%s: getproto", sep->se_proto); 377 return; 378 } 379 size = sizeof ir_sin; 380 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 381 bb_perror_msg("%s/%s: getsockname", 382 sep->se_service, sep->se_proto); 383 return; 384 } 385 386 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { 387 (void) pmap_unset(sep->se_rpcprog, n); 388 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port))) 389 bb_perror_msg("%s %s: pmap_set: %u %u %u %u", 390 sep->se_service, sep->se_proto, 391 sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port)); 392 } 393 } 394 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) 407 { 408 int i; 409 410 free(cp->se_hostaddr); 411 free(cp->se_service); 412 free(cp->se_proto); 413 free(cp->se_user); 414 free(cp->se_group); 415 free(cp->se_server); 416 for (i = 0; i < MAXARGV; i++) 417 free(cp->se_argv[i]); 418 } 419 420 static int bump_nofile(void) 419 421 { 420 422 #define FD_CHUNK 32 421 423 422 struct rlimit rl; 423 424 if (getrlimit (RLIMIT_NOFILE, &rl) < 0) { 425 syslog (LOG_ERR, "getrlimit: %m"); 426 return -1; 427 } 428 rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK); 429 rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK); 430 if (rl.rlim_cur <= rlim_ofile_cur) { 431 syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d", 432 (int) rl.rlim_cur); 433 return -1; 434 } 435 436 if (setrlimit (RLIMIT_NOFILE, &rl) < 0) { 437 syslog (LOG_ERR, "setrlimit: %m"); 438 return -1; 439 } 440 441 rlim_ofile_cur = rl.rlim_cur; 442 return 0; 443 } 444 445 static void setup (servtab_t *sep) 446 { 447 int on = 1; 448 int r; 449 450 if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) { 451 syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto); 452 return; 453 } 454 #define turnon(fd, opt) \ 455 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 456 if (turnon (sep->se_fd, SO_REUSEADDR) < 0) 457 syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 458 #undef turnon 459 460 #ifdef CONFIG_FEATURE_INETD_RPC 461 if (isrpcservice (sep)) { 462 struct passwd *pwd; 424 struct rlimit rl; 425 426 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { 427 bb_perror_msg("getrlimit"); 428 return -1; 429 } 430 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK); 431 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK); 432 if (rl.rlim_cur <= rlim_ofile_cur) { 433 bb_error_msg("bump_nofile: cannot extend file limit, max = %d", 434 (int) rl.rlim_cur); 435 return -1; 436 } 437 438 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { 439 bb_perror_msg("setrlimit"); 440 return -1; 441 } 442 443 rlim_ofile_cur = rl.rlim_cur; 444 return 0; 445 } 446 447 static void setup(servtab_t *sep) 448 { 449 int r; 450 451 sep->se_fd = socket(sep->se_family, sep->se_socktype, 0); 452 if (sep->se_fd < 0) { 453 bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto); 454 return; 455 } 456 setsockopt_reuseaddr(sep->se_fd); 457 458 #if ENABLE_FEATURE_INETD_RPC 459 if (isrpcservice(sep)) { 460 struct passwd *pwd; 461 462 /* 463 * for RPC services, attempt to use a reserved port 464 * if they are going to be running as root. 465 * 466 * Also, zero out the port for all RPC services; let bind() 467 * find one. 468 */ 469 sep->se_ctrladdr_in.sin_port = 0; 470 if (sep->se_user && (pwd = getpwnam(sep->se_user)) && 471 pwd->pw_uid == 0 && uid == 0) 472 r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in); 473 else { 474 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 475 if (r == 0) { 476 socklen_t len = sep->se_ctrladdr_size; 477 int saveerrno = errno; 478 479 /* update se_ctrladdr_in.sin_port */ 480 r = getsockname(sep->se_fd, &sep->se_ctrladdr, &len); 481 if (r <= 0) 482 errno = saveerrno; 483 } 484 } 485 } else 486 #endif 487 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 488 if (r < 0) { 489 bb_perror_msg("%s/%s (%d): bind", 490 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family); 491 close(sep->se_fd); 492 sep->se_fd = -1; 493 if (!timingout) { 494 timingout = 1; 495 alarm(RETRYTIME); 496 } 497 return; 498 } 499 if (sep->se_socktype == SOCK_STREAM) 500 listen(sep->se_fd, global_queuelen); 501 502 FD_SET(sep->se_fd, &allsock); 503 nsock++; 504 if (sep->se_fd > maxsock) { 505 maxsock = sep->se_fd; 506 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) 507 bump_nofile(); 508 } 509 } 510 511 static char *nextline(void) 512 { 513 #define line bb_common_bufsiz1 514 515 char *cp; 516 FILE *fd = fconfig; 517 518 if (fgets(line, sizeof(line), fd) == NULL) 519 return NULL; 520 cp = strchr(line, '\n'); 521 if (cp) 522 *cp = '\0'; 523 return line; 524 } 525 526 static char *skip(char **cpp) /* int report; */ 527 { 528 char *cp = *cpp; 529 char *start; 530 531 /* erp: */ 532 if (*cpp == NULL) { 533 /* if (report) */ 534 /* bb_error_msg("syntax error in inetd config file"); */ 535 return NULL; 536 } 537 538 again: 539 while (*cp == ' ' || *cp == '\t') 540 cp++; 541 if (*cp == '\0') { 542 int c; 543 544 c = getc(fconfig); 545 ungetc(c, fconfig); 546 if (c == ' ' || c == '\t') { 547 cp = nextline(); 548 if (cp) 549 goto again; 550 } 551 *cpp = NULL; 552 /* goto erp; */ 553 return NULL; 554 } 555 start = cp; 556 while (*cp && *cp != ' ' && *cp != '\t') 557 cp++; 558 if (*cp != '\0') 559 *cp++ = '\0'; 560 /* if ((*cpp = cp) == NULL) */ 561 /* goto erp; */ 562 563 *cpp = cp; 564 return start; 565 } 566 567 static servtab_t *new_servtab(void) 568 { 569 return xmalloc(sizeof(servtab_t)); 570 } 571 572 static servtab_t *dupconfig(servtab_t *sep) 573 { 574 servtab_t *newtab; 575 int argc; 576 577 newtab = new_servtab(); 578 memset(newtab, 0, sizeof(servtab_t)); 579 newtab->se_service = xstrdup(sep->se_service); 580 newtab->se_socktype = sep->se_socktype; 581 newtab->se_family = sep->se_family; 582 newtab->se_proto = xstrdup(sep->se_proto); 583 #if ENABLE_FEATURE_INETD_RPC 584 newtab->se_rpcprog = sep->se_rpcprog; 585 newtab->se_rpcversl = sep->se_rpcversl; 586 newtab->se_rpcversh = sep->se_rpcversh; 587 #endif 588 newtab->se_wait = sep->se_wait; 589 newtab->se_user = xstrdup(sep->se_user); 590 newtab->se_group = xstrdup(sep->se_group); 591 #ifdef INETD_FEATURE_ENABLED 592 newtab->se_bi = sep->se_bi; 593 #endif 594 newtab->se_server = xstrdup(sep->se_server); 595 596 for (argc = 0; argc <= MAXARGV; argc++) 597 newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]); 598 newtab->se_max = sep->se_max; 599 600 return newtab; 601 } 602 603 static servtab_t *getconfigent(void) 604 { 605 servtab_t *sep; 606 int argc; 607 char *cp, *arg; 608 char *hostdelim; 609 servtab_t *nsep; 610 servtab_t *psep; 611 612 sep = new_servtab(); 613 614 /* memset(sep, 0, sizeof *sep); */ 615 more: 616 /* freeconfig(sep); */ 617 618 while ((cp = nextline()) && *cp == '#') /* skip comment line */; 619 if (cp == NULL) { 620 /* free(sep); */ 621 return NULL; 622 } 623 624 memset((char *) sep, 0, sizeof *sep); 625 arg = skip(&cp); 626 if (arg == NULL) { 627 /* A blank line. */ 628 goto more; 629 } 630 631 /* Check for a host name. */ 632 hostdelim = strrchr(arg, ':'); 633 if (hostdelim) { 634 *hostdelim = '\0'; 635 sep->se_hostaddr = xstrdup(arg); 636 arg = hostdelim + 1; 637 /* 638 * If the line is of the form `host:', then just change the 639 * default host for the following lines. 640 */ 641 if (*arg == '\0') { 642 arg = skip(&cp); 643 if (cp == NULL) { 644 free(defhost); 645 defhost = sep->se_hostaddr; 646 goto more; 647 } 648 } 649 } else 650 sep->se_hostaddr = xxstrdup(defhost); 651 652 sep->se_service = xxstrdup(arg); 653 arg = skip(&cp); 654 655 if (strcmp(arg, "stream") == 0) 656 sep->se_socktype = SOCK_STREAM; 657 else if (strcmp(arg, "dgram") == 0) 658 sep->se_socktype = SOCK_DGRAM; 659 else if (strcmp(arg, "rdm") == 0) 660 sep->se_socktype = SOCK_RDM; 661 else if (strcmp(arg, "seqpacket") == 0) 662 sep->se_socktype = SOCK_SEQPACKET; 663 else if (strcmp(arg, "raw") == 0) 664 sep->se_socktype = SOCK_RAW; 665 else 666 sep->se_socktype = -1; 667 668 sep->se_proto = xxstrdup(skip(&cp)); 669 670 if (strcmp(sep->se_proto, "unix") == 0) { 671 sep->se_family = AF_UNIX; 672 } else { 673 sep->se_family = AF_INET; 674 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') 675 #if ENABLE_FEATURE_IPV6 676 sep->se_family = AF_INET6; 677 #else 678 bb_error_msg("%s: IPV6 not supported", sep->se_proto); 679 #endif 680 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 681 #if ENABLE_FEATURE_INETD_RPC 682 char *p, *ccp; 683 long l; 684 685 p = strchr(sep->se_service, '/'); 686 if (p == 0) { 687 bb_error_msg("%s: no rpc version", sep->se_service); 688 goto more; 689 } 690 *p++ = '\0'; 691 l = strtol(p, &ccp, 0); 692 if (ccp == p || l < 0 || l > INT_MAX) { 693 badafterall: 694 bb_error_msg("%s/%s: bad rpc version", sep->se_service, p); 695 goto more; 696 } 697 sep->se_rpcversl = sep->se_rpcversh = l; 698 if (*ccp == '-') { 699 p = ccp + 1; 700 l = strtol(p, &ccp, 0); 701 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp) 702 goto badafterall; 703 sep->se_rpcversh = l; 704 } else if (*ccp != '\0') 705 goto badafterall; 706 #else 707 bb_error_msg("%s: rpc services not supported", sep->se_service); 708 #endif 709 } 710 } 711 arg = skip(&cp); 712 if (arg == NULL) 713 goto more; 714 715 { 716 char *s = strchr(arg, '.'); 717 if (s) { 718 *s++ = '\0'; 719 sep->se_max = xatoi(s); 720 } else 721 sep->se_max = toomany; 722 } 723 sep->se_wait = strcmp(arg, "wait") == 0; 724 /* if ((arg = skip(&cp, 1)) == NULL) */ 725 /* goto more; */ 726 sep->se_user = xxstrdup(skip(&cp)); 727 arg = strchr(sep->se_user, '.'); 728 if (arg == NULL) 729 arg = strchr(sep->se_user, ':'); 730 if (arg) { 731 *arg++ = '\0'; 732 sep->se_group = xstrdup(arg); 733 } 734 /* if ((arg = skip(&cp, 1)) == NULL) */ 735 /* goto more; */ 736 737 sep->se_server = xxstrdup(skip(&cp)); 738 if (strcmp(sep->se_server, "internal") == 0) { 739 #ifdef INETD_FEATURE_ENABLED 740 const struct builtin *bi; 741 742 for (bi = builtins; bi->bi_service; bi++) 743 if (bi->bi_socktype == sep->se_socktype && 744 strcmp(bi->bi_service, sep->se_service) == 0) 745 break; 746 if (bi->bi_service == 0) { 747 bb_error_msg("internal service %s unknown", sep->se_service); 748 goto more; 749 } 750 sep->se_bi = bi; 751 sep->se_wait = bi->bi_wait; 752 #else 753 bb_perror_msg("internal service %s unknown", sep->se_service); 754 goto more; 755 #endif 756 } 757 #ifdef INETD_FEATURE_ENABLED 758 else 759 sep->se_bi = NULL; 760 #endif 761 argc = 0; 762 for (arg = skip(&cp); cp; arg = skip(&cp)) { 763 if (argc < MAXARGV) 764 sep->se_argv[argc++] = xxstrdup(arg); 765 } 766 while (argc <= MAXARGV) 767 sep->se_argv[argc++] = NULL; 463 768 464 769 /* 465 * for RPC services, attempt to use a reserved port 466 * if they are going to be running as root. 467 * 468 * Also, zero out the port for all RPC services; let bind() 469 * find one. 770 * Now that we've processed the entire line, check if the hostname 771 * specifier was a comma separated list of hostnames. If so 772 * we'll make new entries for each address. 470 773 */ 471 sep->se_ctrladdr_in.sin_port = 0; 472 if (sep->se_user && (pwd = getpwnam (sep->se_user)) && 473 pwd->pw_uid == 0 && uid == 0) 474 r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in); 475 else { 476 r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 477 if (r == 0) { 478 socklen_t len = sep->se_ctrladdr_size; 479 int saveerrno = errno; 480 481 /* update se_ctrladdr_in.sin_port */ 482 r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len); 483 if (r <= 0) 484 errno = saveerrno; 485 } 486 } 487 } else 488 #endif 489 r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); 490 if (r < 0) { 491 syslog (LOG_ERR, "%s/%s (%d): bind: %m", 492 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family); 493 close (sep->se_fd); 774 while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) { 775 nsep = dupconfig(sep); 776 777 /* 778 * NULL terminate the hostname field of the existing entry, 779 * and make a dup for the new entry. 780 */ 781 *hostdelim++ = '\0'; 782 nsep->se_hostaddr = xstrdup(hostdelim); 783 784 nsep->se_next = sep->se_next; 785 sep->se_next = nsep; 786 } 787 788 nsep = sep; 789 while (nsep != NULL) { 790 nsep->se_checked = 1; 791 if (nsep->se_family == AF_INET) { 792 if (LONE_CHAR(nsep->se_hostaddr, '*')) 793 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY; 794 else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) { 795 struct hostent *hp; 796 797 hp = gethostbyname(nsep->se_hostaddr); 798 if (hp == 0) { 799 bb_error_msg("%s: unknown host", nsep->se_hostaddr); 800 nsep->se_checked = 0; 801 goto skip; 802 } else if (hp->h_addrtype != AF_INET) { 803 bb_error_msg("%s: address isn't an Internet " 804 "address", nsep->se_hostaddr); 805 nsep->se_checked = 0; 806 goto skip; 807 } else { 808 int i = 1; 809 810 memmove(&nsep->se_ctrladdr_in.sin_addr, 811 hp->h_addr_list[0], sizeof(struct in_addr)); 812 while (hp->h_addr_list[i] != NULL) { 813 psep = dupconfig(nsep); 814 psep->se_hostaddr = xxstrdup(nsep->se_hostaddr); 815 psep->se_checked = 1; 816 memmove(&psep->se_ctrladdr_in.sin_addr, 817 hp->h_addr_list[i], sizeof(struct in_addr)); 818 psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in); 819 i++; 820 /* Prepend to list, don't want to look up */ 821 /* its hostname again. */ 822 psep->se_next = sep; 823 sep = psep; 824 } 825 } 826 } 827 } 828 /* XXX BUG?: is this skip: label supposed to remain? */ 829 skip: 830 nsep = nsep->se_next; 831 } 832 833 /* 834 * Finally, free any entries which failed the gethostbyname 835 * check. 836 */ 837 psep = NULL; 838 nsep = sep; 839 while (nsep != NULL) { 840 servtab_t *tsep; 841 842 if (nsep->se_checked == 0) { 843 tsep = nsep; 844 if (psep == NULL) { 845 sep = nsep->se_next; 846 nsep = sep; 847 } else { 848 nsep = nsep->se_next; 849 psep->se_next = nsep; 850 } 851 freeconfig(tsep); 852 } else { 853 nsep->se_checked = 0; 854 psep = nsep; 855 nsep = nsep->se_next; 856 } 857 } 858 859 return sep; 860 } 861 862 #define Block_Using_Signals(m) do { \ 863 sigemptyset(&m); \ 864 sigaddset(&m, SIGCHLD); \ 865 sigaddset(&m, SIGHUP); \ 866 sigaddset(&m, SIGALRM); \ 867 sigprocmask(SIG_BLOCK, &m, NULL); \ 868 } while (0) 869 870 static servtab_t *enter(servtab_t *cp) 871 { 872 servtab_t *sep; 873 sigset_t omask; 874 875 sep = new_servtab(); 876 *sep = *cp; 494 877 sep->se_fd = -1; 495 if (!timingout) { 496 timingout = 1; 497 alarm (RETRYTIME); 498 } 499 return; 500 } 501 if (sep->se_socktype == SOCK_STREAM) 502 listen (sep->se_fd, global_queuelen); 503 504 FD_SET (sep->se_fd, &allsock); 505 nsock++; 506 if (sep->se_fd > maxsock) { 507 maxsock = sep->se_fd; 508 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) 509 bump_nofile (); 510 } 511 } 512 513 static char *nextline (void) 514 { 515 char *cp; 516 FILE *fd = fconfig; 517 518 if (fgets (line, sizeof (line), fd) == NULL) 519 return (NULL); 520 cp = strchr (line, '\n'); 521 if (cp) 522 *cp = '\0'; 523 return (line); 524 } 525 526 static char *skip (char **cpp) /* int report; */ 527 { 528 char *cp = *cpp; 529 char *start; 530 531 /* erp: */ 532 if (*cpp == NULL) { 533 /* if (report) */ 534 /* syslog(LOG_ERR, "syntax error in inetd config file"); */ 535 return (NULL); 536 } 537 538 again: 539 while (*cp == ' ' || *cp == '\t') 540 cp++; 541 if (*cp == '\0') { 542 int c; 543 544 c = getc (fconfig); 545 (void) ungetc (c, fconfig); 546 if (c == ' ' || c == '\t') 547 if ((cp = nextline ())) 548 goto again; 549 *cpp = NULL; 550 /* goto erp; */ 551 return (NULL); 552 } 553 start = cp; 554 while (*cp && *cp != ' ' && *cp != '\t') 555 cp++; 556 if (*cp != '\0') 557 *cp++ = '\0'; 558 /* if ((*cpp = cp) == NULL) */ 559 /* goto erp; */ 560 561 *cpp = cp; 562 return (start); 563 } 564 565 static servtab_t *new_servtab(void) 566 { 567 servtab_t *sep; 568 569 sep = (servtab_t *) malloc (sizeof (servtab_t)); 570 if (sep == NULL) { 571 syslog (LOG_ERR, bb_msg_memory_exhausted); 572 exit (1); 573 } 574 return sep; 575 } 576 577 static servtab_t *dupconfig (servtab_t *sep) 578 { 579 servtab_t *newtab; 580 int argc; 581 582 newtab = new_servtab(); 583 memset (newtab, 0, sizeof (servtab_t)); 584 newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL; 585 newtab->se_socktype = sep->se_socktype; 586 newtab->se_family = sep->se_family; 587 newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL; 588 #ifdef CONFIG_FEATURE_INETD_RPC 589 newtab->se_rpcprog = sep->se_rpcprog; 590 newtab->se_rpcversl = sep->se_rpcversl; 591 newtab->se_rpcversh = sep->se_rpcversh; 592 #endif 593 newtab->se_wait = sep->se_wait; 594 newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL; 595 newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL; 878 #if ENABLE_FEATURE_INETD_RPC 879 sep->se_rpcprog = -1; 880 #endif 881 Block_Using_Signals(omask); 882 sep->se_next = servtab; 883 servtab = sep; 884 sigprocmask(SIG_UNBLOCK, &omask, NULL); 885 return sep; 886 } 887 888 static int matchconf(servtab_t *old, servtab_t *new) 889 { 890 if (strcmp(old->se_service, new->se_service) != 0) 891 return 0; 892 893 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0) 894 return 0; 895 896 if (strcmp(old->se_proto, new->se_proto) != 0) 897 return 0; 898 899 /* 900 * If the new servtab is bound to a specific address, check that the 901 * old servtab is bound to the same entry. If the new service is not 902 * bound to a specific address then the check of se_hostaddr above 903 * is sufficient. 904 */ 905 906 if (old->se_family == AF_INET && new->se_family == AF_INET && 907 memcmp(&old->se_ctrladdr_in.sin_addr, 908 &new->se_ctrladdr_in.sin_addr, 909 sizeof(new->se_ctrladdr_in.sin_addr)) != 0) 910 return 0; 911 912 #if ENABLE_FEATURE_IPV6 913 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 && 914 memcmp(&old->se_ctrladdr_in6.sin6_addr, 915 &new->se_ctrladdr_in6.sin6_addr, 916 sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0) 917 return 0; 918 #endif 919 return 1; 920 } 921 922 static void config(int sig ATTRIBUTE_UNUSED) 923 { 924 servtab_t *sep, *cp, **sepp; 925 sigset_t omask; 926 size_t n; 927 char protoname[10]; 928 929 if (!setconfig()) { 930 bb_perror_msg("%s", config_filename); 931 return; 932 } 933 for (sep = servtab; sep; sep = sep->se_next) 934 sep->se_checked = 0; 935 cp = getconfigent(); 936 while (cp != NULL) { 937 for (sep = servtab; sep; sep = sep->se_next) 938 if (matchconf(sep, cp)) 939 break; 940 941 if (sep != 0) { 942 int i; 943 944 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0) 945 946 Block_Using_Signals(omask); 947 /* 948 * sep->se_wait may be holding the pid of a daemon 949 * that we're waiting for. If so, don't overwrite 950 * it unless the config file explicitly says don't 951 * wait. 952 */ 953 if ( 596 954 #ifdef INETD_FEATURE_ENABLED 597 newtab->se_bi = sep->se_bi; 598 #endif 599 newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0; 600 601 for (argc = 0; argc <= MAXARGV; argc++) 602 newtab->se_argv[argc] = sep->se_argv[argc] ? 603 newstr (sep->se_argv[argc]) : NULL; 604 newtab->se_max = sep->se_max; 605 606 return (newtab); 607 } 608 609 static servtab_t *getconfigent (void) 610 { 611 servtab_t *sep; 612 int argc; 613 char *cp, *arg; 614 char *hostdelim; 615 servtab_t *nsep; 616 servtab_t *psep; 617 618 sep = new_servtab(); 619 620 /* memset(sep, 0, sizeof *sep); */ 621 more: 622 /* freeconfig(sep); */ 623 624 while ((cp = nextline ()) && *cp == '#'); 625 if (cp == NULL) { 626 /* free(sep); */ 627 return (NULL); 628 } 629 630 memset ((char *) sep, 0, sizeof *sep); 631 arg = skip (&cp); 632 if (arg == NULL) { 633 /* A blank line. */ 634 goto more; 635 } 636 637 /* Check for a host name. */ 638 hostdelim = strrchr (arg, ':'); 639 if (hostdelim) { 640 *hostdelim = '\0'; 641 sep->se_hostaddr = newstr (arg); 642 arg = hostdelim + 1; 955 cp->se_bi == 0 && 956 #endif 957 (sep->se_wait == 1 || cp->se_wait == 0)) 958 sep->se_wait = cp->se_wait; 959 SWAP(int, cp->se_max, sep->se_max); 960 SWAP(char *, sep->se_user, cp->se_user); 961 SWAP(char *, sep->se_group, cp->se_group); 962 SWAP(char *, sep->se_server, cp->se_server); 963 for (i = 0; i < MAXARGV; i++) 964 SWAP(char *, sep->se_argv[i], cp->se_argv[i]); 965 #undef SWAP 966 967 #if ENABLE_FEATURE_INETD_RPC 968 if (isrpcservice(sep)) 969 unregister_rpc(sep); 970 sep->se_rpcversl = cp->se_rpcversl; 971 sep->se_rpcversh = cp->se_rpcversh; 972 #endif 973 sigprocmask(SIG_UNBLOCK, &omask, NULL); 974 freeconfig(cp); 975 } else { 976 sep = enter(cp); 977 } 978 sep->se_checked = 1; 979 980 switch (sep->se_family) { 981 case AF_UNIX: 982 if (sep->se_fd != -1) 983 break; 984 (void) unlink(sep->se_service); 985 n = strlen(sep->se_service); 986 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 987 n = sizeof sep->se_ctrladdr_un.sun_path - 1; 988 safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1); 989 sep->se_ctrladdr_un.sun_family = AF_UNIX; 990 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family; 991 setup(sep); 992 break; 993 case AF_INET: 994 sep->se_ctrladdr_in.sin_family = AF_INET; 995 /* se_ctrladdr_in was set in getconfigent */ 996 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; 997 998 #if ENABLE_FEATURE_INETD_RPC 999 if (isrpcservice(sep)) { 1000 struct rpcent *rp; 1001 // FIXME: atoi_or_else(str, 0) would be handy here 1002 sep->se_rpcprog = atoi(sep->se_service); 1003 if (sep->se_rpcprog == 0) { 1004 rp = getrpcbyname(sep->se_service); 1005 if (rp == 0) { 1006 bb_error_msg("%s: unknown rpc service", sep->se_service); 1007 goto serv_unknown; 1008 } 1009 sep->se_rpcprog = rp->r_number; 1010 } 1011 if (sep->se_fd == -1) 1012 setup(sep); 1013 if (sep->se_fd != -1) 1014 register_rpc(sep); 1015 } else 1016 #endif 1017 { 1018 uint16_t port = htons(atoi(sep->se_service)); 1019 // FIXME: atoi_or_else(str, 0) would be handy here 1020 if (!port) { 1021 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname)); 1022 if (isdigit(protoname[strlen(protoname) - 1])) 1023 protoname[strlen(protoname) - 1] = '\0'; 1024 sp = getservbyname(sep->se_service, protoname); 1025 if (sp == 0) { 1026 bb_error_msg("%s/%s: unknown service", 1027 sep->se_service, sep->se_proto); 1028 goto serv_unknown; 1029 } 1030 port = sp->s_port; 1031 } 1032 if (port != sep->se_ctrladdr_in.sin_port) { 1033 sep->se_ctrladdr_in.sin_port = port; 1034 if (sep->se_fd != -1) { 1035 FD_CLR(sep->se_fd, &allsock); 1036 nsock--; 1037 (void) close(sep->se_fd); 1038 } 1039 sep->se_fd = -1; 1040 } 1041 if (sep->se_fd == -1) 1042 setup(sep); 1043 } 1044 break; 1045 #if ENABLE_FEATURE_IPV6 1046 case AF_INET6: 1047 sep->se_ctrladdr_in6.sin6_family = AF_INET6; 1048 /* se_ctrladdr_in was set in getconfigent */ 1049 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6; 1050 1051 #if ENABLE_FEATURE_INETD_RPC 1052 if (isrpcservice(sep)) { 1053 struct rpcent *rp; 1054 1055 sep->se_rpcprog = atoi(sep->se_service); 1056 if (sep->se_rpcprog == 0) { 1057 rp = getrpcbyname(sep->se_service); 1058 if (rp == 0) { 1059 bb_error_msg("%s: unknown rpc service", sep->se_service); 1060 goto serv_unknown; 1061 } 1062 sep->se_rpcprog = rp->r_number; 1063 } 1064 if (sep->se_fd == -1) 1065 setup(sep); 1066 if (sep->se_fd != -1) 1067 register_rpc(sep); 1068 } else 1069 #endif 1070 { 1071 uint16_t port = htons(atoi(sep->se_service)); 1072 1073 if (!port) { 1074 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname)); 1075 if (isdigit(protoname[strlen(protoname) - 1])) 1076 protoname[strlen(protoname) - 1] = '\0'; 1077 sp = getservbyname(sep->se_service, protoname); 1078 if (sp == 0) { 1079 bb_error_msg("%s/%s: unknown service", 1080 sep->se_service, sep->se_proto); 1081 goto serv_unknown; 1082 } 1083 port = sp->s_port; 1084 } 1085 if (port != sep->se_ctrladdr_in6.sin6_port) { 1086 sep->se_ctrladdr_in6.sin6_port = port; 1087 if (sep->se_fd != -1) { 1088 FD_CLR(sep->se_fd, &allsock); 1089 nsock--; 1090 (void) close(sep->se_fd); 1091 } 1092 sep->se_fd = -1; 1093 } 1094 if (sep->se_fd == -1) 1095 setup(sep); 1096 } 1097 break; 1098 #endif /* FEATURE_IPV6 */ 1099 } 1100 serv_unknown: 1101 if (cp->se_next != NULL) { 1102 servtab_t *tmp = cp; 1103 1104 cp = cp->se_next; 1105 free(tmp); 1106 } else { 1107 free(cp); 1108 cp = getconfigent(); 1109 } 1110 } 1111 endconfig(); 643 1112 /* 644 * If the line is of the form `host:', then just change the 645 * default host for the following lines. 1113 * Purge anything not looked at above. 646 1114 */ 647 if (*arg == '\0') { 648 arg = skip (&cp); 649 if (cp == NULL) { 650 free (defhost); 651 defhost = sep->se_hostaddr; 652 goto more; 653 } 654 } 655 } else 656 sep->se_hostaddr = newstr (defhost); 657 658 sep->se_service = newstr (arg); 659 arg = skip (&cp); 660 661 if (strcmp (arg, "stream") == 0) 662 sep->se_socktype = SOCK_STREAM; 663 else if (strcmp (arg, "dgram") == 0) 664 sep->se_socktype = SOCK_DGRAM; 665 else if (strcmp (arg, "rdm") == 0) 666 sep->se_socktype = SOCK_RDM; 667 else if (strcmp (arg, "seqpacket") == 0) 668 sep->se_socktype = SOCK_SEQPACKET; 669 else if (strcmp (arg, "raw") == 0) 670 sep->se_socktype = SOCK_RAW; 671 else 672 sep->se_socktype = -1; 673 674 sep->se_proto = newstr (skip (&cp)); 675 676 if (strcmp (sep->se_proto, "unix") == 0) { 677 sep->se_family = AF_UNIX; 678 } else { 679 sep->se_family = AF_INET; 680 if (sep->se_proto[strlen (sep->se_proto) - 1] == '6') 681 #ifdef CONFIG_FEATURE_IPV6 682 sep->se_family = AF_INET6; 683 #else 684 syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto); 685 #endif 686 if (strncmp (sep->se_proto, "rpc/", 4) == 0) { 687 #ifdef CONFIG_FEATURE_INETD_RPC 688 char *p, *ccp; 689 long l; 690 691 p = strchr (sep->se_service, '/'); 692 if (p == 0) { 693 syslog (LOG_ERR, "%s: no rpc version", sep->se_service); 694 goto more; 695 } 696 *p++ = '\0'; 697 l = strtol (p, &ccp, 0); 698 if (ccp == p || l < 0 || l > INT_MAX) { 699 badafterall: 700 syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p); 701 goto more; 702 } 703 sep->se_rpcversl = sep->se_rpcversh = l; 704 if (*ccp == '-') { 705 p = ccp + 1; 706 l = strtol (p, &ccp, 0); 707 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp) 708 goto badafterall; 709 sep->se_rpcversh = l; 710 } else if (*ccp != '\0') 711 goto badafterall; 712 #else 713 syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service); 714 #endif 715 } 716 } 717 arg = skip (&cp); 718 if (arg == NULL) 719 goto more; 720 721 { 722 char *s = strchr (arg, '.'); 723 if (s) { 724 *s++ = '\0'; 725 sep->se_max = atoi (s); 726 } else 727 sep->se_max = toomany; 728 } 729 sep->se_wait = strcmp (arg, "wait") == 0; 730 /* if ((arg = skip(&cp, 1)) == NULL) */ 731 /* goto more; */ 732 sep->se_user = newstr (skip (&cp)); 733 arg = strchr (sep->se_user, '.'); 734 if (arg == NULL) 735 arg = strchr (sep->se_user, ':'); 736 if (arg) { 737 *arg++ = '\0'; 738 sep->se_group = newstr (arg); 739 } 740 /* if ((arg = skip(&cp, 1)) == NULL) */ 741 /* goto more; */ 742 743 sep->se_server = newstr (skip (&cp)); 744 if (strcmp (sep->se_server, "internal") == 0) { 745 #ifdef INETD_FEATURE_ENABLED 746 const struct builtin *bi; 747 748 for (bi = builtins; bi->bi_service; bi++) 749 if (bi->bi_socktype == sep->se_socktype && 750 strcmp (bi->bi_service, sep->se_service) == 0) 751 break; 752 if (bi->bi_service == 0) { 753 syslog (LOG_ERR, "internal service %s unknown", sep->se_service); 754 goto more; 755 } 756 sep->se_bi = bi; 757 sep->se_wait = bi->bi_wait; 758 #else 759 syslog (LOG_ERR, "internal service %s unknown", sep->se_service); 760 goto more; 761 #endif 762 } 763 #ifdef INETD_FEATURE_ENABLED 764 else 765 sep->se_bi = NULL; 766 #endif 767 argc = 0; 768 for (arg = skip (&cp); cp; arg = skip (&cp)) { 769 if (argc < MAXARGV) 770 sep->se_argv[argc++] = newstr (arg); 771 } 772 while (argc <= MAXARGV) 773 sep->se_argv[argc++] = NULL; 774 775 /* 776 * Now that we've processed the entire line, check if the hostname 777 * specifier was a comma separated list of hostnames. If so 778 * we'll make new entries for each address. 779 */ 780 while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) { 781 nsep = dupconfig (sep); 782 783 /* 784 * NULL terminate the hostname field of the existing entry, 785 * and make a dup for the new entry. 786 */ 787 *hostdelim++ = '\0'; 788 nsep->se_hostaddr = newstr (hostdelim); 789 790 nsep->se_next = sep->se_next; 791 sep->se_next = nsep; 792 } 793 794 nsep = sep; 795 while (nsep != NULL) { 796 nsep->se_checked = 1; 797 if (nsep->se_family == AF_INET) { 798 if (!strcmp (nsep->se_hostaddr, "*")) 799 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY; 800 else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) { 801 struct hostent *hp; 802 803 hp = gethostbyname (nsep->se_hostaddr); 804 if (hp == 0) { 805 syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr); 806 nsep->se_checked = 0; 807 goto skip; 808 } else if (hp->h_addrtype != AF_INET) { 809 syslog (LOG_ERR, 810 "%s: address isn't an Internet " 811 "address", nsep->se_hostaddr); 812 nsep->se_checked = 0; 813 goto skip; 814 } else { 815 int i = 1; 816 817 memmove (&nsep->se_ctrladdr_in.sin_addr, 818 hp->h_addr_list[0], sizeof (struct in_addr)); 819 while (hp->h_addr_list[i] != NULL) { 820 psep = dupconfig (nsep); 821 psep->se_hostaddr = newstr (nsep->se_hostaddr); 822 psep->se_checked = 1; 823 memmove (&psep->se_ctrladdr_in.sin_addr, 824 hp->h_addr_list[i], sizeof (struct in_addr)); 825 psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in); 826 i++; 827 /* Prepend to list, don't want to look up its */ 828 /* hostname again. */ 829 psep->se_next = sep; 830 sep = psep; 831 } 1115 Block_Using_Signals(omask); 1116 sepp = &servtab; 1117 while ((sep = *sepp)) { 1118 if (sep->se_checked) { 1119 sepp = &sep->se_next; 1120 continue; 832 1121 } 833 } 834 } 835 /* XXX BUG?: is this skip: label supposed to remain? */ 836 skip: 837 nsep = nsep->se_next; 838 } 839 840 /* 841 * Finally, free any entries which failed the gethostbyname 842 * check. 843 */ 844 psep = NULL; 845 nsep = sep; 846 while (nsep != NULL) { 847 servtab_t *tsep; 848 849 if (nsep->se_checked == 0) { 850 tsep = nsep; 851 if (psep == NULL) { 852 sep = nsep->se_next; 853 nsep = sep; 854 } else { 855 nsep = nsep->se_next; 856 psep->se_next = nsep; 857 } 858 freeconfig (tsep); 859 } else { 860 nsep->se_checked = 0; 861 psep = nsep; 862 nsep = nsep->se_next; 863 } 864 } 865 866 return (sep); 867 } 868 869 #define Block_Using_Signals(m) do { sigemptyset(&m); \ 870 sigaddset(&m, SIGCHLD); \ 871 sigaddset(&m, SIGHUP); \ 872 sigaddset(&m, SIGALRM); \ 873 sigprocmask(SIG_BLOCK, &m, NULL); \ 874 } while(0) 875 876 877 static servtab_t *enter (servtab_t *cp) 878 { 879 servtab_t *sep; 880 sigset_t omask; 881 882 sep = new_servtab(); 883 *sep = *cp; 884 sep->se_fd = -1; 885 #ifdef CONFIG_FEATURE_INETD_RPC 886 sep->se_rpcprog = -1; 887 #endif 888 Block_Using_Signals(omask); 889 sep->se_next = servtab; 890 servtab = sep; 891 sigprocmask(SIG_UNBLOCK, &omask, NULL); 892 return (sep); 893 } 894 895 static int matchconf (servtab_t *old, servtab_t *new) 896 { 897 if (strcmp (old->se_service, new->se_service) != 0) 898 return (0); 899 900 if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0) 901 return (0); 902 903 if (strcmp (old->se_proto, new->se_proto) != 0) 904 return (0); 905 906 /* 907 * If the new servtab is bound to a specific address, check that the 908 * old servtab is bound to the same entry. If the new service is not 909 * bound to a specific address then the check of se_hostaddr above 910 * is sufficient. 911 */ 912 913 if (old->se_family == AF_INET && new->se_family == AF_INET && 914 memcmp (&old->se_ctrladdr_in.sin_addr, 915 &new->se_ctrladdr_in.sin_addr, 916 sizeof (new->se_ctrladdr_in.sin_addr)) != 0) 917 return (0); 918 919 #ifdef CONFIG_FEATURE_IPV6 920 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 && 921 memcmp (&old->se_ctrladdr_in6.sin6_addr, 922 &new->se_ctrladdr_in6.sin6_addr, 923 sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0) 924 return (0); 925 #endif 926 return (1); 927 } 928 929 static void config (int sig ATTRIBUTE_UNUSED) 930 { 931 servtab_t *sep, *cp, **sepp; 932 sigset_t omask; 933 int add; 934 size_t n; 935 char protoname[10]; 936 937 if (!setconfig ()) { 938 syslog (LOG_ERR, "%s: %m", CONFIG); 939 return; 940 } 941 for (sep = servtab; sep; sep = sep->se_next) 942 sep->se_checked = 0; 943 cp = getconfigent (); 944 while (cp != NULL) { 945 for (sep = servtab; sep; sep = sep->se_next) 946 if (matchconf (sep, cp)) 947 break; 948 add = 0; 949 if (sep != 0) { 950 int i; 951 952 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0) 953 954 Block_Using_Signals(omask); 955 /* 956 * sep->se_wait may be holding the pid of a daemon 957 * that we're waiting for. If so, don't overwrite 958 * it unless the config file explicitly says don't 959 * wait. 960 */ 961 if ( 962 #ifdef INETD_FEATURE_ENABLED 963 cp->se_bi == 0 && 964 #endif 965 (sep->se_wait == 1 || cp->se_wait == 0)) 966 sep->se_wait = cp->se_wait; 967 SWAP (int, cp->se_max, sep->se_max); 968 SWAP (char *, sep->se_user, cp->se_user); 969 SWAP (char *, sep->se_group, cp->se_group); 970 SWAP (char *, sep->se_server, cp->se_server); 971 for (i = 0; i < MAXARGV; i++) 972 SWAP (char *, sep->se_argv[i], cp->se_argv[i]); 973 #undef SWAP 974 975 #ifdef CONFIG_FEATURE_INETD_RPC 976 if (isrpcservice (sep)) 977 unregister_rpc (sep); 978 sep->se_rpcversl = cp->se_rpcversl; 979 sep->se_rpcversh = cp->se_rpcversh; 980 #endif 981 sigprocmask(SIG_UNBLOCK, &omask, NULL); 982 freeconfig (cp); 983 add = 1; 984 } else { 985 sep = enter (cp); 986 } 987 sep->se_checked = 1; 988 989 switch (sep->se_family) { 990 case AF_UNIX: 991 if (sep->se_fd != -1) 992 break; 993 (void) unlink (sep->se_service); 994 n = strlen (sep->se_service); 995 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 996 n = sizeof sep->se_ctrladdr_un.sun_path - 1; 997 safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1); 998 sep->se_ctrladdr_un.sun_family = AF_UNIX; 999 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family; 1000 setup (sep); 1001 break; 1002 case AF_INET: 1003 sep->se_ctrladdr_in.sin_family = AF_INET; 1004 /* se_ctrladdr_in was set in getconfigent */ 1005 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; 1006 1007 #ifdef CONFIG_FEATURE_INETD_RPC 1008 if (isrpcservice (sep)) { 1009 struct rpcent *rp; 1010 1011 sep->se_rpcprog = atoi (sep->se_service); 1012 if (sep->se_rpcprog == 0) { 1013 rp = getrpcbyname (sep->se_service); 1014 if (rp == 0) { 1015 syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service); 1016 goto serv_unknown; 1017 } 1018 sep->se_rpcprog = rp->r_number; 1122 *sepp = sep->se_next; 1123 if (sep->se_fd != -1) { 1124 FD_CLR(sep->se_fd, &allsock); 1125 nsock--; 1126 (void) close(sep->se_fd); 1019 1127 } 1128 #if ENABLE_FEATURE_INETD_RPC 1129 if (isrpcservice(sep)) 1130 unregister_rpc(sep); 1131 #endif 1132 if (sep->se_family == AF_UNIX) 1133 (void) unlink(sep->se_service); 1134 freeconfig(sep); 1135 free(sep); 1136 } 1137 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1138 } 1139 1140 1141 static void reapchild(int sig ATTRIBUTE_UNUSED) 1142 { 1143 pid_t pid; 1144 int save_errno = errno, status; 1145 servtab_t *sep; 1146 1147 for (;;) { 1148 pid = wait3(&status, WNOHANG, NULL); 1149 if (pid <= 0) 1150 break; 1151 for (sep = servtab; sep; sep = sep->se_next) 1152 if (sep->se_wait == pid) { 1153 if (WIFEXITED(status) && WEXITSTATUS(status)) 1154 bb_error_msg("%s: exit status 0x%x", 1155 sep->se_server, WEXITSTATUS(status)); 1156 else if (WIFSIGNALED(status)) 1157 bb_error_msg("%s: exit signal 0x%x", 1158 sep->se_server, WTERMSIG(status)); 1159 sep->se_wait = 1; 1160 FD_SET(sep->se_fd, &allsock); 1161 nsock++; 1162 } 1163 } 1164 errno = save_errno; 1165 } 1166 1167 static void retry(int sig ATTRIBUTE_UNUSED) 1168 { 1169 servtab_t *sep; 1170 1171 timingout = 0; 1172 for (sep = servtab; sep; sep = sep->se_next) { 1173 if (sep->se_fd == -1) { 1174 switch (sep->se_family) { 1175 case AF_UNIX: 1176 case AF_INET: 1177 #if ENABLE_FEATURE_IPV6 1178 case AF_INET6: 1179 #endif 1180 setup(sep); 1181 #if ENABLE_FEATURE_INETD_RPC 1182 if (sep->se_fd != -1 && isrpcservice(sep)) 1183 register_rpc(sep); 1184 #endif 1185 break; 1186 } 1187 } 1188 } 1189 } 1190 1191 static void goaway(int sig ATTRIBUTE_UNUSED) 1192 { 1193 servtab_t *sep; 1194 1195 /* XXX signal race walking sep list */ 1196 for (sep = servtab; sep; sep = sep->se_next) { 1020 1197 if (sep->se_fd == -1) 1021 setup (sep); 1022 if (sep->se_fd != -1) 1023 register_rpc (sep); 1024 } else 1025 #endif 1026 { 1027 u_short port = htons (atoi (sep->se_service)); 1028 1029 if (!port) { 1030 /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname)); 1031 if (isdigit (protoname[strlen (protoname) - 1])) 1032 protoname[strlen (protoname) - 1] = '\0'; 1033 sp = getservbyname (sep->se_service, protoname); 1034 if (sp == 0) { 1035 syslog (LOG_ERR, 1036 "%s/%s: unknown service", sep->se_service, sep->se_proto); 1037 goto serv_unknown; 1038 } 1039 port = sp->s_port; 1198 continue; 1199 1200 switch (sep->se_family) { 1201 case AF_UNIX: 1202 (void) unlink(sep->se_service); 1203 break; 1204 case AF_INET: 1205 #if ENABLE_FEATURE_IPV6 1206 case AF_INET6: 1207 #endif 1208 #if ENABLE_FEATURE_INETD_RPC 1209 if (sep->se_wait == 1 && isrpcservice(sep)) 1210 unregister_rpc(sep); /* XXX signal race */ 1211 #endif 1212 break; 1040 1213 } 1041 if (port != sep->se_ctrladdr_in.sin_port) { 1042 sep->se_ctrladdr_in.sin_port = port; 1043 if (sep->se_fd != -1) { 1044 FD_CLR (sep->se_fd, &allsock); 1045 nsock--; 1046 (void) close (sep->se_fd); 1047 } 1048 sep->se_fd = -1; 1049 } 1050 if (sep->se_fd == -1) 1051 setup (sep); 1052 } 1053 break; 1054 #ifdef CONFIG_FEATURE_IPV6 1055 case AF_INET6: 1056 sep->se_ctrladdr_in6.sin6_family = AF_INET6; 1057 /* se_ctrladdr_in was set in getconfigent */ 1058 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6; 1059 1060 #ifdef CONFIG_FEATURE_INETD_RPC 1061 if (isrpcservice (sep)) { 1062 struct rpcent *rp; 1063 1064 sep->se_rpcprog = atoi (sep->se_service); 1065 if (sep->se_rpcprog == 0) { 1066 rp = getrpcbyname (sep->se_service); 1067 if (rp == 0) { 1068 syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service); 1069 goto serv_unknown; 1070 } 1071 sep->se_rpcprog = rp->r_number; 1072 } 1073 if (sep->se_fd == -1) 1074 setup (sep); 1075 if (sep->se_fd != -1) 1076 register_rpc (sep); 1077 } else 1078 #endif 1079 { 1080 u_short port = htons (atoi (sep->se_service)); 1081 1082 if (!port) { 1083 /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname)); 1084 if (isdigit (protoname[strlen (protoname) - 1])) 1085 protoname[strlen (protoname) - 1] = '\0'; 1086 sp = getservbyname (sep->se_service, protoname); 1087 if (sp == 0) { 1088 syslog (LOG_ERR, 1089 "%s/%s: unknown service", sep->se_service, sep->se_proto); 1090 goto serv_unknown; 1091 } 1092 port = sp->s_port; 1093 } 1094 if (port != sep->se_ctrladdr_in6.sin6_port) { 1095 sep->se_ctrladdr_in6.sin6_port = port; 1096 if (sep->se_fd != -1) { 1097 FD_CLR (sep->se_fd, &allsock); 1098 nsock--; 1099 (void) close (sep->se_fd); 1100 } 1101 sep->se_fd = -1; 1102 } 1103 if (sep->se_fd == -1) 1104 setup (sep); 1105 } 1106 break; 1107 #endif /* CONFIG_FEATURE_IPV6 */ 1108 } 1109 serv_unknown: 1110 if (cp->se_next != NULL) { 1111 servtab_t *tmp = cp; 1112 1113 cp = cp->se_next; 1114 free (tmp); 1115 } else { 1116 free (cp); 1117 cp = getconfigent (); 1118 } 1119 } 1120 endconfig (); 1121 /* 1122 * Purge anything not looked at above. 1123 */ 1124 Block_Using_Signals(omask); 1125 sepp = &servtab; 1126 while ((sep = *sepp)) { 1127 if (sep->se_checked) { 1128 sepp = &sep->se_next; 1129 continue; 1130 } 1131 *sepp = sep->se_next; 1132 if (sep->se_fd != -1) { 1133 FD_CLR (sep->se_fd, &allsock); 1134 nsock--; 1135 (void) close (sep->se_fd); 1136 } 1137 #ifdef CONFIG_FEATURE_INETD_RPC 1138 if (isrpcservice (sep)) 1139 unregister_rpc (sep); 1140 #endif 1141 if (sep->se_family == AF_UNIX) 1142 (void) unlink (sep->se_service); 1143 freeconfig (sep); 1144 free (sep); 1145 } 1146 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1147 } 1148 1149 1150 static void reapchild (int sig ATTRIBUTE_UNUSED) 1151 { 1152 pid_t pid; 1153 int save_errno = errno, status; 1154 servtab_t *sep; 1155 1156 for (;;) { 1157 pid = wait3 (&status, WNOHANG, NULL); 1158 if (pid <= 0) 1159 break; 1160 for (sep = servtab; sep; sep = sep->se_next) 1161 if (sep->se_wait == pid) { 1162 if (WIFEXITED (status) && WEXITSTATUS (status)) 1163 syslog (LOG_WARNING, 1164 "%s: exit status 0x%x", 1165 sep->se_server, WEXITSTATUS (status)); 1166 else if (WIFSIGNALED (status)) 1167 syslog (LOG_WARNING, 1168 "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status)); 1169 sep->se_wait = 1; 1170 FD_SET (sep->se_fd, &allsock); 1171 nsock++; 1172 } 1173 } 1174 errno = save_errno; 1175 } 1176 1177 static void retry (int sig ATTRIBUTE_UNUSED) 1178 { 1179 servtab_t *sep; 1180 1181 timingout = 0; 1182 for (sep = servtab; sep; sep = sep->se_next) { 1183 if (sep->se_fd == -1) { 1184 switch (sep->se_family) { 1185 case AF_UNIX: 1186 case AF_INET: 1187 #ifdef CONFIG_FEATURE_IPV6 1188 case AF_INET6: 1189 #endif 1190 setup (sep); 1191 #ifdef CONFIG_FEATURE_INETD_RPC 1192 if (sep->se_fd != -1 && isrpcservice (sep)) 1193 register_rpc (sep); 1194 #endif 1195 break; 1196 } 1197 } 1198 } 1199 } 1200 1201 static void goaway (int sig ATTRIBUTE_UNUSED) 1202 { 1203 servtab_t *sep; 1204 1205 /* XXX signal race walking sep list */ 1206 for (sep = servtab; sep; sep = sep->se_next) { 1207 if (sep->se_fd == -1) 1208 continue; 1209 1210 switch (sep->se_family) { 1211 case AF_UNIX: 1212 (void) unlink (sep->se_service); 1213 break; 1214 case AF_INET: 1215 #ifdef CONFIG_FEATURE_IPV6 1216 case AF_INET6: 1217 #endif 1218 #ifdef CONFIG_FEATURE_INETD_RPC 1219 if (sep->se_wait == 1 && isrpcservice (sep)) 1220 unregister_rpc (sep); /* XXX signal race */ 1221 #endif 1222 break; 1223 } 1224 (void) close (sep->se_fd); 1225 } 1226 (void) unlink (_PATH_INETDPID); 1227 exit (0); 1214 (void) close(sep->se_fd); 1215 } 1216 remove_pidfile(_PATH_INETDPID); 1217 exit(0); 1228 1218 } 1229 1219 … … 1234 1224 1235 1225 static void 1236 inetd_setproctitle 1237 { 1238 1239 1240 1241 1242 1243 1244 size = sizeof(prt_sin);1245 (void) snprintf(buf, sizeof buf, "-%s", a);1246 if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {1247 char *sa = inet_ntoa(prt_sin.sin_addr);1248 1249 buf[sizeof (buf) - 1 - strlen(sa) - 3] = '\0';1250 strcat(buf, " [");1251 strcat(buf, sa);1252 strcat(buf, "]");1253 1254 strncpy(cp, buf, LastArg - cp);1255 cp += strlen(cp);1256 1257 *cp++ = ' ';1258 } 1259 #endif 1260 1261 1262 int 1263 in etd_main (int argc, char *argv[])1264 { 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1226 inetd_setproctitle(char *a, int s) 1227 { 1228 socklen_t size; 1229 char *cp; 1230 struct sockaddr_in prt_sin; 1231 char buf[80]; 1232 1233 cp = Argv[0]; 1234 size = sizeof(prt_sin); 1235 (void) snprintf(buf, sizeof buf, "-%s", a); 1236 if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) { 1237 char *sa = inet_ntoa(prt_sin.sin_addr); 1238 1239 buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0'; 1240 strcat(buf, " ["); 1241 strcat(buf, sa); 1242 strcat(buf, "]"); 1243 } 1244 strncpy(cp, buf, LastArg - cp); 1245 cp += strlen(cp); 1246 while (cp < LastArg) 1247 *cp++ = ' '; 1248 } 1249 #endif 1250 1251 1252 int inetd_main(int argc, char **argv); 1253 int inetd_main(int argc, char **argv) 1254 { 1255 servtab_t *sep; 1256 struct passwd *pwd; 1257 struct group *grp = NULL; 1258 int tmpint; 1259 struct sigaction sa, sapipe; 1260 int opt; 1261 pid_t pid; 1262 char buf[50]; 1263 char *stoomany; 1264 sigset_t omask, wait_mask; 1275 1265 1276 1266 #ifdef INETD_SETPROCTITLE 1277 extern char **environ; 1278 char **envp = environ; 1279 1280 Argv = argv; 1281 if (envp == 0 || *envp == 0) 1282 envp = argv; 1283 while (*envp) 1284 envp++; 1285 LastArg = envp[-1] + strlen (envp[-1]); 1286 #endif 1287 1288 openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1289 1290 opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany); 1291 if(opt & 1) { 1292 char *e; 1293 1294 toomany = strtoul (stoomany, &e, 0); 1295 if (!(toomany >= 0 && *e == '\0')) { 1296 toomany = TOOMANY; 1297 syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany); 1298 } 1299 } 1300 argc -= optind; 1301 argv += optind; 1302 1303 uid = getuid (); 1304 if (uid != 0) 1305 CONFIG = NULL; 1306 if (argc > 0) 1307 CONFIG = argv[0]; 1308 if (CONFIG == NULL) 1309 bb_error_msg_and_die ("non-root must specify a config file"); 1310 1311 if (!(opt & 2)) { 1312 #ifdef BB_NOMMU 1313 /* reexec for vfork() do continue parent */ 1314 vfork_daemon_rexec (0, 0, argc, argv, "-f"); 1315 #else 1316 bb_xdaemon (0, 0); 1317 #endif 1318 } else { 1319 setsid (); 1320 } 1321 1322 if (uid == 0) { 1323 gid_t gid = getgid (); 1324 1325 /* If run by hand, ensure groups vector gets trashed */ 1326 setgroups (1, &gid); 1327 } 1328 1329 { 1330 FILE *fp; 1331 1332 if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) { 1333 fprintf (fp, "%u\n", getpid ()); 1334 (void) fclose (fp); 1335 } 1336 } 1337 1338 if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) { 1339 syslog (LOG_ERR, "getrlimit: %m"); 1340 } else { 1341 rlim_ofile_cur = rlim_ofile.rlim_cur; 1342 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ 1343 rlim_ofile_cur = OPEN_MAX; 1344 } 1345 1346 memset ((char *) &sa, 0, sizeof (sa)); 1347 sigemptyset (&sa.sa_mask); 1348 sigaddset (&sa.sa_mask, SIGALRM); 1349 sigaddset (&sa.sa_mask, SIGCHLD); 1350 sigaddset (&sa.sa_mask, SIGHUP); 1351 sa.sa_handler = retry; 1352 sigaction (SIGALRM, &sa, NULL); 1353 /* doconfig(); */ 1354 config (SIGHUP); 1355 sa.sa_handler = config; 1356 sigaction (SIGHUP, &sa, NULL); 1357 sa.sa_handler = reapchild; 1358 sigaction (SIGCHLD, &sa, NULL); 1359 sa.sa_handler = goaway; 1360 sigaction (SIGTERM, &sa, NULL); 1361 sa.sa_handler = goaway; 1362 sigaction (SIGINT, &sa, NULL); 1363 sa.sa_handler = SIG_IGN; 1364 sigaction (SIGPIPE, &sa, &sapipe); 1365 memset(&wait_mask, 0, sizeof(wait_mask)); 1366 { 1367 /* space for daemons to overwrite environment for ps */ 1267 char **envp = environ; 1268 1269 Argv = argv; 1270 if (envp == 0 || *envp == 0) 1271 envp = argv; 1272 while (*envp) 1273 envp++; 1274 LastArg = envp[-1] + strlen(envp[-1]); 1275 #endif 1276 1277 uid = getuid(); 1278 if (uid != 0) 1279 config_filename = NULL; 1280 1281 opt = getopt32(argv, "R:f", &stoomany); 1282 if (opt & 1) 1283 toomany = xatoi_u(stoomany); 1284 argv += optind; 1285 argc -= optind; 1286 if (argc) 1287 config_filename = argv[0]; 1288 if (config_filename == NULL) 1289 bb_error_msg_and_die("non-root must specify a config file"); 1290 1291 if (!(opt & 2)) 1292 bb_daemonize_or_rexec(0, argv - optind); 1293 else 1294 bb_sanitize_stdio(); 1295 openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 1296 logmode = LOGMODE_SYSLOG; 1297 1298 if (uid == 0) { 1299 /* If run by hand, ensure groups vector gets trashed */ 1300 gid_t gid = getgid(); 1301 setgroups(1, &gid); 1302 } 1303 1304 write_pidfile(_PATH_INETDPID); 1305 1306 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { 1307 bb_perror_msg("getrlimit"); 1308 } else { 1309 rlim_ofile_cur = rlim_ofile.rlim_cur; 1310 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ 1311 rlim_ofile_cur = OPEN_MAX; 1312 } 1313 1314 memset((char *) &sa, 0, sizeof(sa)); 1315 sigemptyset(&sa.sa_mask); 1316 sigaddset(&sa.sa_mask, SIGALRM); 1317 sigaddset(&sa.sa_mask, SIGCHLD); 1318 sigaddset(&sa.sa_mask, SIGHUP); 1319 sa.sa_handler = retry; 1320 sigaction(SIGALRM, &sa, NULL); 1321 config(SIGHUP); 1322 sa.sa_handler = config; 1323 sigaction(SIGHUP, &sa, NULL); 1324 sa.sa_handler = reapchild; 1325 sigaction(SIGCHLD, &sa, NULL); 1326 sa.sa_handler = goaway; 1327 sigaction(SIGTERM, &sa, NULL); 1328 sa.sa_handler = goaway; 1329 sigaction(SIGINT, &sa, NULL); 1330 sa.sa_handler = SIG_IGN; 1331 sigaction(SIGPIPE, &sa, &sapipe); 1332 memset(&wait_mask, 0, sizeof(wait_mask)); 1333 { 1334 /* space for daemons to overwrite environment for ps */ 1368 1335 #define DUMMYSIZE 100 1369 char dummy[DUMMYSIZE]; 1370 1371 (void) memset (dummy, 'x', DUMMYSIZE - 1); 1372 dummy[DUMMYSIZE - 1] = '\0'; 1373 1374 (void) setenv ("inetd_dummy", dummy, 1); 1375 } 1376 1377 for (;;) { 1378 int n, ctrl = -1; 1379 fd_set readable; 1380 1381 if (nsock == 0) { 1382 Block_Using_Signals(omask); 1383 while (nsock == 0) 1384 sigsuspend (&wait_mask); 1385 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1386 } 1387 1388 readable = allsock; 1389 if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) { 1390 if (n < 0 && errno != EINTR) { 1391 syslog (LOG_WARNING, "select: %m"); 1392 sleep (1); 1393 } 1394 continue; 1395 } 1396 for (sep = servtab; n && sep; sep = sep->se_next) 1397 if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) { 1398 n--; 1399 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 1400 ctrl = accept (sep->se_fd, NULL, NULL); 1401 if (ctrl < 0) { 1402 if (errno == EINTR) 1403 continue; 1404 syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service); 1336 char dummy[DUMMYSIZE]; 1337 1338 (void) memset(dummy, 'x', DUMMYSIZE - 1); 1339 dummy[DUMMYSIZE - 1] = '\0'; 1340 1341 (void) setenv("inetd_dummy", dummy, 1); 1342 } 1343 1344 for (;;) { 1345 int n, ctrl = -1; 1346 fd_set readable; 1347 1348 if (nsock == 0) { 1349 Block_Using_Signals(omask); 1350 while (nsock == 0) 1351 sigsuspend(&wait_mask); 1352 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1353 } 1354 1355 readable = allsock; 1356 n = select(maxsock + 1, &readable, NULL, NULL, NULL); 1357 if (n <= 0) { 1358 if (n < 0 && errno != EINTR) { 1359 bb_perror_msg("select"); 1360 sleep(1); 1361 } 1405 1362 continue; 1406 } 1407 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { 1408 struct sockaddr_in peer; 1409 socklen_t plen = sizeof (peer); 1410 1411 if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) { 1412 syslog (LOG_WARNING, "could not getpeername"); 1413 close (ctrl); 1414 continue; 1363 } 1364 1365 for (sep = servtab; n && sep; sep = sep->se_next) { 1366 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) 1367 continue; 1368 1369 n--; 1370 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 1371 ctrl = accept(sep->se_fd, NULL, NULL); 1372 if (ctrl < 0) { 1373 if (errno == EINTR) 1374 continue; 1375 bb_perror_msg("accept (for %s)", sep->se_service); 1376 continue; 1377 } 1378 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { 1379 struct sockaddr_in peer; 1380 socklen_t plen = sizeof(peer); 1381 1382 if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) { 1383 bb_error_msg("cannot getpeername"); 1384 close(ctrl); 1385 continue; 1386 } 1387 if (ntohs(peer.sin_port) == 20) { 1388 /* XXX ftp bounce */ 1389 close(ctrl); 1390 continue; 1391 } 1392 } 1393 } else 1394 ctrl = sep->se_fd; 1395 1396 Block_Using_Signals(omask); 1397 pid = 0; 1398 #ifdef INETD_FEATURE_ENABLED 1399 if (sep->se_bi == 0 || sep->se_bi->bi_fork) 1400 #endif 1401 { 1402 if (sep->se_count++ == 0) 1403 (void) gettimeofday(&sep->se_time, NULL); 1404 else if (toomany > 0 && sep->se_count >= sep->se_max) { 1405 struct timeval now; 1406 1407 (void) gettimeofday(&now, NULL); 1408 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { 1409 sep->se_time = now; 1410 sep->se_count = 1; 1411 } else { 1412 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1413 close(ctrl); 1414 if (sep->se_family == AF_INET && 1415 ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { 1416 /* 1417 * Cannot close it -- there are 1418 * thieves on the system. 1419 * Simply ignore the connection. 1420 */ 1421 --sep->se_count; 1422 continue; 1423 } 1424 bb_error_msg("%s/%s server failing (looping), service terminated", 1425 sep->se_service, sep->se_proto); 1426 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1427 close(ctrl); 1428 FD_CLR(sep->se_fd, &allsock); 1429 (void) close(sep->se_fd); 1430 sep->se_fd = -1; 1431 sep->se_count = 0; 1432 nsock--; 1433 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1434 if (!timingout) { 1435 timingout = 1; 1436 alarm(RETRYTIME); 1437 } 1438 continue; 1439 } 1440 } 1441 pid = fork(); 1415 1442 } 1416 if (ntohs (peer.sin_port) == 20) { 1417 /* XXX ftp bounce */ 1418 close (ctrl); 1419 continue; 1443 if (pid < 0) { 1444 bb_perror_msg("fork"); 1445 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1446 close(ctrl); 1447 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1448 sleep(1); 1449 continue; 1420 1450 } 1421 } 1422 } else 1423 ctrl = sep->se_fd; 1424 Block_Using_Signals(omask); 1425 pid = 0; 1451 if (pid && sep->se_wait) { 1452 sep->se_wait = pid; 1453 FD_CLR(sep->se_fd, &allsock); 1454 nsock--; 1455 } 1456 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1457 if (pid == 0) { 1426 1458 #ifdef INETD_FEATURE_ENABLED 1427 if (sep->se_bi == 0 || sep->se_bi->bi_fork) 1428 #endif 1429 { 1430 if (sep->se_count++ == 0) 1431 (void) gettimeofday (&sep->se_time, NULL); 1432 else if (toomany > 0 && sep->se_count >= sep->se_max) { 1433 struct timeval now; 1434 1435 (void) gettimeofday (&now, NULL); 1436 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { 1437 sep->se_time = now; 1438 sep->se_count = 1; 1439 } else { 1440 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1441 close (ctrl); 1442 if (sep->se_family == AF_INET && 1443 ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { 1444 /* 1445 * Cannot close it -- there are 1446 * thieves on the system. 1447 * Simply ignore the connection. 1448 */ 1449 --sep->se_count; 1450 continue; 1451 } 1452 syslog (LOG_ERR, 1453 "%s/%s server failing (looping), service terminated", 1454 sep->se_service, sep->se_proto); 1455 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1456 close (ctrl); 1457 FD_CLR (sep->se_fd, &allsock); 1458 (void) close (sep->se_fd); 1459 sep->se_fd = -1; 1460 sep->se_count = 0; 1461 nsock--; 1462 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1463 if (!timingout) { 1464 timingout = 1; 1465 alarm (RETRYTIME); 1466 } 1467 continue; 1459 if (sep->se_bi) { 1460 (*sep->se_bi->bi_fn)(ctrl, sep); 1461 } else 1462 #endif 1463 { 1464 pwd = getpwnam(sep->se_user); 1465 if (pwd == NULL) { 1466 bb_error_msg("getpwnam: %s: no such user", sep->se_user); 1467 goto do_exit1; 1468 } 1469 if (setsid() < 0) 1470 bb_perror_msg("%s: setsid", sep->se_service); 1471 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) { 1472 bb_error_msg("getgrnam: %s: no such group", sep->se_group); 1473 goto do_exit1; 1474 } 1475 if (uid != 0) { 1476 /* a user running private inetd */ 1477 if (uid != pwd->pw_uid) 1478 _exit(1); 1479 } else if (pwd->pw_uid) { 1480 if (sep->se_group) 1481 pwd->pw_gid = grp->gr_gid; 1482 xsetgid((gid_t) pwd->pw_gid); 1483 initgroups(pwd->pw_name, pwd->pw_gid); 1484 xsetuid((uid_t) pwd->pw_uid); 1485 } else if (sep->se_group) { 1486 xsetgid(grp->gr_gid); 1487 setgroups(1, &grp->gr_gid); 1488 } 1489 dup2(ctrl, 0); 1490 if (ctrl) close(ctrl); 1491 dup2(0, 1); 1492 dup2(0, 2); 1493 if (rlim_ofile.rlim_cur != rlim_ofile_cur) 1494 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) 1495 bb_perror_msg("setrlimit"); 1496 closelog(); 1497 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) 1498 (void) close(tmpint); 1499 sigaction(SIGPIPE, &sapipe, NULL); 1500 execv(sep->se_server, sep->se_argv); 1501 bb_perror_msg("execv %s", sep->se_server); 1502 do_exit1: 1503 if (sep->se_socktype != SOCK_STREAM) 1504 recv(0, buf, sizeof(buf), 0); 1505 _exit(1); 1506 } 1468 1507 } 1469 } 1470 pid = fork (); 1471 } 1472 if (pid < 0) { 1473 syslog (LOG_ERR, "fork: %m"); 1474 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1475 close (ctrl); 1476 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1477 sleep (1); 1478 continue; 1479 } 1480 if (pid && sep->se_wait) { 1481 sep->se_wait = pid; 1482 FD_CLR (sep->se_fd, &allsock); 1483 nsock--; 1484 } 1485 sigprocmask(SIG_UNBLOCK, &omask, NULL); 1486 if (pid == 0) { 1487 #ifdef INETD_FEATURE_ENABLED 1488 if (sep->se_bi) { 1489 (*sep->se_bi->bi_fn) (ctrl, sep); 1490 } else 1491 #endif 1492 { 1493 if ((pwd = getpwnam (sep->se_user)) == NULL) { 1494 syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user); 1495 if (sep->se_socktype != SOCK_STREAM) 1496 recv (0, buf, sizeof (buf), 0); 1497 _exit (1); 1498 } 1499 if (setsid () < 0) 1500 syslog (LOG_ERR, "%s: setsid: %m", sep->se_service); 1501 if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) { 1502 syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group); 1503 if (sep->se_socktype != SOCK_STREAM) 1504 recv (0, buf, sizeof (buf), 0); 1505 _exit (1); 1506 } 1507 if (uid != 0) { 1508 /* a user running private inetd */ 1509 if (uid != pwd->pw_uid) 1510 _exit (1); 1511 } else if (pwd->pw_uid) { 1512 if (sep->se_group) { 1513 pwd->pw_gid = grp->gr_gid; 1514 } 1515 xsetgid ((gid_t) pwd->pw_gid); 1516 initgroups (pwd->pw_name, pwd->pw_gid); 1517 xsetuid((uid_t) pwd->pw_uid); 1518 } else if (sep->se_group) { 1519 xsetgid(grp->gr_gid); 1520 setgroups (1, &grp->gr_gid); 1521 } 1522 dup2 (ctrl, 0); 1523 close (ctrl); 1524 dup2 (0, 1); 1525 dup2 (0, 2); 1526 if (rlim_ofile.rlim_cur != rlim_ofile_cur) 1527 if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) 1528 syslog (LOG_ERR, "setrlimit: %m"); 1529 closelog (); 1530 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) 1531 (void) close (tmpint); 1532 sigaction (SIGPIPE, &sapipe, NULL); 1533 execv (sep->se_server, sep->se_argv); 1534 if (sep->se_socktype != SOCK_STREAM) 1535 recv (0, buf, sizeof (buf), 0); 1536 syslog (LOG_ERR, "execv %s: %m", sep->se_server); 1537 _exit (1); 1538 } 1539 } 1540 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1541 close (ctrl); 1542 } 1543 } 1508 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 1509 close(ctrl); 1510 } /* for (sep = servtab...) */ 1511 } /* for (;;) */ 1544 1512 } 1545 1513 … … 1549 1517 #define BUFSIZE 4096 1550 1518 1551 #if defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO)|| \1552 defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN)|| \1553 defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME) 1554 static int dg_badinput 1555 { 1556 if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)1557 return (1);1558 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))1559 return (1);1560 1561 return (0);1562 } 1563 #endif 1564 1565 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO1519 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \ 1520 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \ 1521 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1522 static int dg_badinput(struct sockaddr_in *dg_sin) 1523 { 1524 if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED) 1525 return 1; 1526 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST)) 1527 return 1; 1528 /* XXX compare against broadcast addresses in SIOCGIFCONF list? */ 1529 return 0; 1530 } 1531 #endif 1532 1533 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1566 1534 /* Echo service -- echo data back */ 1567 1535 /* ARGSUSED */ 1568 1536 static void 1569 echo_stream (int s, servtab_t *sep) 1570 { 1571 char buffer[BUFSIZE]; 1572 int i; 1573 1574 inetd_setproctitle (sep->se_service, s); 1575 while ((i = read (s, buffer, sizeof (buffer))) > 0 && 1576 write (s, buffer, i) > 0); 1577 exit (0); 1537 echo_stream(int s, servtab_t *sep) 1538 { 1539 char buffer[BUFSIZE]; 1540 int i; 1541 1542 inetd_setproctitle(sep->se_service, s); 1543 while (1) { 1544 i = read(s, buffer, sizeof(buffer)); 1545 if (i <= 0) break; 1546 /* FIXME: this isnt correct - safe_write()? */ 1547 if (write(s, buffer, i) <= 0) break; 1548 } 1549 exit(0); 1578 1550 } 1579 1551 … … 1581 1553 /* ARGSUSED */ 1582 1554 static void 1583 echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED) 1584 { 1585 char buffer[BUFSIZE]; 1586 int i; 1587 socklen_t size; 1588 /* struct sockaddr_storage ss; */ 1589 struct sockaddr sa; 1590 1591 size = sizeof (sa); 1592 if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0) 1593 return; 1594 if (dg_badinput ((struct sockaddr_in *) &sa)) 1595 return; 1596 (void) sendto (s, buffer, i, 0, &sa, sizeof (sa)); 1597 } 1598 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO */ 1599 1600 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1555 echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1556 { 1557 char buffer[BUFSIZE]; 1558 int i; 1559 socklen_t size; 1560 /* struct sockaddr_storage ss; */ 1561 struct sockaddr sa; 1562 1563 size = sizeof(sa); 1564 i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size); 1565 if (i < 0) 1566 return; 1567 if (dg_badinput((struct sockaddr_in *) &sa)) 1568 return; 1569 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 1570 } 1571 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */ 1572 1573 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1601 1574 /* Discard service -- ignore data */ 1602 1575 /* ARGSUSED */ 1603 1576 static void 1604 discard_stream (int s, servtab_t *sep) 1605 { 1606 char buffer[BUFSIZE]; 1607 1608 inetd_setproctitle (sep->se_service, s); 1609 while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) || 1610 errno == EINTR); 1611 exit (0); 1577 discard_stream(int s, servtab_t *sep) 1578 { 1579 char buffer[BUFSIZE]; 1580 1581 inetd_setproctitle(sep->se_service, s); 1582 while (1) { 1583 errno = 0; 1584 if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR) 1585 exit(0); 1586 } 1612 1587 } 1613 1588 … … 1615 1590 /* ARGSUSED */ 1616 1591 static void 1617 discard_dg 1618 { 1619 1620 1621 (void) read (s, buffer, sizeof(buffer));1622 } 1623 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */1624 1625 1626 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN1592 discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1593 { 1594 char buffer[BUFSIZE]; 1595 1596 (void) read(s, buffer, sizeof(buffer)); 1597 } 1598 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */ 1599 1600 1601 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1627 1602 #define LINESIZ 72 1628 1603 static char ring[128]; … … 1630 1605 1631 1606 static void 1632 initring 1633 { 1634 1635 1636 1637 1638 1639 if (isprint(i))1640 1607 initring(void) 1608 { 1609 int i; 1610 1611 endring = ring; 1612 1613 for (i = 0; i <= 128; ++i) 1614 if (isprint(i)) 1615 *endring++ = i; 1641 1616 } 1642 1617 … … 1644 1619 /* ARGSUSED */ 1645 1620 static void 1646 chargen_stream (int s, servtab_t *sep) 1647 { 1648 char *rs; 1649 int len; 1650 char text[LINESIZ + 2]; 1651 1652 inetd_setproctitle (sep->se_service, s); 1653 1654 if (!endring) { 1655 initring (); 1621 chargen_stream(int s, servtab_t *sep) 1622 { 1623 char *rs; 1624 int len; 1625 char text[LINESIZ + 2]; 1626 1627 inetd_setproctitle(sep->se_service, s); 1628 1629 if (!endring) { 1630 initring(); 1631 rs = ring; 1632 } 1633 1634 text[LINESIZ] = '\r'; 1635 text[LINESIZ + 1] = '\n'; 1656 1636 rs = ring; 1657 } 1658 1659 text[LINESIZ] = '\r'; 1660 text[LINESIZ + 1] = '\n'; 1661 for (rs = ring;;) { 1662 if ((len = endring - rs) >= LINESIZ) 1663 memmove (text, rs, LINESIZ); 1664 else { 1665 memmove (text, rs, len); 1666 memmove (text + len, ring, LINESIZ - len); 1667 } 1668 if (++rs == endring) 1669 rs = ring; 1670 if (write (s, text, sizeof (text)) != sizeof (text)) 1671 break; 1672 } 1673 exit (0); 1637 for (;;) { 1638 len = endring - rs; 1639 if (len >= LINESIZ) 1640 memmove(text, rs, LINESIZ); 1641 else { 1642 memmove(text, rs, len); 1643 memmove(text + len, ring, LINESIZ - len); 1644 } 1645 if (++rs == endring) 1646 rs = ring; 1647 if (write(s, text, sizeof(text)) != sizeof(text)) 1648 break; 1649 } 1650 exit(0); 1674 1651 } 1675 1652 … … 1677 1654 /* ARGSUSED */ 1678 1655 static void 1679 chargen_dg 1680 { 1681 1682 1683 1684 1685 1686 1687 1688 1689 initring();1690 rs = ring;1691 1692 1693 size = sizeof(sa);1694 if (recvfrom (s, text, sizeof(text), 0, &sa, &size) < 0)1695 return;1696 if (dg_badinput((struct sockaddr_in *) &sa))1697 return;1698 1699 1700 memmove(text, rs, LINESIZ);1701 1702 memmove(text, rs, len);1703 memmove(text + len, ring, LINESIZ - len);1704 1705 1706 rs = ring;1707 1708 1709 (void) sendto (s, text, sizeof (text), 0, &sa, sizeof(sa));1710 } 1711 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */1712 1713 1714 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME1656 chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1657 { 1658 /* struct sockaddr_storage ss; */ 1659 struct sockaddr sa; 1660 static char *rs; 1661 int len; 1662 char text[LINESIZ + 2]; 1663 socklen_t size; 1664 1665 if (endring == 0) { 1666 initring(); 1667 rs = ring; 1668 } 1669 1670 size = sizeof(sa); 1671 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 1672 return; 1673 if (dg_badinput((struct sockaddr_in *) &sa)) 1674 return; 1675 1676 if ((len = endring - rs) >= LINESIZ) 1677 memmove(text, rs, LINESIZ); 1678 else { 1679 memmove(text, rs, len); 1680 memmove(text + len, ring, LINESIZ - len); 1681 } 1682 if (++rs == endring) 1683 rs = ring; 1684 text[LINESIZ] = '\r'; 1685 text[LINESIZ + 1] = '\n'; 1686 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 1687 } 1688 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */ 1689 1690 1691 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1715 1692 /* 1716 1693 * Return a machine readable date and time, in the form of the … … 1721 1698 */ 1722 1699 1723 static u _int machtime(void)1724 { 1725 1726 1727 if (gettimeofday(&tv, NULL) < 0) {1728 fprintf(stderr, "Unable to get time of day\n");1729 return (0L);1730 1731 return (htonl ((u_int) tv.tv_sec + 2208988800UL));1700 static unsigned machtime(void) 1701 { 1702 struct timeval tv; 1703 1704 if (gettimeofday(&tv, NULL) < 0) { 1705 fprintf(stderr, "Unable to get time of day\n"); 1706 return 0L; 1707 } 1708 return htonl((unsigned) tv.tv_sec + 2208988800UL); 1732 1709 } 1733 1710 1734 1711 /* ARGSUSED */ 1735 1712 static void 1736 machtime_stream 1737 { 1738 u_intresult;1739 1740 result = machtime();1741 (void) write (s, (char *) &result, sizeof(result));1713 machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1714 { 1715 unsigned result; 1716 1717 result = machtime(); 1718 (void) write(s, (char *) &result, sizeof(result)); 1742 1719 } 1743 1720 1744 1721 /* ARGSUSED */ 1745 1722 static void 1746 machtime_dg 1747 { 1748 u_intresult;1749 1750 1751 1752 1753 1754 size = sizeof(sa);1755 if (recvfrom (s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)1756 return;1757 1758 1759 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||1760 ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)1761 return;1762 result = machtime();1763 (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof(sa));1764 } 1765 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME */1766 1767 1768 #if def CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME1723 machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1724 { 1725 unsigned result; 1726 /* struct sockaddr_storage ss; */ 1727 struct sockaddr sa; 1728 struct sockaddr_in *dg_sin; 1729 socklen_t size; 1730 1731 size = sizeof(sa); 1732 if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0) 1733 return; 1734 /* if (dg_badinput((struct sockaddr *)&ss)) */ 1735 dg_sin = (struct sockaddr_in *) &sa; 1736 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) || 1737 ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2) 1738 return; 1739 result = machtime(); 1740 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 1741 } 1742 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */ 1743 1744 1745 #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1769 1746 /* Return human-readable time of day */ 1770 1747 /* ARGSUSED */ 1771 static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED) 1772 { 1773 char buffer[256]; 1774 time_t t; 1775 1776 t = time (NULL); 1777 1778 (void) sprintf (buffer, "%.24s\r\n", ctime (&t)); 1779 (void) write (s, buffer, strlen (buffer)); 1748 static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1749 { 1750 char buffer[32]; 1751 time_t t; 1752 1753 t = time(NULL); 1754 1755 // fdprintf instead? 1756 (void) sprintf(buffer, "%.24s\r\n", ctime(&t)); 1757 (void) write(s, buffer, strlen(buffer)); 1780 1758 } 1781 1759 … … 1783 1761 /* ARGSUSED */ 1784 1762 void 1785 daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED) 1786 { 1787 char buffer[256]; 1788 time_t t; 1789 /* struct sockaddr_storage ss; */ 1790 struct sockaddr sa; 1791 socklen_t size; 1792 1793 t = time ((time_t *) 0); 1794 1795 size = sizeof (sa); 1796 if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0) 1797 return; 1798 if (dg_badinput ((struct sockaddr_in *) &sa)) 1799 return; 1800 (void) sprintf (buffer, "%.24s\r\n", ctime (&t)); 1801 (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa)); 1802 } 1803 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */ 1804 /* vi: set sw=4 ts=4: */ 1763 daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1764 { 1765 char buffer[256]; 1766 time_t t; 1767 /* struct sockaddr_storage ss; */ 1768 struct sockaddr sa; 1769 socklen_t size; 1770 1771 t = time(NULL); 1772 1773 size = sizeof(sa); 1774 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 1775 return; 1776 if (dg_badinput((struct sockaddr_in *) &sa)) 1777 return; 1778 (void) sprintf(buffer, "%.24s\r\n", ctime(&t)); 1779 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 1780 } 1781 #endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */ -
branches/2.2.5/mindi-busybox/networking/interface.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * stolen from net-tools-1.59 and stripped down for busybox by … … 15 16 * one or more of the system's networking interfaces. 16 17 * 17 * Version: $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $18 18 * 19 19 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> … … 32 32 */ 33 33 34 #include "inet_common.h"35 #include <stdio.h>36 #include <errno.h>37 #include <stdlib.h>38 #include <string.h>39 #include <unistd.h>40 #include <fcntl.h>41 #include <ctype.h>42 #include <sys/ioctl.h>43 #include <sys/types.h>44 34 #include <net/if.h> 45 35 #include <net/if_arp.h> 46 #include "busybox.h" 47 48 #ifdef CONFIG_FEATURE_IPV6 36 #include "inet_common.h" 37 #include "libbb.h" 38 39 #if ENABLE_FEATURE_IPV6 49 40 # define HAVE_AFINET6 1 50 41 #else … … 55 46 #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" 56 47 57 #if HAVE_AFINET648 #ifdef HAVE_AFINET6 58 49 59 50 #ifndef _LINUX_IN6_H … … 70 61 #endif 71 62 72 #endif 63 #endif /* HAVE_AFINET6 */ 73 64 74 65 /* Defines for glibc2.0 users. */ … … 91 82 #endif 92 83 93 /* This structure defines protocol families and their handlers. */94 struct aftype {95 const char *name;96 const char *title;97 int af;98 int alen;99 char *(*print) (unsigned char *);100 char *(*sprint) (struct sockaddr *, int numeric);101 int (*input) (int type, char *bufp, struct sockaddr *);102 void (*herror) (char *text);103 int (*rprint) (int options);104 int (*rinput) (int typ, int ext, char **argv);105 106 /* may modify src */107 int (*getmask) (char *src, struct sockaddr * mask, char *name);108 109 int fd;110 char *flag_file;111 };112 113 84 /* Display an Internet socket address. */ 114 static char *INET_sprint(struct sockaddr *sap, int numeric) 115 { 116 static char buff[128]; 117 85 static const char *INET_sprint(struct sockaddr *sap, int numeric) 86 { 87 static char *buff; 88 89 free(buff); 118 90 if (sap->sa_family == 0xFFFF || sap->sa_family == 0) 119 return safe_strncpy(buff, "[NONE SET]", sizeof(buff)); 120 121 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, 122 numeric, 0xffffff00) != 0) 123 return (NULL); 124 125 return (buff); 126 } 127 128 static struct aftype inet_aftype = { 91 return "[NONE SET]"; 92 buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00); 93 return buff; 94 } 95 96 #ifdef UNUSED_AND_BUGGY 97 static int INET_getsock(char *bufp, struct sockaddr *sap) 98 { 99 char *sp = bufp, *bp; 100 unsigned int i; 101 unsigned val; 102 struct sockaddr_in *sock_in; 103 104 sock_in = (struct sockaddr_in *) sap; 105 sock_in->sin_family = AF_INET; 106 sock_in->sin_port = 0; 107 108 val = 0; 109 bp = (char *) &val; 110 for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) { 111 *sp = toupper(*sp); 112 113 if ((unsigned)(*sp - 'A') <= 5) 114 bp[i] |= (int) (*sp - ('A' - 10)); 115 else if (isdigit(*sp)) 116 bp[i] |= (int) (*sp - '0'); 117 else 118 return -1; 119 120 bp[i] <<= 4; 121 sp++; 122 *sp = toupper(*sp); 123 124 if ((unsigned)(*sp - 'A') <= 5) 125 bp[i] |= (int) (*sp - ('A' - 10)); 126 else if (isdigit(*sp)) 127 bp[i] |= (int) (*sp - '0'); 128 else 129 return -1; 130 131 sp++; 132 } 133 sock_in->sin_addr.s_addr = htonl(val); 134 135 return (sp - bufp); 136 } 137 #endif 138 139 static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap) 140 { 141 return INET_resolve(bufp, (struct sockaddr_in *) sap, 0); 142 /* 143 switch (type) { 144 case 1: 145 return (INET_getsock(bufp, sap)); 146 case 256: 147 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1)); 148 default: 149 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0)); 150 } 151 */ 152 } 153 154 static const struct aftype inet_aftype = { 129 155 .name = "inet", 130 156 .title = "DARPA Internet", … … 132 158 .alen = 4, 133 159 .sprint = INET_sprint, 134 . fd = -1135 }; 136 137 #if HAVE_AFINET6160 .input = INET_input, 161 }; 162 163 #ifdef HAVE_AFINET6 138 164 139 165 /* Display an Internet socket address. */ 140 166 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ 141 static char *INET6_sprint(struct sockaddr *sap, int numeric) 142 { 143 static char buff[128]; 144 167 static const char *INET6_sprint(struct sockaddr *sap, int numeric) 168 { 169 static char *buff; 170 171 free(buff); 145 172 if (sap->sa_family == 0xFFFF || sap->sa_family == 0) 146 return safe_strncpy(buff, "[NONE SET]", sizeof(buff)); 147 if (INET6_rresolve 148 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0) 149 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff)); 150 return (buff); 151 } 152 153 static struct aftype inet6_aftype = { 173 return "[NONE SET]"; 174 buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric); 175 return buff; 176 } 177 178 #ifdef UNUSED 179 static int INET6_getsock(char *bufp, struct sockaddr *sap) 180 { 181 struct sockaddr_in6 *sin6; 182 183 sin6 = (struct sockaddr_in6 *) sap; 184 sin6->sin6_family = AF_INET6; 185 sin6->sin6_port = 0; 186 187 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0) 188 return -1; 189 190 return 16; /* ?;) */ 191 } 192 #endif 193 194 static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap) 195 { 196 return INET6_resolve(bufp, (struct sockaddr_in6 *) sap); 197 /* 198 switch (type) { 199 case 1: 200 return (INET6_getsock(bufp, sap)); 201 default: 202 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); 203 } 204 */ 205 } 206 207 static const struct aftype inet6_aftype = { 154 208 .name = "inet6", 155 209 .title = "IPv6", … … 157 211 .alen = sizeof(struct in6_addr), 158 212 .sprint = INET6_sprint, 159 . fd = -1160 }; 161 162 #endif 213 .input = INET6_input, 214 }; 215 216 #endif /* HAVE_AFINET6 */ 163 217 164 218 /* Display an UNSPEC address. */ 165 219 static char *UNSPEC_print(unsigned char *ptr) 166 220 { 167 static char buff[sizeof(struct sockaddr) * 3 + 1]; 221 static char *buff; 222 168 223 char *pos; 169 224 unsigned int i; 170 225 226 if (!buff); 227 buff = xmalloc(sizeof(struct sockaddr) * 3 + 1); 171 228 pos = buff; 172 229 for (i = 0; i < sizeof(struct sockaddr); i++) { … … 177 234 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */ 178 235 *--pos = '\0'; 179 return (buff);236 return buff; 180 237 } 181 238 182 239 /* Display an UNSPEC socket address. */ 183 static char *UNSPEC_sprint(struct sockaddr *sap, int numeric) 184 { 185 static char buf[64]; 186 240 static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric) 241 { 187 242 if (sap->sa_family == 0xFFFF || sap->sa_family == 0) 188 return safe_strncpy(buf, "[NONE SET]", sizeof(buf)); 189 return (UNSPEC_print((unsigned char *)sap->sa_data)); 190 } 191 192 static struct aftype unspec_aftype = { 193 "unspec", "UNSPEC", AF_UNSPEC, 0, 194 UNSPEC_print, UNSPEC_sprint, NULL, NULL, 195 NULL, 196 }; 197 198 static struct aftype * const aftypes[] = { 243 return "[NONE SET]"; 244 return UNSPEC_print((unsigned char *)sap->sa_data); 245 } 246 247 static const struct aftype unspec_aftype = { 248 .name = "unspec", 249 .title = "UNSPEC", 250 .af = AF_UNSPEC, 251 .alen = 0, 252 .print = UNSPEC_print, 253 .sprint = UNSPEC_sprint, 254 }; 255 256 static const struct aftype *const aftypes[] = { 199 257 &inet_aftype, 200 #if HAVE_AFINET6258 #ifdef HAVE_AFINET6 201 259 &inet6_aftype, 202 260 #endif … … 206 264 207 265 /* Check our protocol family table for this family. */ 208 static struct aftype *get_afntype(int af) 209 { 210 struct aftype * const *afp; 266 const struct aftype *get_aftype(const char *name) 267 { 268 const struct aftype *const *afp; 269 270 afp = aftypes; 271 while (*afp != NULL) { 272 if (!strcmp((*afp)->name, name)) 273 return (*afp); 274 afp++; 275 } 276 return NULL; 277 } 278 279 /* Check our protocol family table for this family. */ 280 static const struct aftype *get_afntype(int af) 281 { 282 const struct aftype *const *afp; 211 283 212 284 afp = aftypes; 213 285 while (*afp != NULL) { 214 286 if ((*afp)->af == af) 215 return (*afp);287 return *afp; 216 288 afp++; 217 289 } 218 return (NULL); 219 } 220 221 /* Check our protocol family table for this family and return its socket */ 222 static int get_socket_for_af(int af) 223 { 224 struct aftype * const *afp; 225 226 afp = aftypes; 227 while (*afp != NULL) { 228 if ((*afp)->af == af) 229 return (*afp)->fd; 230 afp++; 231 } 232 return -1; 290 return NULL; 233 291 } 234 292 … … 284 342 285 343 286 int interface_opt_a = 0; /* show all interfaces*/344 smallint interface_opt_a; /* show all interfaces */ 287 345 288 346 static struct interface *int_list, *int_last; 289 static int skfd = -1; /* generic raw socket desc. */ 290 291 292 static int sockets_open(int family) 293 { 294 struct aftype * const *aft; 295 int sfd = -1; 296 static int force = -1; 297 298 if (force < 0) { 299 force = 0; 300 if (get_linux_version_code() < KERNEL_VERSION(2,1,0)) 301 force = 1; 302 if (access("/proc/net", R_OK)) 303 force = 1; 304 } 305 for (aft = aftypes; *aft; aft++) { 306 struct aftype *af = *aft; 307 int type = SOCK_DGRAM; 308 309 if (af->af == AF_UNSPEC) 310 continue; 311 if (family && family != af->af) 312 continue; 313 if (af->fd != -1) { 314 sfd = af->fd; 315 continue; 316 } 317 /* Check some /proc file first to not stress kmod */ 318 if (!family && !force && af->flag_file) { 319 if (access(af->flag_file, R_OK)) 320 continue; 321 } 322 af->fd = socket(af->af, type, 0); 323 if (af->fd >= 0) 324 sfd = af->fd; 325 } 326 if (sfd < 0) { 327 bb_error_msg("No usable address families found."); 328 } 329 return sfd; 330 } 331 332 #ifdef CONFIG_FEATURE_CLEAN_UP 333 static void sockets_close(void) 334 { 335 struct aftype * const *aft; 336 for (aft = aftypes; *aft != NULL; aft++) { 337 struct aftype *af = *aft; 338 if( af->fd != -1 ) { 339 close(af->fd); 340 af->fd = -1; 341 } 342 } 343 } 344 #endif 345 347 348 349 #if 0 346 350 /* like strcmp(), but knows about numbers */ 351 except that the freshly added calls to xatoul() brf on ethernet aliases with 352 uClibc with e.g.: ife->name='lo' name='eth0:1' 347 353 static int nstrcmp(const char *a, const char *b) 348 354 { … … 363 369 364 370 if (isdigit(*a) && isdigit(*b)) { 365 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;371 return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1; 366 372 } 367 373 return *a - *b; 368 374 } 375 #endif 369 376 370 377 static struct interface *add_interface(char *name) … … 373 380 374 381 for (ife = int_last; ife; ife = ife->prev) { 375 int n = nstrcmp(ife->name, name);382 int n = /*n*/strcmp(ife->name, name); 376 383 377 384 if (n == 0) … … 392 399 *nextp = new; 393 400 return new; 394 }395 396 397 static int if_readconf(void)398 {399 int numreqs = 30;400 struct ifconf ifc;401 struct ifreq *ifr;402 int n, err = -1;403 int skfd2;404 405 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets406 (as of 2.1.128) */407 skfd2 = get_socket_for_af(AF_INET);408 if (skfd2 < 0) {409 bb_perror_msg(("warning: no inet socket available"));410 /* Try to soldier on with whatever socket we can get hold of. */411 skfd2 = sockets_open(0);412 if (skfd2 < 0)413 return -1;414 }415 416 ifc.ifc_buf = NULL;417 for (;;) {418 ifc.ifc_len = sizeof(struct ifreq) * numreqs;419 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);420 421 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {422 perror("SIOCGIFCONF");423 goto out;424 }425 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {426 /* assume it overflowed and try again */427 numreqs += 10;428 continue;429 }430 break;431 }432 433 ifr = ifc.ifc_req;434 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {435 add_interface(ifr->ifr_name);436 ifr++;437 }438 err = 0;439 440 out:441 free(ifc.ifc_buf);442 return err;443 401 } 444 402 … … 477 435 * args. */ 478 436 479 /* static const char * 437 /* static const char *const ss_fmt[] = { */ 480 438 /* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */ 481 439 /* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */ … … 485 443 /* Lie about the size of the int pointed to for %n. */ 486 444 #if INT_MAX == LONG_MAX 487 static const char * 445 static const char *const ss_fmt[] = { 488 446 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u", 489 447 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u", … … 491 449 }; 492 450 #else 493 static const char * 451 static const char *const ss_fmt[] = { 494 452 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu", 495 453 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu", … … 542 500 } 543 501 502 static int if_readconf(void) 503 { 504 int numreqs = 30; 505 struct ifconf ifc; 506 struct ifreq *ifr; 507 int n, err = -1; 508 int skfd; 509 510 ifc.ifc_buf = NULL; 511 512 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets 513 (as of 2.1.128) */ 514 skfd = socket(AF_INET, SOCK_DGRAM, 0); 515 if (skfd < 0) { 516 bb_perror_msg("error: no inet socket available"); 517 return -1; 518 } 519 520 for (;;) { 521 ifc.ifc_len = sizeof(struct ifreq) * numreqs; 522 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); 523 524 if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) { 525 goto out; 526 } 527 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) { 528 /* assume it overflowed and try again */ 529 numreqs += 10; 530 continue; 531 } 532 break; 533 } 534 535 ifr = ifc.ifc_req; 536 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { 537 add_interface(ifr->ifr_name); 538 ifr++; 539 } 540 err = 0; 541 542 out: 543 close(skfd); 544 free(ifc.ifc_buf); 545 return err; 546 } 547 544 548 static int if_readlist_proc(char *target) 545 549 { 546 static int proc_read; 550 static smallint proc_read; 551 547 552 FILE *fh; 548 553 char buf[512]; … … 557 562 fh = fopen(_PATH_PROCNET_DEV, "r"); 558 563 if (!fh) { 559 bb_perror_msg(" Warning: cannot open %s. Limited output.", _PATH_PROCNET_DEV);564 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV); 560 565 return if_readconf(); 561 566 } … … 577 582 } 578 583 if (ferror(fh)) { 579 perror(_PATH_PROCNET_DEV);584 bb_perror_msg(_PATH_PROCNET_DEV); 580 585 err = -1; 581 586 proc_read = 0; … … 588 593 { 589 594 int err = if_readlist_proc(NULL); 590 595 /* Needed in order to get ethN:M aliases */ 591 596 if (!err) 592 597 err = if_readconf(); … … 594 599 } 595 600 596 static int for_all_interfaces(int (*doit) (struct interface *, void *),597 void *cookie)598 {599 struct interface *ife;600 601 if (!int_list && (if_readlist() < 0))602 return -1;603 for (ife = int_list; ife; ife = ife->next) {604 int err = doit(ife, cookie);605 606 if (err)607 return err;608 }609 return 0;610 }611 612 601 /* Fetch the interface configuration from the kernel. */ 613 602 static int if_fetch(struct interface *ife) 614 603 { 615 604 struct ifreq ifr; 616 int fd;617 605 char *ifname = ife->name; 618 619 strcpy(ifr.ifr_name, ifname); 620 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) 621 return (-1); 606 int skfd; 607 608 skfd = xsocket(AF_INET, SOCK_DGRAM, 0); 609 610 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 611 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { 612 close(skfd); 613 return -1; 614 } 622 615 ife->flags = ifr.ifr_flags; 623 616 624 strcpy(ifr.ifr_name, ifname); 625 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) 626 memset(ife->hwaddr, 0, 32); 627 else 617 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 618 memset(ife->hwaddr, 0, 32); 619 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) 628 620 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); 629 621 630 622 ife->type = ifr.ifr_hwaddr.sa_family; 631 623 632 strcpy(ifr.ifr_name, ifname); 633 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) 634 ife->metric = 0; 635 else 624 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 625 ife->metric = 0; 626 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) 636 627 ife->metric = ifr.ifr_metric; 637 628 638 strcpy(ifr.ifr_name, ifname); 639 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) 640 ife->mtu = 0; 641 else 629 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 630 ife->mtu = 0; 631 if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) 642 632 ife->mtu = ifr.ifr_mtu; 643 633 634 memset(&ife->map, 0, sizeof(struct ifmap)); 644 635 #ifdef SIOCGIFMAP 645 str cpy(ifr.ifr_name, ifname);636 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 646 637 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) 647 638 ife->map = ifr.ifr_map; 648 else 649 #endif 650 memset(&ife->map, 0, sizeof(struct ifmap)); 639 #endif 651 640 652 641 #ifdef HAVE_TXQUEUELEN 653 strcpy(ifr.ifr_name, ifname); 654 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0) 655 ife->tx_queue_len = -1; /* unknown value */ 656 else 642 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 643 ife->tx_queue_len = -1; /* unknown value */ 644 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) 657 645 ife->tx_queue_len = ifr.ifr_qlen; 658 646 #else … … 660 648 #endif 661 649 662 /* IPv4 address? */ 663 fd = get_socket_for_af(AF_INET); 664 if (fd >= 0) { 665 strcpy(ifr.ifr_name, ifname); 666 ifr.ifr_addr.sa_family = AF_INET; 667 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { 668 ife->has_ip = 1; 669 ife->addr = ifr.ifr_addr; 670 strcpy(ifr.ifr_name, ifname); 671 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0) 672 memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); 673 else 674 ife->dstaddr = ifr.ifr_dstaddr; 675 676 strcpy(ifr.ifr_name, ifname); 677 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) 678 memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); 679 else 680 ife->broadaddr = ifr.ifr_broadaddr; 681 682 strcpy(ifr.ifr_name, ifname); 683 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) 684 memset(&ife->netmask, 0, sizeof(struct sockaddr)); 685 else 686 ife->netmask = ifr.ifr_netmask; 687 } else 688 memset(&ife->addr, 0, sizeof(struct sockaddr)); 689 } 690 650 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 651 ifr.ifr_addr.sa_family = AF_INET; 652 memset(&ife->addr, 0, sizeof(struct sockaddr)); 653 if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) { 654 ife->has_ip = 1; 655 ife->addr = ifr.ifr_addr; 656 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 657 memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); 658 if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) 659 ife->dstaddr = ifr.ifr_dstaddr; 660 661 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 662 memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); 663 if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) 664 ife->broadaddr = ifr.ifr_broadaddr; 665 666 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 667 memset(&ife->netmask, 0, sizeof(struct sockaddr)); 668 if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) 669 ife->netmask = ifr.ifr_netmask; 670 } 671 672 close(skfd); 691 673 return 0; 692 674 } … … 696 678 { 697 679 if (if_fetch(ife) < 0) { 698 c har *errmsg;680 const char *errmsg; 699 681 700 682 if (errno == ENODEV) { … … 711 693 } 712 694 713 /* This structure defines hardware protocols and their handlers. */714 struct hwtype {715 const char * const name;716 const char *title;717 int type;718 int alen;719 char *(*print) (unsigned char *);720 int (*input) (char *, struct sockaddr *);721 int (*activate) (int fd);722 int suppress_null_addr;723 };724 725 695 static const struct hwtype unspec_hwtype = { 726 696 .name = "unspec", … … 738 708 #include <net/if_arp.h> 739 709 740 #if ( __GLIBC__ >=2 && __GLIBC_MINOR>= 1) || defined(_NEWLIB_VERSION)710 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION) 741 711 #include <net/ethernet.h> 742 712 #else … … 747 717 static char *pr_ether(unsigned char *ptr) 748 718 { 749 static char buff[64]; 750 751 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X", 719 static char *buff; 720 721 free(buff); 722 buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X", 752 723 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), 753 724 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) 754 725 ); 755 return (buff); 756 } 726 return buff; 727 } 728 729 static int in_ether(const char *bufp, struct sockaddr *sap); 757 730 758 731 static const struct hwtype ether_hwtype = { … … 761 734 .type = ARPHRD_ETHER, 762 735 .alen = ETH_ALEN, 763 .print = pr_ether 764 }; 736 .print = pr_ether, 737 .input = in_ether 738 }; 739 740 static unsigned hexchar2int(char c) 741 { 742 if (isdigit(c)) 743 return c - '0'; 744 c &= ~0x20; /* a -> A */ 745 if ((unsigned)(c - 'A') <= 5) 746 return c - ('A' - 10); 747 return ~0U; 748 } 749 750 /* Input an Ethernet address and convert to binary. */ 751 static int in_ether(const char *bufp, struct sockaddr *sap) 752 { 753 unsigned char *ptr; 754 char c; 755 int i; 756 unsigned val; 757 758 sap->sa_family = ether_hwtype.type; 759 ptr = (unsigned char*) sap->sa_data; 760 761 i = 0; 762 while ((*bufp != '\0') && (i < ETH_ALEN)) { 763 val = hexchar2int(*bufp++) * 0x10; 764 if (val > 0xff) { 765 errno = EINVAL; 766 return -1; 767 } 768 c = *bufp; 769 if (c == ':' || c == 0) 770 val >>= 4; 771 else { 772 val |= hexchar2int(c); 773 if (val > 0xff) { 774 errno = EINVAL; 775 return -1; 776 } 777 } 778 if (c != 0) 779 bufp++; 780 *ptr++ = (unsigned char) val; 781 i++; 782 783 /* We might get a semicolon here - not required. */ 784 if (*bufp == ':') { 785 bufp++; 786 } 787 } 788 return 0; 789 } 765 790 766 791 #include <net/if_arp.h> … … 772 797 }; 773 798 774 #if def CONFIG_FEATURE_IPV6799 #if ENABLE_FEATURE_IPV6 775 800 static const struct hwtype sit_hwtype = { 776 801 .name = "sit", … … 779 804 .print = UNSPEC_print, 780 805 .suppress_null_addr = 1 781 } 782 #endif 783 784 static const struct hwtype * 806 }; 807 #endif 808 809 static const struct hwtype *const hwtypes[] = { 785 810 &loop_hwtype, 786 811 ðer_hwtype, 787 812 &ppp_hwtype, 788 813 &unspec_hwtype, 789 #if def CONFIG_FEATURE_IPV6814 #if ENABLE_FEATURE_IPV6 790 815 &sit_hwtype, 791 816 #endif … … 794 819 795 820 #ifdef IFF_PORTSEL 796 static const char * 821 static const char *const if_port_text[] = { 797 822 /* Keep in step with <linux/netdevice.h> */ 798 823 "unknown", … … 808 833 809 834 /* Check our hardware type table for this type. */ 810 static const struct hwtype *get_hwntype(int type) 811 { 812 const struct hwtype * const *hwp; 835 const struct hwtype *get_hwtype(const char *name) 836 { 837 const struct hwtype *const *hwp; 838 839 hwp = hwtypes; 840 while (*hwp != NULL) { 841 if (!strcmp((*hwp)->name, name)) 842 return (*hwp); 843 hwp++; 844 } 845 return NULL; 846 } 847 848 /* Check our hardware type table for this type. */ 849 const struct hwtype *get_hwntype(int type) 850 { 851 const struct hwtype *const *hwp; 813 852 814 853 hwp = hwtypes; 815 854 while (*hwp != NULL) { 816 855 if ((*hwp)->type == type) 817 return (*hwp);856 return *hwp; 818 857 hwp++; 819 858 } 820 return (NULL);859 return NULL; 821 860 } 822 861 … … 833 872 } 834 873 835 static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";874 static const char TRext[] ALIGN1 = "\0\0\0Ki\0Mi\0Gi\0Ti"; 836 875 837 876 static void print_bytes_scaled(unsigned long long ull, const char *end) … … 858 897 } 859 898 860 static const char * const ife_print_flags_strs[] = {861 "UP ",862 "BROADCAST ",863 "DEBUG ",864 "LOOPBACK ",865 "POINTOPOINT ",866 "NOTRAILERS ",867 "RUNNING ",868 "NOARP ",869 "PROMISC ",870 "ALLMULTI ",871 "SLAVE ",872 "MASTER ",873 "MULTICAST ",874 #ifdef HAVE_DYNAMIC875 "DYNAMIC "876 #endif877 };878 879 static const unsigned short ife_print_flags_mask[] = {880 IFF_UP,881 IFF_BROADCAST,882 IFF_DEBUG,883 IFF_LOOPBACK,884 IFF_POINTOPOINT,885 IFF_NOTRAILERS,886 IFF_RUNNING,887 IFF_NOARP,888 IFF_PROMISC,889 IFF_ALLMULTI,890 IFF_SLAVE,891 IFF_MASTER,892 IFF_MULTICAST,893 #ifdef HAVE_DYNAMIC894 IFF_DYNAMIC895 #endif896 0897 };898 899 899 static void ife_print(struct interface *ptr) 900 900 { 901 struct aftype *ap;901 const struct aftype *ap; 902 902 const struct hwtype *hw; 903 903 int hf; 904 904 int can_compress = 0; 905 905 906 #if HAVE_AFINET6906 #ifdef HAVE_AFINET6 907 907 FILE *f; 908 908 char addr6[40], devname[20]; … … 938 938 } 939 939 #endif 940 p rintf("\n");940 puts(""); 941 941 942 942 if (ptr->has_ip) { … … 952 952 } 953 953 954 #if HAVE_AFINET6954 #ifdef HAVE_AFINET6 955 955 956 956 #define IPV6_ADDR_ANY 0x0000U … … 971 971 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */ 972 972 973 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { 973 f = fopen(_PATH_PROCNET_IFINET6, "r"); 974 if (f != NULL) { 974 975 while (fscanf 975 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %0 2x %02x %02x %02x %20s\n",976 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", 976 977 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], 977 978 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, 978 &dad_status, devname) != EOF) { 979 &dad_status, devname) != EOF 980 ) { 979 981 if (!strcmp(devname, ptr->name)) { 980 982 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", … … 985 987 sap.sin6_family = AF_INET6; 986 988 printf(" inet6 addr: %s/%d", 987 inet6_aftype.sprint((struct sockaddr *) &sap, 1),989 INET6_sprint((struct sockaddr *) &sap, 1), 988 990 plen); 989 991 printf(" Scope:"); 990 992 switch (scope & IPV6_ADDR_SCOPE_MASK) { 991 993 case 0: 992 p rintf("Global");994 puts("Global"); 993 995 break; 994 996 case IPV6_ADDR_LINKLOCAL: 995 p rintf("Link");997 puts("Link"); 996 998 break; 997 999 case IPV6_ADDR_SITELOCAL: 998 p rintf("Site");1000 puts("Site"); 999 1001 break; 1000 1002 case IPV6_ADDR_COMPATv4: 1001 p rintf("Compat");1003 puts("Compat"); 1002 1004 break; 1003 1005 case IPV6_ADDR_LOOPBACK: 1004 p rintf("Host");1006 puts("Host"); 1005 1007 break; 1006 1008 default: 1007 p rintf("Unknown");1009 puts("Unknown"); 1008 1010 } 1009 printf("\n");1010 1011 } 1011 1012 } … … 1020 1021 printf("[NO FLAGS] "); 1021 1022 } else { 1022 int i = 0; 1023 static const char ife_print_flags_strs[] ALIGN1 = 1024 "UP\0" 1025 "BROADCAST\0" 1026 "DEBUG\0" 1027 "LOOPBACK\0" 1028 "POINTOPOINT\0" 1029 "NOTRAILERS\0" 1030 "RUNNING\0" 1031 "NOARP\0" 1032 "PROMISC\0" 1033 "ALLMULTI\0" 1034 "SLAVE\0" 1035 "MASTER\0" 1036 "MULTICAST\0" 1037 #ifdef HAVE_DYNAMIC 1038 "DYNAMIC\0" 1039 #endif 1040 ; 1041 static const unsigned short ife_print_flags_mask[] ALIGN2 = { 1042 IFF_UP, 1043 IFF_BROADCAST, 1044 IFF_DEBUG, 1045 IFF_LOOPBACK, 1046 IFF_POINTOPOINT, 1047 IFF_NOTRAILERS, 1048 IFF_RUNNING, 1049 IFF_NOARP, 1050 IFF_PROMISC, 1051 IFF_ALLMULTI, 1052 IFF_SLAVE, 1053 IFF_MASTER, 1054 IFF_MULTICAST 1055 #ifdef HAVE_DYNAMIC 1056 ,IFF_DYNAMIC 1057 #endif 1058 }; 1059 const unsigned short *mask = ife_print_flags_mask; 1060 const char *str = ife_print_flags_strs; 1023 1061 do { 1024 if (ptr->flags & ife_print_flags_mask[i]) {1025 printf( ife_print_flags_strs[i]);1062 if (ptr->flags & *mask) { 1063 printf("%s ", str); 1026 1064 } 1027 } while (ife_print_flags_mask[++i]); 1065 mask++; 1066 str += strlen(str) + 1; 1067 } while (*str); 1028 1068 } 1029 1069 … … 1034 1074 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive); 1035 1075 #endif 1036 p rintf("\n");1076 puts(""); 1037 1077 1038 1078 /* If needed, display the interface statistics. */ … … 1083 1123 if (ptr->map.dma) 1084 1124 printf("DMA chan:%x ", ptr->map.dma); 1085 printf("\n"); 1086 } 1087 printf("\n"); 1088 } 1089 1090 1091 static int do_if_print(struct interface *ife, void *cookie) 1092 { 1093 int *opt_a = (int *) cookie; 1125 puts(""); 1126 } 1127 puts(""); 1128 } 1129 1130 1131 static int do_if_print(struct interface *ife) /*, int *opt_a)*/ 1132 { 1094 1133 int res; 1095 1134 1096 1135 res = do_if_fetch(ife); 1097 1136 if (res >= 0) { 1098 if ((ife->flags & IFF_UP) || *opt_a)1137 if ((ife->flags & IFF_UP) || interface_opt_a) 1099 1138 ife_print(ife); 1100 1139 } … … 1112 1151 } 1113 1152 1153 #ifdef UNUSED 1154 static int for_all_interfaces(int (*doit) (struct interface *, void *), 1155 void *cookie) 1156 { 1157 struct interface *ife; 1158 1159 if (!int_list && (if_readlist() < 0)) 1160 return -1; 1161 for (ife = int_list; ife; ife = ife->next) { 1162 int err = doit(ife, cookie); 1163 1164 if (err) 1165 return err; 1166 } 1167 return 0; 1168 } 1169 #endif 1170 1114 1171 /* for ipv4 add/del modes */ 1115 1172 static int if_print(char *ifname) 1116 1173 { 1174 struct interface *ife; 1117 1175 int res; 1118 1176 1119 1177 if (!ifname) { 1120 res = for_all_interfaces(do_if_print, &interface_opt_a); 1121 } else { 1122 struct interface *ife; 1123 1124 ife = lookup_interface(ifname); 1125 res = do_if_fetch(ife); 1126 if (res >= 0) 1127 ife_print(ife); 1128 } 1178 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/ 1179 if (!int_list && (if_readlist() < 0)) 1180 return -1; 1181 for (ife = int_list; ife; ife = ife->next) { 1182 int err = do_if_print(ife); /*, &interface_opt_a);*/ 1183 if (err) 1184 return err; 1185 } 1186 return 0; 1187 } 1188 ife = lookup_interface(ifname); 1189 res = do_if_fetch(ife); 1190 if (res >= 0) 1191 ife_print(ife); 1129 1192 return res; 1130 1193 } 1131 1194 1132 int display_interfaces(char *ifname);1133 1195 int display_interfaces(char *ifname) 1134 1196 { 1135 1197 int status; 1136 1198 1137 /* Create a channel to the NET kernel. */1138 if ((skfd = sockets_open(0)) < 0) {1139 bb_perror_msg_and_die("socket");1140 }1141 1142 /* Do we have to show the current setup? */1143 1199 status = if_print(ifname); 1144 #ifdef CONFIG_FEATURE_CLEAN_UP 1145 sockets_close(); 1146 #endif 1147 exit(status < 0); 1148 } 1200 1201 return (status < 0); /* status < 0 == 1 -- error */ 1202 } -
branches/2.2.5/mindi-busybox/networking/ip.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ip.c "ip" utility frontend. … … 10 11 * 11 12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 13 * Bernhard Fischer rewrote to use index_in_substr_array 12 14 */ 13 15 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 #include <syslog.h> 18 #include <fcntl.h> 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 #include <string.h> 16 #include "libbb.h" 22 17 23 18 #include "libiproute/utils.h" 24 19 #include "libiproute/ip_common.h" 25 20 26 #include "busybox.h" 21 #if ENABLE_FEATURE_IP_ADDRESS \ 22 || ENABLE_FEATURE_IP_ROUTE \ 23 || ENABLE_FEATURE_IP_LINK \ 24 || ENABLE_FEATURE_IP_TUNNEL \ 25 || ENABLE_FEATURE_IP_RULE 27 26 28 #if 0 29 int preferred_family = AF_UNSPEC; 30 int oneline = 0;31 char * _SL_ = NULL; 27 static int ATTRIBUTE_NORETURN ip_print_help(int ATTRIBUTE_UNUSED ac, char ATTRIBUTE_UNUSED **av) 28 { 29 bb_show_usage(); 30 } 32 31 33 void ip_parse_common_args(int *argcp, char ***argvp) 32 static int (*ip_func)(int argc, char **argv) = ip_print_help; 33 34 static int ip_do(int argc, char **argv) 34 35 { 35 int argc = *argcp; 36 char **argv = *argvp; 36 ip_parse_common_args(&argc, &argv); 37 return ip_func(argc-1, argv+1); 38 } 37 39 38 while (argc > 1) { 39 char *opt = argv[1]; 40 41 if (strcmp(opt,"--") == 0) { 42 argc--; argv++; 43 break; 44 } 45 46 if (opt[0] != '-') 47 break; 48 49 if (opt[1] == '-') 50 opt++; 51 52 if (matches(opt, "-family") == 0) { 53 argc--; 54 argv++; 55 if (strcmp(argv[1], "inet") == 0) 56 preferred_family = AF_INET; 57 else if (strcmp(argv[1], "inet6") == 0) 58 preferred_family = AF_INET6; 59 else if (strcmp(argv[1], "link") == 0) 60 preferred_family = AF_PACKET; 61 else 62 invarg(bb_msg_invalid_arg, argv[1], "-family"); 63 } else if (strcmp(opt, "-4") == 0) { 64 preferred_family = AF_INET; 65 } else if (strcmp(opt, "-6") == 0) { 66 preferred_family = AF_INET6; 67 } else if (strcmp(opt, "-0") == 0) { 68 preferred_family = AF_PACKET; 69 } else if (matches(opt, "-oneline") == 0) { 70 ++oneline; 71 } else { 72 bb_show_usage(); 73 } 74 argc--; argv++; 75 } 76 _SL_ = oneline ? "\\" : "\n" ; 40 #if ENABLE_FEATURE_IP_ADDRESS 41 int ipaddr_main(int argc, char **argv); 42 int ipaddr_main(int argc, char **argv) 43 { 44 ip_func = do_ipaddr; 45 return ip_do(argc, argv); 46 } 47 #endif 48 #if ENABLE_FEATURE_IP_LINK 49 int iplink_main(int argc, char **argv); 50 int iplink_main(int argc, char **argv) 51 { 52 ip_func = do_iplink; 53 return ip_do(argc, argv); 54 } 55 #endif 56 #if ENABLE_FEATURE_IP_ROUTE 57 int iproute_main(int argc, char **argv); 58 int iproute_main(int argc, char **argv) 59 { 60 ip_func = do_iproute; 61 return ip_do(argc, argv); 62 } 63 #endif 64 #if ENABLE_FEATURE_IP_RULE 65 int iprule_main(int argc, char **argv); 66 int iprule_main(int argc, char **argv) 67 { 68 ip_func = do_iprule; 69 return ip_do(argc, argv); 70 } 71 #endif 72 #if ENABLE_FEATURE_IP_TUNNEL 73 int iptunnel_main(int argc, char **argv); 74 int iptunnel_main(int argc, char **argv) 75 { 76 ip_func = do_iptunnel; 77 return ip_do(argc, argv); 77 78 } 78 79 #endif 79 80 81 82 int ip_main(int argc, char **argv); 80 83 int ip_main(int argc, char **argv) 81 84 { 82 int ret = EXIT_FAILURE; 85 static const char keywords[] ALIGN1 = 86 USE_FEATURE_IP_ADDRESS("address\0") 87 USE_FEATURE_IP_ROUTE("route\0") 88 USE_FEATURE_IP_LINK("link\0") 89 USE_FEATURE_IP_TUNNEL("tunnel\0" "tunl\0") 90 USE_FEATURE_IP_RULE("rule\0") 91 ; 92 enum { 93 USE_FEATURE_IP_ADDRESS(IP_addr,) 94 USE_FEATURE_IP_ROUTE(IP_route,) 95 USE_FEATURE_IP_LINK(IP_link,) 96 USE_FEATURE_IP_TUNNEL(IP_tunnel, IP_tunl,) 97 USE_FEATURE_IP_RULE(IP_rule,) 98 IP_none 99 }; 83 100 84 101 ip_parse_common_args(&argc, &argv); 85 86 102 if (argc > 1) { 87 #ifdef CONFIG_FEATURE_IP_ADDRESS 88 if (matches(argv[1], "address") == 0) { 89 ret = do_ipaddr(argc-2, argv+2); 90 } 103 int key = index_in_substrings(keywords, argv[1]); 104 argc -= 2; 105 argv += 2; 106 #if ENABLE_FEATURE_IP_ADDRESS 107 if (key == IP_addr) 108 ip_func = do_ipaddr; 91 109 #endif 92 #ifdef CONFIG_FEATURE_IP_ROUTE 93 if (matches(argv[1], "route") == 0) { 94 ret = do_iproute(argc-2, argv+2); 95 } 110 #if ENABLE_FEATURE_IP_ROUTE 111 if (key == IP_route) 112 ip_func = do_iproute; 96 113 #endif 97 #ifdef CONFIG_FEATURE_IP_LINK 98 if (matches(argv[1], "link") == 0) { 99 ret = do_iplink(argc-2, argv+2); 100 } 114 #if ENABLE_FEATURE_IP_LINK 115 if (key == IP_link) 116 ip_func = do_iplink; 101 117 #endif 102 #ifdef CONFIG_FEATURE_IP_TUNNEL 103 if (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0) { 104 ret = do_iptunnel(argc-2, argv+2); 105 } 118 #if ENABLE_FEATURE_IP_TUNNEL 119 if (key == IP_tunnel || key == IP_tunl) 120 ip_func = do_iptunnel; 121 #endif 122 #if ENABLE_FEATURE_IP_RULE 123 if (key == IP_rule) 124 ip_func = do_iprule; 106 125 #endif 107 126 } 108 if (ret) { 109 bb_show_usage(); 110 } 111 return(EXIT_SUCCESS); 127 return ip_func(argc, argv); 112 128 } 129 130 #endif /* any of ENABLE_FEATURE_IP_xxx is 1 */ -
branches/2.2.5/mindi-busybox/networking/ipcalc.c
r821 r1765 1 /* vi: set sw=4 ts=4 ai: */1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 3 * Mini ipcalc implementation for busybox … … 13 13 */ 14 14 15 #include "busybox.h"16 #include <ctype.h>17 15 #include <getopt.h> 18 16 #include <sys/socket.h> 19 17 #include <arpa/inet.h> 20 18 21 # define IPCALC_MSG(CMD,ALTCMD) if (mode & SILENT) {ALTCMD;} else {CMD;}19 #include "libbb.h" 22 20 23 21 #define CLASS_A_NETMASK ntohl(0xFF000000) … … 39 37 } 40 38 41 #if def CONFIG_FEATURE_IPCALC_FANCY39 #if ENABLE_FEATURE_IPCALC_FANCY 42 40 static int get_prefix(unsigned long netmask) 43 41 { … … 46 44 47 45 netmask = htonl(netmask); 48 while (msk) {46 while (msk) { 49 47 if (netmask & msk) 50 48 ret++; … … 57 55 #endif 58 56 57 59 58 #define NETMASK 0x01 60 59 #define BROADCAST 0x02 … … 65 64 66 65 #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS 67 static const struct option long_options[] = { 68 {"netmask", no_argument, NULL, 'm'}, 69 {"broadcast", no_argument, NULL, 'b'}, 70 {"network", no_argument, NULL, 'n'}, 71 #ifdef CONFIG_FEATURE_IPCALC_FANCY 72 {"prefix", no_argument, NULL, 'p'}, 73 {"hostname", no_argument, NULL, 'h'}, 74 {"silent", no_argument, NULL, 's'}, 75 #endif 76 {NULL, 0, NULL, 0} 77 }; 78 #else 79 #define long_options 0 66 static const char ipcalc_longopts[] ALIGN1 = 67 "netmask\0" No_argument "m" 68 "broadcast\0" No_argument "b" 69 "network\0" No_argument "n" 70 # if ENABLE_FEATURE_IPCALC_FANCY 71 "prefix\0" No_argument "p" 72 "hostname\0" No_argument "h" 73 "silent\0" No_argument "s" 74 # endif 75 ; 80 76 #endif 81 77 82 83 78 int ipcalc_main(int argc, char **argv); 84 79 int ipcalc_main(int argc, char **argv) 85 80 { 86 unsigned long mode;81 unsigned opt; 87 82 int have_netmask = 0; 88 83 in_addr_t netmask, broadcast, network, ipaddr; … … 90 85 char *ipstr; 91 86 92 if (ENABLE_FEATURE_IPCALC_LONG_OPTIONS) 93 bb_applet_long_options = long_options; 94 95 mode = bb_getopt_ulflags(argc, argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs")); 96 87 #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS 88 applet_long_options = ipcalc_longopts; 89 #endif 90 opt = getopt32(argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs")); 97 91 argc -= optind; 98 92 argv += optind; 99 if ( mode& (BROADCAST | NETWORK | NETPREFIX)) {93 if (opt & (BROADCAST | NETWORK | NETPREFIX)) { 100 94 if (argc > 2 || argc <= 0) 101 95 bb_show_usage(); … … 104 98 bb_show_usage(); 105 99 } 100 if (opt & SILENT) 101 logmode = LOGMODE_NONE; /* Suppress error_msg() output */ 106 102 107 103 ipstr = argv[0]; … … 112 108 prefixstr = ipstr; 113 109 114 while (*prefixstr) {110 while (*prefixstr) { 115 111 if (*prefixstr == '/') { 116 112 *prefixstr = (char)0; 117 113 prefixstr++; 118 114 if (*prefixstr) { 119 unsigned int msk; 120 121 if (safe_strtoul(prefixstr, &netprefix) || netprefix > 32) { 122 IPCALC_MSG(bb_error_msg_and_die("bad IP prefix: %s\n", prefixstr), 123 exit(EXIT_FAILURE)); 124 } 115 unsigned msk; 116 netprefix = xatoul_range(prefixstr, 0, 32); 125 117 netmask = 0; 126 118 msk = 0x80000000; … … 143 135 144 136 if (ipaddr == 0) { 145 IPCALC_MSG(bb_error_msg_and_die("bad IP address: %s", argv[0]), 146 exit(EXIT_FAILURE)); 137 bb_error_msg_and_die("bad IP address: %s", argv[0]); 147 138 } 148 139 ipaddr = a.s_addr; … … 150 141 if (argc == 2) { 151 142 if (ENABLE_FEATURE_IPCALC_FANCY && have_netmask) { 152 IPCALC_MSG(bb_error_msg_and_die("Use prefix or netmask, not both.\n"), 153 exit(EXIT_FAILURE)); 143 bb_error_msg_and_die("use prefix or netmask, not both"); 154 144 } 155 145 156 146 netmask = inet_aton(argv[1], &a); 157 147 if (netmask == 0) { 158 IPCALC_MSG(bb_error_msg_and_die("bad netmask: %s", argv[1]), 159 exit(EXIT_FAILURE)); 148 bb_error_msg_and_die("bad netmask: %s", argv[1]); 160 149 } 161 150 netmask = a.s_addr; … … 167 156 } 168 157 169 if ( mode& NETMASK) {158 if (opt & NETMASK) { 170 159 printf("NETMASK=%s\n", inet_ntoa((*(struct in_addr *) &netmask))); 171 160 } 172 161 173 if ( mode& BROADCAST) {162 if (opt & BROADCAST) { 174 163 broadcast = (ipaddr & netmask) | ~netmask; 175 164 printf("BROADCAST=%s\n", inet_ntoa((*(struct in_addr *) &broadcast))); 176 165 } 177 166 178 if ( mode& NETWORK) {167 if (opt & NETWORK) { 179 168 network = ipaddr & netmask; 180 169 printf("NETWORK=%s\n", inet_ntoa((*(struct in_addr *) &network))); … … 182 171 183 172 if (ENABLE_FEATURE_IPCALC_FANCY) { 184 if ( mode& NETPREFIX) {173 if (opt & NETPREFIX) { 185 174 printf("PREFIX=%i\n", get_prefix(netmask)); 186 175 } 187 176 188 if ( mode& HOSTNAME) {177 if (opt & HOSTNAME) { 189 178 struct hostent *hostinfo; 190 179 int x; … … 192 181 hostinfo = gethostbyaddr((char *) &ipaddr, sizeof(ipaddr), AF_INET); 193 182 if (!hostinfo) { 194 IPCALC_MSG(bb_herror_msg_and_die( 195 "cannot find hostname for %s", argv[0]),); 196 exit(EXIT_FAILURE); 183 bb_herror_msg_and_die("cannot find hostname for %s", argv[0]); 197 184 } 198 185 for (x = 0; hostinfo->h_name[x]; x++) { -
branches/2.2.5/mindi-busybox/networking/libiproute/ip_common.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 #ifndef _IP_COMMON_H 2 3 #define _IP_COMMON_H 1 3 4 4 #include " busybox.h"5 #include "libbb.h" 5 6 #include <asm/types.h> 6 7 #include <linux/netlink.h> 7 8 #include <linux/rtnetlink.h> 8 9 10 extern int preferred_family; 11 extern char * _SL_; 9 #if !defined IFA_RTA 10 #include <linux/if_addr.h> 11 #endif 12 #if !defined IFLA_RTA 13 #include <linux/if_link.h> 14 #endif 12 15 13 16 extern void ip_parse_common_args(int *argcp, char ***argvp); … … 17 20 extern void iplink_usage(void) ATTRIBUTE_NORETURN; 18 21 extern void ipneigh_reset_filter(void); 22 19 23 extern int do_ipaddr(int argc, char **argv); 20 24 extern int do_iproute(int argc, char **argv); -
branches/2.2.5/mindi-busybox/networking/libiproute/ip_parse_common_args.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ip.c "ip" utility frontend. … … 15 16 */ 16 17 17 #include <string.h> 18 19 #include "libbb.h" 18 #include "ip_common.h" /* #include "libbb.h" is inside */ 20 19 #include "utils.h" 21 #include "ip_common.h"22 23 20 24 21 int preferred_family = AF_UNSPEC; 25 int oneline = 0;26 char * _SL_ = NULL;22 smallint oneline; 23 char _SL_; 27 24 28 25 void ip_parse_common_args(int *argcp, char ***argvp) … … 30 27 int argc = *argcp; 31 28 char **argv = *argvp; 29 static const char ip_common_commands[] ALIGN1 = 30 "-family\0""inet\0""inet6\0""link\0" 31 "-4\0""-6\0""-0\0""-oneline\0"; 32 enum { 33 ARG_family = 1, 34 ARG_inet, 35 ARG_inet6, 36 ARG_link, 37 ARG_IPv4, 38 ARG_IPv6, 39 ARG_packet, 40 ARG_oneline 41 }; 42 smalluint arg; 32 43 33 44 while (argc > 1) { … … 35 46 36 47 if (strcmp(opt,"--") == 0) { 37 argc--; argv++; 48 argc--; 49 argv++; 38 50 break; 39 51 } 40 41 52 if (opt[0] != '-') 42 53 break; 43 44 54 if (opt[1] == '-') 45 55 opt++; 46 47 if ( matches(opt, "-family") == 0) {56 arg = index_in_strings(ip_common_commands, opt) + 1; 57 if (arg == ARG_family) { 48 58 argc--; 49 59 argv++; 50 if (! argv[1]) 51 bb_show_usage(); 52 if (strcmp(argv[1], "inet") == 0) 60 if (!argv[1]) 61 bb_show_usage(); 62 arg = index_in_strings(ip_common_commands, argv[1]) + 1; 63 if (arg == ARG_inet) 53 64 preferred_family = AF_INET; 54 else if ( strcmp(argv[1], "inet6") == 0)65 else if (arg == ARG_inet6) 55 66 preferred_family = AF_INET6; 56 else if ( strcmp(argv[1], "link") == 0)67 else if (arg == ARG_link) 57 68 preferred_family = AF_PACKET; 58 69 else 59 70 invarg(argv[1], "protocol family"); 60 } else if ( strcmp(opt, "-4") == 0) {71 } else if (arg == ARG_IPv4) { 61 72 preferred_family = AF_INET; 62 } else if ( strcmp(opt, "-6") == 0) {73 } else if (arg == ARG_IPv6) { 63 74 preferred_family = AF_INET6; 64 } else if ( strcmp(opt, "-0") == 0) {75 } else if (arg == ARG_packet) { 65 76 preferred_family = AF_PACKET; 66 } else if ( matches(opt, "-oneline") == 0) {77 } else if (arg == ARG_oneline) { 67 78 ++oneline; 68 79 } else { 69 80 bb_show_usage(); 70 81 } 71 argc--; argv++; 82 argc--; 83 argv++; 72 84 } 73 _SL_ = oneline ? "\\" : "\n";85 _SL_ = oneline ? '\\' : '\n'; 74 86 *argcp = argc; 75 87 *argvp = argv; -
branches/2.2.5/mindi-busybox/networking/libiproute/ipaddress.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ipaddress.c "ip address". … … 10 11 */ 11 12 12 #include "libbb.h" 13 #include <sys/socket.h> 14 #include <sys/ioctl.h> 15 13 //#include <sys/socket.h> 14 //#include <sys/ioctl.h> 16 15 #include <fnmatch.h> 17 #include <string.h>18 #include <unistd.h>19 20 16 #include <net/if.h> 21 17 #include <net/if_arp.h> 22 18 19 #include "ip_common.h" /* #include "libbb.h" is inside */ 23 20 #include "rt_names.h" 24 21 #include "utils.h" 25 #include "ip_common.h" 26 27 28 static struct 29 { 22 23 24 typedef struct filter_t { 30 25 int ifindex; 31 26 int family; … … 42 37 int flushe; 43 38 struct rtnl_handle *rth; 44 } filter; 39 } filter_t; 40 41 #define filter (*(filter_t*)&bb_common_bufsiz1) 42 45 43 46 44 static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown) … … 49 47 flags &= ~IFF_RUNNING; 50 48 #define _PF(f) if (flags&IFF_##f) { \ 51 flags &= ~IFF_##f 49 flags &= ~IFF_##f; \ 52 50 fprintf(fp, #f "%s", flags ? "," : ""); } 53 51 _PF(LOOPBACK); … … 86 84 87 85 memset(&ifr, 0, sizeof(ifr)); 88 strcpy(ifr.ifr_name, name); 89 if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) { 90 perror("SIOCGIFXQLEN"); 86 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 87 if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) { 91 88 close(s); 92 89 return; … … 99 96 100 97 static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, 101 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)98 const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) 102 99 { 103 100 FILE *fp = (FILE*)arg; … … 125 122 return -1; 126 123 } 127 if (filter.label && 128 (!filter.family || filter.family == AF_PACKET) && 129 fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) 130 return 0; 124 if (filter.label 125 && (!filter.family || filter.family == AF_PACKET) 126 && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0) 127 ) { 128 return 0; 129 } 131 130 132 131 if (n->nlmsg_type == RTM_DELLINK) … … 166 165 if (!filter.family || filter.family == AF_PACKET) { 167 166 SPRINT_BUF(b1); 168 fprintf(fp, "%s", _SL_); 169 fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); 167 fprintf(fp, "%c link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); 170 168 171 169 if (tb[IFLA_ADDRESS]) { … … 186 184 } 187 185 } 188 fp rintf(fp, "\n");186 fputc('\n', fp); 189 187 fflush(fp); 190 188 return 0; … … 194 192 { 195 193 if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { 196 perror("Failed to send flush request\n");194 bb_perror_msg("failed to send flush request"); 197 195 return -1; 198 196 } … … 341 339 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); 342 340 char buf[128]; 343 fp rintf(fp, "%s", _SL_);341 fputc(_SL_, fp); 344 342 if (ci->ifa_valid == 0xFFFFFFFFU) 345 343 sprintf(buf, "valid_lft forever"); … … 352 350 fprintf(fp, " %s", buf); 353 351 } 354 fp rintf(fp, "\n");352 fputc('\n', fp); 355 353 fflush(fp); 356 354 return 0; … … 366 364 static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp) 367 365 { 368 for ( ;ainfo ;ainfo = ainfo->next) {366 for (; ainfo; ainfo = ainfo->next) { 369 367 struct nlmsghdr *n = &ainfo->h; 370 368 struct ifaddrmsg *ifa = NLMSG_DATA(n); … … 412 410 } 413 411 412 /* Return value becomes exitcode. It's okay to not return at all */ 414 413 int ipaddr_list_or_flush(int argc, char **argv, int flush) 415 414 { 416 static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 };415 static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; 417 416 418 417 struct nlmsg_list *linfo = NULL; … … 431 430 if (flush) { 432 431 if (argc <= 0) { 433 bb_error_msg(bb_msg_requires_arg, "flush"); 434 return -1; 432 bb_error_msg_and_die(bb_msg_requires_arg, "flush"); 435 433 } 436 434 if (filter.family == AF_PACKET) { 437 bb_error_msg("Cannot flush link addresses."); 438 return -1; 435 bb_error_msg_and_die("cannot flush link addresses"); 439 436 } 440 437 } 441 438 442 439 while (argc > 0) { 443 const int option_num = compare_string_array(option, *argv);440 const int option_num = index_in_strings(option, *argv); 444 441 switch (option_num) { 445 442 case 0: /* to */ … … 484 481 } 485 482 486 if (rtnl_open(&rth, 0) < 0) 487 exit(1); 488 489 if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { 490 bb_perror_msg_and_die("Cannot send dump request"); 491 } 492 493 if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) { 494 bb_error_msg_and_die("Dump terminated"); 495 } 483 xrtnl_open(&rth); 484 485 xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK); 486 xrtnl_dump_filter(&rth, store_nlmsg, &linfo); 496 487 497 488 if (filter_dev) { 498 filter.ifindex = ll_name_to_index(filter_dev); 499 if (filter.ifindex <= 0) { 500 bb_error_msg("Device \"%s\" does not exist", filter_dev); 501 return -1; 502 } 489 filter.ifindex = xll_name_to_index(filter_dev); 503 490 } 504 491 … … 512 499 513 500 for (;;) { 514 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { 515 perror("Cannot send dump request"); 516 exit(1); 517 } 501 xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); 518 502 filter.flushed = 0; 519 if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) { 520 fprintf(stderr, "Flush terminated\n"); 521 exit(1); 522 } 503 xrtnl_dump_filter(&rth, print_addrinfo, stdout); 523 504 if (filter.flushed == 0) { 524 fflush(stdout);525 505 return 0; 526 506 } 527 507 if (flush_update() < 0) 528 exit(1);508 return 1; 529 509 } 530 510 } 531 511 532 512 if (filter.family != AF_PACKET) { 533 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { 534 bb_perror_msg_and_die("Cannot send dump request"); 535 } 536 537 if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) { 538 bb_error_msg_and_die("Dump terminated"); 539 } 513 xrtnl_wilddump_request(&rth, filter.family, RTM_GETADDR); 514 xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); 540 515 } 541 516 … … 601 576 } 602 577 603 for (l =linfo; l; l = l->next) {578 for (l = linfo; l; l = l->next) { 604 579 if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { 605 580 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); … … 607 582 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); 608 583 } 609 fflush(stdout); 610 } 611 612 exit(0);584 fflush(stdout); /* why? */ 585 } 586 587 return 0; 613 588 } 614 589 … … 616 591 { 617 592 if (lcl->family == AF_INET) { 618 if (lcl->bytelen >= 1 && *( __u8*)&lcl->data == 127)593 if (lcl->bytelen >= 1 && *(uint8_t*)&lcl->data == 127) 619 594 return RT_SCOPE_HOST; 620 595 } … … 622 597 } 623 598 599 /* Return value becomes exitcode. It's okay to not return at all */ 624 600 static int ipaddr_modify(int cmd, int argc, char **argv) 625 601 { 626 static const char *const option[] = { 627 "peer", "remote", "broadcast", "brd", 628 "anycast", "scope", "dev", "label", "local", 0 629 }; 630 602 static const char option[] ALIGN1 = 603 "peer\0""remote\0""broadcast\0""brd\0" 604 "anycast\0""scope\0""dev\0""label\0""local\0"; 631 605 struct rtnl_handle rth; 632 606 struct { 633 struct nlmsghdr 634 struct ifaddrmsg 635 char 607 struct nlmsghdr n; 608 struct ifaddrmsg ifa; 609 char buf[256]; 636 610 } req; 637 char 638 char 611 char *d = NULL; 612 char *l = NULL; 639 613 inet_prefix lcl; 640 614 inet_prefix peer; … … 643 617 int brd_len = 0; 644 618 int any_len = 0; 645 intscoped = 0;619 bool scoped = 0; 646 620 647 621 memset(&req, 0, sizeof(req)); … … 653 627 654 628 while (argc > 0) { 655 const int option_num = compare_string_array(option, *argv);629 const int option_num = index_in_strings(option, *argv); 656 630 switch (option_num) { 657 631 case 0: /* peer */ … … 678 652 duparg("broadcast", *argv); 679 653 } 680 if ( strcmp(*argv, "+") == 0) {654 if (LONE_CHAR(*argv, '+')) { 681 655 brd_len = -1; 682 656 } 683 else if ( strcmp(*argv, "-") == 0) {657 else if (LONE_DASH(*argv)) { 684 658 brd_len = -2; 685 659 } else { … … 748 722 return -1; 749 723 } 750 if (l && matches(d, l) != 0) {724 if (l && strncmp(d, l, strlen(d)) != 0) { 751 725 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); 752 726 } … … 763 737 int i; 764 738 if (req.ifa.ifa_family != AF_INET) { 765 bb_error_msg("Broadcast can be set only for IPv4 addresses"); 766 return -1; 739 bb_error_msg_and_die("broadcast can be set only for IPv4 addresses"); 767 740 } 768 741 brd = peer; … … 781 754 req.ifa.ifa_scope = default_scope(&lcl); 782 755 783 if (rtnl_open(&rth, 0) < 0) 784 exit(1); 756 xrtnl_open(&rth); 785 757 786 758 ll_init_map(&rth); 787 759 788 if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { 789 bb_error_msg("Cannot find device \"%s\"", d); 790 return -1; 791 } 760 req.ifa.ifa_index = xll_name_to_index(d); 792 761 793 762 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 794 exit(2); 795 796 exit(0); 797 } 798 763 return 2; 764 765 return 0; 766 } 767 768 /* Return value becomes exitcode. It's okay to not return at all */ 799 769 int do_ipaddr(int argc, char **argv) 800 770 { 801 static const char *const commands[] = { 802 "add", "delete", "list", "show", "lst", "flush", 0 803 }; 804 805 int command_num = 2; 771 static const char commands[] ALIGN1 = 772 "add\0""delete\0""list\0""show\0""lst\0""flush\0"; 773 774 int command_num = 2; /* default command is list */ 806 775 807 776 if (*argv) { 808 command_num = compare_string_array(commands, *argv); 809 } 810 switch (command_num) { 811 case 0: /* add */ 812 return ipaddr_modify(RTM_NEWADDR, argc-1, argv+1); 813 case 1: /* delete */ 814 return ipaddr_modify(RTM_DELADDR, argc-1, argv+1); 815 case 2: /* list */ 816 case 3: /* show */ 817 case 4: /* lst */ 818 return ipaddr_list_or_flush(argc-1, argv+1, 0); 819 case 5: /* flush */ 820 return ipaddr_list_or_flush(argc-1, argv+1, 1); 821 } 822 bb_error_msg_and_die("Unknown command %s", *argv); 823 } 777 command_num = index_in_substrings(commands, *argv); 778 } 779 if (command_num < 0 || command_num > 5) 780 bb_error_msg_and_die("unknown command %s", *argv); 781 --argc; 782 ++argv; 783 if (command_num == 0) /* add */ 784 return ipaddr_modify(RTM_NEWADDR, argc, argv); 785 else if (command_num == 1) /* delete */ 786 return ipaddr_modify(RTM_DELADDR, argc, argv); 787 else if (command_num == 5) /* flush */ 788 return ipaddr_list_or_flush(argc, argv, 1); 789 else /* 2 == list, 3 == show, 4 == lst */ 790 return ipaddr_list_or_flush(argc, argv, 0); 791 } -
branches/2.2.5/mindi-busybox/networking/libiproute/iplink.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 * iplink.c 3 * iplink.c "ip link". 3 4 * 4 * Authors: 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 6 * 6 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 7 8 */ 8 9 9 #include "libbb.h" 10 11 #include <sys/ioctl.h> 12 #include <sys/socket.h> 13 14 #include <errno.h> 15 #include <string.h> 16 #include <unistd.h> 17 10 //#include <sys/ioctl.h> 11 //#include <sys/socket.h> 18 12 #include <net/if.h> 19 13 #include <net/if_packet.h> 20 14 #include <netpacket/packet.h> 21 22 15 #include <net/ethernet.h> 23 16 17 #include "ip_common.h" /* #include "libbb.h" is inside */ 24 18 #include "rt_names.h" 25 19 #include "utils.h" 26 #include "ip_common.h" 27 28 /* take from linux/sockios.h */ 20 21 /* taken from linux/sockios.h */ 29 22 #define SIOCSIFNAME 0x8923 /* set interface name */ 30 23 31 static int do_link; 32 33 static int on_off(char *msg) 34 { 35 bb_error_msg("Error: argument of \"%s\" must be \"on\" or \"off\"", msg); 36 return -1; 37 } 38 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 } 29 30 /* Exits on error */ 39 31 static int get_ctl_fd(void) 40 32 { 41 int s_errno;42 33 int fd; 43 34 … … 45 36 if (fd >= 0) 46 37 return fd; 47 s_errno = errno;48 38 fd = socket(PF_PACKET, SOCK_DGRAM, 0); 49 39 if (fd >= 0) 50 40 return fd; 51 fd = socket(PF_INET6, SOCK_DGRAM, 0); 52 if (fd >= 0) 53 return fd; 54 errno = s_errno; 55 perror("Cannot create control socket"); 56 return -1; 57 } 58 59 static int do_chflags(char *dev, __u32 flags, __u32 mask) 41 return xsocket(PF_INET6, SOCK_DGRAM, 0); 42 } 43 44 /* Exits on error */ 45 static void do_chflags(char *dev, uint32_t flags, uint32_t mask) 60 46 { 61 47 struct ifreq ifr; 62 48 int fd; 63 int err; 64 65 strcpy(ifr.ifr_name, dev); 49 50 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 66 51 fd = get_ctl_fd(); 67 if (fd < 0) 68 return -1; 69 err = ioctl(fd, SIOCGIFFLAGS, &ifr); 70 if (err) { 71 perror("SIOCGIFFLAGS"); 72 close(fd); 73 return -1; 74 } 75 if ((ifr.ifr_flags^flags)&mask) { 52 xioctl(fd, SIOCGIFFLAGS, &ifr); 53 if ((ifr.ifr_flags ^ flags) & mask) { 76 54 ifr.ifr_flags &= ~mask; 77 ifr.ifr_flags |= mask&flags; 78 err = ioctl(fd, SIOCSIFFLAGS, &ifr); 79 if (err) 80 perror("SIOCSIFFLAGS"); 55 ifr.ifr_flags |= mask & flags; 56 xioctl(fd, SIOCSIFFLAGS, &ifr); 81 57 } 82 58 close(fd); 83 return err; 84 } 85 86 static intdo_changename(char *dev, char *newdev)59 } 60 61 /* Exits on error */ 62 static void do_changename(char *dev, char *newdev) 87 63 { 88 64 struct ifreq ifr; 89 65 int fd; 90 int err; 91 92 strcpy(ifr.ifr_name, dev); 93 strcpy(ifr.ifr_newname, newdev); 66 67 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 68 strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname)); 94 69 fd = get_ctl_fd(); 95 if (fd < 0) 96 return -1; 97 err = ioctl(fd, SIOCSIFNAME, &ifr); 98 if (err) { 99 perror("SIOCSIFNAME"); 100 close(fd); 101 return -1; 102 } 70 xioctl(fd, SIOCSIFNAME, &ifr); 103 71 close(fd); 104 return err; 105 } 106 107 static intset_qlen(char *dev, int qlen)72 } 73 74 /* Exits on error */ 75 static void set_qlen(char *dev, int qlen) 108 76 { 109 77 struct ifreq ifr; … … 111 79 112 80 s = get_ctl_fd(); 113 if (s < 0)114 return -1;115 116 81 memset(&ifr, 0, sizeof(ifr)); 117 str cpy(ifr.ifr_name, dev);82 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 118 83 ifr.ifr_qlen = qlen; 119 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { 120 perror("SIOCSIFXQLEN"); 121 close(s); 122 return -1; 123 } 124 close(s); 125 126 return 0; 127 } 128 129 static int set_mtu(char *dev, int mtu) 84 xioctl(s, SIOCSIFTXQLEN, &ifr); 85 close(s); 86 } 87 88 /* Exits on error */ 89 static void set_mtu(char *dev, int mtu) 130 90 { 131 91 struct ifreq ifr; … … 133 93 134 94 s = get_ctl_fd(); 135 if (s < 0)136 return -1;137 138 95 memset(&ifr, 0, sizeof(ifr)); 139 str cpy(ifr.ifr_name, dev);96 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 140 97 ifr.ifr_mtu = mtu; 141 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { 142 perror("SIOCSIFMTU"); 143 close(s); 144 return -1; 145 } 146 close(s); 147 148 return 0; 149 } 150 98 xioctl(s, SIOCSIFMTU, &ifr); 99 close(s); 100 } 101 102 /* Exits on error */ 151 103 static int get_address(char *dev, int *htype) 152 104 { … … 156 108 int s; 157 109 158 s = socket(PF_PACKET, SOCK_DGRAM, 0); 159 if (s < 0) { 160 perror("socket(PF_PACKET)"); 161 return -1; 162 } 110 s = xsocket(PF_PACKET, SOCK_DGRAM, 0); 163 111 164 112 memset(&ifr, 0, sizeof(ifr)); 165 strcpy(ifr.ifr_name, dev); 166 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { 167 perror("SIOCGIFINDEX"); 168 close(s); 169 return -1; 170 } 113 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 114 xioctl(s, SIOCGIFINDEX, &ifr); 171 115 172 116 memset(&me, 0, sizeof(me)); … … 174 118 me.sll_ifindex = ifr.ifr_ifindex; 175 119 me.sll_protocol = htons(ETH_P_LOOP); 176 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { 177 perror("bind"); 178 close(s); 179 return -1; 180 } 120 xbind(s, (struct sockaddr*)&me, sizeof(me)); 181 121 182 122 alen = sizeof(me); 183 123 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { 184 perror("getsockname"); 185 close(s); 186 return -1; 124 bb_perror_msg_and_die("getsockname"); 187 125 } 188 126 close(s); … … 191 129 } 192 130 193 static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) 131 /* Exits on error */ 132 static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) 194 133 { 195 134 int alen; 196 135 197 136 memset(ifr, 0, sizeof(*ifr)); 198 str cpy(ifr->ifr_name, dev);137 strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name)); 199 138 ifr->ifr_hwaddr.sa_family = hatype; 200 139 alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla); 201 140 if (alen < 0) 202 return -1;141 exit(1); 203 142 if (alen != halen) { 204 bb_error_msg("Wrong address (%s) length: expected %d bytes", lla, halen); 205 return -1; 206 } 207 return 0; 208 } 209 210 static int set_address(struct ifreq *ifr, int brd) 143 bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen); 144 } 145 } 146 147 /* Exits on error */ 148 static void set_address(struct ifreq *ifr, int brd) 211 149 { 212 150 int s; 213 151 214 152 s = get_ctl_fd(); 215 if (s < 0) 216 return -1; 217 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { 218 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); 219 close(s); 220 return -1; 221 } 222 close(s); 223 return 0; 224 } 225 226 153 if (brd) 154 xioctl(s, SIOCSIFHWBROADCAST, ifr); 155 else 156 xioctl(s, SIOCSIFHWADDR, ifr); 157 close(s); 158 } 159 160 161 /* Return value becomes exitcode. It's okay to not return at all */ 227 162 static int do_set(int argc, char **argv) 228 163 { 229 164 char *dev = NULL; 230 __u32mask = 0;231 __u32flags = 0;165 uint32_t mask = 0; 166 uint32_t flags = 0; 232 167 int qlen = -1; 233 168 int mtu = -1; … … 237 172 char *newname = NULL; 238 173 int htype, halen; 174 static const char keywords[] ALIGN1 = 175 "up\0""down\0""name\0""mtu\0""multicast\0""arp\0""addr\0""dev\0" 176 "on\0""off\0"; 177 enum { ARG_up = 1, ARG_down, ARG_name, ARG_mtu, ARG_multicast, ARG_arp, 178 ARG_addr, ARG_dev, PARM_on, PARM_off }; 179 smalluint key; 239 180 240 181 while (argc > 0) { 241 if (strcmp(*argv, "up") == 0) { 182 key = index_in_strings(keywords, *argv) + 1; 183 if (key == ARG_up) { 242 184 mask |= IFF_UP; 243 185 flags |= IFF_UP; 244 } else if ( strcmp(*argv, "down") == 0) {186 } else if (key == ARG_down) { 245 187 mask |= IFF_UP; 246 188 flags &= ~IFF_UP; 247 } else if ( strcmp(*argv, "name") == 0) {189 } else if (key == ARG_name) { 248 190 NEXT_ARG(); 249 191 newname = *argv; 250 } else if ( strcmp(*argv, "mtu") == 0) {192 } else if (key == ARG_mtu) { 251 193 NEXT_ARG(); 252 194 if (mtu != -1) … … 254 196 if (get_integer(&mtu, *argv, 0)) 255 197 invarg(*argv, "mtu"); 256 } else if ( strcmp(*argv, "multicast") == 0) {198 } else if (key == ARG_multicast) { 257 199 NEXT_ARG(); 258 200 mask |= IFF_MULTICAST; 259 if (strcmp(*argv, "on") == 0) { 201 key = index_in_strings(keywords, *argv) + 1; 202 if (key == PARM_on) { 260 203 flags |= IFF_MULTICAST; 261 } else if ( strcmp(*argv, "off") == 0) {204 } else if (key == PARM_off) { 262 205 flags &= ~IFF_MULTICAST; 263 206 } else 264 returnon_off("multicast");265 } else if ( strcmp(*argv, "arp") == 0) {207 on_off("multicast"); 208 } else if (key == ARG_arp) { 266 209 NEXT_ARG(); 267 210 mask |= IFF_NOARP; 268 if (strcmp(*argv, "on") == 0) { 211 key = index_in_strings(keywords, *argv) + 1; 212 if (key == PARM_on) { 269 213 flags &= ~IFF_NOARP; 270 } else if ( strcmp(*argv, "off") == 0) {214 } else if (key == PARM_off) { 271 215 flags |= IFF_NOARP; 272 216 } else 273 return on_off("noarp");274 } else if ( strcmp(*argv, "addr") == 0) {217 on_off("arp"); 218 } else if (key == ARG_addr) { 275 219 NEXT_ARG(); 276 220 newaddr = *argv; 277 221 } else { 278 if ( strcmp(*argv, "dev") == 0) {222 if (key == ARG_dev) { 279 223 NEXT_ARG(); 280 224 } … … 287 231 288 232 if (!dev) { 289 bb_error_msg(bb_msg_requires_arg, "\"dev\""); 290 exit(-1); 233 bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\""); 291 234 } 292 235 293 236 if (newaddr || newbrd) { 294 237 halen = get_address(dev, &htype); 295 if (halen < 0)296 return -1;297 238 if (newaddr) { 298 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) 299 return -1; 239 parse_address(dev, htype, halen, newaddr, &ifr0); 300 240 } 301 241 if (newbrd) { 302 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) 303 return -1; 242 parse_address(dev, htype, halen, newbrd, &ifr1); 304 243 } 305 244 } 306 245 307 246 if (newname && strcmp(dev, newname)) { 308 if (do_changename(dev, newname) < 0) 309 return -1; 247 do_changename(dev, newname); 310 248 dev = newname; 311 249 } 312 250 if (qlen != -1) { 313 if (set_qlen(dev, qlen) < 0) 314 return -1; 251 set_qlen(dev, qlen); 315 252 } 316 253 if (mtu != -1) { 317 if (set_mtu(dev, mtu) < 0) 318 return -1; 254 set_mtu(dev, mtu); 319 255 } 320 256 if (newaddr || newbrd) { 321 257 if (newbrd) { 322 if (set_address(&ifr1, 1) < 0) 323 return -1; 258 set_address(&ifr1, 1); 324 259 } 325 260 if (newaddr) { 326 if (set_address(&ifr0, 0) < 0) 327 return -1; 261 set_address(&ifr0, 0); 328 262 } 329 263 } 330 264 if (mask) 331 returndo_chflags(dev, flags, mask);265 do_chflags(dev, flags, mask); 332 266 return 0; 333 267 } … … 336 270 { 337 271 preferred_family = AF_PACKET; 338 do_link = 1;339 272 return ipaddr_list_or_flush(argc, argv, 0); 340 273 } 341 274 275 /* Return value becomes exitcode. It's okay to not return at all */ 342 276 int do_iplink(int argc, char **argv) 343 277 { 344 if (argc > 0) { 345 if (matches(*argv, "set") == 0) 346 return do_set(argc-1, argv+1); 347 if (matches(*argv, "show") == 0 || 348 matches(*argv, "lst") == 0 || 349 matches(*argv, "list") == 0) 350 return ipaddr_list_link(argc-1, argv+1); 351 } else 278 static const char keywords[] ALIGN1 = 279 "set\0""show\0""lst\0""list\0"; 280 smalluint key; 281 if (argc <= 0) 352 282 return ipaddr_list_link(0, NULL); 353 354 bb_error_msg("Command \"%s\" is unknown.", *argv); 355 exit(-1); 356 } 283 key = index_in_substrings(keywords, *argv) + 1; 284 if (key == 0) 285 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 286 argc--; argv++; 287 if (key == 1) /* set */ 288 return do_set(argc, argv); 289 else /* show, lst, list */ 290 return ipaddr_list_link(argc, argv); 291 } -
branches/2.2.5/mindi-busybox/networking/libiproute/iproute.c
r821 r1765 14 14 */ 15 15 16 #include "libbb.h" 17 18 #include <sys/socket.h> 19 20 #include <string.h> 21 #include <fcntl.h> 22 #include <unistd.h> 23 16 #include "ip_common.h" /* #include "libbb.h" is inside */ 24 17 #include "rt_names.h" 25 18 #include "utils.h" 26 #include "ip_common.h"27 19 28 20 #ifndef RTAX_RTTVAR … … 31 23 32 24 33 static struct 34 { 25 typedef struct filter_t { 35 26 int tb; 36 27 int flushed; … … 52 43 inet_prefix rsrc; 53 44 inet_prefix msrc; 54 } filter; 45 } filter_t; 46 47 #define filter (*(filter_t*)&bb_common_bufsiz1) 55 48 56 49 static int flush_update(void) 57 50 { 58 51 if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { 59 perror("Failed to send flush request\n");52 bb_perror_msg("failed to send flush request"); 60 53 return -1; 61 54 } 62 55 filter.flushp = 0; 63 56 return 0; 57 } 58 59 static unsigned get_hz(void) 60 { 61 static unsigned hz_internal; 62 FILE *fp; 63 64 if (hz_internal) 65 return hz_internal; 66 67 fp = fopen("/proc/net/psched", "r"); 68 if (fp) { 69 unsigned nom, denom; 70 71 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) 72 if (nom == 1000000) 73 hz_internal = denom; 74 fclose(fp); 75 } 76 if (!hz_internal) 77 hz_internal = sysconf(_SC_CLK_TCK); 78 return hz_internal; 64 79 } 65 80 … … 86 101 return 0; 87 102 len -= NLMSG_LENGTH(sizeof(*r)); 88 if (len < 0) { 89 bb_error_msg("wrong nlmsg len %d", len); 90 return -1; 91 } 103 if (len < 0) 104 bb_error_msg_and_die("wrong nlmsg len %d", len); 92 105 93 106 if (r->rtm_family == AF_INET6) … … 170 183 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { 171 184 if (flush_update()) 172 return -1;185 bb_error_msg_and_die("flush"); 173 186 } 174 187 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); … … 249 262 } 250 263 if (tb[RTA_PRIORITY]) { 251 fprintf(fp, " metric %d ", *( __u32*)RTA_DATA(tb[RTA_PRIORITY]));264 fprintf(fp, " metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY])); 252 265 } 253 266 if (r->rtm_family == AF_INET6) { … … 257 270 } 258 271 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { 259 static int hz;260 if (!hz) {261 hz = get_hz();262 }263 272 if (r->rtm_flags & RTM_F_CLONED) { 264 fprintf(fp, "% scache ", _SL_);273 fprintf(fp, "%c cache ", _SL_); 265 274 } 266 275 if (ci->rta_expires) { 267 fprintf(fp, " expires %dsec", ci->rta_expires /hz);276 fprintf(fp, " expires %dsec", ci->rta_expires / get_hz()); 268 277 } 269 278 if (ci->rta_error != 0) { … … 278 287 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); 279 288 } 280 fp rintf(fp, "\n");289 fputc('\n', fp); 281 290 fflush(fp); 282 291 return 0; 283 292 } 284 293 294 /* Return value becomes exitcode. It's okay to not return at all */ 285 295 static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) 286 296 { 297 static const char keywords[] ALIGN1 = 298 "src\0""via\0""mtu\0""lock\0""protocol\0"USE_FEATURE_IP_RULE("table\0") 299 "dev\0""oif\0""to\0"; 300 enum { 301 ARG_src, 302 ARG_via, 303 ARG_mtu, PARM_lock, 304 ARG_protocol, 305 USE_FEATURE_IP_RULE(ARG_table,) 306 ARG_dev, 307 ARG_oif, 308 ARG_to 309 }; 310 enum { 311 gw_ok = 1 << 0, 312 dst_ok = 1 << 1, 313 proto_ok = 1 << 2, 314 type_ok = 1 << 3 315 }; 287 316 struct rtnl_handle rth; 288 317 struct { … … 291 320 char buf[1024]; 292 321 } req; 293 char 322 char mxbuf[256]; 294 323 struct rtattr * mxrta = (void*)mxbuf; 295 324 unsigned mxlock = 0; 296 char *d = NULL; 297 int gw_ok = 0; 298 int dst_ok = 0; 299 int proto_ok = 0; 300 int type_ok = 0; 325 char *d = NULL; 326 smalluint ok = 0; 327 int arg; 301 328 302 329 memset(&req, 0, sizeof(req)); … … 319 346 320 347 while (argc > 0) { 321 if (strcmp(*argv, "src") == 0) { 348 arg = index_in_substrings(keywords, *argv); 349 if (arg == ARG_src) { 322 350 inet_prefix addr; 351 NEXT_ARG(); 352 get_addr(&addr, *argv, req.r.rtm_family); 353 if (req.r.rtm_family == AF_UNSPEC) 354 req.r.rtm_family = addr.family; 355 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); 356 } else if (arg == ARG_via) { 357 inet_prefix addr; 358 ok |= gw_ok; 323 359 NEXT_ARG(); 324 360 get_addr(&addr, *argv, req.r.rtm_family); … … 326 362 req.r.rtm_family = addr.family; 327 363 } 328 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);329 } else if (strcmp(*argv, "via") == 0) {330 inet_prefix addr;331 gw_ok = 1;332 NEXT_ARG();333 get_addr(&addr, *argv, req.r.rtm_family);334 if (req.r.rtm_family == AF_UNSPEC) {335 req.r.rtm_family = addr.family;336 }337 364 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); 338 } else if ( strcmp(*argv, "mtu") == 0) {365 } else if (arg == ARG_mtu) { 339 366 unsigned mtu; 340 367 NEXT_ARG(); 341 if ( strcmp(*argv, "lock") == 0) {368 if (index_in_strings(keywords, *argv) == PARM_lock) { 342 369 mxlock |= (1<<RTAX_MTU); 343 370 NEXT_ARG(); 344 371 } 345 if (get_unsigned(&mtu, *argv, 0)) {372 if (get_unsigned(&mtu, *argv, 0)) 346 373 invarg(*argv, "mtu"); 347 }348 374 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); 349 } else if ( matches(*argv, "protocol") == 0) {375 } else if (arg == ARG_protocol) { 350 376 uint32_t prot; 351 377 NEXT_ARG(); … … 353 379 invarg(*argv, "protocol"); 354 380 req.r.rtm_protocol = prot; 355 proto_ok =1; 356 } else if (strcmp(*argv, "dev") == 0 || 357 strcmp(*argv, "oif") == 0) { 381 ok |= proto_ok; 382 #if ENABLE_FEATURE_IP_RULE 383 } else if (arg == ARG_table) { 384 uint32_t tid; 385 NEXT_ARG(); 386 if (rtnl_rttable_a2n(&tid, *argv)) 387 invarg(*argv, "table"); 388 req.r.rtm_table = tid; 389 #endif 390 } else if (arg == ARG_dev || arg == ARG_oif) { 358 391 NEXT_ARG(); 359 392 d = *argv; … … 362 395 inet_prefix dst; 363 396 364 if ( strcmp(*argv, "to") == 0) {365 NEXT_ARG(); 366 } 367 if ((**argv < '0' || **argv > '9') &&368 397 if (arg == ARG_to) { 398 NEXT_ARG(); 399 } 400 if ((**argv < '0' || **argv > '9') 401 && rtnl_rtntype_a2n(&type, *argv) == 0) { 369 402 NEXT_ARG(); 370 403 req.r.rtm_type = type; 371 type_ok = 1;372 } 373 374 if ( dst_ok) {404 ok |= type_ok; 405 } 406 407 if (ok & dst_ok) { 375 408 duparg2("to", *argv); 376 409 } … … 380 413 } 381 414 req.r.rtm_dst_len = dst.bitlen; 382 dst_ok = 1;415 ok |= dst_ok; 383 416 if (dst.bytelen) { 384 417 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); … … 388 421 } 389 422 390 if (rtnl_open(&rth, 0) < 0) { 391 exit(1); 392 } 423 xrtnl_open(&rth); 393 424 394 425 if (d) { … … 398 429 399 430 if (d) { 400 if ((idx = ll_name_to_index(d)) == 0) { 401 bb_error_msg("Cannot find device \"%s\"", d); 402 return -1; 403 } 431 idx = xll_name_to_index(d); 404 432 addattr32(&req.n, sizeof(req), RTA_OIF, idx); 405 433 } … … 413 441 } 414 442 443 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT) 444 req.r.rtm_scope = RT_SCOPE_HOST; 445 else if (req.r.rtm_type == RTN_BROADCAST || 446 req.r.rtm_type == RTN_MULTICAST || 447 req.r.rtm_type == RTN_ANYCAST) 448 req.r.rtm_scope = RT_SCOPE_LINK; 449 else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) { 450 if (cmd == RTM_DELROUTE) 451 req.r.rtm_scope = RT_SCOPE_NOWHERE; 452 else if (!(ok & gw_ok)) 453 req.r.rtm_scope = RT_SCOPE_LINK; 454 } 455 415 456 if (req.r.rtm_family == AF_UNSPEC) { 416 457 req.r.rtm_family = AF_INET; … … 418 459 419 460 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { 420 exit(2);461 return 2; 421 462 } 422 463 … … 444 485 req.rtm.rtm_flags |= RTM_F_CLONED; 445 486 446 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); 447 } 448 449 static int iproute_flush_cache(void) 450 { 451 #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush" 452 453 int len; 454 int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY); 455 char *buffer = "-1"; 487 return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr)); 488 } 489 490 static void iproute_flush_cache(void) 491 { 492 static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush"; 493 int flush_fd = open_or_warn(fn, O_WRONLY); 456 494 457 495 if (flush_fd < 0) { 458 fprintf (stderr, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH); 459 return -1; 460 } 461 462 len = strlen (buffer); 463 464 if ((write (flush_fd, (void *)buffer, len)) < len) { 465 fprintf (stderr, "Cannot flush routing cache\n"); 466 return -1; 496 return; 497 } 498 499 if (write(flush_fd, "-1", 2) < 2) { 500 bb_perror_msg("cannot flush routing cache"); 501 return; 467 502 } 468 503 close(flush_fd); 469 return 0;470 504 } 471 505 … … 477 511 } 478 512 513 /* Return value becomes exitcode. It's okay to not return at all */ 479 514 static int iproute_list_or_flush(int argc, char **argv, int flush) 480 515 { … … 483 518 char *id = NULL; 484 519 char *od = NULL; 485 520 static const char keywords[] ALIGN1 = 521 "protocol\0""all\0""dev\0""oif\0""iif\0""via\0""table\0""cache\0" /*all*/ 522 "from\0""root\0""match\0""exact\0""to\0"/*root match exact*/; 523 enum { 524 ARG_proto, PARM_all, 525 ARG_dev, 526 ARG_oif, 527 ARG_iif, 528 ARG_via, 529 ARG_table, PARM_cache, /*PARM_all,*/ 530 ARG_from, PARM_root, PARM_match, PARM_exact, 531 ARG_to /*PARM_root, PARM_match, PARM_exact*/ 532 }; 533 int arg, parm; 486 534 iproute_reset_filter(); 487 535 filter.tb = RT_TABLE_MAIN; 488 536 489 if (flush && argc <= 0) { 490 bb_error_msg(bb_msg_requires_arg, "\"ip route flush\""); 491 return -1; 492 } 537 if (flush && argc <= 0) 538 bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\""); 493 539 494 540 while (argc > 0) { 495 if (matches(*argv, "protocol") == 0) { 541 arg = index_in_substrings(keywords, *argv); 542 if (arg == ARG_proto) { 496 543 uint32_t prot = 0; 497 544 NEXT_ARG(); 498 545 filter.protocolmask = -1; 499 546 if (rtnl_rtprot_a2n(&prot, *argv)) { 500 if ( strcmp(*argv, "all") != 0) {547 if (index_in_strings(keywords, *argv) != PARM_all) 501 548 invarg(*argv, "protocol"); 502 }503 549 prot = 0; 504 550 filter.protocolmask = 0; 505 551 } 506 552 filter.protocol = prot; 507 } else if (strcmp(*argv, "dev") == 0 || 508 strcmp(*argv, "oif") == 0) { 553 } else if (arg == ARG_dev || arg == ARG_oif) { 509 554 NEXT_ARG(); 510 555 od = *argv; 511 } else if ( strcmp(*argv, "iif") == 0) {556 } else if (arg == ARG_iif) { 512 557 NEXT_ARG(); 513 558 id = *argv; 514 } else if (matches(*argv, "from") == 0) { 515 NEXT_ARG(); 516 if (matches(*argv, "root") == 0) { 559 } else if (arg == ARG_via) { 560 NEXT_ARG(); 561 get_prefix(&filter.rvia, *argv, do_ipv6); 562 } else if (arg == ARG_table) { 563 NEXT_ARG(); 564 parm = index_in_substrings(keywords, *argv); 565 if (parm == PARM_cache) 566 filter.tb = -1; 567 else if (parm == PARM_all) 568 filter.tb = 0; 569 else 570 invarg(*argv, "table"); 571 } else if (arg == ARG_from) { 572 NEXT_ARG(); 573 parm = index_in_substrings(keywords, *argv); 574 if (parm == PARM_root) { 517 575 NEXT_ARG(); 518 576 get_prefix(&filter.rsrc, *argv, do_ipv6); 519 } else if ( matches(*argv, "match") == 0) {577 } else if (parm == PARM_match) { 520 578 NEXT_ARG(); 521 579 get_prefix(&filter.msrc, *argv, do_ipv6); 522 580 } else { 523 if ( matches(*argv, "exact") == 0) {581 if (parm == PARM_exact) 524 582 NEXT_ARG(); 525 }526 583 get_prefix(&filter.msrc, *argv, do_ipv6); 527 584 filter.rsrc = filter.msrc; 528 585 } 529 586 } else { 530 if (matches(*argv, "to") == 0) { 531 NEXT_ARG(); 532 } 533 if (matches(*argv, "root") == 0) { 587 /* parm = arg; // would be more plausible, we reuse arg here */ 588 if (arg == ARG_to) { 589 NEXT_ARG(); 590 arg = index_in_substrings(keywords, *argv); 591 } 592 if (arg == PARM_root) { 534 593 NEXT_ARG(); 535 594 get_prefix(&filter.rdst, *argv, do_ipv6); 536 } else if ( matches(*argv, "match") == 0) {595 } else if (arg == PARM_match) { 537 596 NEXT_ARG(); 538 597 get_prefix(&filter.mdst, *argv, do_ipv6); 539 } else if (matches(*argv, "table") == 0) {540 NEXT_ARG();541 if (matches(*argv, "cache") == 0) {542 filter.tb = -1;543 } else if (matches(*argv, "main") != 0) {544 invarg(*argv, "table");545 }546 } else if (matches(*argv, "cache") == 0) {547 filter.tb = -1;548 598 } else { 549 if ( matches(*argv, "exact") == 0) {599 if (arg == PARM_exact) 550 600 NEXT_ARG(); 551 }552 601 get_prefix(&filter.mdst, *argv, do_ipv6); 553 602 filter.rdst = filter.mdst; 554 603 } 555 604 } 556 argc--; argv++; 605 argc--; 606 argv++; 557 607 } 558 608 … … 561 611 } 562 612 563 if (rtnl_open(&rth, 0) < 0) { 564 exit(1); 565 } 613 xrtnl_open(&rth); 566 614 567 615 ll_init_map(&rth); … … 571 619 572 620 if (id) { 573 if ((idx = ll_name_to_index(id)) == 0) { 574 bb_error_msg("Cannot find device \"%s\"", id); 575 return -1; 576 } 621 idx = xll_name_to_index(id); 577 622 filter.iif = idx; 578 623 filter.iifmask = -1; 579 624 } 580 625 if (od) { 581 if ((idx = ll_name_to_index(od)) == 0) { 582 bb_error_msg("Cannot find device \"%s\"", od); 583 } 626 idx = xll_name_to_index(od); 584 627 filter.oif = idx; 585 628 filter.oifmask = -1; … … 603 646 604 647 for (;;) { 605 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { 606 perror("Cannot send dump request"); 607 return -1; 608 } 648 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE); 609 649 filter.flushed = 0; 610 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { 611 bb_error_msg("Flush terminated\n"); 612 return -1; 613 } 614 if (filter.flushed == 0) { 615 fflush(stdout); 650 xrtnl_dump_filter(&rth, print_route, stdout); 651 if (filter.flushed == 0) 616 652 return 0; 617 } 618 if (flush_update() < 0) 619 exit(1); 653 if (flush_update()) 654 return 1; 620 655 } 621 656 } 622 657 623 658 if (filter.tb != -1) { 624 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { 625 bb_perror_msg_and_die("Cannot send dump request"); 626 } 627 } else { 628 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { 629 bb_perror_msg_and_die("Cannot send dump request"); 630 } 631 } 632 633 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { 634 bb_error_msg_and_die("Dump terminated"); 635 } 636 637 exit(0); 638 } 639 640 659 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE); 660 } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { 661 bb_perror_msg_and_die("cannot send dump request"); 662 } 663 xrtnl_dump_filter(&rth, print_route, stdout); 664 665 return 0; 666 } 667 668 669 /* Return value becomes exitcode. It's okay to not return at all */ 641 670 static int iproute_get(int argc, char **argv) 642 671 { 643 672 struct rtnl_handle rth; 644 673 struct { 645 struct nlmsghdr 646 struct rtmsg 647 char 674 struct nlmsghdr n; 675 struct rtmsg r; 676 char buf[1024]; 648 677 } req; 649 char 650 char 651 intconnected = 0;652 intfrom_ok = 0;653 static const char * const options[]=654 { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };678 char *idev = NULL; 679 char *odev = NULL; 680 bool connected = 0; 681 bool from_ok = 0; 682 static const char options[] ALIGN1 = 683 "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0"; 655 684 656 685 memset(&req, 0, sizeof(req)); … … 671 700 672 701 while (argc > 0) { 673 switch ( compare_string_array(options, *argv)) {702 switch (index_in_strings(options, *argv)) { 674 703 case 0: /* from */ 675 704 { … … 724 753 } 725 754 726 if (rtnl_open(&rth, 0) < 0) 727 exit(1); 755 xrtnl_open(&rth); 728 756 729 757 ll_init_map(&rth); … … 733 761 734 762 if (idev) { 735 if ((idx = ll_name_to_index(idev)) == 0) { 736 bb_error_msg("Cannot find device \"%s\"", idev); 737 return -1; 738 } 763 idx = xll_name_to_index(idev); 739 764 addattr32(&req.n, sizeof(req), RTA_IIF, idx); 740 765 } 741 766 if (odev) { 742 if ((idx = ll_name_to_index(odev)) == 0) { 743 bb_error_msg("Cannot find device \"%s\"", odev); 744 return -1; 745 } 767 idx = xll_name_to_index(odev); 746 768 addattr32(&req.n, sizeof(req), RTA_OIF, idx); 747 769 } … … 753 775 754 776 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) { 755 exit(2);777 return 2; 756 778 } 757 779 … … 761 783 struct rtattr * tb[RTA_MAX+1]; 762 784 763 if (print_route(NULL, &req.n, (void*)stdout) < 0) { 764 bb_error_msg_and_die("An error :-)"); 765 } 785 print_route(NULL, &req.n, (void*)stdout); 766 786 767 787 if (req.n.nlmsg_type != RTM_NEWROUTE) { 768 bb_error_msg("Not a route?"); 769 return -1; 788 bb_error_msg_and_die("not a route?"); 770 789 } 771 790 len -= NLMSG_LENGTH(sizeof(*r)); 772 791 if (len < 0) { 773 bb_error_msg("Wrong len %d", len); 774 return -1; 792 bb_error_msg_and_die("wrong len %d", len); 775 793 } 776 794 … … 782 800 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); 783 801 } else if (!tb[RTA_SRC]) { 784 bb_error_msg("Failed to connect the route"); 785 return -1; 802 bb_error_msg_and_die("failed to connect the route"); 786 803 } 787 804 if (!odev && tb[RTA_OIF]) { … … 798 815 799 816 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) { 800 exit(2); 801 } 802 } 803 804 if (print_route(NULL, &req.n, (void*)stdout) < 0) { 805 bb_error_msg_and_die("An error :-)"); 806 } 807 808 exit(0); 809 } 810 817 return 2; 818 } 819 } 820 print_route(NULL, &req.n, (void*)stdout); 821 return 0; 822 } 823 824 /* Return value becomes exitcode. It's okay to not return at all */ 811 825 int do_iproute(int argc, char **argv) 812 826 { 813 static const char * const ip_route_commands[] = 814 { "add", "append", "change", "chg", "delete", "del", "get", 815 "list", "show", "prepend", "replace", "test", "flush", 0 }; 816 int command_num = 7; 817 unsigned int flags = 0; 827 static const char ip_route_commands[] ALIGN1 = 828 /*0-3*/ "add\0""append\0""change\0""chg\0" 829 /*4-7*/ "delete\0""get\0""list\0""show\0" 830 /*8..*/ "prepend\0""replace\0""test\0""flush\0"; 831 int command_num = 6; 832 unsigned flags = 0; 818 833 int cmd = RTM_NEWROUTE; 819 834 835 /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */ 836 /* It probably means that it is using "first match" rule */ 820 837 if (*argv) { 821 command_num = compare_string_array(ip_route_commands, *argv);822 } 823 switch (command_num) {824 case 0: /* add */838 command_num = index_in_substrings(ip_route_commands, *argv); 839 } 840 switch (command_num) { 841 case 0: /* add */ 825 842 flags = NLM_F_CREATE|NLM_F_EXCL; 826 843 break; … … 833 850 break; 834 851 case 4: /* delete */ 835 case 5: /* del */836 852 cmd = RTM_DELROUTE; 837 853 break; 838 case 6: /* get */854 case 5: /* get */ 839 855 return iproute_get(argc-1, argv+1); 840 case 7: /* list */841 case 8: /* show */856 case 6: /* list */ 857 case 7: /* show */ 842 858 return iproute_list_or_flush(argc-1, argv+1, 0); 843 case 9: /* prepend */859 case 8: /* prepend */ 844 860 flags = NLM_F_CREATE; 845 case 10: /* replace */861 case 9: /* replace */ 846 862 flags = NLM_F_CREATE|NLM_F_REPLACE; 847 case 1 1: /* test */863 case 10: /* test */ 848 864 flags = NLM_F_EXCL; 849 case 1 2: /* flush */865 case 11: /* flush */ 850 866 return iproute_list_or_flush(argc-1, argv+1, 1); 851 867 default: 852 bb_error_msg_and_die(" Unknown command %s", *argv);868 bb_error_msg_and_die("unknown command %s", *argv); 853 869 } 854 870 -
branches/2.2.5/mindi-busybox/networking/libiproute/iptunnel.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * iptunnel.c "ip tunnel" … … 14 15 */ 15 16 16 #include "libbb.h"17 #include <sys/socket.h>18 #include <sys/ioctl.h>19 20 #include <string.h>21 #include <unistd.h>22 23 17 #include <netinet/ip.h> 24 25 18 #include <net/if.h> 26 19 #include <net/if_arp.h> 27 28 20 #include <asm/types.h> 29 21 #ifndef __constant_htons … … 32 24 #include <linux/if_tunnel.h> 33 25 26 #include "ip_common.h" /* #include "libbb.h" is inside */ 34 27 #include "rt_names.h" 35 28 #include "utils.h" 36 #include "ip_common.h" 37 38 29 30 31 /* Dies on error */ 39 32 static int do_ioctl_get_ifindex(char *dev) 40 33 { … … 42 35 int fd; 43 36 44 strcpy(ifr.ifr_name, dev); 45 fd = socket(AF_INET, SOCK_DGRAM, 0); 46 if (ioctl(fd, SIOCGIFINDEX, &ifr)) { 47 bb_perror_msg("ioctl"); 48 return 0; 49 } 37 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 38 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 39 xioctl(fd, SIOCGIFINDEX, &ifr); 50 40 close(fd); 51 41 return ifr.ifr_ifindex; … … 53 43 54 44 static int do_ioctl_get_iftype(char *dev) 55 {56 struct ifreq ifr;57 int fd;58 59 strcpy(ifr.ifr_name, dev);60 fd = socket(AF_INET, SOCK_DGRAM, 0);61 if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {62 bb_perror_msg("ioctl");63 return -1;64 }65 close(fd);66 return ifr.ifr_addr.sa_family;67 }68 69 70 static char *do_ioctl_get_ifname(int idx)71 {72 static struct ifreq ifr;73 int fd;74 75 ifr.ifr_ifindex = idx;76 fd = socket(AF_INET, SOCK_DGRAM, 0);77 if (ioctl(fd, SIOCGIFNAME, &ifr)) {78 bb_perror_msg("ioctl");79 return NULL;80 }81 close(fd);82 return ifr.ifr_name;83 }84 85 86 87 static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p)88 45 { 89 46 struct ifreq ifr; … … 91 48 int err; 92 49 93 strcpy(ifr.ifr_name, basedev); 94 ifr.ifr_ifru.ifru_data = (void*)p; 95 fd = socket(AF_INET, SOCK_DGRAM, 0); 96 err = ioctl(fd, SIOCGETTUNNEL, &ifr); 97 if (err) { 98 bb_perror_msg("ioctl"); 99 } 50 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 51 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 52 err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr); 100 53 close(fd); 101 return err ;102 } 103 104 static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p)54 return err ? -1 : ifr.ifr_addr.sa_family; 55 } 56 57 static char *do_ioctl_get_ifname(int idx) 105 58 { 106 59 struct ifreq ifr; … … 108 61 int err; 109 62 110 if (cmd == SIOCCHGTUNNEL && p->name[0]) { 111 strcpy(ifr.ifr_name, p->name); 112 } else { 113 strcpy(ifr.ifr_name, basedev); 114 } 115 ifr.ifr_ifru.ifru_data = (void*)p; 116 fd = socket(AF_INET, SOCK_DGRAM, 0); 117 err = ioctl(fd, cmd, &ifr); 118 if (err) { 119 bb_perror_msg("ioctl"); 120 } 63 ifr.ifr_ifindex = idx; 64 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 65 err = ioctl_or_warn(fd, SIOCGIFNAME, &ifr); 121 66 close(fd); 122 return err ;123 } 124 125 static int do_ del_ioctl(char *basedev, struct ip_tunnel_parm *p)67 return err ? NULL : xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name)); 68 } 69 70 static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p) 126 71 { 127 72 struct ifreq ifr; … … 129 74 int err; 130 75 131 if (p->name[0]) { 132 strcpy(ifr.ifr_name, p->name); 133 } else { 134 strcpy(ifr.ifr_name, basedev); 135 } 76 strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); 136 77 ifr.ifr_ifru.ifru_data = (void*)p; 137 fd = socket(AF_INET, SOCK_DGRAM, 0); 138 err = ioctl(fd, SIOCDELTUNNEL, &ifr); 139 if (err) { 140 bb_perror_msg("ioctl"); 141 } 78 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 79 err = ioctl_or_warn(fd, SIOCGETTUNNEL, &ifr); 142 80 close(fd); 143 81 return err; 144 82 } 145 83 146 static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) 147 { 84 /* Dies on error, otherwise returns 0 */ 85 static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p) 86 { 87 struct ifreq ifr; 88 int fd; 89 90 if (cmd == SIOCCHGTUNNEL && p->name[0]) { 91 strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); 92 } else { 93 strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); 94 } 95 ifr.ifr_ifru.ifru_data = (void*)p; 96 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 97 #if ENABLE_IOCTL_HEX2STR_ERROR 98 /* #define magic will turn ioctl# into string */ 99 if (cmd == SIOCCHGTUNNEL) 100 xioctl(fd, SIOCCHGTUNNEL, &ifr); 101 else 102 xioctl(fd, SIOCADDTUNNEL, &ifr); 103 #else 104 xioctl(fd, cmd, &ifr); 105 #endif 106 close(fd); 107 return 0; 108 } 109 110 /* Dies on error, otherwise returns 0 */ 111 static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p) 112 { 113 struct ifreq ifr; 114 int fd; 115 116 if (p->name[0]) { 117 strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); 118 } else { 119 strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name)); 120 } 121 ifr.ifr_ifru.ifru_data = (void*)p; 122 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 123 xioctl(fd, SIOCDELTUNNEL, &ifr); 124 close(fd); 125 return 0; 126 } 127 128 /* Dies on error */ 129 static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) 130 { 131 static const char keywords[] ALIGN1 = 132 "mode\0""ipip\0""ip/ip\0""gre\0""gre/ip\0""sit\0""ipv6/ip\0" 133 "key\0""ikey\0""okey\0""seq\0""iseq\0""oseq\0" 134 "csum\0""icsum\0""ocsum\0""nopmtudisc\0""pmtudisc\0" 135 "remote\0""any\0""local\0""dev\0" 136 "ttl\0""inherit\0""tos\0""dsfield\0" 137 "name\0"; 138 enum { 139 ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip, 140 ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq, 141 ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc, 142 ARG_remote, ARG_any, ARG_local, ARG_dev, 143 ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield, 144 ARG_name 145 }; 148 146 int count = 0; 149 147 char medium[IFNAMSIZ]; 148 int key; 149 150 150 memset(p, 0, sizeof(*p)); 151 151 memset(&medium, 0, sizeof(medium)); … … 154 154 p->iph.ihl = 5; 155 155 #ifndef IP_DF 156 #define IP_DF 0x4000 /* Flag: "Don't Fragment"*/156 #define IP_DF 0x4000 /* Flag: "Don't Fragment" */ 157 157 #endif 158 158 p->iph.frag_off = htons(IP_DF); 159 159 160 160 while (argc > 0) { 161 if (strcmp(*argv, "mode") == 0) { 162 NEXT_ARG(); 163 if (strcmp(*argv, "ipip") == 0 || 164 strcmp(*argv, "ip/ip") == 0) { 161 key = index_in_strings(keywords, *argv); 162 if (key == ARG_mode) { 163 NEXT_ARG(); 164 key = index_in_strings(keywords, *argv); 165 if (key == ARG_ipip || 166 key == ARG_ip_ip) { 165 167 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { 166 bb_error_msg("You managed to ask for more than one tunnel mode."); 167 exit(-1); 168 bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); 168 169 } 169 170 p->iph.protocol = IPPROTO_IPIP; 170 } else if ( strcmp(*argv, "gre") == 0||171 strcmp(*argv, "gre/ip") == 0) {171 } else if (key == ARG_gre || 172 key == ARG_gre_ip) { 172 173 if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { 173 bb_error_msg("You managed to ask for more than one tunnel mode."); 174 exit(-1); 174 bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); 175 175 } 176 176 p->iph.protocol = IPPROTO_GRE; 177 } else if ( strcmp(*argv, "sit") == 0||178 strcmp(*argv, "ipv6/ip") == 0) {177 } else if (key == ARG_sit || 178 key == ARG_ip6_ip) { 179 179 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { 180 bb_error_msg("You managed to ask for more than one tunnel mode."); 181 exit(-1); 180 bb_error_msg_and_die("you managed to ask for more than one tunnel mode"); 182 181 } 183 182 p->iph.protocol = IPPROTO_IPV6; 184 183 } else { 185 bb_error_msg("Cannot guess tunnel mode."); 186 exit(-1); 187 } 188 } else if (strcmp(*argv, "key") == 0) { 184 bb_error_msg_and_die("cannot guess tunnel mode"); 185 } 186 } else if (key == ARG_key) { 189 187 unsigned uval; 190 188 NEXT_ARG(); … … 195 193 else { 196 194 if (get_unsigned(&uval, *argv, 0)<0) { 197 bb_error_msg("invalid value of \"key\""); 198 exit(-1); 195 bb_error_msg_and_die("invalid value of \"key\""); 199 196 } 200 197 p->i_key = p->o_key = htonl(uval); 201 198 } 202 } else if ( strcmp(*argv, "ikey") == 0) {199 } else if (key == ARG_ikey) { 203 200 unsigned uval; 204 201 NEXT_ARG(); … … 208 205 else { 209 206 if (get_unsigned(&uval, *argv, 0)<0) { 210 bb_error_msg("invalid value of \"ikey\""); 211 exit(-1); 207 bb_error_msg_and_die("invalid value of \"ikey\""); 212 208 } 213 209 p->i_key = htonl(uval); 214 210 } 215 } else if ( strcmp(*argv, "okey") == 0) {211 } else if (key == ARG_okey) { 216 212 unsigned uval; 217 213 NEXT_ARG(); … … 221 217 else { 222 218 if (get_unsigned(&uval, *argv, 0)<0) { 223 bb_error_msg("invalid value of \"okey\""); 224 exit(-1); 219 bb_error_msg_and_die("invalid value of \"okey\""); 225 220 } 226 221 p->o_key = htonl(uval); 227 222 } 228 } else if ( strcmp(*argv, "seq") == 0) {223 } else if (key == ARG_seq) { 229 224 p->i_flags |= GRE_SEQ; 230 225 p->o_flags |= GRE_SEQ; 231 } else if ( strcmp(*argv, "iseq") == 0) {226 } else if (key == ARG_iseq) { 232 227 p->i_flags |= GRE_SEQ; 233 } else if ( strcmp(*argv, "oseq") == 0) {228 } else if (key == ARG_oseq) { 234 229 p->o_flags |= GRE_SEQ; 235 } else if ( strcmp(*argv, "csum") == 0) {230 } else if (key == ARG_csum) { 236 231 p->i_flags |= GRE_CSUM; 237 232 p->o_flags |= GRE_CSUM; 238 } else if ( strcmp(*argv, "icsum") == 0) {233 } else if (key == ARG_icsum) { 239 234 p->i_flags |= GRE_CSUM; 240 } else if ( strcmp(*argv, "ocsum") == 0) {235 } else if (key == ARG_ocsum) { 241 236 p->o_flags |= GRE_CSUM; 242 } else if ( strcmp(*argv, "nopmtudisc") == 0) {237 } else if (key == ARG_nopmtudisc) { 243 238 p->iph.frag_off = 0; 244 } else if ( strcmp(*argv, "pmtudisc") == 0) {239 } else if (key == ARG_pmtudisc) { 245 240 p->iph.frag_off = htons(IP_DF); 246 } else if (strcmp(*argv, "remote") == 0) { 247 NEXT_ARG(); 248 if (strcmp(*argv, "any")) 241 } else if (key == ARG_remote) { 242 NEXT_ARG(); 243 key = index_in_strings(keywords, *argv); 244 if (key == ARG_any) 249 245 p->iph.daddr = get_addr32(*argv); 250 } else if (strcmp(*argv, "local") == 0) { 251 NEXT_ARG(); 252 if (strcmp(*argv, "any")) 246 } else if (key == ARG_local) { 247 NEXT_ARG(); 248 key = index_in_strings(keywords, *argv); 249 if (key == ARG_any) 253 250 p->iph.saddr = get_addr32(*argv); 254 } else if ( strcmp(*argv, "dev") == 0) {251 } else if (key == ARG_dev) { 255 252 NEXT_ARG(); 256 253 strncpy(medium, *argv, IFNAMSIZ-1); 257 } else if ( strcmp(*argv, "ttl") == 0) {254 } else if (key == ARG_ttl) { 258 255 unsigned uval; 259 256 NEXT_ARG(); 260 if (strcmp(*argv, "inherit") != 0) { 257 key = index_in_strings(keywords, *argv); 258 if (key != ARG_inherit) { 261 259 if (get_unsigned(&uval, *argv, 0)) 262 260 invarg(*argv, "TTL"); … … 265 263 p->iph.ttl = uval; 266 264 } 267 } else if (strcmp(*argv, "tos") == 0 || 268 matches(*argv, "dsfield") == 0) { 269 __u32 uval; 270 NEXT_ARG(); 271 if (strcmp(*argv, "inherit") != 0) { 265 } else if (key == ARG_tos || 266 key == ARG_dsfield) { 267 uint32_t uval; 268 NEXT_ARG(); 269 key = index_in_strings(keywords, *argv); 270 if (key != ARG_inherit) { 272 271 if (rtnl_dsfield_a2n(&uval, *argv)) 273 272 invarg(*argv, "TOS"); … … 276 275 p->iph.tos = 1; 277 276 } else { 278 if ( strcmp(*argv, "name") == 0) {277 if (key == ARG_name) { 279 278 NEXT_ARG(); 280 279 } … … 286 285 memset(&old_p, 0, sizeof(old_p)); 287 286 if (do_get_ioctl(*argv, &old_p)) 288 return -1;287 exit(1); 289 288 *p = old_p; 290 289 } 291 290 } 292 291 count++; 293 argc--; argv++;294 }295 292 argc--; 293 argv++; 294 } 296 295 297 296 if (p->iph.protocol == 0) { … … 306 305 if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { 307 306 if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { 308 bb_error_msg("Keys are not allowed with ipip and sit."); 309 return -1; 307 bb_error_msg_and_die("keys are not allowed with ipip and sit"); 310 308 } 311 309 } … … 313 311 if (medium[0]) { 314 312 p->link = do_ioctl_get_ifindex(medium); 315 if (p->link == 0)316 return -1;317 313 } 318 314 … … 326 322 } 327 323 if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { 328 bb_error_msg("Broadcast tunnel requires a source address."); 329 return -1; 330 } 331 return 0; 332 } 333 334 324 bb_error_msg_and_die("broadcast tunnel requires a source address"); 325 } 326 } 327 328 329 /* Return value becomes exitcode. It's okay to not return at all */ 335 330 static int do_add(int cmd, int argc, char **argv) 336 331 { 337 332 struct ip_tunnel_parm p; 338 333 339 if (parse_args(argc, argv, cmd, &p) < 0) 340 return -1; 334 parse_args(argc, argv, cmd, &p); 341 335 342 336 if (p.iph.ttl && p.iph.frag_off == 0) { 343 bb_error_msg("ttl != 0 and noptmudisc are incompatible"); 344 return -1; 337 bb_error_msg_and_die("ttl != 0 and noptmudisc are incompatible"); 345 338 } 346 339 … … 353 346 return do_add_ioctl(cmd, "sit0", &p); 354 347 default: 355 bb_error_msg("cannot determine tunnel mode (ipip, gre or sit)"); 356 return -1; 357 } 358 return -1; 359 } 360 348 bb_error_msg_and_die("cannot determine tunnel mode (ipip, gre or sit)"); 349 } 350 } 351 352 /* Return value becomes exitcode. It's okay to not return at all */ 361 353 static int do_del(int argc, char **argv) 362 354 { 363 355 struct ip_tunnel_parm p; 364 356 365 if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0) 366 return -1; 357 parse_args(argc, argv, SIOCDELTUNNEL, &p); 367 358 368 359 switch (p.iph.protocol) { … … 376 367 return do_del_ioctl(p.name, &p); 377 368 } 378 return -1;379 369 } 380 370 … … 399 389 if (p->link) { 400 390 char *n = do_ioctl_get_ifname(p->link); 401 if (n) 391 if (n) { 402 392 printf(" dev %s ", n); 393 free(n); 394 } 403 395 } 404 396 if (p->iph.ttl) … … 409 401 SPRINT_BUF(b1); 410 402 printf(" tos"); 411 if (p->iph.tos &1)403 if (p->iph.tos & 1) 412 404 printf(" inherit"); 413 if (p->iph.tos &~1)414 printf("%c%s ", p->iph.tos &1 ? '/' : ' ',415 rtnl_dsfield_n2a(p->iph.tos &~1, b1, sizeof(b1)));416 } 417 if (!(p->iph.frag_off &htons(IP_DF)))405 if (p->iph.tos & ~1) 406 printf("%c%s ", p->iph.tos & 1 ? '/' : ' ', 407 rtnl_dsfield_n2a(p->iph.tos & ~1, b1, sizeof(b1))); 408 } 409 if (!(p->iph.frag_off & htons(IP_DF))) 418 410 printf(" nopmtudisc"); 419 411 420 if ((p->i_flags &GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)412 if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key) 421 413 printf(" key %s", s3); 422 else if ((p->i_flags |p->o_flags)&GRE_KEY) {423 if (p->i_flags &GRE_KEY)414 else if ((p->i_flags | p->o_flags) & GRE_KEY) { 415 if (p->i_flags & GRE_KEY) 424 416 printf(" ikey %s ", s3); 425 if (p->o_flags &GRE_KEY)417 if (p->o_flags & GRE_KEY) 426 418 printf(" okey %s ", s4); 427 419 } 428 420 429 if (p->i_flags &GRE_SEQ)430 printf("% sDrop packets out of sequence.\n", _SL_);431 if (p->i_flags &GRE_CSUM)432 printf("% sChecksum in received packet is required.", _SL_);433 if (p->o_flags &GRE_SEQ)434 printf("% sSequence packets on output.", _SL_);435 if (p->o_flags &GRE_CSUM)436 printf("% sChecksum output packets.", _SL_);437 } 438 439 static intdo_tunnels_list(struct ip_tunnel_parm *p)421 if (p->i_flags & GRE_SEQ) 422 printf("%c Drop packets out of sequence.\n", _SL_); 423 if (p->i_flags & GRE_CSUM) 424 printf("%c Checksum in received packet is required.", _SL_); 425 if (p->o_flags & GRE_SEQ) 426 printf("%c Sequence packets on output.", _SL_); 427 if (p->o_flags & GRE_CSUM) 428 printf("%c Checksum output packets.", _SL_); 429 } 430 431 static void do_tunnels_list(struct ip_tunnel_parm *p) 440 432 { 441 433 char name[IFNAMSIZ]; 442 unsigned long 443 rx_fifo, rx_frame,444 tx_bytes, tx_packets, tx_errs, tx_drops,445 tx_fifo, tx_colls, tx_carrier, rx_multi;434 unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, 435 rx_fifo, rx_frame, 436 tx_bytes, tx_packets, tx_errs, tx_drops, 437 tx_fifo, tx_colls, tx_carrier, rx_multi; 446 438 int type; 447 439 struct ip_tunnel_parm p1; 448 449 440 char buf[512]; 450 FILE *fp = fopen("/proc/net/dev", "r"); 441 FILE *fp = fopen_or_warn("/proc/net/dev", "r"); 442 451 443 if (fp == NULL) { 452 perror("fopen"); 453 return -1; 444 return; 454 445 } 455 446 … … 459 450 while (fgets(buf, sizeof(buf), fp) != NULL) { 460 451 char *ptr; 461 buf[sizeof(buf) - 1] = 0; 462 if ((ptr = strchr(buf, ':')) == NULL || 452 453 /*buf[sizeof(buf) - 1] = 0; - fgets is safe anyway */ 454 ptr = strchr(buf, ':'); 455 if (ptr == NULL || 463 456 (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { 464 bb_error_msg(" Wrong format of /proc/net/dev. Sorry.");465 return -1;457 bb_error_msg("wrong format of /proc/net/dev"); 458 return; 466 459 } 467 460 if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", … … 475 468 type = do_ioctl_get_iftype(name); 476 469 if (type == -1) { 477 bb_error_msg(" Failed toget type of [%s]", name);470 bb_error_msg("cannot get type of [%s]", name); 478 471 continue; 479 472 } … … 490 483 continue; 491 484 print_tunnel(&p1); 492 p rintf("\n");493 } 494 return 0; 495 } 496 485 puts(""); 486 } 487 } 488 489 /* Return value becomes exitcode. It's okay to not return at all */ 497 490 static int do_show(int argc, char **argv) 498 491 { … … 500 493 struct ip_tunnel_parm p; 501 494 502 if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) 503 return -1; 495 parse_args(argc, argv, SIOCGETTUNNEL, &p); 504 496 505 497 switch (p.iph.protocol) { … … 521 513 522 514 print_tunnel(&p); 523 p rintf("\n");515 puts(""); 524 516 return 0; 525 517 } 526 518 519 /* Return value becomes exitcode. It's okay to not return at all */ 527 520 int do_iptunnel(int argc, char **argv) 528 521 { 529 if (argc > 0) { 530 if (matches(*argv, "add") == 0) 531 return do_add(SIOCADDTUNNEL, argc-1, argv+1); 532 if (matches(*argv, "change") == 0) 533 return do_add(SIOCCHGTUNNEL, argc-1, argv+1); 534 if (matches(*argv, "del") == 0) 535 return do_del(argc-1, argv+1); 536 if (matches(*argv, "show") == 0 || 537 matches(*argv, "lst") == 0 || 538 matches(*argv, "list") == 0) 539 return do_show(argc-1, argv+1); 540 } else 541 return do_show(0, NULL); 542 543 bb_error_msg("Command \"%s\" is unknown.", *argv); 544 exit(-1); 545 } 522 static const char keywords[] ALIGN1 = 523 "add\0""change\0""delete\0""show\0""list\0""lst\0"; 524 enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst }; 525 int key; 526 527 if (argc) { 528 key = index_in_substrings(keywords, *argv); 529 if (key < 0) 530 bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); 531 --argc; 532 ++argv; 533 if (key == ARG_add) 534 return do_add(SIOCADDTUNNEL, argc, argv); 535 if (key == ARG_change) 536 return do_add(SIOCCHGTUNNEL, argc, argv); 537 if (key == ARG_del) 538 return do_del(argc, argv); 539 } 540 return do_show(argc, argv); 541 } -
branches/2.2.5/mindi-busybox/networking/libiproute/libnetlink.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * libnetlink.c RTnetlink service routines. … … 11 12 */ 12 13 14 #include <sys/socket.h> 15 #include <sys/uio.h> 16 13 17 #include "libbb.h" 14 #include <sys/socket.h>15 16 #include <errno.h>17 #include <string.h>18 #include <time.h>19 #include <unistd.h>20 21 #include <sys/uio.h>22 23 18 #include "libnetlink.h" 24 19 … … 28 23 } 29 24 30 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)25 int xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) 31 26 { 32 27 socklen_t addr_len; … … 34 29 memset(rth, 0, sizeof(rth)); 35 30 36 rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 37 if (rth->fd < 0) { 38 bb_perror_msg("Cannot open netlink socket"); 39 return -1; 40 } 31 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 41 32 42 33 memset(&rth->local, 0, sizeof(rth->local)); 43 34 rth->local.nl_family = AF_NETLINK; 44 rth->local.nl_groups = subscriptions; 45 46 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { 47 bb_perror_msg("Cannot bind netlink socket"); 48 return -1; 49 } 35 /*rth->local.nl_groups = subscriptions;*/ 36 37 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)); 50 38 addr_len = sizeof(rth->local); 51 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { 52 bb_perror_msg("Cannot getsockname"); 53 return -1; 54 } 55 if (addr_len != sizeof(rth->local)) { 56 bb_error_msg("Wrong address length %d", addr_len); 57 return -1; 58 } 59 if (rth->local.nl_family != AF_NETLINK) { 60 bb_error_msg("Wrong address family %d", rth->local.nl_family); 61 return -1; 62 } 39 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) 40 bb_perror_msg_and_die("cannot getsockname"); 41 if (addr_len != sizeof(rth->local)) 42 bb_error_msg_and_die("wrong address length %d", addr_len); 43 if (rth->local.nl_family != AF_NETLINK) 44 bb_error_msg_and_die("wrong address family %d", rth->local.nl_family); 63 45 rth->seq = time(NULL); 64 46 return 0; 65 47 } 66 48 67 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)49 int xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 68 50 { 69 51 struct { … … 83 65 req.g.rtgen_family = family; 84 66 85 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); 67 return xsendto(rth->fd, (void*)&req, sizeof(req), 68 (struct sockaddr*)&nladdr, sizeof(nladdr)); 86 69 } 87 70 … … 93 76 nladdr.nl_family = AF_NETLINK; 94 77 95 return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));78 return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr)); 96 79 } 97 80 … … 120 103 } 121 104 122 int rtnl_dump_filter(struct rtnl_handle *rth,123 124 void *arg1,125 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),126 void *arg2)127 { 128 char 105 static int rtnl_dump_filter(struct rtnl_handle *rth, 106 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 107 void *arg1/*, 108 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 109 void *arg2*/) 110 { 111 char buf[8192]; 129 112 struct sockaddr_nl nladdr; 130 113 struct iovec iov = { buf, sizeof(buf) }; … … 164 147 h->nlmsg_pid != rth->local.nl_pid || 165 148 h->nlmsg_seq != rth->dump) { 166 if (junk) {149 /* if (junk) { 167 150 err = junk(&nladdr, h, arg2); 168 if (err < 0) {151 if (err < 0) 169 152 return err; 170 } 171 } 153 } */ 172 154 goto skip_it; 173 155 } … … 187 169 } 188 170 err = filter(&nladdr, h, arg1); 189 if (err < 0) {171 if (err < 0) 190 172 return err; 191 }192 173 193 174 skip_it: … … 195 176 } 196 177 if (msg.msg_flags & MSG_TRUNC) { 197 bb_error_msg(" Message truncated");178 bb_error_msg("message truncated"); 198 179 continue; 199 180 } 200 181 if (status) { 201 bb_error_msg_and_die("!!!Remnant of size %d", status); 202 } 203 } 182 bb_error_msg_and_die("remnant of size %d!", status); 183 } 184 } 185 } 186 187 int xrtnl_dump_filter(struct rtnl_handle *rth, 188 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 189 void *arg1) 190 { 191 int ret = rtnl_dump_filter(rth, filter, arg1/*, NULL, NULL*/); 192 if (ret < 0) 193 bb_error_msg_and_die("dump terminated"); 194 return ret; 204 195 } 205 196 … … 234 225 235 226 if (status < 0) { 236 bb_perror_msg(" Cannot talk to rtnetlink");227 bb_perror_msg("cannot talk to rtnetlink"); 237 228 return -1; 238 229 } … … 265 256 if (l<0 || len>status) { 266 257 if (msg.msg_flags & MSG_TRUNC) { 267 bb_error_msg(" Truncated message");258 bb_error_msg("truncated message"); 268 259 return -1; 269 260 } 270 bb_error_msg_and_die(" !!!malformed message: len=%d", len);261 bb_error_msg_and_die("malformed message: len=%d!", len); 271 262 } 272 263 … … 304 295 } 305 296 306 bb_error_msg(" Unexpected reply!!!");297 bb_error_msg("unexpected reply!"); 307 298 308 299 status -= NLMSG_ALIGN(len); … … 310 301 } 311 302 if (msg.msg_flags & MSG_TRUNC) { 312 bb_error_msg(" Message truncated");303 bb_error_msg("message truncated"); 313 304 continue; 314 305 } 315 306 if (status) { 316 bb_error_msg_and_die(" !!!Remnant of size %d", status);317 } 318 } 319 } 320 321 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32data)307 bb_error_msg_and_die("remnant of size %d!", status); 308 } 309 } 310 } 311 312 int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) 322 313 { 323 314 int len = RTA_LENGTH(4); … … 348 339 } 349 340 350 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32data)341 int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) 351 342 { 352 343 int len = RTA_LENGTH(4); … … 390 381 } 391 382 if (len) { 392 bb_error_msg(" !!!Deficit %d, rta_len=%d", len, rta->rta_len);393 } 394 return 0; 395 } 383 bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); 384 } 385 return 0; 386 } -
branches/2.2.5/mindi-busybox/networking/libiproute/libnetlink.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 #ifndef __LIBNETLINK_H__ 2 3 #define __LIBNETLINK_H__ 1 3 4 4 #include <asm/types.h> 5 #include <linux/types.h> 6 /* We need linux/types.h because older kernels use __u32 etc 7 * in linux/[rt]netlink.h. 2.6.19 seems to be ok, though */ 5 8 #include <linux/netlink.h> 6 9 #include <linux/rtnetlink.h> … … 11 14 struct sockaddr_nl local; 12 15 struct sockaddr_nl peer; 13 __u32seq;14 __u32dump;16 uint32_t seq; 17 uint32_t dump; 15 18 }; 16 19 17 extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions);20 extern int xrtnl_open(struct rtnl_handle *rth); 18 21 extern void rtnl_close(struct rtnl_handle *rth); 19 extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);22 extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); 20 23 extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); 21 extern int rtnl_dump_filter(struct rtnl_handle *rth, 22 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 23 void *arg1, 24 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 25 void *arg2); 24 extern int xrtnl_dump_filter(struct rtnl_handle *rth, 25 int (*filter)(struct sockaddr_nl*, struct nlmsghdr *n, void*), 26 void *arg1); 26 27 extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 27 28 29 28 unsigned groups, struct nlmsghdr *answer, 29 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 30 void *jarg); 30 31 extern int rtnl_send(struct rtnl_handle *rth, char *buf, int); 31 32 32 33 33 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32data);34 extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data); 34 35 extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen); 35 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32data);36 extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data); 36 37 extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen); 37 38 38 39 extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); 39 40 40 41 41 #endif /* __LIBNETLINK_H__ */ 42 -
branches/2.2.5/mindi-busybox/networking/libiproute/ll_addr.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ll_addr.c … … 10 11 */ 11 12 12 #include "libbb.h"13 14 #include <string.h>15 13 #include <net/if_arp.h> 16 14 15 #include "libbb.h" 17 16 #include "rt_names.h" 18 17 #include "utils.h" … … 31 30 for (i=0; i<alen; i++) { 32 31 if (i==0) { 33 snprintf(buf+l, blen, " %02x", addr[i]);32 snprintf(buf+l, blen, ":%02x"+1, addr[i]); 34 33 blen -= 2; 35 34 l += 2; … … 48 47 inet_prefix pfx; 49 48 if (get_addr_1(&pfx, arg, AF_INET)) { 50 bb_error_msg("\"%s\" is invalid lladdr .", arg);49 bb_error_msg("\"%s\" is invalid lladdr", arg); 51 50 return -1; 52 51 } … … 67 66 } 68 67 if (sscanf(arg, "%x", &temp) != 1) { 69 bb_error_msg("\"%s\" is invalid lladdr .", arg);68 bb_error_msg("\"%s\" is invalid lladdr", arg); 70 69 return -1; 71 70 } 72 71 if (temp < 0 || temp > 255) { 73 bb_error_msg("\"%s\" is invalid lladdr .", arg);72 bb_error_msg("\"%s\" is invalid lladdr", arg); 74 73 return -1; 75 74 } -
branches/2.2.5/mindi-busybox/networking/libiproute/ll_map.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ll_map.c … … 11 12 */ 12 13 14 #include <net/if.h> /* struct ifreq and co. */ 15 13 16 #include "libbb.h" 14 #include <string.h>15 16 17 #include "libnetlink.h" 17 18 #include "ll_map.h" 18 19 19 struct idxmap 20 { 21 struct idxmap * next; 22 int index; 23 int type; 24 int alen; 25 unsigned flags; 26 unsigned char addr[8]; 27 char name[16]; 20 struct idxmap { 21 struct idxmap *next; 22 int index; 23 int type; 24 int alen; 25 unsigned flags; 26 unsigned char addr[8]; 27 char name[16]; 28 28 }; 29 29 30 30 static struct idxmap *idxmap[16]; 31 32 static struct idxmap *find_by_index(int idx) 33 { 34 struct idxmap *im; 35 36 for (im = idxmap[idx & 0xF]; im; im = im->next) 37 if (im->index == idx) 38 return im; 39 return NULL; 40 } 31 41 32 42 int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) … … 43 53 return -1; 44 54 45 46 55 memset(tb, 0, sizeof(tb)); 47 56 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); … … 49 58 return 0; 50 59 51 h = ifi->ifi_index &0xF;60 h = ifi->ifi_index & 0xF; 52 61 53 for (imp =&idxmap[h]; (im=*imp)!=NULL; imp = &im->next)62 for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next) 54 63 if (im->index == ifi->ifi_index) 55 break;64 goto found; 56 65 57 if (im == NULL) { 58 im = xmalloc(sizeof(*im)); 59 im->next = *imp; 60 im->index = ifi->ifi_index; 61 *imp = im; 62 } 63 66 im = xmalloc(sizeof(*im)); 67 im->next = *imp; 68 im->index = ifi->ifi_index; 69 *imp = im; 70 found: 64 71 im->type = ifi->ifi_type; 65 72 im->flags = ifi->ifi_flags; … … 84 91 if (idx == 0) 85 92 return "*"; 86 for (im = idxmap[idx&0xF]; im; im = im->next)87 if (im->index == idx)88 93 im = find_by_index(idx); 94 if (im) 95 return im->name; 89 96 snprintf(buf, 16, "if%d", idx); 90 97 return buf; … … 99 106 } 100 107 108 #ifdef UNUSED 101 109 int ll_index_to_type(int idx) 102 110 { … … 105 113 if (idx == 0) 106 114 return -1; 107 for (im = idxmap[idx&0xF]; im; im = im->next)108 if (im->index == idx)109 115 im = find_by_index(idx); 116 if (im) 117 return im->type; 110 118 return -1; 111 119 } 120 #endif 112 121 113 122 unsigned ll_index_to_flags(int idx) … … 117 126 if (idx == 0) 118 127 return 0; 119 120 for (im = idxmap[idx&0xF]; im; im = im->next) 121 if (im->index == idx) 122 return im->flags; 128 im = find_by_index(idx); 129 if (im) 130 return im->flags; 123 131 return 0; 124 132 } 125 133 126 int ll_name_to_index(char *name)134 int xll_name_to_index(const char *const name) 127 135 { 136 int ret = 0; 137 int sock_fd; 138 139 /* caching is not warranted - no users which repeatedly call it */ 140 #ifdef UNUSED 128 141 static char ncache[16]; 129 142 static int icache; 143 130 144 struct idxmap *im; 131 145 int i; 132 146 133 147 if (name == NULL) 134 return 0; 135 if (icache && strcmp(name, ncache) == 0) 136 return icache; 137 for (i=0; i<16; i++) { 148 goto out; 149 if (icache && strcmp(name, ncache) == 0) { 150 ret = icache; 151 goto out; 152 } 153 for (i = 0; i < 16; i++) { 138 154 for (im = idxmap[i]; im; im = im->next) { 139 155 if (strcmp(im->name, name) == 0) { 140 156 icache = im->index; 141 157 strcpy(ncache, name); 142 return im->index; 158 ret = im->index; 159 goto out; 143 160 } 144 161 } 145 162 } 146 return 0; 163 /* We have not found the interface in our cache, but the kernel 164 * may still know about it. One reason is that we may be using 165 * module on-demand loading, which means that the kernel will 166 * load the module and make the interface exist only when 167 * we explicitely request it (check for dev_load() in net/core/dev.c). 168 * I can think of other similar scenario, but they are less common... 169 * Jean II */ 170 #endif 171 172 sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 173 if (sock_fd) { 174 struct ifreq ifr; 175 int tmp; 176 177 strncpy(ifr.ifr_name, name, IFNAMSIZ); 178 ifr.ifr_ifindex = -1; 179 tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr); 180 close(sock_fd); 181 if (tmp >= 0) 182 /* In theory, we should redump the interface list 183 * to update our cache, this is left as an exercise 184 * to the reader... Jean II */ 185 ret = ifr.ifr_ifindex; 186 } 187 /* out:*/ 188 if (ret <= 0) 189 bb_error_msg_and_die("cannot find device \"%s\"", name); 190 return ret; 147 191 } 148 192 149 193 int ll_init_map(struct rtnl_handle *rth) 150 194 { 151 if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { 152 perror("Cannot send dump request"); 153 exit(1); 154 } 155 156 if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) { 157 fprintf(stderr, "Dump terminated\n"); 158 exit(1); 159 } 195 xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK); 196 xrtnl_dump_filter(rth, ll_remember_index, &idxmap); 160 197 return 0; 161 198 } -
branches/2.2.5/mindi-busybox/networking/libiproute/ll_map.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 #ifndef __LL_MAP_H__ 2 3 #define __LL_MAP_H__ 1 3 4 4 externint ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);5 externint ll_init_map(struct rtnl_handle *rth);6 extern int ll_name_to_index(char *name);7 externconst char *ll_index_to_name(int idx);8 externconst char *ll_idx_n2a(int idx, char *buf);9 extern int ll_index_to_type(int idx); 10 externunsigned ll_index_to_flags(int idx);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); 10 /* int ll_index_to_type(int idx); */ 11 unsigned ll_index_to_flags(int idx); 11 12 12 13 #endif /* __LL_MAP_H__ */ -
branches/2.2.5/mindi-busybox/networking/libiproute/ll_proto.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ll_proto.c … … 11 12 12 13 #include "libbb.h" 13 #include <string.h>14 15 14 #include "rt_names.h" 16 15 #include "utils.h" 17 16 18 #if __GLIBC__ >=2 && __GLIBC_MINOR>= 117 #if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 19 18 #include <net/ethernet.h> 20 19 #else … … 25 24 static struct { 26 25 int id; 27 c har *name;26 const char *name; 28 27 } llproto_names[] = { 29 28 __PF(LOOP,loop) … … 98 97 id = ntohs(id); 99 98 100 for (i=0; i <sizeof(llproto_names)/sizeof(llproto_names[0]); i++) {99 for (i=0; i < ARRAY_SIZE(llproto_names); i++) { 101 100 if (llproto_names[i].id == id) 102 101 return llproto_names[i].name; … … 109 108 { 110 109 int i; 111 for (i=0; i <sizeof(llproto_names)/sizeof(llproto_names[0]); i++) {110 for (i=0; i < ARRAY_SIZE(llproto_names); i++) { 112 111 if (strcasecmp(llproto_names[i].name, buf) == 0) { 113 112 *id = htons(llproto_names[i].id); -
branches/2.2.5/mindi-busybox/networking/libiproute/ll_types.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * ll_types.c … … 9 10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 11 */ 11 #include <stdio.h>12 12 #include <arpa/inet.h> 13 14 13 #include <linux/if_arp.h> 15 14 15 #include "libbb.h" 16 16 #include "rt_names.h" 17 17 18 const char 18 const char* ll_type_n2a(int type, char *buf, int len) 19 19 { 20 20 #define __PF(f,n) { ARPHRD_##f, #n }, 21 static struct {21 static const struct { 22 22 int type; 23 c har *name;23 const char *name; 24 24 } arphrd_names[] = { 25 25 { 0, "generic" }, … … 109 109 110 110 int i; 111 for (i =0; i<sizeof(arphrd_names)/sizeof(arphrd_names[0]); i++) {111 for (i = 0; i < ARRAY_SIZE(arphrd_names); i++) { 112 112 if (arphrd_names[i].type == type) 113 113 return arphrd_names[i].name; -
branches/2.2.5/mindi-busybox/networking/libiproute/rt_names.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * rt_names.c rtnetlink names DB. … … 9 10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 11 */ 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <stdint.h> 12 13 #include "libbb.h" 16 14 #include "rt_names.h" 17 15 18 static void rtnl_tab_initialize(c har *file,char **tab, int size)16 static void rtnl_tab_initialize(const char *file, const char **tab, int size) 19 17 { 20 18 char buf[512]; … … 33 31 if (*p == '#' || *p == '\n' || *p == 0) 34 32 continue; 35 if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 && 36 sscanf(p, "0x%x %s #", &id, namebuf) != 2 && 37 sscanf(p, "%d %s\n", &id, namebuf) != 2 && 38 sscanf(p, "%d %s #", &id, namebuf) != 2) { 39 fprintf(stderr, "Database %s is corrupted at %s\n", 33 if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 34 && sscanf(p, "0x%x %s #", &id, namebuf) != 2 35 && sscanf(p, "%d %s\n", &id, namebuf) != 2 36 && sscanf(p, "%d %s #", &id, namebuf) != 2 37 ) { 38 bb_error_msg("database %s is corrupted at %s", 40 39 file, p); 41 40 return; 42 41 } 43 42 44 if (id <0 || id>size)43 if (id < 0 || id > size) 45 44 continue; 46 45 47 tab[id] = strdup(namebuf);46 tab[id] = xstrdup(namebuf); 48 47 } 49 48 fclose(fp); … … 51 50 52 51 53 static char * rtnl_rtprot_tab[256] = { 54 "none", 55 "redirect", 56 "kernel", 57 "boot", 58 "static", 59 NULL, 60 NULL, 61 NULL, 62 "gated", 63 "ra", 64 "mrt", 65 "zebra", 66 "bird", 67 }; 68 69 70 71 static int rtnl_rtprot_init; 52 static const char **rtnl_rtprot_tab; /* [256] */ 72 53 73 54 static void rtnl_rtprot_initialize(void) 74 55 { 75 rtnl_rtprot_init = 1; 56 static const char *const init_tab[] = { 57 "none", 58 "redirect", 59 "kernel", 60 "boot", 61 "static", 62 NULL, 63 NULL, 64 NULL, 65 "gated", 66 "ra", 67 "mrt", 68 "zebra", 69 "bird", 70 }; 71 if (rtnl_rtprot_tab) return; 72 rtnl_rtprot_tab = xzalloc(256 * sizeof(rtnl_rtprot_tab[0])); 73 memcpy(rtnl_rtprot_tab, init_tab, sizeof(init_tab)); 76 74 rtnl_tab_initialize("/etc/iproute2/rt_protos", 77 75 rtnl_rtprot_tab, 256); 78 76 } 79 77 80 const char * rtnl_rtprot_n2a(int id, char *buf, int len) 81 { 82 if (id<0 || id>=256){83 snprintf(buf, len, "%d", id);84 return buf;85 }86 if (!rtnl_rtprot_tab[id]) {87 if (!rtnl_rtprot_init) 88 89 } 78 79 const char* rtnl_rtprot_n2a(int id, char *buf, int len) 80 { 81 if (id < 0 || id >= 256) { 82 snprintf(buf, len, "%d", id); 83 return buf; 84 } 85 86 rtnl_rtprot_initialize(); 87 90 88 if (rtnl_rtprot_tab[id]) 91 89 return rtnl_rtprot_tab[id]; … … 96 94 int rtnl_rtprot_a2n(uint32_t *id, char *arg) 97 95 { 98 static char *cache = NULL; 99 static unsigned long res; 100 char *end; 101 int i; 102 103 if (cache && strcmp(cache, arg) == 0) { 104 *id = res; 105 return 0; 106 } 107 108 if (!rtnl_rtprot_init) 109 rtnl_rtprot_initialize(); 110 111 for (i=0; i<256; i++) { 96 static const char *cache = NULL; 97 static unsigned long res; 98 int i; 99 100 if (cache && strcmp(cache, arg) == 0) { 101 *id = res; 102 return 0; 103 } 104 105 rtnl_rtprot_initialize(); 106 107 for (i = 0; i < 256; i++) { 112 108 if (rtnl_rtprot_tab[i] && 113 109 strcmp(rtnl_rtprot_tab[i], arg) == 0) { … … 119 115 } 120 116 121 res = strtoul(arg, &end, 0);122 if ( !end || end == arg || *end|| res > 255)117 res = bb_strtoul(arg, NULL, 0); 118 if (errno || res > 255) 123 119 return -1; 124 120 *id = res; … … 127 123 128 124 129 130 static char * rtnl_rtscope_tab[256] = { 131 "global", 132 }; 133 134 static int rtnl_rtscope_init; 125 static const char **rtnl_rtscope_tab; /* [256] */ 135 126 136 127 static void rtnl_rtscope_initialize(void) 137 128 { 138 rtnl_rtscope_init = 1; 129 if (rtnl_rtscope_tab) return; 130 rtnl_rtscope_tab = xzalloc(256 * sizeof(rtnl_rtscope_tab[0])); 131 rtnl_rtscope_tab[0] = "global"; 139 132 rtnl_rtscope_tab[255] = "nowhere"; 140 133 rtnl_rtscope_tab[254] = "host"; … … 145 138 } 146 139 147 const char * rtnl_rtscope_n2a(int id, char *buf, int len) 148 { 149 if (id<0 || id>=256){150 snprintf(buf, len, "%d", id);151 return buf;152 }153 if (!rtnl_rtscope_tab[id]) {154 if (!rtnl_rtscope_init) 155 156 } 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); 145 return buf; 146 } 147 148 rtnl_rtscope_initialize(); 149 157 150 if (rtnl_rtscope_tab[id]) 158 151 return rtnl_rtscope_tab[id]; … … 163 156 int rtnl_rtscope_a2n(uint32_t *id, char *arg) 164 157 { 165 static char *cache = NULL; 166 static unsigned long res; 167 char *end; 168 int i; 169 170 if (cache && strcmp(cache, arg) == 0) { 171 *id = res; 172 return 0; 173 } 174 175 if (!rtnl_rtscope_init) 176 rtnl_rtscope_initialize(); 177 178 for (i=0; i<256; i++) { 158 static const char *cache = NULL; 159 static unsigned long res; 160 int i; 161 162 if (cache && strcmp(cache, arg) == 0) { 163 *id = res; 164 return 0; 165 } 166 167 rtnl_rtscope_initialize(); 168 169 for (i = 0; i < 256; i++) { 179 170 if (rtnl_rtscope_tab[i] && 180 171 strcmp(rtnl_rtscope_tab[i], arg) == 0) { … … 186 177 } 187 178 188 res = strtoul(arg, &end, 0);189 if ( !end || end == arg || *end|| res > 255)179 res = bb_strtoul(arg, NULL, 0); 180 if (errno || res > 255) 190 181 return -1; 191 182 *id = res; … … 194 185 195 186 196 197 static char * rtnl_rtrealm_tab[256] = { 198 "unknown", 199 }; 200 201 static int rtnl_rtrealm_init; 187 static const char **rtnl_rtrealm_tab; /* [256] */ 202 188 203 189 static void rtnl_rtrealm_initialize(void) 204 190 { 205 rtnl_rtrealm_init = 1; 191 if (rtnl_rtrealm_tab) return; 192 rtnl_rtrealm_tab = xzalloc(256 * sizeof(rtnl_rtrealm_tab[0])); 193 rtnl_rtrealm_tab[0] = "unknown"; 206 194 rtnl_tab_initialize("/etc/iproute2/rt_realms", 207 195 rtnl_rtrealm_tab, 256); 208 196 } 209 197 198 210 199 int rtnl_rtrealm_a2n(uint32_t *id, char *arg) 211 200 { 212 static char *cache = NULL; 213 static unsigned long res; 214 char *end; 215 int i; 216 217 if (cache && strcmp(cache, arg) == 0) { 218 *id = res; 219 return 0; 220 } 221 222 if (!rtnl_rtrealm_init) 223 rtnl_rtrealm_initialize(); 224 225 for (i=0; i<256; i++) { 201 static const char *cache = NULL; 202 static unsigned long res; 203 int i; 204 205 if (cache && strcmp(cache, arg) == 0) { 206 *id = res; 207 return 0; 208 } 209 210 rtnl_rtrealm_initialize(); 211 212 for (i = 0; i < 256; i++) { 226 213 if (rtnl_rtrealm_tab[i] && 227 214 strcmp(rtnl_rtrealm_tab[i], arg) == 0) { … … 233 220 } 234 221 235 res = strtoul(arg, &end, 0);236 if ( !end || end == arg || *end|| res > 255)222 res = bb_strtoul(arg, NULL, 0); 223 if (errno || res > 255) 237 224 return -1; 238 225 *id = res; … … 240 227 } 241 228 242 243 244 static char * rtnl_rtdsfield_tab[256] = { 245 "0", 246 }; 247 248 static int rtnl_rtdsfield_init; 229 #if ENABLE_FEATURE_IP_RULE 230 const char* rtnl_rtrealm_n2a(int id, char *buf, int len) 231 { 232 if (id < 0 || id >= 256) { 233 snprintf(buf, len, "%d", id); 234 return buf; 235 } 236 237 rtnl_rtrealm_initialize(); 238 239 if (rtnl_rtrealm_tab[id]) 240 return rtnl_rtrealm_tab[id]; 241 snprintf(buf, len, "%d", id); 242 return buf; 243 } 244 #endif 245 246 247 static const char **rtnl_rtdsfield_tab; /* [256] */ 249 248 250 249 static void rtnl_rtdsfield_initialize(void) 251 250 { 252 rtnl_rtdsfield_init = 1; 251 if (rtnl_rtdsfield_tab) return; 252 rtnl_rtdsfield_tab = xzalloc(256 * sizeof(rtnl_rtdsfield_tab[0])); 253 rtnl_rtdsfield_tab[0] = "0"; 253 254 rtnl_tab_initialize("/etc/iproute2/rt_dsfield", 254 255 rtnl_rtdsfield_tab, 256); 255 256 } 256 257 258 257 259 const char * rtnl_dsfield_n2a(int id, char *buf, int len) 258 260 { 259 if (id<0 || id>=256) { 260 snprintf(buf, len, "%d", id); 261 return buf; 262 } 263 if (!rtnl_rtdsfield_tab[id]) { 264 if (!rtnl_rtdsfield_init) 265 rtnl_rtdsfield_initialize(); 266 } 261 if (id < 0 || id >= 256) { 262 snprintf(buf, len, "%d", id); 263 return buf; 264 } 265 266 rtnl_rtdsfield_initialize(); 267 267 268 if (rtnl_rtdsfield_tab[id]) 268 269 return rtnl_rtdsfield_tab[id]; … … 274 275 int rtnl_dsfield_a2n(uint32_t *id, char *arg) 275 276 { 276 static char *cache = NULL; 277 static unsigned long res; 278 char *end; 279 int i; 280 281 if (cache && strcmp(cache, arg) == 0) { 282 *id = res; 283 return 0; 284 } 285 286 if (!rtnl_rtdsfield_init) 287 rtnl_rtdsfield_initialize(); 288 289 for (i=0; i<256; i++) { 277 static const char *cache = NULL; 278 static unsigned long res; 279 int i; 280 281 if (cache && strcmp(cache, arg) == 0) { 282 *id = res; 283 return 0; 284 } 285 286 rtnl_rtdsfield_initialize(); 287 288 for (i = 0; i < 256; i++) { 290 289 if (rtnl_rtdsfield_tab[i] && 291 290 strcmp(rtnl_rtdsfield_tab[i], arg) == 0) { … … 297 296 } 298 297 299 res = strtoul(arg, &end, 16);300 if ( !end || end == arg || *end|| res > 255)298 res = bb_strtoul(arg, NULL, 16); 299 if (errno || res > 255) 301 300 return -1; 302 301 *id = res; … … 304 303 } 305 304 305 306 #if ENABLE_FEATURE_IP_RULE 307 static const char **rtnl_rttable_tab; /* [256] */ 308 309 static void rtnl_rttable_initialize(void) 310 { 311 if (rtnl_rtdsfield_tab) return; 312 rtnl_rttable_tab = xzalloc(256 * sizeof(rtnl_rttable_tab[0])); 313 rtnl_rttable_tab[0] = "unspec"; 314 rtnl_rttable_tab[255] = "local"; 315 rtnl_rttable_tab[254] = "main"; 316 rtnl_rttable_tab[253] = "default"; 317 rtnl_tab_initialize("/etc/iproute2/rt_tables", rtnl_rttable_tab, 256); 318 } 319 320 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); 325 return buf; 326 } 327 328 rtnl_rttable_initialize(); 329 330 if (rtnl_rttable_tab[id]) 331 return rtnl_rttable_tab[id]; 332 snprintf(buf, len, "%d", id); 333 return buf; 334 } 335 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 347 rtnl_rttable_initialize(); 348 349 for (i = 0; i < 256; i++) { 350 if (rtnl_rttable_tab[i] && strcmp(rtnl_rttable_tab[i], arg) == 0) { 351 cache = (char*)rtnl_rttable_tab[i]; 352 res = i; 353 *id = res; 354 return 0; 355 } 356 } 357 358 i = bb_strtoul(arg, NULL, 0); 359 if (errno || i > 255) 360 return -1; 361 *id = i; 362 return 0; 363 } 364 365 #endif -
branches/2.2.5/mindi-busybox/networking/libiproute/rt_names.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 #ifndef RT_NAMES_H_ 2 3 #define RT_NAMES_H_ 1 … … 6 7 extern const char* rtnl_rtprot_n2a(int id, char *buf, int len); 7 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); 8 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); 9 12 extern int rtnl_rtprot_a2n(uint32_t *id, char *arg); 10 13 extern int rtnl_rtscope_a2n(uint32_t *id, char *arg); 11 14 extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg); 12 15 extern int rtnl_dsfield_a2n(uint32_t *id, char *arg); 16 extern int rtnl_rttable_a2n(uint32_t *id, char *arg); 13 17 14 18 15 extern const char 19 extern const char* ll_type_n2a(int type, char *buf, int len); 16 20 17 extern const char *ll_addr_n2a(unsigned char *addr, int alen, int type,21 extern const char* ll_addr_n2a(unsigned char *addr, int alen, int type, 18 22 char *buf, int blen); 19 23 extern int ll_addr_a2n(unsigned char *lladdr, int len, char *arg); 20 24 21 extern const char 25 extern const char* ll_proto_n2a(unsigned short id, char *buf, int len); 22 26 extern int ll_proto_a2n(unsigned short *id, char *buf); 23 27 24 25 28 #endif -
branches/2.2.5/mindi-busybox/networking/libiproute/rtm_map.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * rtm_map.c … … 11 12 */ 12 13 13 #include <stdlib.h> 14 #include <string.h> 15 14 #include "libbb.h" 16 15 #include "rt_names.h" 17 16 #include "utils.h" 18 17 19 c har *rtnl_rtntype_n2a(int id, char *buf, int len)18 const char *rtnl_rtntype_n2a(int id, char *buf, int len) 20 19 { 21 20 switch (id) { … … 53 52 int rtnl_rtntype_a2n(int *id, char *arg) 54 53 { 54 static const char keywords[] ALIGN1 = 55 "local\0""nat\0""broadcast\0""brd\0""anycast\0" 56 "multicast\0""prohibit\0""unreachable\0""blackhole\0" 57 "xresolve\0""unicast\0""throw\0"; 58 enum { 59 ARG_local = 1, ARG_nat, ARG_broadcast, ARG_brd, ARG_anycast, 60 ARG_multicast, ARG_prohibit, ARG_unreachable, ARG_blackhole, 61 ARG_xresolve, ARG_unicast, ARG_throw 62 }; 63 const smalluint key = index_in_substrings(keywords, arg) + 1; 55 64 char *end; 56 65 unsigned long res; 57 66 58 if ( strcmp(arg, "local") == 0)67 if (key == ARG_local) 59 68 res = RTN_LOCAL; 60 else if ( strcmp(arg, "nat") == 0)69 else if (key == ARG_nat) 61 70 res = RTN_NAT; 62 else if (matches(arg, "broadcast") == 0 || 63 strcmp(arg, "brd") == 0) 71 else if (key == ARG_broadcast || key == ARG_brd) 64 72 res = RTN_BROADCAST; 65 else if ( matches(arg, "anycast") == 0)73 else if (key == ARG_anycast) 66 74 res = RTN_ANYCAST; 67 else if ( matches(arg, "multicast") == 0)75 else if (key == ARG_multicast) 68 76 res = RTN_MULTICAST; 69 else if ( matches(arg, "prohibit") == 0)77 else if (key == ARG_prohibit) 70 78 res = RTN_PROHIBIT; 71 else if ( matches(arg, "unreachable") == 0)79 else if (key == ARG_unreachable) 72 80 res = RTN_UNREACHABLE; 73 else if ( matches(arg, "blackhole") == 0)81 else if (key == ARG_blackhole) 74 82 res = RTN_BLACKHOLE; 75 else if ( matches(arg, "xresolve") == 0)83 else if (key == ARG_xresolve) 76 84 res = RTN_XRESOLVE; 77 else if ( matches(arg, "unicast") == 0)85 else if (key == ARG_unicast) 78 86 res = RTN_UNICAST; 79 else if ( strcmp(arg, "throw") == 0)87 else if (key == ARG_throw) 80 88 res = RTN_THROW; 81 89 else { … … 88 96 } 89 97 90 int get_rt_realms( __u32*realms, char *arg)98 int get_rt_realms(uint32_t *realms, char *arg) 91 99 { 92 __u32realm = 0;100 uint32_t realm = 0; 93 101 char *p = strchr(arg, '/'); 94 102 -
branches/2.2.5/mindi-busybox/networking/libiproute/rtm_map.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 #ifndef __RTM_MAP_H__ 2 3 #define __RTM_MAP_H__ 1 3 4 4 c har *rtnl_rtntype_n2a(int id, char *buf, int len);5 const char *rtnl_rtntype_n2a(int id, char *buf, int len); 5 6 int rtnl_rtntype_a2n(int *id, char *arg); 6 7 7 int get_rt_realms( __u32*realms, char *arg);8 int get_rt_realms(uint32_t *realms, char *arg); 8 9 9 10 -
branches/2.2.5/mindi-busybox/networking/libiproute/utils.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * utils.c … … 12 13 13 14 #include "libbb.h" 14 15 #include <string.h>16 #include <unistd.h>17 18 15 #include "utils.h" 19 16 #include "inet_common.h" … … 32 29 return 0; 33 30 } 34 31 //XXX: FIXME: use some libbb function instead 35 32 int get_unsigned(unsigned *val, char *arg, int base) 36 33 { … … 47 44 } 48 45 49 int get_u32( __u32* val, char *arg, int base)46 int get_u32(uint32_t * val, char *arg, int base) 50 47 { 51 48 unsigned long res; … … 61 58 } 62 59 63 int get_u16( __u16* val, char *arg, int base)60 int get_u16(uint16_t * val, char *arg, int base) 64 61 { 65 62 unsigned long res; … … 75 72 } 76 73 77 int get_u8( __u8* val, char *arg, int base)74 int get_u8(uint8_t * val, char *arg, int base) 78 75 { 79 76 unsigned long res; … … 89 86 } 90 87 91 int get_s16( __s16* val, char *arg, int base)88 int get_s16(int16_t * val, char *arg, int base) 92 89 { 93 90 long res; … … 103 100 } 104 101 105 int get_s8( __s8* val, char *arg, int base)102 int get_s8(int8_t * val, char *arg, int base) 106 103 { 107 104 long res; … … 125 122 memset(addr, 0, sizeof(*addr)); 126 123 127 if (strcmp(name, bb_ INET_default) == 0 ||124 if (strcmp(name, bb_str_default) == 0 || 128 125 strcmp(name, "all") == 0 || strcmp(name, "any") == 0) { 129 126 addr->family = family; … … 169 166 memset(dst, 0, sizeof(*dst)); 170 167 171 if (strcmp(arg, bb_ INET_default) == 0 || strcmp(arg, "any") == 0) {168 if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) { 172 169 dst->family = family; 173 170 dst->bytelen = 0; … … 178 175 slash = strchr(arg, '/'); 179 176 if (slash) 180 *slash = 0;177 *slash = '\0'; 181 178 err = get_addr_1(dst, arg, family); 182 179 if (err == 0) { … … 197 194 } 198 195 } 199 196 done: 200 197 if (slash) 201 198 *slash = '/'; … … 206 203 { 207 204 if (family == AF_PACKET) { 208 bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context .", arg);205 bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg); 209 206 } 210 207 if (get_addr_1(dst, arg, family)) { 211 bb_error_msg_and_die("an inet address is expected rather than \"%s\" .", arg);208 bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg); 212 209 } 213 210 return 0; … … 217 214 { 218 215 if (family == AF_PACKET) { 219 bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context .", arg);216 bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg); 220 217 } 221 218 if (get_prefix_1(dst, arg, family)) { 222 bb_error_msg_and_die("an inet address is expected rather than \"%s\" .", arg);223 } 224 return 0; 225 } 226 227 __u32get_addr32(char *name)219 bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg); 220 } 221 return 0; 222 } 223 224 uint32_t get_addr32(char *name) 228 225 { 229 226 inet_prefix addr; … … 237 234 void incomplete_command(void) 238 235 { 239 bb_error_msg("Command line is not complete. Try option \"help\""); 240 exit(-1); 241 } 242 243 void invarg(const char * const arg, const char * const opt) 244 { 245 bb_error_msg(bb_msg_invalid_arg, arg, opt); 246 exit(-1); 247 } 248 249 void duparg(char *key, char *arg) 250 { 251 bb_error_msg("duplicate \"%s\": \"%s\" is the second value.", key, arg); 252 exit(-1); 253 } 254 255 void duparg2(char *key, char *arg) 256 { 257 bb_error_msg("either \"%s\" is duplicate, or \"%s\" is a garbage.", key, arg); 258 exit(-1); 259 } 260 261 int matches(char *cmd, char *pattern) 262 { 263 int len = strlen(cmd); 264 265 if (len > strlen(pattern)) { 266 return -1; 267 } 268 return memcmp(pattern, cmd, len); 236 bb_error_msg_and_die("command line is not complete, try option \"help\""); 237 } 238 239 void invarg(const char *arg, const char *opt) 240 { 241 bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt); 242 } 243 244 void duparg(const char *key, const char *arg) 245 { 246 bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg); 247 } 248 249 void duparg2(const char *key, const char *arg) 250 { 251 bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg); 269 252 } 270 253 271 254 int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits) 272 255 { 273 __u32*a1 = a->data;274 __u32*a2 = b->data;256 uint32_t *a1 = a->data; 257 uint32_t *a2 = b->data; 275 258 int words = bits >> 0x05; 276 259 … … 282 265 283 266 if (bits) { 284 __u32w1, w2;285 __u32mask;267 uint32_t w1, w2; 268 uint32_t mask; 286 269 287 270 w1 = a1[words]; … … 295 278 296 279 return 0; 297 }298 299 int __iproute2_hz_internal;300 301 int __get_hz(void)302 {303 int hz = 0;304 FILE *fp = fopen("/proc/net/psched", "r");305 306 if (fp) {307 unsigned nom, denom;308 309 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)310 if (nom == 1000000)311 hz = denom;312 fclose(fp);313 }314 if (hz)315 return hz;316 return sysconf(_SC_CLK_TCK);317 280 } 318 281 … … 347 310 } 348 311 } 349 if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) { 350 snprintf(buf, buflen - 1, "%s", h_ent->h_name); 351 return buf; 312 if (len > 0) { 313 h_ent = gethostbyaddr(addr, len, af); 314 if (h_ent != NULL) { 315 safe_strncpy(buf, h_ent->h_name, buflen); 316 return buf; 317 } 352 318 } 353 319 } -
branches/2.2.5/mindi-busybox/networking/libiproute/utils.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 #ifndef __UTILS_H__ 2 3 #define __UTILS_H__ 1 3 4 #include "libbb.h"5 #include <asm/types.h>6 #include <resolv.h>7 4 8 5 #include "libnetlink.h" … … 11 8 12 9 extern int preferred_family; 13 extern int show_stats;14 extern int show_details;15 extern int show_raw;16 extern int resolve_hosts;17 extern int oneline;18 extern char *_SL_;10 extern smallint show_stats; /* UNUSED */ 11 extern smallint show_details; /* UNUSED */ 12 extern smallint show_raw; /* UNUSED */ 13 extern smallint resolve_hosts; /* UNUSED */ 14 extern smallint oneline; 15 extern char _SL_; 19 16 20 17 #ifndef IPPROTO_ESP … … 30 27 extern void incomplete_command(void) ATTRIBUTE_NORETURN; 31 28 32 #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while (0)29 #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while (0) 33 30 34 31 typedef struct 35 32 { 36 __u8family;37 __u8bytelen;38 __s16bitlen;39 __u32data[4];33 uint8_t family; 34 uint8_t bytelen; 35 int16_t bitlen; 36 uint32_t data[4]; 40 37 } inet_prefix; 41 38 … … 45 42 #endif 46 43 47 struct dn_naddr 48 { 44 struct dn_naddr { 49 45 unsigned short a_len; 50 46 unsigned char a_addr[DN_MAXADDL]; … … 58 54 }; 59 55 60 extern __u32get_addr32(char *name);56 extern uint32_t get_addr32(char *name); 61 57 extern int get_addr_1(inet_prefix *dst, char *arg, int family); 62 58 extern int get_prefix_1(inet_prefix *dst, char *arg, int family); … … 69 65 #define get_ushort get_u16 70 66 #define get_short get_s16 71 extern int get_u32( __u32*val, char *arg, int base);72 extern int get_u16( __u16*val, char *arg, int base);73 extern int get_s16( __s16*val, char *arg, int base);74 extern int get_u8( __u8*val, char *arg, int base);75 extern int get_s8( __s8*val, char *arg, int base);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); 76 72 77 73 extern const char *format_host(int af, int len, void *addr, char *buf, int buflen); 78 74 extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen); 79 75 80 void invarg(const char * const, const char * const) ATTRIBUTE_NORETURN; 81 void duparg(char *, char *) ATTRIBUTE_NORETURN; 82 void duparg2(char *, char *) ATTRIBUTE_NORETURN; 83 int matches(char *arg, char *pattern); 84 extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); 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; 79 int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); 85 80 86 81 const char *dnet_ntop(int af, const void *addr, char *str, size_t len); … … 90 85 int ipx_pton(int af, const char *src, void *addr); 91 86 92 extern int __iproute2_hz_internal;93 extern int __get_hz(void);94 95 static __inline__ int get_hz(void)96 {97 if (__iproute2_hz_internal == 0)98 __iproute2_hz_internal = __get_hz();99 return __iproute2_hz_internal;100 }101 102 87 #endif /* __UTILS_H__ */ -
branches/2.2.5/mindi-busybox/networking/nameif.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * nameif.c - Naming Interfaces based on MAC address for busybox. … … 9 10 */ 10 11 11 #include "busybox.h" 12 13 #include <sys/syslog.h> 14 #include <sys/socket.h> 15 #include <sys/ioctl.h> 16 #include <errno.h> 17 #include <string.h> 18 #include <unistd.h> 12 #include "libbb.h" 13 #include <syslog.h> 19 14 #include <net/if.h> 20 15 #include <netinet/ether.h> … … 47 42 } mactable_t; 48 43 49 static unsigned long flags;50 51 static void serror(const char *s, ...) ATTRIBUTE_NORETURN;52 53 static void serror(const char *s, ...)54 {55 va_list ap;56 57 va_start(ap, s);58 59 if (flags & 1) {60 openlog(bb_applet_name, 0, LOG_LOCAL0);61 vsyslog(LOG_ERR, s, ap);62 closelog();63 } else {64 bb_verror_msg(s, ap);65 putc('\n', stderr);66 }67 va_end(ap);68 69 exit(EXIT_FAILURE);70 }71 72 44 /* Check ascii str_macaddr, convert and copy to *mac */ 73 45 static struct ether_addr *cc_macaddr(const char *str_macaddr) … … 77 49 lmac = ether_aton(str_macaddr); 78 50 if (lmac == NULL) 79 serror("cannot parse MAC %s", str_macaddr);51 bb_error_msg_and_die("cannot parse MAC %s", str_macaddr); 80 52 mac = xmalloc(ETH_ALEN); 81 53 memcpy(mac, lmac, ETH_ALEN); … … 84 56 } 85 57 58 int nameif_main(int argc, char **argv); 86 59 int nameif_main(int argc, char **argv) 87 60 { … … 94 67 mactable_t *ch; 95 68 96 flags = bb_getopt_ulflags(argc, argv, "sc:", &fname); 69 if (1 & getopt32(argv, "sc:", &fname)) { 70 openlog(applet_name, 0, LOG_LOCAL0); 71 logmode = LOGMODE_SYSLOG; 72 } 97 73 98 74 if ((argc - optind) & 1) … … 103 79 104 80 while (*a) { 105 106 81 if (strlen(*a) > IF_NAMESIZE) 107 serror("interface name `%s' too long", *a); 82 bb_error_msg_and_die("interface name '%s' " 83 "too long", *a); 108 84 ch = xzalloc(sizeof(mactable_t)); 109 ch->ifname = bb_xstrdup(*a++);85 ch->ifname = xstrdup(*a++); 110 86 ch->mac = cc_macaddr(*a++); 111 87 if (clist) … … 115 91 } 116 92 } else { 117 ifh = bb_xfopen(fname, "r");93 ifh = xfopen(fname, "r"); 118 94 119 while ((line = bb_get_line_from_file(ifh)) != NULL) {95 while ((line = xmalloc_fgets(ifh)) != NULL) { 120 96 char *line_ptr; 121 97 size_t name_length; … … 128 104 name_length = strcspn(line_ptr, " \t"); 129 105 ch = xzalloc(sizeof(mactable_t)); 130 ch->ifname = bb_xstrndup(line_ptr, name_length);106 ch->ifname = xstrndup(line_ptr, name_length); 131 107 if (name_length > IF_NAMESIZE) 132 serror("interface name `%s' too long", ch->ifname); 108 bb_error_msg_and_die("interface name '%s' " 109 "too long", ch->ifname); 133 110 line_ptr += name_length; 134 111 line_ptr += strspn(line_ptr, " \t"); … … 145 122 } 146 123 147 if ((ctl_sk = socket(PF_INET, SOCK_DGRAM, 0)) == -1) 148 serror("socket: %m"); 124 ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0); 149 125 150 126 while (clist) { … … 173 149 174 150 strcpy(ifr.ifr_newname, ch->ifname); 175 i f (ioctl(ctl_sk, SIOCSIFNAME, &ifr) < 0)176 serror("cannot change ifname %s to %s: %m",177 151 ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, 152 "cannot change ifname %s to %s", 153 ifr.ifr_name, ch->ifname); 178 154 179 155 /* Remove list entry of renamed interface */ -
branches/2.2.5/mindi-busybox/networking/nc.c
r821 r1765 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* nc: mini-netcat - built from the ground up for LRP 3 Copyright (C) 1998 Charles P. Wright 4 5 0.0.1 6K It works. 6 0.0.2 5K Smaller and you can also check the exit condition if you wish. 7 0.0.3 Uses select() 8 9 19980918 Busy Boxed! Dave Cinege 10 19990512 Uses Select. Charles P. Wright 11 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright 12 13 Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <signal.h> 21 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <netdb.h> 27 #include <sys/ioctl.h> 28 #include "busybox.h" 3 * 4 * Copyright (C) 1998, 1999 Charles P. Wright 5 * Copyright (C) 1998 Dave Cinege 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 */ 9 10 #include "libbb.h" 11 12 #if ENABLE_DESKTOP 13 #include "nc_bloaty.c" 14 #else 15 16 /* Lots of small differences in features 17 * when compared to "standard" nc 18 */ 29 19 30 20 static void timeout(int signum) 31 21 { 32 bb_error_msg_and_die(" Timed out");22 bb_error_msg_and_die("timed out"); 33 23 } 34 24 25 int nc_main(int argc, char **argv); 35 26 int nc_main(int argc, char **argv) 36 27 { 37 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x; 38 39 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE 40 char *pr00gie = NULL; 41 #endif 42 43 struct sockaddr_in address; 44 struct hostent *hostinfo; 45 28 /* sfd sits _here_ only because of "repeat" option (-l -l). */ 29 int sfd = sfd; /* for gcc */ 30 int cfd = 0; 31 unsigned lport = 0; 32 SKIP_NC_SERVER(const) unsigned do_listen = 0; 33 SKIP_NC_EXTRA (const) unsigned wsecs = 0; 34 SKIP_NC_EXTRA (const) unsigned delay = 0; 35 SKIP_NC_EXTRA (const int execparam = 0;) 36 USE_NC_EXTRA (char **execparam = NULL;) 37 len_and_sockaddr *lsa; 46 38 fd_set readfds, testfds; 47 48 while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) { 49 switch (opt) { 50 case 'l': 51 do_listen++; 52 break; 53 case 'p': 54 lport = bb_lookup_port(optarg, "tcp", 0); 55 break; 56 case 'i': 57 delay = atoi(optarg); 58 break; 59 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE 60 case 'e': 61 pr00gie = optarg; 62 break; 63 #endif 64 case 'w': 65 wsecs = atoi(optarg); 66 break; 67 default: 68 bb_show_usage(); 69 } 70 } 71 72 if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) 73 bb_show_usage(); 74 75 sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0); 76 x = 1; 77 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1) 78 bb_perror_msg_and_die("reuseaddr"); 79 address.sin_family = AF_INET; 39 int opt; /* must be signed (getopt returns -1) */ 40 41 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { 42 /* getopt32 is _almost_ usable: 43 ** it cannot handle "... -e prog -prog-opt" */ 44 while ((opt = getopt(argc, argv, 45 "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0 46 ) { 47 if (ENABLE_NC_SERVER && opt=='l') USE_NC_SERVER(do_listen++); 48 else if (ENABLE_NC_SERVER && opt=='p') { 49 USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); 50 } 51 else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg)); 52 else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg)); 53 else if (ENABLE_NC_EXTRA && opt=='f') USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); 54 else if (ENABLE_NC_EXTRA && opt=='e' && optind<=argc) { 55 /* We cannot just 'break'. We should let getopt finish. 56 ** Or else we won't be able to find where 57 ** 'host' and 'port' params are 58 ** (think "nc -w 60 host port -e prog"). */ 59 USE_NC_EXTRA( 60 char **p; 61 // +2: one for progname (optarg) and one for NULL 62 execparam = xzalloc(sizeof(char*) * (argc - optind + 2)); 63 p = execparam; 64 *p++ = optarg; 65 while (optind < argc) { 66 *p++ = argv[optind++]; 67 } 68 ) 69 /* optind points to argv[arvc] (NULL) now. 70 ** FIXME: we assume that getopt will not count options 71 ** possibly present on "-e prog args" and will not 72 ** include them into final value of optind 73 ** which is to be used ... */ 74 } else bb_show_usage(); 75 } 76 argv += optind; /* ... here! */ 77 argc -= optind; 78 // -l and -f don't mix 79 if (do_listen && cfd) bb_show_usage(); 80 // Listen or file modes need zero arguments, client mode needs 2 81 if (do_listen || cfd) { 82 if (argc) bb_show_usage(); 83 } else { 84 if (!argc || argc > 2) bb_show_usage(); 85 } 86 } else { 87 if (argc != 3) bb_show_usage(); 88 argc--; 89 argv++; 90 } 80 91 81 92 if (wsecs) { … … 84 95 } 85 96 86 if (lport != 0) { 87 memset(&address.sin_addr, 0, sizeof(address.sin_addr)); 88 address.sin_port = lport; 89 90 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address)); 91 } 92 93 if (do_listen) { 94 socklen_t addrlen = sizeof(address); 95 96 bb_xlisten(sfd, 1); 97 if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) 98 bb_perror_msg_and_die("accept"); 99 100 close(sfd); 101 sfd = tmpfd; 102 } else { 103 hostinfo = xgethostbyname(argv[optind]); 104 105 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; 106 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); 107 108 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) 109 bb_perror_msg_and_die("connect"); 97 if (!cfd) { 98 if (do_listen) { 99 /* create_and_bind_stream_or_die(NULL, lport) 100 * would've work wonderfully, but we need 101 * to know lsa */ 102 sfd = xsocket_stream(&lsa); 103 if (lport) 104 set_nport(lsa, htons(lport)); 105 setsockopt_reuseaddr(sfd); 106 xbind(sfd, &lsa->sa, lsa->len); 107 xlisten(sfd, do_listen); /* can be > 1 */ 108 /* If we didn't specify a port number, 109 * query and print it after listen() */ 110 if (!lport) { 111 socklen_t addrlen = lsa->len; 112 getsockname(sfd, &lsa->sa, &addrlen); 113 lport = get_nport(&lsa->sa); 114 fdprintf(2, "%d\n", ntohs(lport)); 115 } 116 fcntl(sfd, F_SETFD, FD_CLOEXEC); 117 accept_again: 118 cfd = accept(sfd, NULL, 0); 119 if (cfd < 0) 120 bb_perror_msg_and_die("accept"); 121 if (!execparam) 122 close(sfd); 123 } else { 124 cfd = create_and_connect_stream_or_die(argv[0], 125 argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0); 126 } 110 127 } 111 128 … … 115 132 } 116 133 117 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE118 134 /* -e given? */ 119 if (pr00gie) { 120 dup2(sfd, 0); 121 close(sfd); 135 if (execparam) { 136 signal(SIGCHLD, SIG_IGN); 137 // With more than one -l, repeatedly act as server. 138 if (do_listen > 1 && vfork()) { 139 /* parent */ 140 // This is a bit weird as cleanup goes, since we wind up with no 141 // stdin/stdout/stderr. But it's small and shouldn't hurt anything. 142 // We check for cfd == 0 above. 143 logmode = LOGMODE_NONE; 144 close(0); 145 close(1); 146 close(2); 147 goto accept_again; 148 } 149 /* child (or main thread if no multiple -l) */ 150 if (cfd) { 151 dup2(cfd, 0); 152 close(cfd); 153 } 122 154 dup2(0, 1); 123 155 dup2(0, 2); 124 execl(pr00gie, pr00gie, NULL);156 USE_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) 125 157 /* Don't print stuff or it will go over the wire.... */ 126 _exit(-1); 127 } 128 #endif /* CONFIG_NC_GAPING_SECURITY_HOLE */ 158 _exit(127); 159 } 160 161 // Select loop copying stdin to cfd, and cfd to stdout. 129 162 130 163 FD_ZERO(&readfds); 131 FD_SET( sfd, &readfds);164 FD_SET(cfd, &readfds); 132 165 FD_SET(STDIN_FILENO, &readfds); 133 166 134 while (1) {167 for (;;) { 135 168 int fd; 136 169 int ofd; … … 142 175 bb_perror_msg_and_die("select"); 143 176 177 #define iobuf bb_common_bufsiz1 144 178 for (fd = 0; fd < FD_SETSIZE; fd++) { 145 179 if (FD_ISSET(fd, &testfds)) { 146 if ((nread = safe_read(fd, bb_common_bufsiz1, 147 sizeof(bb_common_bufsiz1))) < 0) 148 { 149 bb_perror_msg_and_die(bb_msg_read_error); 150 } 151 152 if (fd == sfd) { 153 if (nread == 0) 180 nread = safe_read(fd, iobuf, sizeof(iobuf)); 181 if (fd == cfd) { 182 if (nread < 1) 154 183 exit(0); 155 184 ofd = STDOUT_FILENO; 156 185 } else { 157 if (nread <= 0) { 158 shutdown(sfd, 1 /* send */ ); 159 close(STDIN_FILENO); 186 if (nread<1) { 187 // Close outgoing half-connection so they get EOF, but 188 // leave incoming alone so we can see response. 189 shutdown(cfd, 1); 160 190 FD_CLR(STDIN_FILENO, &readfds); 161 191 } 162 ofd = sfd;192 ofd = cfd; 163 193 } 164 165 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0) 166 bb_perror_msg_and_die(bb_msg_write_error); 167 if (delay > 0) { 168 sleep(delay); 169 } 194 xwrite(ofd, iobuf, nread); 195 if (delay > 0) sleep(delay); 170 196 } 171 197 } 172 198 } 173 199 } 200 #endif -
branches/2.2.5/mindi-busybox/networking/netstat.c
r821 r1765 6 6 * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com> 7 7 * 8 * This program is free software; you can redistribute it and/or modify9 * it under the terms of the GNU General Public License as published by10 * the Free Software Foundation; either version 2 of the License, or11 * (at your option) any later version.12 *13 * This program is distributed in the hope that it will be useful,14 * but WITHOUT ANY WARRANTY; without even the implied warranty of15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU16 * General Public License for more details.17 *18 * You should have received a copy of the GNU General Public License19 * along with this program; if not, write to the Free Software20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA21 *22 8 * 2002-04-20 23 9 * IPV6 support added by Bart Visscher <magick@linux-fan.com> 10 * 11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 24 12 */ 25 13 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <stdarg.h> 30 #include <signal.h> 31 #include <errno.h> 32 #include <sys/stat.h> 33 #include <dirent.h> 34 #include <unistd.h> 14 #include "libbb.h" 35 15 #include "inet_common.h" 36 #include "busybox.h"37 #include "pwd_.h"38 39 #ifdef CONFIG_ROUTE40 extern void displayroutes(int noresolve, int netstatfmt);41 #endif42 43 #define NETSTAT_CONNECTED 0x0144 #define NETSTAT_LISTENING 0x0245 #define NETSTAT_NUMERIC 0x0446 #define NETSTAT_TCP 0x1047 #define NETSTAT_UDP 0x2048 #define NETSTAT_RAW 0x4049 #define NETSTAT_UNIX 0x8050 51 static int flags = NETSTAT_CONNECTED |52 NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;53 54 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)55 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)56 #define PROGNAME_WIDTH2(s) #s57 58 #define PRG_HASH_SIZE 21159 16 60 17 enum { 61 TCP_ESTABLISHED = 1, 62 TCP_SYN_SENT, 63 TCP_SYN_RECV, 64 TCP_FIN_WAIT1, 65 TCP_FIN_WAIT2, 66 TCP_TIME_WAIT, 67 TCP_CLOSE, 68 TCP_CLOSE_WAIT, 69 TCP_LAST_ACK, 70 TCP_LISTEN, 71 TCP_CLOSING /* now a valid state */ 18 OPT_extended = 0x4, 19 OPT_showroute = 0x100, 20 OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE, 72 21 }; 73 74 static const char * const tcp_state[] = 75 { 76 "", 77 "ESTABLISHED", 78 "SYN_SENT", 79 "SYN_RECV", 80 "FIN_WAIT1", 81 "FIN_WAIT2", 82 "TIME_WAIT", 83 "CLOSE", 84 "CLOSE_WAIT", 85 "LAST_ACK", 86 "LISTEN", 87 "CLOSING" 22 # define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W") 23 24 #define NETSTAT_CONNECTED 0x01 25 #define NETSTAT_LISTENING 0x02 26 #define NETSTAT_NUMERIC 0x04 27 /* Must match getopt32 option string */ 28 #define NETSTAT_TCP 0x10 29 #define NETSTAT_UDP 0x20 30 #define NETSTAT_RAW 0x40 31 #define NETSTAT_UNIX 0x80 32 #define NETSTAT_ALLPROTO (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX) 33 34 static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; 35 36 enum { 37 TCP_ESTABLISHED = 1, 38 TCP_SYN_SENT, 39 TCP_SYN_RECV, 40 TCP_FIN_WAIT1, 41 TCP_FIN_WAIT2, 42 TCP_TIME_WAIT, 43 TCP_CLOSE, 44 TCP_CLOSE_WAIT, 45 TCP_LAST_ACK, 46 TCP_LISTEN, 47 TCP_CLOSING /* now a valid state */ 88 48 }; 89 49 50 static const char *const tcp_state[] = { 51 "", 52 "ESTABLISHED", 53 "SYN_SENT", 54 "SYN_RECV", 55 "FIN_WAIT1", 56 "FIN_WAIT2", 57 "TIME_WAIT", 58 "CLOSE", 59 "CLOSE_WAIT", 60 "LAST_ACK", 61 "LISTEN", 62 "CLOSING" 63 }; 64 90 65 typedef enum { 91 SS_FREE = 0,/* not allocated */92 SS_UNCONNECTED,/* unconnected to any socket */93 SS_CONNECTING,/* in process of connecting */94 SS_CONNECTED,/* connected to socket */95 SS_DISCONNECTING/* in process of disconnecting */66 SS_FREE = 0, /* not allocated */ 67 SS_UNCONNECTED, /* unconnected to any socket */ 68 SS_CONNECTING, /* in process of connecting */ 69 SS_CONNECTED, /* connected to socket */ 70 SS_DISCONNECTING /* in process of disconnecting */ 96 71 } socket_state; 97 72 98 #define SO_ACCEPTCON (1<<16) /* performed a listen */ 99 #define SO_WAITDATA (1<<17) /* wait data to read */ 100 #define SO_NOSPACE (1<<18) /* no space to write */ 101 102 static char *itoa(unsigned int i) 103 { 104 /* 21 digits plus null terminator, good for 64-bit or smaller ints */ 105 static char local[22]; 106 char *p = &local[21]; 107 *p-- = '\0'; 108 do { 109 *p-- = '0' + i % 10; 110 i /= 10; 111 } while (i > 0); 112 return p + 1; 113 } 114 115 static char *get_sname(int port, const char *proto, int num) 116 { 117 char *str=itoa(ntohs(port)); 118 if (num) { 73 #define SO_ACCEPTCON (1<<16) /* performed a listen */ 74 #define SO_WAITDATA (1<<17) /* wait data to read */ 75 #define SO_NOSPACE (1<<18) /* no space to write */ 76 77 /* Standard printout size */ 78 #define PRINT_IP_MAX_SIZE 23 79 #define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s\n" 80 #define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State\n" 81 82 /* When there are IPv6 connections the IPv6 addresses will be 83 * truncated to none-recognition. The '-W' option makes the 84 * address columns wide enough to accomodate for longest possible 85 * IPv6 addresses, i.e. addresses of the form 86 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd 87 */ 88 #define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ 89 #define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s\n" 90 #define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State\n" 91 92 static const char *net_conn_line = PRINT_NET_CONN; 93 94 95 #if ENABLE_FEATURE_IPV6 96 static void build_ipv6_addr(char* local_addr, struct sockaddr_in6* localaddr) 97 { 98 char addr6[INET6_ADDRSTRLEN]; 99 struct in6_addr in6; 100 101 sscanf(local_addr, "%08X%08X%08X%08X", 102 &in6.s6_addr32[0], &in6.s6_addr32[1], 103 &in6.s6_addr32[2], &in6.s6_addr32[3]); 104 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 105 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr->sin6_addr); 106 107 localaddr->sin6_family = AF_INET6; 108 } 109 #endif 110 111 #if ENABLE_FEATURE_IPV6 112 static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr) 113 #else 114 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; 120 } 121 122 static const char *get_sname(int port, const char *proto, int numeric) 123 { 124 if (!port) 125 return "*"; 126 if (!numeric) { 127 struct servent *se = getservbyport(port, proto); 128 if (se) 129 return se->s_name; 130 } 131 /* hummm, we may return static buffer here!! */ 132 return itoa(ntohs(port)); 133 } 134 135 static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric) 136 { 137 enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) }; 138 char *host, *host_port; 139 140 /* Code which used "*" for INADDR_ANY is removed: it's ambiguous in IPv6, 141 * while "0.0.0.0" is not. */ 142 143 host = numeric ? xmalloc_sockaddr2dotted_noport(addr) 144 : xmalloc_sockaddr2host_noport(addr); 145 146 host_port = xasprintf("%s:%s", host, get_sname(htons(port), proto, numeric)); 147 free(host); 148 return host_port; 149 } 150 151 static void tcp_do_one(int lnr, const char *line) 152 { 153 char local_addr[64], rem_addr[64]; 154 char more[512]; 155 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 156 #if ENABLE_FEATURE_IPV6 157 struct sockaddr_in6 localaddr, remaddr; 158 #else 159 struct sockaddr_in localaddr, remaddr; 160 #endif 161 unsigned long rxq, txq, time_len, retr, inode; 162 163 if (lnr == 0) 164 return; 165 166 more[0] = '\0'; 167 num = sscanf(line, 168 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 169 &d, local_addr, &local_port, 170 rem_addr, &rem_port, &state, 171 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 172 173 if (strlen(local_addr) > 8) { 174 #if ENABLE_FEATURE_IPV6 175 build_ipv6_addr(local_addr, &localaddr); 176 build_ipv6_addr(rem_addr, &remaddr); 177 #endif 119 178 } else { 120 struct servent *se=getservbyport(port,proto); 121 if (se) 122 str=se->s_name; 123 } 124 if (!port) { 125 str="*"; 126 } 127 return str; 128 } 129 130 static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric) 131 { 132 char *port_name; 133 134 #ifdef CONFIG_FEATURE_IPV6 135 if (addr->sa_family == AF_INET6) { 136 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr, 137 (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0); 138 } else 139 #endif 140 { 141 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr, 142 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0), 143 0xffffffff); 144 } 145 port_name=get_sname(htons(port), proto, numeric); 146 if ((strlen(ip_port) + strlen(port_name)) > 22) 147 ip_port[22 - strlen(port_name)] = '\0'; 148 ip_port+=strlen(ip_port); 149 strcat(ip_port, ":"); 150 strcat(ip_port, port_name); 151 } 152 153 static void tcp_do_one(int lnr, const char *line) 179 build_ipv4_addr(local_addr, &localaddr); 180 build_ipv4_addr(rem_addr, &remaddr); 181 } 182 183 if (num < 10) { 184 bb_error_msg("warning, got bogus tcp line"); 185 return; 186 } 187 188 if ((rem_port && (flags & NETSTAT_CONNECTED)) 189 || (!rem_port && (flags & NETSTAT_LISTENING)) 190 ) { 191 char *l = ip_port_str( 192 (struct sockaddr *) &localaddr, local_port, 193 "tcp", flags & NETSTAT_NUMERIC); 194 char *r = ip_port_str( 195 (struct sockaddr *) &remaddr, rem_port, 196 "tcp", flags & NETSTAT_NUMERIC); 197 printf(net_conn_line, 198 "tcp", rxq, txq, l, r, tcp_state[state]); 199 free(l); 200 free(r); 201 } 202 } 203 204 static void udp_do_one(int lnr, const char *line) 154 205 { 155 206 char local_addr[64], rem_addr[64]; … … 157 208 char more[512]; 158 209 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 159 #if def CONFIG_FEATURE_IPV6210 #if ENABLE_FEATURE_IPV6 160 211 struct sockaddr_in6 localaddr, remaddr; 161 char addr6[INET6_ADDRSTRLEN];162 struct in6_addr in6;163 212 #else 164 213 struct sockaddr_in localaddr, remaddr; … … 171 220 more[0] = '\0'; 172 221 num = sscanf(line, 173 174 175 176 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); 177 226 178 227 if (strlen(local_addr) > 8) { 179 #ifdef CONFIG_FEATURE_IPV6 180 sscanf(local_addr, "%08X%08X%08X%08X", 181 &in6.s6_addr32[0], &in6.s6_addr32[1], 182 &in6.s6_addr32[2], &in6.s6_addr32[3]); 183 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 184 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr); 185 sscanf(rem_addr, "%08X%08X%08X%08X", 186 &in6.s6_addr32[0], &in6.s6_addr32[1], 187 &in6.s6_addr32[2], &in6.s6_addr32[3]); 188 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 189 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr); 190 localaddr.sin6_family = AF_INET6; 191 remaddr.sin6_family = AF_INET6; 228 #if ENABLE_FEATURE_IPV6 229 /* Demangle what the kernel gives us */ 230 build_ipv6_addr(local_addr, &localaddr); 231 build_ipv6_addr(rem_addr, &remaddr); 192 232 #endif 193 233 } else { 194 sscanf(local_addr, "%X", 195 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 196 sscanf(rem_addr, "%X", 197 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr); 198 ((struct sockaddr *) &localaddr)->sa_family = AF_INET; 199 ((struct sockaddr *) &remaddr)->sa_family = AF_INET; 234 build_ipv4_addr(local_addr, &localaddr); 235 build_ipv4_addr(rem_addr, &remaddr); 200 236 } 201 237 202 238 if (num < 10) { 203 bb_error_msg("warning, got bogus tcp line."); 204 return; 205 } 206 state_str = tcp_state[state]; 207 if ((rem_port && (flags&NETSTAT_CONNECTED)) || 208 (!rem_port && (flags&NETSTAT_LISTENING))) 209 { 210 snprint_ip_port(local_addr, sizeof(local_addr), 211 (struct sockaddr *) &localaddr, local_port, 212 "tcp", flags&NETSTAT_NUMERIC); 213 214 snprint_ip_port(rem_addr, sizeof(rem_addr), 215 (struct sockaddr *) &remaddr, rem_port, 216 "tcp", flags&NETSTAT_NUMERIC); 217 218 printf("tcp %6ld %6ld %-23s %-23s %-12s\n", 219 rxq, txq, local_addr, rem_addr, state_str); 220 221 } 222 } 223 224 static void udp_do_one(int lnr, const char *line) 225 { 226 char local_addr[64], rem_addr[64]; 227 char *state_str, more[512]; 228 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 229 #ifdef CONFIG_FEATURE_IPV6 230 struct sockaddr_in6 localaddr, remaddr; 231 char addr6[INET6_ADDRSTRLEN]; 232 struct in6_addr in6; 233 #else 234 struct sockaddr_in localaddr, remaddr; 235 #endif 236 unsigned long rxq, txq, time_len, retr, inode; 237 238 if (lnr == 0) 239 return; 240 241 more[0] = '\0'; 242 num = sscanf(line, 243 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 244 &d, local_addr, &local_port, 245 rem_addr, &rem_port, &state, 246 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 247 248 if (strlen(local_addr) > 8) { 249 #ifdef CONFIG_FEATURE_IPV6 250 /* Demangle what the kernel gives us */ 251 sscanf(local_addr, "%08X%08X%08X%08X", 252 &in6.s6_addr32[0], &in6.s6_addr32[1], 253 &in6.s6_addr32[2], &in6.s6_addr32[3]); 254 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 255 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr); 256 sscanf(rem_addr, "%08X%08X%08X%08X", 257 &in6.s6_addr32[0], &in6.s6_addr32[1], 258 &in6.s6_addr32[2], &in6.s6_addr32[3]); 259 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 260 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr); 261 localaddr.sin6_family = AF_INET6; 262 remaddr.sin6_family = AF_INET6; 263 #endif 264 } else { 265 sscanf(local_addr, "%X", 266 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 267 sscanf(rem_addr, "%X", 268 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr); 269 ((struct sockaddr *) &localaddr)->sa_family = AF_INET; 270 ((struct sockaddr *) &remaddr)->sa_family = AF_INET; 271 } 272 273 if (num < 10) { 274 bb_error_msg("warning, got bogus udp line."); 239 bb_error_msg("warning, got bogus udp line"); 275 240 return; 276 241 } … … 279 244 state_str = "ESTABLISHED"; 280 245 break; 281 282 246 case TCP_CLOSE: 283 247 state_str = ""; 284 248 break; 285 286 249 default: 287 250 state_str = "UNKNOWN"; … … 289 252 } 290 253 291 #ifdef CONFIG_FEATURE_IPV6 292 # define notnull(A) (((A.sin6_family == AF_INET6) && \ 293 ((A.sin6_addr.s6_addr32[0]) || \ 294 (A.sin6_addr.s6_addr32[1]) || \ 295 (A.sin6_addr.s6_addr32[2]) || \ 296 (A.sin6_addr.s6_addr32[3]))) || \ 297 ((A.sin6_family == AF_INET) && \ 298 ((struct sockaddr_in *) &A)->sin_addr.s_addr)) 254 #if ENABLE_FEATURE_IPV6 255 # define notnull(A) ( \ 256 ( (A.sin6_family == AF_INET6) \ 257 && (A.sin6_addr.s6_addr32[0] | A.sin6_addr.s6_addr32[1] | \ 258 A.sin6_addr.s6_addr32[2] | A.sin6_addr.s6_addr32[3]) \ 259 ) || ( \ 260 (A.sin6_family == AF_INET) \ 261 && ((struct sockaddr_in*)&A)->sin_addr.s_addr \ 262 ) \ 263 ) 299 264 #else 300 265 # define notnull(A) (A.sin_addr.s_addr) 301 266 #endif 302 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||303 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))304 267 { 305 snprint_ip_port(local_addr, sizeof(local_addr), 306 (struct sockaddr *) &localaddr, local_port, 307 "udp", flags&NETSTAT_NUMERIC); 308 309 snprint_ip_port(rem_addr, sizeof(rem_addr), 310 (struct sockaddr *) &remaddr, rem_port, 311 "udp", flags&NETSTAT_NUMERIC); 312 313 printf("udp %6ld %6ld %-23s %-23s %-12s\n", 314 rxq, txq, local_addr, rem_addr, state_str); 315 268 int have_remaddr = notnull(remaddr); 269 if ((have_remaddr && (flags & NETSTAT_CONNECTED)) 270 || (!have_remaddr && (flags & NETSTAT_LISTENING)) 271 ) { 272 char *l = ip_port_str( 273 (struct sockaddr *) &localaddr, local_port, 274 "udp", flags & NETSTAT_NUMERIC); 275 char *r = ip_port_str( 276 (struct sockaddr *) &remaddr, rem_port, 277 "udp", flags & NETSTAT_NUMERIC); 278 printf(net_conn_line, 279 "udp", rxq, txq, l, r, state_str); 280 free(l); 281 free(r); 282 } 316 283 } 317 284 } … … 320 287 { 321 288 char local_addr[64], rem_addr[64]; 322 char *state_str,more[512];289 char more[512]; 323 290 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 324 #if def CONFIG_FEATURE_IPV6291 #if ENABLE_FEATURE_IPV6 325 292 struct sockaddr_in6 localaddr, remaddr; 326 char addr6[INET6_ADDRSTRLEN];327 struct in6_addr in6;328 293 #else 329 294 struct sockaddr_in localaddr, remaddr; … … 336 301 more[0] = '\0'; 337 302 num = sscanf(line, 338 339 340 341 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); 342 307 343 308 if (strlen(local_addr) > 8) { 344 #ifdef CONFIG_FEATURE_IPV6 345 sscanf(local_addr, "%08X%08X%08X%08X", 346 &in6.s6_addr32[0], &in6.s6_addr32[1], 347 &in6.s6_addr32[2], &in6.s6_addr32[3]); 348 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 349 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr); 350 sscanf(rem_addr, "%08X%08X%08X%08X", 351 &in6.s6_addr32[0], &in6.s6_addr32[1], 352 &in6.s6_addr32[2], &in6.s6_addr32[3]); 353 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 354 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr); 355 localaddr.sin6_family = AF_INET6; 356 remaddr.sin6_family = AF_INET6; 309 #if ENABLE_FEATURE_IPV6 310 build_ipv6_addr(local_addr, &localaddr); 311 build_ipv6_addr(rem_addr, &remaddr); 357 312 #endif 358 313 } else { 359 sscanf(local_addr, "%X", 360 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 361 sscanf(rem_addr, "%X", 362 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr); 363 ((struct sockaddr *) &localaddr)->sa_family = AF_INET; 364 ((struct sockaddr *) &remaddr)->sa_family = AF_INET; 314 build_ipv4_addr(local_addr, &localaddr); 315 build_ipv4_addr(rem_addr, &remaddr); 365 316 } 366 317 367 318 if (num < 10) { 368 bb_error_msg("warning, got bogus raw line."); 369 return; 370 } 371 state_str=itoa(state); 372 373 #ifdef CONFIG_FEATURE_IPV6 374 # define notnull(A) (((A.sin6_family == AF_INET6) && \ 375 ((A.sin6_addr.s6_addr32[0]) || \ 376 (A.sin6_addr.s6_addr32[1]) || \ 377 (A.sin6_addr.s6_addr32[2]) || \ 378 (A.sin6_addr.s6_addr32[3]))) || \ 379 ((A.sin6_family == AF_INET) && \ 380 ((struct sockaddr_in *) &A)->sin_addr.s_addr)) 381 #else 382 # define notnull(A) (A.sin_addr.s_addr) 383 #endif 384 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || 385 (!notnull(remaddr) && (flags&NETSTAT_LISTENING))) 319 bb_error_msg("warning, got bogus raw line"); 320 return; 321 } 322 386 323 { 387 snprint_ip_port(local_addr, sizeof(local_addr), 388 (struct sockaddr *) &localaddr, local_port, 389 "raw", flags&NETSTAT_NUMERIC); 390 391 snprint_ip_port(rem_addr, sizeof(rem_addr), 392 (struct sockaddr *) &remaddr, rem_port, 393 "raw", flags&NETSTAT_NUMERIC); 394 395 printf("raw %6ld %6ld %-23s %-23s %-12s\n", 396 rxq, txq, local_addr, rem_addr, state_str); 397 398 } 399 } 400 401 #define HAS_INODE 1 324 int have_remaddr = notnull(remaddr); 325 if ((have_remaddr && (flags & NETSTAT_CONNECTED)) 326 || (!have_remaddr && (flags & NETSTAT_LISTENING)) 327 ) { 328 char *l = ip_port_str( 329 (struct sockaddr *) &localaddr, local_port, 330 "raw", flags & NETSTAT_NUMERIC); 331 char *r = ip_port_str( 332 (struct sockaddr *) &remaddr, rem_port, 333 "raw", flags & NETSTAT_NUMERIC); 334 printf(net_conn_line, 335 "raw", rxq, txq, l, r, itoa(state)); 336 free(l); 337 free(r); 338 } 339 } 340 } 402 341 403 342 static void unix_do_one(int nr, const char *line) 404 343 { 405 static int has = 0; 344 static smallint has_inode = 0; 345 406 346 char path[PATH_MAX], ss_flags[32]; 407 c har *ss_proto, *ss_state, *ss_type;347 const char *ss_proto, *ss_state, *ss_type; 408 348 int num, state, type, inode; 409 349 void *d; … … 412 352 if (nr == 0) { 413 353 if (strstr(line, "Inode")) 414 has |= HAS_INODE;354 has_inode = 1; 415 355 return; 416 356 } 417 357 path[0] = '\0'; 418 358 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s", 419 359 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path); 420 360 if (num < 6) { 421 bb_error_msg("warning, got bogus unix line .");422 return; 423 } 424 if (! (has & HAS_INODE))425 s nprintf(path,sizeof(path),"%d",inode);426 427 if ((flags &(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {361 bb_error_msg("warning, got bogus unix line"); 362 return; 363 } 364 if (!has_inode) 365 sprintf(path, "%d", inode); 366 367 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) { 428 368 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) { 429 if (!(flags &NETSTAT_LISTENING))369 if (!(flags & NETSTAT_LISTENING)) 430 370 return; 431 371 } else { 432 if (!(flags &NETSTAT_CONNECTED))372 if (!(flags & NETSTAT_CONNECTED)) 433 373 return; 434 374 } … … 439 379 ss_proto = "unix"; 440 380 break; 441 442 381 default: 443 382 ss_proto = "??"; … … 448 387 ss_type = "STREAM"; 449 388 break; 450 451 389 case SOCK_DGRAM: 452 390 ss_type = "DGRAM"; 453 391 break; 454 455 392 case SOCK_RAW: 456 393 ss_type = "RAW"; 457 394 break; 458 459 395 case SOCK_RDM: 460 396 ss_type = "RDM"; 461 397 break; 462 463 398 case SOCK_SEQPACKET: 464 399 ss_type = "SEQPACKET"; 465 400 break; 466 467 401 default: 468 402 ss_type = "UNKNOWN"; … … 473 407 ss_state = "FREE"; 474 408 break; 475 476 409 case SS_UNCONNECTED: 477 410 /* … … 485 418 } 486 419 break; 487 488 420 case SS_CONNECTING: 489 421 ss_state = "CONNECTING"; 490 422 break; 491 492 423 case SS_CONNECTED: 493 424 ss_state = "CONNECTED"; 494 425 break; 495 496 426 case SS_DISCONNECTING: 497 427 ss_state = "DISCONNECTING"; 498 428 break; 499 500 429 default: 501 430 ss_state = "UNKNOWN"; … … 509 438 if (unix_flags & SO_NOSPACE) 510 439 strcat(ss_flags, "N "); 511 512 440 strcat(ss_flags, "]"); 513 441 514 442 printf("%-5s %-6ld %-11s %-10s %-13s ", 515 443 ss_proto, refcnt, ss_flags, ss_type, ss_state); 516 if (has & HAS_INODE)517 printf("%-6d ", inode);444 if (has_inode) 445 printf("%-6d ", inode); 518 446 else 519 447 printf("- "); … … 531 459 static void do_info(const char *file, const char *name, void (*proc)(int, const char *)) 532 460 { 533 char buffer[8192];534 461 int lnr = 0; 535 462 FILE *procinfo; … … 538 465 if (procinfo == NULL) { 539 466 if (errno != ENOENT) { 540 perror(file);467 bb_perror_msg("%s", file); 541 468 } else { 542 bb_error_msg("no support for `%s' on this system.", name);469 bb_error_msg("no support for '%s' on this system", name); 543 470 } 544 } else { 545 do { 546 if (fgets(buffer, sizeof(buffer), procinfo)) 547 (proc)(lnr++, buffer); 548 } while (!feof(procinfo)); 549 fclose(procinfo); 550 } 471 return; 472 } 473 do { 474 char *buffer = xmalloc_fgets(procinfo); 475 if (buffer) { 476 (proc)(lnr++, buffer); 477 free(buffer); 478 } 479 } while (!feof(procinfo)); 480 fclose(procinfo); 551 481 } 552 482 … … 555 485 */ 556 486 487 int netstat_main(int argc, char **argv); 557 488 int netstat_main(int argc, char **argv) 558 489 { 559 int opt; 560 int new_flags=0; 561 int showroute = 0, extended = 0; 562 #ifdef CONFIG_FEATURE_IPV6 563 int inet=1; 564 int inet6=1; 565 #else 566 # define inet 1 567 # define inet6 0 568 #endif 569 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1) 570 switch (opt) { 571 case 'l': 572 flags &= ~NETSTAT_CONNECTED; 573 flags |= NETSTAT_LISTENING; 574 break; 575 case 'a': 576 flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; 577 break; 578 case 'n': 579 flags |= NETSTAT_NUMERIC; 580 break; 581 case 'r': 582 showroute = 1; 583 break; 584 case 'e': 585 extended = 1; 586 break; 587 case 't': 588 new_flags |= NETSTAT_TCP; 589 break; 590 case 'u': 591 new_flags |= NETSTAT_UDP; 592 break; 593 case 'w': 594 new_flags |= NETSTAT_RAW; 595 break; 596 case 'x': 597 new_flags |= NETSTAT_UNIX; 598 break; 599 default: 600 bb_show_usage(); 601 } 602 if ( showroute ) { 603 #ifdef CONFIG_ROUTE 604 displayroutes ( flags & NETSTAT_NUMERIC, !extended ); 490 const char *net_conn_line_header = PRINT_NET_CONN_HEADER; 491 unsigned opt; 492 #if ENABLE_FEATURE_IPV6 493 smallint inet = 1; 494 smallint inet6 = 1; 495 #else 496 enum { inet = 1, inet6 = 0 }; 497 #endif 498 499 /* Option string must match NETSTAT_xxx constants */ 500 opt = getopt32(argv, NETSTAT_OPTS); 501 if (opt & 0x1) { // -l 502 flags &= ~NETSTAT_CONNECTED; 503 flags |= NETSTAT_LISTENING; 504 } 505 if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a 506 //if (opt & 0x4) // -e 507 if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n 508 //if (opt & 0x10) // -t: NETSTAT_TCP 509 //if (opt & 0x20) // -u: NETSTAT_UDP 510 //if (opt & 0x40) // -w: NETSTAT_RAW 511 //if (opt & 0x80) // -x: NETSTAT_UNIX 512 if (opt & OPT_showroute) { // -r 513 #if ENABLE_ROUTE 514 bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); 605 515 return 0; 606 516 #else 607 bb_error_msg_and_die( "-r (display routing table) is not compiled in." ); 608 #endif 609 } 610 611 if (new_flags) { 612 flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX); 613 flags |= new_flags; 614 } 615 if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { 517 bb_show_usage(); 518 #endif 519 } 520 521 if (opt & OPT_widedisplay) { // -W 522 net_conn_line = PRINT_NET_CONN_WIDE; 523 net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; 524 } 525 526 opt &= NETSTAT_ALLPROTO; 527 if (opt) { 528 flags &= ~NETSTAT_ALLPROTO; 529 flags |= opt; 530 } 531 if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { 616 532 printf("Active Internet connections "); /* xxx */ 617 533 618 if ((flags &(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))534 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) 619 535 printf("(servers and established)"); 620 else { 621 if (flags&NETSTAT_LISTENING) 622 printf("(only servers)"); 623 else 624 printf("(w/o servers)"); 625 } 626 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n"); 627 } 628 if (inet && flags&NETSTAT_TCP) 629 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one); 630 #ifdef CONFIG_FEATURE_IPV6 631 if (inet6 && flags&NETSTAT_TCP) 632 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one); 633 #endif 634 if (inet && flags&NETSTAT_UDP) 635 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one); 636 #ifdef CONFIG_FEATURE_IPV6 637 if (inet6 && flags&NETSTAT_UDP) 638 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one); 639 #endif 640 if (inet && flags&NETSTAT_RAW) 641 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one); 642 #ifdef CONFIG_FEATURE_IPV6 643 if (inet6 && flags&NETSTAT_RAW) 644 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one); 645 #endif 646 if (flags&NETSTAT_UNIX) { 536 else if (flags & NETSTAT_LISTENING) 537 printf("(only servers)"); 538 else 539 printf("(w/o servers)"); 540 printf(net_conn_line_header, "Local Address", "Foreign Address"); 541 } 542 if (inet && flags & NETSTAT_TCP) 543 do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one); 544 #if ENABLE_FEATURE_IPV6 545 if (inet6 && flags & NETSTAT_TCP) 546 do_info(_PATH_PROCNET_TCP6, "AF INET6 (tcp)", tcp_do_one); 547 #endif 548 if (inet && flags & NETSTAT_UDP) 549 do_info(_PATH_PROCNET_UDP, "AF INET (udp)", udp_do_one); 550 #if ENABLE_FEATURE_IPV6 551 if (inet6 && flags & NETSTAT_UDP) 552 do_info(_PATH_PROCNET_UDP6, "AF INET6 (udp)", udp_do_one); 553 #endif 554 if (inet && flags & NETSTAT_RAW) 555 do_info(_PATH_PROCNET_RAW, "AF INET (raw)", raw_do_one); 556 #if ENABLE_FEATURE_IPV6 557 if (inet6 && flags & NETSTAT_RAW) 558 do_info(_PATH_PROCNET_RAW6, "AF INET6 (raw)", raw_do_one); 559 #endif 560 if (flags & NETSTAT_UNIX) { 647 561 printf("Active UNIX domain sockets "); 648 if ((flags &(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))562 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) 649 563 printf("(servers and established)"); 650 else { 651 if (flags&NETSTAT_LISTENING) 652 printf("(only servers)"); 653 else 654 printf("(w/o servers)"); 655 } 656 564 else if (flags & NETSTAT_LISTENING) 565 printf("(only servers)"); 566 else 567 printf("(w/o servers)"); 657 568 printf("\nProto RefCnt Flags Type State I-Node Path\n"); 658 do_info(_PATH_PROCNET_UNIX, "AF UNIX",unix_do_one);569 do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one); 659 570 } 660 571 return 0; -
branches/2.2.5/mindi-busybox/networking/nslookup.c
r821 r1765 9 9 * added by Ben Zeckel <bzeckel@hmc.edu> June 2001 10 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 * 11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 25 12 */ 26 13 27 #include <ctype.h>28 #include <errno.h>29 #include <stdio.h>30 #include <string.h>31 #include <stdlib.h>32 33 #include <stdint.h>34 #include <netdb.h>35 #include <sys/socket.h>36 #include <sys/types.h>37 #include <netinet/in.h>38 14 #include <resolv.h> 39 #include <arpa/inet.h> 40 #include "busybox.h" 15 #include "libbb.h" 41 16 42 17 /* 43 |I'm only implementing non-interactive mode;44 |I totally forgot nslookup even had an interactive mode.18 * I'm only implementing non-interactive mode; 19 * I totally forgot nslookup even had an interactive mode. 45 20 */ 46 21 47 /* only works for IPv4 */ 48 static int addr_fprint(char *addr) 22 /* Examples of 'standard' nslookup output 23 * $ nslookup yahoo.com 24 * Server: 128.193.0.10 25 * Address: 128.193.0.10#53 26 * 27 * Non-authoritative answer: 28 * Name: yahoo.com 29 * Address: 216.109.112.135 30 * Name: yahoo.com 31 * Address: 66.94.234.13 32 * 33 * $ nslookup 204.152.191.37 34 * Server: 128.193.4.20 35 * Address: 128.193.4.20#53 36 * 37 * Non-authoritative answer: 38 * 37.191.152.204.in-addr.arpa canonical name = 37.32-27.191.152.204.in-addr.arpa. 39 * 37.32-27.191.152.204.in-addr.arpa name = zeus-pub2.kernel.org. 40 * 41 * Authoritative answers can be found from: 42 * 32-27.191.152.204.in-addr.arpa nameserver = ns1.kernel.org. 43 * 32-27.191.152.204.in-addr.arpa nameserver = ns2.kernel.org. 44 * 32-27.191.152.204.in-addr.arpa nameserver = ns3.kernel.org. 45 * ns1.kernel.org internet address = 140.211.167.34 46 * ns2.kernel.org internet address = 204.152.191.4 47 * ns3.kernel.org internet address = 204.152.191.36 48 */ 49 50 static int print_host(const char *hostname, const char *header) 49 51 { 50 uint8_t split[4]; 51 uint32_t ip; 52 uint32_t *x = (uint32_t *) addr; 52 /* We can't use xhost2sockaddr() - we want to get ALL addresses, 53 * not just one */ 53 54 54 ip = ntohl(*x); 55 split[0] = (ip & 0xff000000) >> 24; 56 split[1] = (ip & 0x00ff0000) >> 16; 57 split[2] = (ip & 0x0000ff00) >> 8; 58 split[3] = (ip & 0x000000ff); 59 printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]); 60 return 0; 61 } 55 struct addrinfo *result = NULL; 56 int rc; 57 struct addrinfo hint; 62 58 63 /* takes the NULL-terminated array h_addr_list, and 64 * prints its contents appropriately 65 */ 66 static int addr_list_fprint(char **h_addr_list) 67 { 68 int i, j; 69 char *addr_string = (h_addr_list[1]) 70 ? "Addresses: " : "Address: "; 59 memset(&hint, 0 , sizeof(hint)); 60 /* hint.ai_family = AF_UNSPEC; - zero anyway */ 61 /* Needed. Or else we will get each address thrice (or more) 62 * for each possible socket type (tcp,udp,raw...): */ 63 hint.ai_socktype = SOCK_STREAM; 64 // hint.ai_flags = AI_CANONNAME; 65 rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result); 71 66 72 printf("%s ", addr_string);73 for (i = 0, j = 0; h_addr_list[i]; i++, j++) {74 addr_fprint(h_addr_list[i]);67 if (!rc) { 68 struct addrinfo *cur = result; 69 unsigned cnt = 0; 75 70 76 /* real nslookup does this */ 77 if (j == 4) { 78 if (h_addr_list[i + 1]) { 79 printf("\n "); 71 printf("%-10s %s\n", header, hostname); 72 // printf("%s\n", cur->ai_canonname); ? 73 while (cur) { 74 char *dotted, *revhost; 75 dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr); 76 revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr); 77 78 printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n'); 79 if (revhost) { 80 puts(revhost); 81 if (ENABLE_FEATURE_CLEAN_UP) 82 free(revhost); 80 83 } 81 j = 0; 82 } else { 83 if (h_addr_list[i + 1]) { 84 printf(", "); 85 } 84 if (ENABLE_FEATURE_CLEAN_UP) 85 free(dotted); 86 cur = cur->ai_next; 86 87 } 87 88 } else { 89 #if ENABLE_VERBOSE_RESOLUTION_ERRORS 90 bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc)); 91 #else 92 bb_error_msg("can't resolve '%s'", hostname); 93 #endif 88 94 } 89 printf("\n"); 90 return 0; 91 } 92 93 /* print the results as nslookup would */ 94 static struct hostent *hostent_fprint(struct hostent *host, const char *server_host) 95 { 96 if (host) { 97 printf("%s %s\n", server_host, host->h_name); 98 addr_list_fprint(host->h_addr_list); 99 } else { 100 printf("*** Unknown host\n"); 101 } 102 return host; 103 } 104 105 /* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+ 106 * into a uint32_t 107 */ 108 static uint32_t str_to_addr(const char *addr) 109 { 110 uint32_t split[4]; 111 uint32_t ip; 112 113 sscanf(addr, "%d.%d.%d.%d", 114 &split[0], &split[1], &split[2], &split[3]); 115 116 /* assuming sscanf worked */ 117 ip = (split[0] << 24) | 118 (split[1] << 16) | (split[2] << 8) | (split[3]); 119 120 return htonl(ip); 121 } 122 123 /* gethostbyaddr wrapper */ 124 static struct hostent *gethostbyaddr_wrapper(const char *address) 125 { 126 struct in_addr addr; 127 128 addr.s_addr = str_to_addr(address); 129 return gethostbyaddr((char *) &addr, 4, AF_INET); /* IPv4 only for now */ 95 if (ENABLE_FEATURE_CLEAN_UP) 96 freeaddrinfo(result); 97 return (rc != 0); 130 98 } 131 99 132 100 /* lookup the default nameserver and display it */ 133 static inlinevoid server_print(void)101 static void server_print(void) 134 102 { 135 struct sockaddr_in def = _res.nsaddr_list[0]; 136 char *ip = inet_ntoa(def.sin_addr); 103 char *server; 137 104 138 hostent_fprint(gethostbyaddr_wrapper(ip), "Server:"); 139 printf("\n"); 105 server = xmalloc_sockaddr2dotted_noport((struct sockaddr*)&_res.nsaddr_list[0]); 106 /* I honestly don't know what to do if DNS server has _IPv6 address_. 107 * Probably it is listed in 108 * _res._u._ext_.nsaddrs[MAXNS] (of type "struct sockaddr_in6*" each) 109 * but how to find out whether resolver uses 110 * _res.nsaddr_list[] or _res._u._ext_.nsaddrs[], or both? 111 * Looks like classic design from hell, BIND-grade. Hard to surpass. */ 112 print_host(server, "Server:"); 113 if (ENABLE_FEATURE_CLEAN_UP) 114 free(server); 115 puts(""); 140 116 } 141 117 142 118 /* alter the global _res nameserver structure to use 143 119 an explicit dns server instead of what is in /etc/resolv.h */ 144 static inlinevoid set_default_dns(char *server)120 static void set_default_dns(char *server) 145 121 { 146 122 struct in_addr server_in_addr; 147 123 148 if(inet_aton(server,&server_in_addr)) 149 { 124 if (inet_pton(AF_INET, server, &server_in_addr) > 0) { 150 125 _res.nscount = 1; 151 126 _res.nsaddr_list[0].sin_addr = server_in_addr; … … 153 128 } 154 129 155 /* naive function to check whether char *s is an ip address */ 156 static int is_ip_address(const char *s) 157 { 158 while (*s) { 159 if ((isdigit(*s)) || (*s == '.')) { 160 s++; 161 continue; 162 } 163 return 0; 164 } 165 return 1; 166 } 167 168 /* ________________________________________________________________________ */ 130 int nslookup_main(int argc, char **argv); 169 131 int nslookup_main(int argc, char **argv) 170 132 { 171 struct hostent *host; 133 /* We allow 1 or 2 arguments. 134 * The first is the name to be looked up and the second is an 135 * optional DNS server with which to do the lookup. 136 * More than 3 arguments is an error to follow the pattern of the 137 * standard nslookup */ 172 138 173 /* 174 * initialize DNS structure _res used in printing the default 175 * name server and in the explicit name server option feature. 176 */ 139 if (argc < 2 || *argv[1] == '-' || argc > 3) 140 bb_show_usage(); 177 141 142 /* initialize DNS structure _res used in printing the default 143 * name server and in the explicit name server option feature. */ 178 144 res_init(); 145 /* rfc2133 says this enables IPv6 lookups */ 146 /* (but it also says "may be enabled in /etc/resolv.conf|) */ 147 /*_res.options |= RES_USE_INET6;*/ 179 148 180 /* 181 * We allow 1 or 2 arguments. 182 * The first is the name to be looked up and the second is an 183 * optional DNS server with which to do the lookup. 184 * More than 3 arguments is an error to follow the pattern of the 185 * standard nslookup 186 */ 187 188 if (argc < 2 || *argv[1]=='-' || argc > 3) 189 bb_show_usage(); 190 else if(argc == 3) 149 if (argc == 3) 191 150 set_default_dns(argv[2]); 192 151 193 152 server_print(); 194 if (is_ip_address(argv[1])) { 195 host = gethostbyaddr_wrapper(argv[1]); 196 } else { 197 host = xgethostbyname(argv[1]); 198 } 199 hostent_fprint(host, "Name: "); 200 if (host) { 201 return EXIT_SUCCESS; 202 } 203 return EXIT_FAILURE; 153 return print_host(argv[1], "Name:"); 204 154 } 205 206 /* $Id: nslookup.c,v 1.33 2004/10/13 07:25:01 andersen Exp $ */ -
branches/2.2.5/mindi-busybox/networking/ping.c
r821 r1765 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * $Id: ping.c,v 1.56 2004/03/15 08:28:48 andersen Exp $4 3 * Mini ping implementation for busybox 5 4 * … … 8 7 * Adapted from the ping in netkit-base 0.10: 9 8 * Copyright (c) 1989 The Regents of the University of California. 10 * Derived from software contributed to Berkeley by Mike Muuss. 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to Berkeley by 12 * Mike Muuss. 11 13 * 12 14 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 13 15 */ 14 15 #include <sys/param.h> 16 #include <sys/socket.h> 17 #include <sys/file.h> 18 #include <sys/times.h> 19 #include <signal.h> 20 21 #include <netinet/in.h> 22 #include <netinet/ip.h> 16 /* from ping6.c: 17 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> 18 * 19 * This version of ping is adapted from the ping in netkit-base 0.10, 20 * which is: 21 * 22 * Original copyright notice is retained at the end of this file. 23 * 24 * This version is an adaptation of ping.c from busybox. 25 * The code was modified by Bart Visscher <magick@linux-fan.com> 26 */ 27 28 #include <net/if.h> 23 29 #include <netinet/ip_icmp.h> 24 #include <arpa/inet.h> 25 #include <netdb.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <errno.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include "busybox.h" 33 30 #include "libbb.h" 31 32 #if ENABLE_PING6 33 #include <netinet/icmp6.h> 34 /* I see RENUMBERED constants in bits/in.h - !!? 35 * What a fuck is going on with libc? Is it a glibc joke? */ 36 #ifdef IPV6_2292HOPLIMIT 37 #undef IPV6_HOPLIMIT 38 #define IPV6_HOPLIMIT IPV6_2292HOPLIMIT 39 #endif 40 #endif 34 41 35 42 enum { … … 40 47 MAX_DUP_CHK = (8 * 128), 41 48 MAXWAIT = 10, 42 PINGINTERVAL = 1 /*second */49 PINGINTERVAL = 1, /* 1 second */ 43 50 }; 44 51 45 #define O_QUIET (1 << 0) 52 /* common routines */ 53 54 static int in_cksum(unsigned short *buf, int sz) 55 { 56 int nleft = sz; 57 int sum = 0; 58 unsigned short *w = buf; 59 unsigned short ans = 0; 60 61 while (nleft > 1) { 62 sum += *w++; 63 nleft -= 2; 64 } 65 66 if (nleft == 1) { 67 *(unsigned char *) (&ans) = *(unsigned char *) w; 68 sum += ans; 69 } 70 71 sum = (sum >> 16) + (sum & 0xFFFF); 72 sum += (sum >> 16); 73 ans = ~sum; 74 return ans; 75 } 76 77 #if !ENABLE_FEATURE_FANCY_PING 78 79 /* simple version */ 80 81 static char *hostname; 82 83 static void noresp(int ign ATTRIBUTE_UNUSED) 84 { 85 printf("No response from %s\n", hostname); 86 exit(EXIT_FAILURE); 87 } 88 89 static void ping4(len_and_sockaddr *lsa) 90 { 91 struct sockaddr_in pingaddr; 92 struct icmp *pkt; 93 int pingsock, c; 94 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; 95 96 pingsock = create_icmp_socket(); 97 pingaddr = lsa->sin; 98 99 pkt = (struct icmp *) packet; 100 memset(pkt, 0, sizeof(packet)); 101 pkt->icmp_type = ICMP_ECHO; 102 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); 103 104 c = xsendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 105 (struct sockaddr *) &pingaddr, sizeof(pingaddr)); 106 107 /* listen for replies */ 108 while (1) { 109 struct sockaddr_in from; 110 socklen_t fromlen = sizeof(from); 111 112 c = recvfrom(pingsock, packet, sizeof(packet), 0, 113 (struct sockaddr *) &from, &fromlen); 114 if (c < 0) { 115 if (errno != EINTR) 116 bb_perror_msg("recvfrom"); 117 continue; 118 } 119 if (c >= 76) { /* ip + icmp */ 120 struct iphdr *iphdr = (struct iphdr *) packet; 121 122 pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ 123 if (pkt->icmp_type == ICMP_ECHOREPLY) 124 break; 125 } 126 } 127 if (ENABLE_FEATURE_CLEAN_UP) 128 close(pingsock); 129 } 130 131 #if ENABLE_PING6 132 static void ping6(len_and_sockaddr *lsa) 133 { 134 struct sockaddr_in6 pingaddr; 135 struct icmp6_hdr *pkt; 136 int pingsock, c; 137 int sockopt; 138 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; 139 140 pingsock = create_icmp6_socket(); 141 pingaddr = lsa->sin6; 142 143 pkt = (struct icmp6_hdr *) packet; 144 memset(pkt, 0, sizeof(packet)); 145 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 146 147 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 148 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 149 150 c = xsendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr), 151 (struct sockaddr *) &pingaddr, sizeof(pingaddr)); 152 153 /* listen for replies */ 154 while (1) { 155 struct sockaddr_in6 from; 156 socklen_t fromlen = sizeof(from); 157 158 c = recvfrom(pingsock, packet, sizeof(packet), 0, 159 (struct sockaddr *) &from, &fromlen); 160 if (c < 0) { 161 if (errno != EINTR) 162 bb_perror_msg("recvfrom"); 163 continue; 164 } 165 if (c >= 8) { /* icmp6_hdr */ 166 pkt = (struct icmp6_hdr *) packet; 167 if (pkt->icmp6_type == ICMP6_ECHO_REPLY) 168 break; 169 } 170 } 171 if (ENABLE_FEATURE_CLEAN_UP) 172 close(pingsock); 173 } 174 #endif 175 176 int ping_main(int argc, char **argv); 177 int ping_main(int argc, char **argv) 178 { 179 len_and_sockaddr *lsa; 180 #if ENABLE_PING6 181 sa_family_t af = AF_UNSPEC; 182 183 while ((++argv)[0] && argv[0][0] == '-') { 184 if (argv[0][1] == '4') { 185 af = AF_INET; 186 continue; 187 } 188 if (argv[0][1] == '6') { 189 af = AF_INET6; 190 continue; 191 } 192 bb_show_usage(); 193 } 194 #else 195 argv++; 196 #endif 197 198 hostname = *argv; 199 if (!hostname) 200 bb_show_usage(); 201 202 #if ENABLE_PING6 203 lsa = xhost_and_af2sockaddr(hostname, 0, af); 204 #else 205 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 206 #endif 207 /* Set timer _after_ DNS resolution */ 208 signal(SIGALRM, noresp); 209 alarm(5); /* give the host 5000ms to respond */ 210 211 #if ENABLE_PING6 212 if (lsa->sa.sa_family == AF_INET6) 213 ping6(lsa); 214 else 215 #endif 216 ping4(lsa); 217 printf("%s is alive!\n", hostname); 218 return EXIT_SUCCESS; 219 } 220 221 222 #else /* FEATURE_FANCY_PING */ 223 224 225 /* full(er) version */ 226 227 #define OPT_STRING ("qvc:s:I:4" USE_PING6("6")) 228 enum { 229 OPT_QUIET = 1 << 0, 230 OPT_VERBOSE = 1 << 1, 231 OPT_c = 1 << 2, 232 OPT_s = 1 << 3, 233 OPT_I = 1 << 4, 234 OPT_IPV4 = 1 << 5, 235 OPT_IPV6 = (1 << 6) * ENABLE_PING6, 236 }; 237 238 239 struct globals { 240 int pingsock; 241 len_and_sockaddr *source_lsa; 242 unsigned datalen; 243 int if_index; 244 unsigned long ntransmitted, nreceived, nrepeats, pingcount; 245 uint16_t myid; 246 unsigned tmin, tmax; /* in us */ 247 unsigned long long tsum; /* in us, sum of all times */ 248 const char *hostname; 249 const char *dotted; 250 union { 251 struct sockaddr sa; 252 struct sockaddr_in sin; 253 #if ENABLE_PING6 254 struct sockaddr_in6 sin6; 255 #endif 256 } pingaddr; 257 char rcvd_tbl[MAX_DUP_CHK / 8]; 258 }; 259 #define G (*(struct globals*)&bb_common_bufsiz1) 260 #define pingsock (G.pingsock ) 261 #define source_lsa (G.source_lsa ) 262 #define datalen (G.datalen ) 263 #define if_index (G.if_index ) 264 #define ntransmitted (G.ntransmitted) 265 #define nreceived (G.nreceived ) 266 #define nrepeats (G.nrepeats ) 267 #define pingcount (G.pingcount ) 268 #define myid (G.myid ) 269 #define tmin (G.tmin ) 270 #define tmax (G.tmax ) 271 #define tsum (G.tsum ) 272 #define hostname (G.hostname ) 273 #define dotted (G.dotted ) 274 #define pingaddr (G.pingaddr ) 275 #define rcvd_tbl (G.rcvd_tbl ) 276 void BUG_ping_globals_too_big(void); 277 #define INIT_G() do { \ 278 if (sizeof(G) > COMMON_BUFSIZE) \ 279 BUG_ping_globals_too_big(); \ 280 pingsock = -1; \ 281 tmin = UINT_MAX; \ 282 } while (0) 283 46 284 47 285 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ … … 51 289 #define TST(bit) (A(bit) & B(bit)) 52 290 53 static void ping(const char *host);54 55 /* common routines */56 static int in_cksum(unsigned short *buf, int sz)57 {58 int nleft = sz;59 int sum = 0;60 unsigned short *w = buf;61 unsigned short ans = 0;62 63 while (nleft > 1) {64 sum += *w++;65 nleft -= 2;66 }67 68 if (nleft == 1) {69 *(unsigned char *) (&ans) = *(unsigned char *) w;70 sum += ans;71 }72 73 sum = (sum >> 16) + (sum & 0xFFFF);74 sum += (sum >> 16);75 ans = ~sum;76 return (ans);77 }78 79 /* simple version */80 #ifndef CONFIG_FEATURE_FANCY_PING81 static char *hostname = NULL;82 static void noresp(int ign)83 {84 printf("No response from %s\n", hostname);85 exit(EXIT_FAILURE);86 }87 88 static void ping(const char *host)89 {90 struct hostent *h;91 struct sockaddr_in pingaddr;92 struct icmp *pkt;93 int pingsock, c;94 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];95 96 pingsock = create_icmp_socket();97 98 memset(&pingaddr, 0, sizeof(struct sockaddr_in));99 100 pingaddr.sin_family = AF_INET;101 h = xgethostbyname(host);102 memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));103 hostname = h->h_name;104 105 pkt = (struct icmp *) packet;106 memset(pkt, 0, sizeof(packet));107 pkt->icmp_type = ICMP_ECHO;108 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));109 110 c = sendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 0,111 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));112 113 if (c < 0) {114 if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);115 bb_perror_msg_and_die("sendto");116 }117 118 signal(SIGALRM, noresp);119 alarm(5); /* give the host 5000ms to respond */120 /* listen for replies */121 while (1) {122 struct sockaddr_in from;123 socklen_t fromlen = sizeof(from);124 125 if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,126 (struct sockaddr *) &from, &fromlen)) < 0) {127 if (errno == EINTR)128 continue;129 bb_perror_msg("recvfrom");130 continue;131 }132 if (c >= 76) { /* ip + icmp */133 struct iphdr *iphdr = (struct iphdr *) packet;134 135 pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */136 if (pkt->icmp_type == ICMP_ECHOREPLY)137 break;138 }139 }140 if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);141 printf("%s is alive!\n", hostname);142 return;143 }144 145 int ping_main(int argc, char **argv)146 {147 argc--;148 argv++;149 if (argc < 1)150 bb_show_usage();151 ping(*argv);152 return EXIT_SUCCESS;153 }154 155 #else /* ! CONFIG_FEATURE_FANCY_PING */156 /* full(er) version */157 static struct sockaddr_in pingaddr;158 static int pingsock = -1;159 static int datalen; /* intentionally uninitialized to work around gcc bug */160 161 static long ntransmitted, nreceived, nrepeats, pingcount;162 static int myid, options;163 static unsigned long tmin = ULONG_MAX, tmax, tsum;164 static char rcvd_tbl[MAX_DUP_CHK / 8];165 166 #ifndef CONFIG_FEATURE_FANCY_PING6167 static168 #endif169 struct hostent *hostent;170 171 static void sendping(int);172 static void pingstats(int);173 static void unpack(char *, int, struct sockaddr_in *);174 175 291 /**************************************************************************/ 176 292 177 static void pingstats(int junk) 178 { 179 int status; 180 293 static void pingstats(int junk ATTRIBUTE_UNUSED) 294 { 181 295 signal(SIGINT, SIG_IGN); 182 296 183 printf("\n--- %s ping statistics ---\n", host ent->h_name);184 printf("%l dpackets transmitted, ", ntransmitted);185 printf("%l dpackets received, ", nreceived);297 printf("\n--- %s ping statistics ---\n", hostname); 298 printf("%lu packets transmitted, ", ntransmitted); 299 printf("%lu packets received, ", nreceived); 186 300 if (nrepeats) 187 printf("%l dduplicates, ", nrepeats);301 printf("%lu duplicates, ", nrepeats); 188 302 if (ntransmitted) 189 printf("%ld%% packet loss\n", 190 (ntransmitted - nreceived) * 100 / ntransmitted); 191 if (nreceived) 192 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", 193 tmin / 10, tmin % 10, 194 (tsum / (nreceived + nrepeats)) / 10, 195 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); 196 if (nreceived != 0) 197 status = EXIT_SUCCESS; 198 else 199 status = EXIT_FAILURE; 200 exit(status); 201 } 202 203 static void sendping(int junk) 204 { 205 struct icmp *pkt; 206 int i; 207 char packet[datalen + ICMP_MINLEN]; 208 209 pkt = (struct icmp *) packet; 303 ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted; 304 printf("%lu%% packet loss\n", ntransmitted); 305 if (tmin != UINT_MAX) { 306 unsigned tavg = tsum / (nreceived + nrepeats); 307 printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n", 308 tmin / 1000, tmin % 1000, 309 tavg / 1000, tavg % 1000, 310 tmax / 1000, tmax % 1000); 311 } 312 exit(nreceived == 0); /* (nreceived == 0) is true (1) -- 'failure' */ 313 } 314 315 static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt) 316 { 317 int sz; 318 319 CLR((uint16_t)ntransmitted % MAX_DUP_CHK); 320 ntransmitted++; 321 322 /* sizeof(pingaddr) can be larger than real sa size, but I think 323 * it doesn't matter */ 324 sz = xsendto(pingsock, pkt, size_pkt, &pingaddr.sa, sizeof(pingaddr)); 325 if (sz != size_pkt) 326 bb_error_msg_and_die(bb_msg_write_error); 327 328 signal(SIGALRM, sp); 329 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ 330 alarm(PINGINTERVAL); 331 } else { /* done, wait for the last ping to come back */ 332 /* todo, don't necessarily need to wait so long... */ 333 signal(SIGALRM, pingstats); 334 alarm(MAXWAIT); 335 } 336 } 337 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); 210 343 211 344 pkt->icmp_type = ICMP_ECHO; 212 345 pkt->icmp_code = 0; 213 346 pkt->icmp_cksum = 0; 214 pkt->icmp_seq = htons(ntransmitted ++);347 pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 215 348 pkt->icmp_id = myid; 216 CLR(ntohs(pkt->icmp_seq) % MAX_DUP_CHK); 217 218 gettimeofday((struct timeval *) &pkt->icmp_dun, NULL); 219 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); 220 221 i = sendto(pingsock, packet, sizeof(packet), 0, 222 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); 223 224 if (i < 0) 225 bb_perror_msg_and_die("sendto"); 226 else if ((size_t)i != sizeof(packet)) 227 bb_error_msg_and_die("ping wrote %d chars; %d expected", i, 228 (int)sizeof(packet)); 229 230 signal(SIGALRM, sendping); 231 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ 232 alarm(PINGINTERVAL); 233 } else { /* done, wait for the last ping to come back */ 234 /* todo, don't necessarily need to wait so long... */ 235 signal(SIGALRM, pingstats); 236 alarm(MAXWAIT); 237 } 238 } 239 240 static char *icmp_type_name (int id) 349 350 /* We don't do hton, because we will read it back on the same machine */ 351 /*if (datalen >= 4)*/ 352 *(uint32_t*)&pkt->icmp_dun = monotonic_us(); 353 354 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); 355 356 sendping_tail(sendping4, pkt, datalen + ICMP_MINLEN); 357 } 358 #if ENABLE_PING6 359 static void sendping6(int junk ATTRIBUTE_UNUSED) 360 { 361 struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4); 362 363 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 364 pkt->icmp6_code = 0; 365 pkt->icmp6_cksum = 0; 366 pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 367 pkt->icmp6_id = myid; 368 369 /*if (datalen >= 4)*/ 370 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 371 372 sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); 373 } 374 #endif 375 376 static const char *icmp_type_name(int id) 241 377 { 242 378 switch (id) { 243 case ICMP_ECHOREPLY: return "Echo Reply"; 244 case ICMP_DEST_UNREACH: return "Destination Unreachable"; 245 case ICMP_SOURCE_QUENCH: return "Source Quench"; 246 case ICMP_REDIRECT: return "Redirect (change route)"; 247 case ICMP_ECHO: return "Echo Request"; 248 case ICMP_TIME_EXCEEDED: return "Time Exceeded"; 249 case ICMP_PARAMETERPROB: return "Parameter Problem"; 250 case ICMP_TIMESTAMP: return "Timestamp Request"; 251 case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; 252 case ICMP_INFO_REQUEST: return "Information Request"; 253 case ICMP_INFO_REPLY: return "Information Reply"; 254 case ICMP_ADDRESS: return "Address Mask Request"; 255 case ICMP_ADDRESSREPLY: return "Address Mask Reply"; 256 default: return "unknown ICMP type"; 257 } 258 } 259 260 static void unpack(char *buf, int sz, struct sockaddr_in *from) 261 { 262 struct icmp *icmppkt; 263 struct iphdr *iphdr; 264 struct timeval tv, *tp; 265 int hlen, dupflag; 266 unsigned long triptime; 267 268 gettimeofday(&tv, NULL); 269 270 /* check IP header */ 271 iphdr = (struct iphdr *) buf; 272 hlen = iphdr->ihl << 2; 273 /* discard if too short */ 274 if (sz < (datalen + ICMP_MINLEN)) 275 return; 276 277 sz -= hlen; 278 icmppkt = (struct icmp *) (buf + hlen); 279 280 if (icmppkt->icmp_id != myid) 281 return; /* not our ping */ 282 283 if (icmppkt->icmp_type == ICMP_ECHOREPLY) { 284 u_int16_t recv_seq = ntohs(icmppkt->icmp_seq); 285 ++nreceived; 286 tp = (struct timeval *) icmppkt->icmp_data; 287 288 if ((tv.tv_usec -= tp->tv_usec) < 0) { 289 --tv.tv_sec; 290 tv.tv_usec += 1000000; 291 } 292 tv.tv_sec -= tp->tv_sec; 293 294 triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); 379 case ICMP_ECHOREPLY: return "Echo Reply"; 380 case ICMP_DEST_UNREACH: return "Destination Unreachable"; 381 case ICMP_SOURCE_QUENCH: return "Source Quench"; 382 case ICMP_REDIRECT: return "Redirect (change route)"; 383 case ICMP_ECHO: return "Echo Request"; 384 case ICMP_TIME_EXCEEDED: return "Time Exceeded"; 385 case ICMP_PARAMETERPROB: return "Parameter Problem"; 386 case ICMP_TIMESTAMP: return "Timestamp Request"; 387 case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; 388 case ICMP_INFO_REQUEST: return "Information Request"; 389 case ICMP_INFO_REPLY: return "Information Reply"; 390 case ICMP_ADDRESS: return "Address Mask Request"; 391 case ICMP_ADDRESSREPLY: return "Address Mask Reply"; 392 default: return "unknown ICMP type"; 393 } 394 } 395 #if ENABLE_PING6 396 /* RFC3542 changed some definitions from RFC2292 for no good reason, whee! 397 * the newer 3542 uses a MLD_ prefix where as 2292 uses ICMP6_ prefix */ 398 #ifndef MLD_LISTENER_QUERY 399 # define MLD_LISTENER_QUERY ICMP6_MEMBERSHIP_QUERY 400 #endif 401 #ifndef MLD_LISTENER_REPORT 402 # define MLD_LISTENER_REPORT ICMP6_MEMBERSHIP_REPORT 403 #endif 404 #ifndef MLD_LISTENER_REDUCTION 405 # define MLD_LISTENER_REDUCTION ICMP6_MEMBERSHIP_REDUCTION 406 #endif 407 static const char *icmp6_type_name(int id) 408 { 409 switch (id) { 410 case ICMP6_DST_UNREACH: return "Destination Unreachable"; 411 case ICMP6_PACKET_TOO_BIG: return "Packet too big"; 412 case ICMP6_TIME_EXCEEDED: return "Time Exceeded"; 413 case ICMP6_PARAM_PROB: return "Parameter Problem"; 414 case ICMP6_ECHO_REPLY: return "Echo Reply"; 415 case ICMP6_ECHO_REQUEST: return "Echo Request"; 416 case MLD_LISTENER_QUERY: return "Listener Query"; 417 case MLD_LISTENER_REPORT: return "Listener Report"; 418 case MLD_LISTENER_REDUCTION: return "Listener Reduction"; 419 default: return "unknown ICMP type"; 420 } 421 } 422 #endif 423 424 static void unpack_tail(int sz, uint32_t *tp, 425 const char *from_str, 426 uint16_t recv_seq, int ttl) 427 { 428 const char *dupmsg = " (DUP!)"; 429 unsigned triptime = triptime; /* for gcc */ 430 431 ++nreceived; 432 433 if (tp) { 434 /* (int32_t) cast is for hypothetical 64-bit unsigned */ 435 /* (doesn't hurt 32-bit real-world anyway) */ 436 triptime = (int32_t) ((uint32_t)monotonic_us() - *tp); 295 437 tsum += triptime; 296 438 if (triptime < tmin) … … 298 440 if (triptime > tmax) 299 441 tmax = triptime; 300 301 if (TST(recv_seq % MAX_DUP_CHK)) { 302 ++nrepeats; 303 --nreceived; 304 dupflag = 1; 305 } else { 306 SET(recv_seq % MAX_DUP_CHK); 307 dupflag = 0; 308 } 309 310 if (options & O_QUIET) 311 return; 312 313 printf("%d bytes from %s: icmp_seq=%u", sz, 314 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), 315 recv_seq); 316 printf(" ttl=%d", iphdr->ttl); 317 printf(" time=%lu.%lu ms", triptime / 10, triptime % 10); 318 if (dupflag) 319 printf(" (DUP!)"); 320 printf("\n"); 321 } else 322 if (icmppkt->icmp_type != ICMP_ECHO) 323 bb_error_msg("Warning: Got ICMP %d (%s)", 324 icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type)); 442 } 443 444 if (TST(recv_seq % MAX_DUP_CHK)) { 445 ++nrepeats; 446 --nreceived; 447 } else { 448 SET(recv_seq % MAX_DUP_CHK); 449 dupmsg += 7; 450 } 451 452 if (option_mask32 & OPT_QUIET) 453 return; 454 455 printf("%d bytes from %s: seq=%u ttl=%d", sz, 456 from_str, recv_seq, ttl); 457 if (tp) 458 printf(" time=%u.%03u ms", triptime / 1000, triptime % 1000); 459 puts(dupmsg); 325 460 fflush(stdout); 326 461 } 327 328 static void ping(const char *host) 462 static void unpack4(char *buf, int sz, struct sockaddr_in *from) 463 { 464 struct icmp *icmppkt; 465 struct iphdr *iphdr; 466 int hlen; 467 468 /* discard if too short */ 469 if (sz < (datalen + ICMP_MINLEN)) 470 return; 471 472 /* check IP header */ 473 iphdr = (struct iphdr *) buf; 474 hlen = iphdr->ihl << 2; 475 sz -= hlen; 476 icmppkt = (struct icmp *) (buf + hlen); 477 if (icmppkt->icmp_id != myid) 478 return; /* not our ping */ 479 480 if (icmppkt->icmp_type == ICMP_ECHOREPLY) { 481 uint16_t recv_seq = ntohs(icmppkt->icmp_seq); 482 uint32_t *tp = NULL; 483 484 if (sz >= ICMP_MINLEN + sizeof(uint32_t)) 485 tp = (uint32_t *) icmppkt->icmp_data; 486 unpack_tail(sz, tp, 487 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), 488 recv_seq, iphdr->ttl); 489 } else if (icmppkt->icmp_type != ICMP_ECHO) { 490 bb_error_msg("warning: got ICMP %d (%s)", 491 icmppkt->icmp_type, 492 icmp_type_name(icmppkt->icmp_type)); 493 } 494 } 495 #if ENABLE_PING6 496 static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) 497 { 498 struct icmp6_hdr *icmppkt; 499 char buf[INET6_ADDRSTRLEN]; 500 501 /* discard if too short */ 502 if (sz < (datalen + sizeof(struct icmp6_hdr))) 503 return; 504 505 icmppkt = (struct icmp6_hdr *) packet; 506 if (icmppkt->icmp6_id != myid) 507 return; /* not our ping */ 508 509 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { 510 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq); 511 uint32_t *tp = NULL; 512 513 if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) 514 tp = (uint32_t *) &icmppkt->icmp6_data8[4]; 515 unpack_tail(sz, tp, 516 inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr, 517 buf, sizeof(buf)), 518 recv_seq, hoplimit); 519 } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { 520 bb_error_msg("warning: got ICMP %d (%s)", 521 icmppkt->icmp6_type, 522 icmp6_type_name(icmppkt->icmp6_type)); 523 } 524 } 525 #endif 526 527 static void ping4(len_and_sockaddr *lsa) 329 528 { 330 529 char packet[datalen + MAXIPLEN + MAXICMPLEN]; … … 332 531 333 532 pingsock = create_icmp_socket(); 334 335 memset(&pingaddr, 0, sizeof(struct sockaddr_in)); 336 337 pingaddr.sin_family = AF_INET; 338 hostent = xgethostbyname(host); 339 if (hostent->h_addrtype != AF_INET) 340 bb_error_msg_and_die("unknown address type; only AF_INET is currently supported."); 341 342 memcpy(&pingaddr.sin_addr, hostent->h_addr, sizeof(pingaddr.sin_addr)); 533 pingaddr.sin = lsa->sin; 534 if (source_lsa) { 535 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF, 536 &source_lsa->sa, source_lsa->len)) 537 bb_error_msg_and_die("can't set multicast source interface"); 538 xbind(pingsock, &source_lsa->sa, source_lsa->len); 539 } 343 540 344 541 /* enable broadcast pings */ 345 sockopt = 1; 346 setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, 347 sizeof(sockopt)); 542 setsockopt_broadcast(pingsock); 348 543 349 544 /* set recv buf for broadcast pings */ 350 sockopt = 48 * 1024; 351 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, 352 sizeof(sockopt)); 353 354 printf("PING %s (%s): %d data bytes\n", 355 hostent->h_name, 356 inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), 357 datalen); 545 sockopt = 48 * 1024; /* explain why 48k? */ 546 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 358 547 359 548 signal(SIGINT, pingstats); 360 549 361 550 /* start the ping's going ... */ 362 sendping (0);551 sendping4(0); 363 552 364 553 /* listen for replies */ … … 368 557 int c; 369 558 370 if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,371 (struct sockaddr *) &from, &fromlen)) < 0) {372 if (errno == EINTR)373 continue;374 bb_perror_msg("recvfrom");559 c = recvfrom(pingsock, packet, sizeof(packet), 0, 560 (struct sockaddr *) &from, &fromlen); 561 if (c < 0) { 562 if (errno != EINTR) 563 bb_perror_msg("recvfrom"); 375 564 continue; 376 565 } 377 unpack (packet, c, &from);566 unpack4(packet, c, &from); 378 567 if (pingcount > 0 && nreceived >= pingcount) 379 568 break; 380 569 } 570 } 571 #if ENABLE_PING6 572 extern int BUG_bad_offsetof_icmp6_cksum(void); 573 static void ping6(len_and_sockaddr *lsa) 574 { 575 char packet[datalen + MAXIPLEN + MAXICMPLEN]; 576 int sockopt; 577 struct msghdr msg; 578 struct sockaddr_in6 from; 579 struct iovec iov; 580 char control_buf[CMSG_SPACE(36)]; 581 582 pingsock = create_icmp6_socket(); 583 pingaddr.sin6 = lsa->sin6; 584 /* untested whether "-I addr" really works for IPv6: */ 585 if (source_lsa) 586 xbind(pingsock, &source_lsa->sa, source_lsa->len); 587 588 #ifdef ICMP6_FILTER 589 { 590 struct icmp6_filter filt; 591 if (!(option_mask32 & OPT_VERBOSE)) { 592 ICMP6_FILTER_SETBLOCKALL(&filt); 593 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); 594 } else { 595 ICMP6_FILTER_SETPASSALL(&filt); 596 } 597 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 598 sizeof(filt)) < 0) 599 bb_error_msg_and_die("setsockopt(ICMP6_FILTER)"); 600 } 601 #endif /*ICMP6_FILTER*/ 602 603 /* enable broadcast pings */ 604 setsockopt_broadcast(pingsock); 605 606 /* set recv buf for broadcast pings */ 607 sockopt = 48 * 1024; /* explain why 48k? */ 608 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 609 610 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 611 if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2) 612 BUG_bad_offsetof_icmp6_cksum(); 613 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 614 615 /* request ttl info to be returned in ancillary data */ 616 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1)); 617 618 if (if_index) 619 pingaddr.sin6.sin6_scope_id = if_index; 620 621 signal(SIGINT, pingstats); 622 623 /* start the ping's going ... */ 624 sendping6(0); 625 626 /* listen for replies */ 627 msg.msg_name = &from; 628 msg.msg_namelen = sizeof(from); 629 msg.msg_iov = &iov; 630 msg.msg_iovlen = 1; 631 msg.msg_control = control_buf; 632 iov.iov_base = packet; 633 iov.iov_len = sizeof(packet); 634 while (1) { 635 int c; 636 struct cmsghdr *mp; 637 int hoplimit = -1; 638 msg.msg_controllen = sizeof(control_buf); 639 640 c = recvmsg(pingsock, &msg, 0); 641 if (c < 0) { 642 if (errno != EINTR) 643 bb_perror_msg("recvfrom"); 644 continue; 645 } 646 for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) { 647 if (mp->cmsg_level == SOL_IPV6 648 && mp->cmsg_type == IPV6_HOPLIMIT 649 /* don't check len - we trust the kernel: */ 650 /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */ 651 ) { 652 hoplimit = *(int*)CMSG_DATA(mp); 653 } 654 } 655 unpack6(packet, c, &from, hoplimit); 656 if (pingcount > 0 && nreceived >= pingcount) 657 break; 658 } 659 } 660 #endif 661 662 static void ping(len_and_sockaddr *lsa) 663 { 664 printf("PING %s (%s)", hostname, dotted); 665 if (source_lsa) { 666 printf(" from %s", 667 xmalloc_sockaddr2dotted_noport(&source_lsa->sa)); 668 } 669 printf(": %d data bytes\n", datalen); 670 671 #if ENABLE_PING6 672 if (lsa->sa.sa_family == AF_INET6) 673 ping6(lsa); 674 else 675 #endif 676 ping4(lsa); 677 } 678 679 int ping_main(int argc, char **argv); 680 int ping_main(int argc, char **argv) 681 { 682 len_and_sockaddr *lsa; 683 char *opt_c, *opt_s, *opt_I; 684 USE_PING6(sa_family_t af = AF_UNSPEC;) 685 686 INIT_G(); 687 688 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ 689 690 /* exactly one argument needed, -v and -q don't mix */ 691 opt_complementary = "=1:q--v:v--q"; 692 getopt32(argv, OPT_STRING, &opt_c, &opt_s, &opt_I); 693 if (option_mask32 & OPT_c) pingcount = xatoul(opt_c); // -c 694 if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s 695 if (option_mask32 & OPT_I) { // -I 696 if_index = if_nametoindex(opt_I); 697 if (!if_index) { 698 /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */ 699 source_lsa = xdotted2sockaddr(opt_I, 0); 700 } 701 } 702 myid = (uint16_t) getpid(); 703 hostname = argv[optind]; 704 #if ENABLE_PING6 705 if (option_mask32 & OPT_IPV4) 706 af = AF_INET; 707 if (option_mask32 & OPT_IPV6) 708 af = AF_INET6; 709 lsa = xhost_and_af2sockaddr(hostname, 0, af); 710 #else 711 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 712 #endif 713 714 if (source_lsa && source_lsa->sa.sa_family != lsa->sa.sa_family) 715 /* leaking it here... */ 716 source_lsa = NULL; 717 718 dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa); 719 ping(lsa); 381 720 pingstats(0); 382 }383 384 int ping_main(int argc, char **argv)385 {386 char *thisarg;387 388 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */389 390 argc--;391 argv++;392 options = 0;393 /* Parse any options */394 while (argc >= 1 && **argv == '-') {395 thisarg = *argv;396 thisarg++;397 switch (*thisarg) {398 case 'q':399 options |= O_QUIET;400 break;401 case 'c':402 if (--argc <= 0)403 bb_show_usage();404 argv++;405 pingcount = atoi(*argv);406 break;407 case 's':408 if (--argc <= 0)409 bb_show_usage();410 argv++;411 datalen = atoi(*argv);412 break;413 default:414 bb_show_usage();415 }416 argc--;417 argv++;418 }419 if (argc < 1)420 bb_show_usage();421 422 myid = getpid() & 0xFFFF;423 ping(*argv);424 721 return EXIT_SUCCESS; 425 722 } 426 #endif /* ! CONFIG_FEATURE_FANCY_PING */ 723 #endif /* FEATURE_FANCY_PING */ 724 725 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); 732 } 733 #endif 734 735 /* from ping6.c: 736 * Copyright (c) 1989 The Regents of the University of California. 737 * All rights reserved. 738 * 739 * This code is derived from software contributed to Berkeley by 740 * Mike Muuss. 741 * 742 * Redistribution and use in source and binary forms, with or without 743 * modification, are permitted provided that the following conditions 744 * are met: 745 * 1. Redistributions of source code must retain the above copyright 746 * notice, this list of conditions and the following disclaimer. 747 * 2. Redistributions in binary form must reproduce the above copyright 748 * notice, this list of conditions and the following disclaimer in the 749 * documentation and/or other materials provided with the distribution. 750 * 751 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 752 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 753 * 754 * 4. Neither the name of the University nor the names of its contributors 755 * may be used to endorse or promote products derived from this software 756 * without specific prior written permission. 757 * 758 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 759 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 760 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 761 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 762 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 763 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 764 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 765 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 766 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 767 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 768 * SUCH DAMAGE. 769 */ -
branches/2.2.5/mindi-busybox/networking/route.c
r821 r1765 13 13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 14 14 * 15 * $Id: route.c,v 1.26 2004/03/19 23:27:08 mjn3 Exp $16 15 * 17 16 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> … … 27 26 */ 28 27 29 #include <stdio.h>30 #include <stdlib.h>31 #include <string.h>32 #include <errno.h>33 #include <assert.h>34 #include <unistd.h>35 #include <fcntl.h>36 28 #include <getopt.h> 37 #include <sys/types.h>38 #include <sys/ioctl.h>39 29 #include <net/route.h> 40 30 #include <net/if.h> 41 #include "busybox.h" 31 32 #include "libbb.h" 42 33 #include "inet_common.h" 34 43 35 44 36 #ifndef RTF_UP … … 59 51 #endif 60 52 61 #if defined (SIOCADDRTOLD) || defined(RTF_IRTT) /* route */53 #if defined(SIOCADDRTOLD) || defined(RTF_IRTT) /* route */ 62 54 #define HAVE_NEW_ADDRT 1 63 55 #endif … … 72 64 73 65 /* The RTACTION entries must agree with tbl_verb[] below! */ 74 #define RTACTION_ADD 75 #define RTACTION_DEL 66 #define RTACTION_ADD 1 67 #define RTACTION_DEL 2 76 68 77 69 /* For the various tbl_*[] arrays, the 1st byte is the offset to 78 70 * the next entry and the 2nd byte is return value. */ 79 71 80 #define NET_FLAG 81 #define HOST_FLAG 72 #define NET_FLAG 1 73 #define HOST_FLAG 2 82 74 83 75 /* We remap '-' to '#' to avoid problems with getopt. */ 84 static const char tbl_hash_net_host[] =76 static const char tbl_hash_net_host[] ALIGN1 = 85 77 "\007\001#net\0" 86 78 /* "\010\002#host\0" */ … … 88 80 ; 89 81 90 #define KW_TAKES_ARG 91 #define KW_SETS_FLAG 92 93 #define KW_IPVx_METRIC 94 #define KW_IPVx_NETMASK 95 #define KW_IPVx_GATEWAY 96 #define KW_IPVx_MSS 97 #define KW_IPVx_WINDOW 98 #define KW_IPVx_IRTT 99 #define KW_IPVx_DEVICE 100 101 #define KW_IPVx_FLAG_ONLY 102 #define KW_IPVx_REJECT 103 #define KW_IPVx_MOD 104 #define KW_IPVx_DYN 105 #define KW_IPVx_REINSTATE 106 107 static const char tbl_ipvx[] =82 #define KW_TAKES_ARG 020 83 #define KW_SETS_FLAG 040 84 85 #define KW_IPVx_METRIC 020 86 #define KW_IPVx_NETMASK 021 87 #define KW_IPVx_GATEWAY 022 88 #define KW_IPVx_MSS 023 89 #define KW_IPVx_WINDOW 024 90 #define KW_IPVx_IRTT 025 91 #define KW_IPVx_DEVICE 026 92 93 #define KW_IPVx_FLAG_ONLY 040 94 #define KW_IPVx_REJECT 040 95 #define KW_IPVx_MOD 041 96 #define KW_IPVx_DYN 042 97 #define KW_IPVx_REINSTATE 043 98 99 static const char tbl_ipvx[] ALIGN1 = 108 100 /* 020 is the "takes an arg" bit */ 109 101 #if HAVE_NEW_ADDRT … … 167 159 int skfd, isnet, xflag; 168 160 169 assert((action == RTACTION_ADD) || (action == RTACTION_DEL));170 171 161 /* Grab the -net or -host options. Remember they were transformed. */ 172 162 xflag = kw_lookup(tbl_hash_net_host, &args); … … 178 168 179 169 /* Clean out the RTREQ structure. */ 180 memset( (char *) &rt, 0, sizeof(struct rtentry));170 memset(&rt, 0, sizeof(rt)); 181 171 182 172 { … … 186 176 /* recognize x.x.x.x/mask format. */ 187 177 prefix = strchr(target, '/'); 188 if (prefix) {178 if (prefix) { 189 179 int prefix_len; 190 180 191 prefix_len = bb_xgetularg10_bnd(prefix+1, 0, 32);181 prefix_len = xatoul_range(prefix+1, 0, 32); 192 182 mask_in_addr(rt) = htonl( ~ (0xffffffffUL >> prefix_len)); 193 183 *prefix = '\0'; … … 197 187 } else { 198 188 /* Default netmask. */ 199 netmask = bb_ INET_default;189 netmask = bb_str_default; 200 190 } 201 191 /* Prefer hostname lookup is -host flag (xflag==1) was given. */ … … 205 195 bb_error_msg_and_die("resolving %s", target); 206 196 } 207 if (prefix) {197 if (prefix) { 208 198 /* do not destroy prefix for process args */ 209 199 *prefix = '/'; … … 229 219 #if HAVE_NEW_ADDRT 230 220 if (k == KW_IPVx_METRIC) { 231 rt.rt_metric = bb_xgetularg10(args_m1) + 1;221 rt.rt_metric = xatoul(args_m1) + 1; 232 222 continue; 233 223 } … … 270 260 if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */ 271 261 rt.rt_flags |= RTF_MSS; 272 rt.rt_mss = bb_xgetularg10_bnd(args_m1, 64, 32768);262 rt.rt_mss = xatoul_range(args_m1, 64, 32768); 273 263 continue; 274 264 } … … 276 266 if (k == KW_IPVx_WINDOW) { /* Check valid window bounds. */ 277 267 rt.rt_flags |= RTF_WINDOW; 278 rt.rt_window = bb_xgetularg10_bnd(args_m1, 128, INT_MAX);268 rt.rt_window = xatoul_range(args_m1, 128, INT_MAX); 279 269 continue; 280 270 } … … 283 273 if (k == KW_IPVx_IRTT) { 284 274 rt.rt_flags |= RTF_IRTT; 285 rt.rt_irtt = bb_xgetularg10(args_m1);275 rt.rt_irtt = xatoul(args_m1); 286 276 rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ 287 277 #if 0 /* FIXME: do we need to check anything of this? */ … … 308 298 #ifdef RTF_REJECT 309 299 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) { 310 rt.rt_dev = "lo";300 rt.rt_dev = (char*)"lo"; 311 301 } 312 302 #endif … … 336 326 337 327 /* Create a socket to the INET kernel. */ 338 skfd = bb_xsocket(AF_INET, SOCK_DGRAM, 0); 339 340 if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) { 341 bb_perror_msg_and_die("SIOC[ADD|DEL]RT"); 342 } 328 skfd = xsocket(AF_INET, SOCK_DGRAM, 0); 329 330 if (action == RTACTION_ADD) 331 xioctl(skfd, SIOCADDRT, &rt); 332 else 333 xioctl(skfd, SIOCDELRT, &rt); 343 334 344 335 if (ENABLE_FEATURE_CLEAN_UP) close(skfd); 345 336 } 346 337 347 #if def CONFIG_FEATURE_IPV6338 #if ENABLE_FEATURE_IPV6 348 339 349 340 static void INET6_setroute(int action, char **args) … … 354 345 const char *devname; 355 346 356 assert((action == RTACTION_ADD) || (action == RTACTION_DEL));357 358 {359 347 /* We know args isn't NULL from the check in route_main. */ 360 348 const char *target = *args++; 361 349 362 if (strcmp(target, bb_ INET_default) == 0) {350 if (strcmp(target, bb_str_default) == 0) { 363 351 prefix_len = 0; 364 352 memset(&sa6, 0, sizeof(sa6)); … … 367 355 if ((cp = strchr(target, '/'))) { /* Yes... const to non is ok. */ 368 356 *cp = 0; 369 prefix_len = bb_xgetularg10_bnd(cp+1, 0, 128);357 prefix_len = xatoul_range(cp+1, 0, 128); 370 358 } else { 371 359 prefix_len = 128; … … 375 363 } 376 364 } 377 }378 365 379 366 /* Clean out the RTREQ structure. */ 380 memset( (char *) &rt, 0, sizeof(struct in6_rtmsg));367 memset(&rt, 0, sizeof(rt)); 381 368 382 369 memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr)); … … 399 386 400 387 if (k == KW_IPVx_METRIC) { 401 rt.rtmsg_metric = bb_xgetularg10(args_m1);388 rt.rtmsg_metric = xatoul(args_m1); 402 389 continue; 403 390 } … … 430 417 431 418 /* Create a socket to the INET6 kernel. */ 432 skfd = bb_xsocket(AF_INET6, SOCK_DGRAM, 0);419 skfd = xsocket(AF_INET6, SOCK_DGRAM, 0); 433 420 434 421 rt.rtmsg_ifindex = 0; … … 437 424 struct ifreq ifr; 438 425 memset(&ifr, 0, sizeof(ifr)); 439 strcpy(ifr.ifr_name, devname); 440 441 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) { 442 bb_perror_msg_and_die("SIOGIFINDEX"); 443 } 426 strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)); 427 xioctl(skfd, SIOGIFINDEX, &ifr); 444 428 rt.rtmsg_ifindex = ifr.ifr_ifindex; 445 429 } 446 430 447 431 /* Tell the kernel to accept this route. */ 448 if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) { 449 bb_perror_msg_and_die("SIOC[ADD|DEL]RT"); 450 } 432 if (action == RTACTION_ADD) 433 xioctl(skfd, SIOCADDRT, &rt); 434 else 435 xioctl(skfd, SIOCDELRT, &rt); 451 436 452 437 if (ENABLE_FEATURE_CLEAN_UP) close(skfd); … … 454 439 #endif 455 440 456 static const unsigned intflagvals[] = { /* Must agree with flagchars[]. */441 static const unsigned flagvals[] = { /* Must agree with flagchars[]. */ 457 442 RTF_GATEWAY, 458 443 RTF_HOST, … … 460 445 RTF_DYNAMIC, 461 446 RTF_MODIFIED, 462 #if def CONFIG_FEATURE_IPV6447 #if ENABLE_FEATURE_IPV6 463 448 RTF_DEFAULT, 464 449 RTF_ADDRCONF, … … 470 455 #define IPV6_MASK (RTF_GATEWAY|RTF_HOST|RTF_DEFAULT|RTF_ADDRCONF|RTF_CACHE) 471 456 472 static const char flagchars[] = /* Must agree with flagvals[]. */ 457 /* Must agree with flagvals[]. */ 458 static const char flagchars[] ALIGN1 = 473 459 "GHRDM" 474 #if def CONFIG_FEATURE_IPV6460 #if ENABLE_FEATURE_IPV6 475 461 "DAC" 476 462 #endif 477 463 ; 478 464 479 static 480 #ifndef CONFIG_FEATURE_IPV6 481 __inline 482 #endif 483 void set_flags(char *flagstr, int flags) 465 static void set_flags(char *flagstr, int flags) 484 466 { 485 467 int i; … … 487 469 *flagstr++ = 'U'; 488 470 489 for (i =0 ; (*flagstr = flagchars[i]) != 0; i++) {471 for (i = 0; (*flagstr = flagchars[i]) != 0; i++) { 490 472 if (flags & flagvals[i]) { 491 473 ++flagstr; … … 495 477 496 478 /* also used in netstat */ 497 void displayroutes(int noresolve, int netstatfmt); 498 void displayroutes(int noresolve, int netstatfmt) 479 void bb_displayroutes(int noresolve, int netstatfmt) 499 480 { 500 char devname[64], flags[16], sdest[16], sgw[16];501 unsigned long intd, g, m;481 char devname[64], flags[16], *sdest, *sgw; 482 unsigned long d, g, m; 502 483 int flgs, ref, use, metric, mtu, win, ir; 503 484 struct sockaddr_in s_addr; 504 485 struct in_addr mask; 505 486 506 FILE *fp = bb_xfopen("/proc/net/route", "r"); 507 508 bb_printf("Kernel IP routing table\n" 509 "Destination Gateway Genmask" 510 " Flags %s Iface\n", 511 netstatfmt ? " MSS Window irtt" : "Metric Ref Use"); 487 FILE *fp = xfopen("/proc/net/route", "r"); 488 489 printf("Kernel IP routing table\n" 490 "Destination Gateway Genmask Flags %s Iface\n", 491 netstatfmt ? " MSS Window irtt" : "Metric Ref Use"); 512 492 513 493 if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */ … … 523 503 break; 524 504 } 525 505 ERROR: 526 506 bb_error_msg_and_die("fscanf"); 527 507 } … … 541 521 s_addr.sin_family = AF_INET; 542 522 s_addr.sin_addr.s_addr = d; 543 INET_rresolve(sdest, sizeof(sdest), &s_addr, 544 (noresolve | 0x8000), m); /* Default instead of *. */ 545 523 sdest = INET_rresolve(&s_addr, (noresolve | 0x8000), m); /* 'default' instead of '*' */ 546 524 s_addr.sin_addr.s_addr = g; 547 INET_rresolve(sgw, sizeof(sgw), &s_addr, 548 (noresolve | 0x4000), m); /* Host instead of net. */ 549 525 sgw = INET_rresolve(&s_addr, (noresolve | 0x4000), m); /* Host instead of net */ 550 526 mask.s_addr = m; 551 bb_printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask), flags); 527 /* "%15.15s" truncates hostnames, do we really want that? */ 528 printf("%-15.15s %-15.15s %-16s%-6s", sdest, sgw, inet_ntoa(mask), flags); 529 free(sdest); 530 free(sgw); 552 531 if (netstatfmt) { 553 bb_printf("%5d %-5d %6d %s\n", mtu, win, ir, devname);532 printf("%5d %-5d %6d %s\n", mtu, win, ir, devname); 554 533 } else { 555 bb_printf("%-6d %-2d %7d %s\n", metric, ref, use, devname);534 printf("%-6d %-2d %7d %s\n", metric, ref, use, devname); 556 535 } 557 536 } 558 537 } 559 538 560 #if def CONFIG_FEATURE_IPV6539 #if ENABLE_FEATURE_IPV6 561 540 562 541 static void INET6_displayroutes(int noresolve) 563 542 { 564 char addr6[128], naddr6[128];543 char addr6[128], *naddr6; 565 544 /* In addr6x, we store both 40-byte ':'-delimited ipv6 addresses. 566 545 * We read the non-delimited strings into the tail of the buffer … … 574 553 struct sockaddr_in6 snaddr6; 575 554 576 FILE *fp = bb_xfopen("/proc/net/ipv6_route", "r");577 578 bb_printf("Kernel IPv6 routing table\n%-44s%-40s"555 FILE *fp = xfopen("/proc/net/ipv6_route", "r"); 556 557 printf("Kernel IPv6 routing table\n%-44s%-40s" 579 558 "Flags Metric Ref Use Iface\n", 580 559 "Destination", "Next Hop"); … … 589 568 break; 590 569 } 591 570 ERROR: 592 571 bb_error_msg_and_die("fscanf"); 593 572 } … … 602 581 do { 603 582 if (!*p) { 604 if (i ==40) { /* nul terminator for 1st address? */583 if (i == 40) { /* nul terminator for 1st address? */ 605 584 addr6x[39] = 0; /* Fixup... need 0 instead of ':'. */ 606 585 ++p; /* Skip and continue. */ … … 610 589 } 611 590 addr6x[i++] = *p++; 612 if (!((i+1) %5)) {591 if (!((i+1) % 5)) { 613 592 addr6x[i++] = ':'; 614 593 } … … 627 606 (struct sockaddr *) &snaddr6.sin6_addr); 628 607 snaddr6.sin6_family = AF_INET6; 629 INET6_rresolve(naddr6, sizeof(naddr6), 630 (struct sockaddr_in6 *) &snaddr6, 631 #if 0 632 (noresolve | 0x8000) /* Default instead of *. */ 633 #else 608 naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6, 634 609 0x0fff /* Apparently, upstream never resolves. */ 635 #endif636 610 ); 637 611 … … 639 613 snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len); 640 614 r += 40; 615 free(naddr6); 641 616 } else { /* 2nd pass */ 642 617 /* Print the info. */ 643 bb_printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n", 644 addr6, naddr6, flags, metric, refcnt, use, iface); 618 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n", 619 addr6, naddr6, flags, metric, refcnt, use, iface); 620 free(naddr6); 645 621 break; 646 622 } … … 651 627 #endif 652 628 653 #define ROUTE_OPT_A 654 #define ROUTE_OPT_n 655 #define ROUTE_OPT_e 656 #define ROUTE_OPT_INET6 629 #define ROUTE_OPT_A 0x01 630 #define ROUTE_OPT_n 0x02 631 #define ROUTE_OPT_e 0x04 632 #define ROUTE_OPT_INET6 0x08 /* Not an actual option. See below. */ 657 633 658 634 /* 1st byte is offset to next entry offset. 2nd byte is return value. */ 659 static const char tbl_verb[] = /* 2nd byte matches RTACTION_* code */ 635 /* 2nd byte matches RTACTION_* code */ 636 static const char tbl_verb[] ALIGN1 = 660 637 "\006\001add\0" 661 638 "\006\002del\0" 662 639 /* "\011\002delete\0" */ 663 "\010\002delete" /* Sincelast, we can save a byte. */640 "\010\002delete" /* Since it's last, we can save a byte. */ 664 641 ; 665 642 643 int route_main(int argc, char **argv); 666 644 int route_main(int argc, char **argv) 667 645 { 668 unsigned longopt;646 unsigned opt; 669 647 int what; 670 648 char *family; 649 char **p; 671 650 672 651 /* First, remap '-net' and '-host' to avoid getopt problems. */ 673 { 674 char **p = argv; 675 676 while (*++p) { 677 if ((strcmp(*p, "-net") == 0) || (strcmp(*p, "-host") == 0)) { 678 p[0][0] = '#'; 679 } 680 } 681 } 682 683 opt = bb_getopt_ulflags(argc, argv, "A:ne", &family); 684 685 if ((opt & ROUTE_OPT_A) && strcmp(family, "inet")) { 686 #ifdef CONFIG_FEATURE_IPV6 652 p = argv; 653 while (*++p) { 654 if (strcmp(*p, "-net") == 0 || strcmp(*p, "-host") == 0) { 655 p[0][0] = '#'; 656 } 657 } 658 659 opt = getopt32(argv, "A:ne", &family); 660 661 if ((opt & ROUTE_OPT_A) && strcmp(family, "inet") != 0) { 662 #if ENABLE_FEATURE_IPV6 687 663 if (strcmp(family, "inet6") == 0) { 688 664 opt |= ROUTE_OPT_INET6; /* Set flag for ipv6. */ … … 697 673 if (!*argv) { 698 674 int noresolve = (opt & ROUTE_OPT_n) ? 0x0fff : 0; 699 #if def CONFIG_FEATURE_IPV6675 #if ENABLE_FEATURE_IPV6 700 676 if (opt & ROUTE_OPT_INET6) 701 677 INET6_displayroutes(noresolve); 702 678 else 703 679 #endif 704 displayroutes(noresolve, opt & ROUTE_OPT_e); 705 706 bb_xferror_stdout(); 707 bb_fflush_stdout_and_exit(EXIT_SUCCESS); 680 bb_displayroutes(noresolve, opt & ROUTE_OPT_e); 681 682 fflush_stdout_and_exit(EXIT_SUCCESS); 708 683 } 709 684 … … 714 689 } 715 690 716 #if def CONFIG_FEATURE_IPV6691 #if ENABLE_FEATURE_IPV6 717 692 if (opt & ROUTE_OPT_INET6) 718 693 INET6_setroute(what, argv); -
branches/2.2.5/mindi-busybox/networking/telnet.c
r821 r1765 23 23 24 24 #include <termios.h> 25 #include <unistd.h>26 #include <errno.h>27 #include <stdlib.h>28 #include <stdarg.h>29 #include <string.h>30 #include <signal.h>31 25 #include <arpa/telnet.h> 32 #include <sys/types.h>33 #include <sys/socket.h>34 26 #include <netinet/in.h> 35 #include "busybox.h" 36 37 #if 0 38 enum { DOTRACE = 1 }; 39 #endif 27 #include "libbb.h" 40 28 41 29 #ifdef DOTRACE 42 #include <arpa/inet.h> /* for inet_ntoa()... */43 30 #define TRACE(x, y) do { if (x) printf y; } while (0) 44 31 #else … … 46 33 #endif 47 34 48 #define DATABUFSIZE 12849 #define IACBUFSIZE 12850 51 35 enum { 36 DATABUFSIZE = 128, 37 IACBUFSIZE = 128, 38 52 39 CHM_TRY = 0, 53 40 CHM_ON = 1, … … 64 51 }; 65 52 66 #define WriteCS(fd, str) write(fd, str, sizeof str -1)67 68 53 typedef unsigned char byte; 69 54 70 /* use globals to reduce size ??? */ /* test this hypothesis later */ 71 static struct Globalvars { 72 int netfd; /* console fd:s are 0 and 1 (and 2) */ 73 /* same buffer used both for network and console read/write */ 74 char buf[DATABUFSIZE]; /* allocating so static size is smaller */ 55 struct globals { 56 int netfd; /* console fd:s are 0 and 1 (and 2) */ 57 short iaclen; /* could even use byte */ 75 58 byte telstate; /* telnet negotiation state from network input */ 76 59 byte telwish; /* DO, DONT, WILL, WONT */ … … 79 62 byte gotsig; 80 63 byte do_termios; 64 #if ENABLE_FEATURE_TELNET_TTYPE 65 char *ttype; 66 #endif 67 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 68 const char *autologin; 69 #endif 70 #if ENABLE_FEATURE_AUTOWIDTH 71 int win_width, win_height; 72 #endif 73 /* same buffer used both for network and console read/write */ 74 char buf[DATABUFSIZE]; 81 75 /* buffer to handle telnet negotiations */ 82 76 char iacbuf[IACBUFSIZE]; 83 short iaclen; /* could even use byte */84 77 struct termios termios_def; 85 78 struct termios termios_raw; 86 } G; 87 88 #define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ 89 90 #ifdef USE_GLOBALVAR_PTR 91 struct Globalvars * Gptr; 92 #define G (*Gptr) 93 #endif 94 95 static inline void iacflush(void) 96 { 97 write(G.netfd, G.iacbuf, G.iaclen); 98 G.iaclen = 0; 99 } 79 }; 80 #define G (*(struct globals*)&bb_common_bufsiz1) 81 void BUG_telnet_globals_too_big(void); 82 #define INIT_G() do { \ 83 if (sizeof(G) > COMMON_BUFSIZE) \ 84 BUG_telnet_globals_too_big(); \ 85 /* memset(&G, 0, sizeof G); - already is */ \ 86 } while (0) 100 87 101 88 /* Function prototypes */ … … 107 94 static int subneg(byte c); 108 95 109 /* Some globals */ 110 static int one = 1; 111 112 #ifdef CONFIG_FEATURE_TELNET_TTYPE 113 static char *ttype; 114 #endif 115 116 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 117 static const char *autologin; 118 #endif 119 120 #ifdef CONFIG_FEATURE_AUTOWIDTH 121 static int win_width, win_height; 122 #endif 96 static void iacflush(void) 97 { 98 write(G.netfd, G.iacbuf, G.iaclen); 99 G.iaclen = 0; 100 } 101 102 #define write_str(fd, str) write(fd, str, sizeof(str) - 1) 123 103 124 104 static void doexit(int ev) … … 135 115 rawmode(); 136 116 137 WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"117 write_str(1, "\r\nConsole escape. Commands are:\r\n\n" 138 118 " l go to line mode\r\n" 139 119 " c go to character mode\r\n" … … 144 124 doexit(1); 145 125 146 switch (b) 147 { 126 switch (b) { 148 127 case 'l': 149 if (!G.gotsig) 150 { 128 if (!G.gotsig) { 151 129 do_linemode(); 152 130 goto rrturn; … … 154 132 break; 155 133 case 'c': 156 if (G.gotsig) 157 { 134 if (G.gotsig) { 158 135 will_charmode(); 159 136 goto rrturn; … … 169 146 } 170 147 171 WriteCS(1, "continuing...\r\n");148 write_str(1, "continuing...\r\n"); 172 149 173 150 if (G.gotsig) … … 178 155 179 156 } 157 180 158 static void handlenetoutput(int len) 181 159 { … … 190 168 * first - I cannot use programs like sz/rz 191 169 * second - the 0x0D is sent as one character and if the next 192 * 170 * char is 0x0A then it's eaten by a server side. 193 171 * third - whay doy you have to make 'many write()s'? 194 * 172 * I don't understand. 195 173 * So I implemented it. It's realy useful for me. I hope that 196 174 * others people will find it interesting to. … … 210 188 outbuf[j++] = *p; 211 189 if (*p == 0xff) 212 190 outbuf[j++] = 0xff; 213 191 else if (*p == 0x0d) 214 outbuf[j++] = 0x00; 215 } 216 if (j > 0 ) 217 write(G.netfd, outbuf, j); 218 } 219 192 outbuf[j++] = 0x00; 193 } 194 if (j > 0) 195 write(G.netfd, outbuf, j); 196 } 220 197 221 198 static void handlenetinput(int len) … … 293 270 } 294 271 295 296 /* ******************************* */ 297 298 static inline void putiac(int c) 272 static void putiac(int c) 299 273 { 300 274 G.iacbuf[G.iaclen++] = c; 301 275 } 302 303 276 304 277 static void putiac2(byte wwdd, byte c) … … 312 285 } 313 286 314 #if 0 315 static void putiac1(byte c) 316 { 317 if (G.iaclen + 2 > IACBUFSIZE) 318 iacflush(); 319 320 putiac(IAC); 321 putiac(c); 322 } 323 #endif 324 325 #ifdef CONFIG_FEATURE_TELNET_TTYPE 287 #if ENABLE_FEATURE_TELNET_TTYPE 326 288 static void putiac_subopt(byte c, char *str) 327 289 { … … 336 298 putiac(0); 337 299 338 while (*str)300 while (*str) 339 301 putiac(*str++); 340 302 … … 344 306 #endif 345 307 346 #if def CONFIG_FEATURE_TELNET_AUTOLOGIN308 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 347 309 static void putiac_subopt_autologin(void) 348 310 { 349 int len = strlen( autologin) + 6; // (2 + 1 + 1 + strlen + 2)350 c har *user = "USER";311 int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) 312 const char *user = "USER"; 351 313 352 314 if (G.iaclen + len > IACBUFSIZE) … … 359 321 putiac(NEW_ENV_VAR); 360 322 361 while (*user)323 while (*user) 362 324 putiac(*user++); 363 325 364 326 putiac(NEW_ENV_VALUE); 365 327 366 while (*autologin)367 putiac(* autologin++);328 while (*G.autologin) 329 putiac(*G.autologin++); 368 330 369 331 putiac(IAC); … … 372 334 #endif 373 335 374 #if def CONFIG_FEATURE_AUTOWIDTH336 #if ENABLE_FEATURE_AUTOWIDTH 375 337 static void putiac_naws(byte c, int x, int y) 376 338 { … … 392 354 #endif 393 355 394 /* void putiacstring (subneg strings) */ 395 396 /* ******************************* */ 397 398 static char const escapecharis[] = "\r\nEscape character is "; 356 static char const escapecharis[] ALIGN1 = "\r\nEscape character is "; 399 357 400 358 static void setConMode(void) 401 359 { 402 if (G.telflags & UF_ECHO) 403 { 360 if (G.telflags & UF_ECHO) { 404 361 if (G.charmode == CHM_TRY) { 405 362 G.charmode = CHM_ON; … … 407 364 rawmode(); 408 365 } 409 } 410 else 411 { 366 } else { 412 367 if (G.charmode != CHM_OFF) { 413 368 G.charmode = CHM_OFF; … … 418 373 } 419 374 420 /* ******************************* */421 422 375 static void will_charmode(void) 423 376 { … … 442 395 } 443 396 444 /* ******************************* */ 445 446 static inline void to_notsup(char c)447 { 448 if (G.telwish == WILL) putiac2(DONT, c);449 else if (G.telwish == DO)putiac2(WONT, c);450 } 451 452 static inlinevoid to_echo(void)397 static void to_notsup(char c) 398 { 399 if (G.telwish == WILL) 400 putiac2(DONT, c); 401 else if (G.telwish == DO) 402 putiac2(WONT, c); 403 } 404 405 static void to_echo(void) 453 406 { 454 407 /* if server requests ECHO, don't agree */ 455 if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } 456 else if (G.telwish == DONT) return; 457 458 if (G.telflags & UF_ECHO) 459 { 408 if (G.telwish == DO) { 409 putiac2(WONT, TELOPT_ECHO); 410 return; 411 } 412 if (G.telwish == DONT) 413 return; 414 415 if (G.telflags & UF_ECHO) { 460 416 if (G.telwish == WILL) 461 417 return; 462 } 463 else 464 if (G.telwish == WONT) 465 return; 418 } else if (G.telwish == WONT) 419 return; 466 420 467 421 if (G.charmode != CHM_OFF) … … 474 428 475 429 setConMode(); 476 WriteCS(1, "\r\n"); /* sudden modec */477 } 478 479 static inlinevoid to_sga(void)430 write_str(1, "\r\n"); /* sudden modec */ 431 } 432 433 static void to_sga(void) 480 434 { 481 435 /* daemon always sends will/wont, client do/dont */ 482 436 483 if (G.telflags & UF_SGA) 484 { 437 if (G.telflags & UF_SGA) { 485 438 if (G.telwish == WILL) 486 439 return; 487 } 488 else 489 if (G.telwish == WONT) 490 return; 440 } else if (G.telwish == WONT) 441 return; 491 442 492 443 if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ … … 494 445 else 495 446 putiac2(DONT, TELOPT_SGA); 496 497 return; 498 } 499 500 #ifdef CONFIG_FEATURE_TELNET_TTYPE 501 static inline void to_ttype(void) 447 } 448 449 #if ENABLE_FEATURE_TELNET_TTYPE 450 static void to_ttype(void) 502 451 { 503 452 /* Tell server we will (or won't) do TTYPE */ 504 453 505 if (ttype)454 if (G.ttype) 506 455 putiac2(WILL, TELOPT_TTYPE); 507 456 else 508 457 putiac2(WONT, TELOPT_TTYPE); 509 510 return; 511 } 512 #endif 513 514 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 515 static inline void to_new_environ(void) 458 } 459 #endif 460 461 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 462 static void to_new_environ(void) 516 463 { 517 464 /* Tell server we will (or will not) do AUTOLOGIN */ 518 465 519 if ( autologin)466 if (G.autologin) 520 467 putiac2(WILL, TELOPT_NEW_ENVIRON); 521 468 else 522 469 putiac2(WONT, TELOPT_NEW_ENVIRON); 523 524 return; 525 } 526 #endif 527 528 #ifdef CONFIG_FEATURE_AUTOWIDTH 529 static inline void to_naws(void) 470 } 471 #endif 472 473 #if ENABLE_FEATURE_AUTOWIDTH 474 static void to_naws(void) 530 475 { 531 476 /* Tell server we will do NAWS */ 532 477 putiac2(WILL, TELOPT_NAWS); 533 return;534 478 } 535 479 #endif … … 537 481 static void telopt(byte c) 538 482 { 539 switch (c) 540 { 541 case TELOPT_ECHO: to_echo(); break; 542 case TELOPT_SGA: to_sga(); break; 543 #ifdef CONFIG_FEATURE_TELNET_TTYPE 544 case TELOPT_TTYPE: to_ttype();break; 545 #endif 546 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 547 case TELOPT_NEW_ENVIRON: to_new_environ(); break; 548 #endif 549 #ifdef CONFIG_FEATURE_AUTOWIDTH 550 case TELOPT_NAWS: to_naws(); 551 putiac_naws(c, win_width, win_height); 552 break; 553 #endif 554 default: to_notsup(c); 555 break; 556 } 557 } 558 559 560 /* ******************************* */ 483 switch (c) { 484 case TELOPT_ECHO: 485 to_echo(); break; 486 case TELOPT_SGA: 487 to_sga(); break; 488 #if ENABLE_FEATURE_TELNET_TTYPE 489 case TELOPT_TTYPE: 490 to_ttype(); break; 491 #endif 492 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 493 case TELOPT_NEW_ENVIRON: 494 to_new_environ(); break; 495 #endif 496 #if ENABLE_FEATURE_AUTOWIDTH 497 case TELOPT_NAWS: 498 to_naws(); 499 putiac_naws(c, G.win_width, G.win_height); 500 break; 501 #endif 502 default: 503 to_notsup(c); 504 break; 505 } 506 } 561 507 562 508 /* subnegotiation -- ignore all (except TTYPE,NAWS) */ 563 564 509 static int subneg(byte c) 565 510 { 566 switch (G.telstate) 567 { 511 switch (G.telstate) { 568 512 case TS_SUB1: 569 513 if (c == IAC) 570 514 G.telstate = TS_SUB2; 571 #if def CONFIG_FEATURE_TELNET_TTYPE515 #if ENABLE_FEATURE_TELNET_TTYPE 572 516 else 573 517 if (c == TELOPT_TTYPE) 574 putiac_subopt(TELOPT_TTYPE, ttype);575 #endif 576 #if def CONFIG_FEATURE_TELNET_AUTOLOGIN518 putiac_subopt(TELOPT_TTYPE, G.ttype); 519 #endif 520 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 577 521 else 578 522 if (c == TELOPT_NEW_ENVIRON) … … 589 533 } 590 534 591 /* ******************************* */592 593 535 static void fgotsig(int sig) 594 536 { … … 599 541 static void rawmode(void) 600 542 { 601 if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw); 543 if (G.do_termios) 544 tcsetattr(0, TCSADRAIN, &G.termios_raw); 602 545 } 603 546 604 547 static void cookmode(void) 605 548 { 606 if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def); 607 } 608 549 if (G.do_termios) 550 tcsetattr(0, TCSADRAIN, &G.termios_def); 551 } 552 553 int telnet_main(int argc, char** argv); 609 554 int telnet_main(int argc, char** argv) 610 555 { 556 char *host; 557 int port; 611 558 int len; 612 struct sockaddr_in s_in;613 559 #ifdef USE_POLL 614 560 struct pollfd ufds[2]; … … 618 564 #endif 619 565 620 #ifdef CONFIG_FEATURE_AUTOWIDTH 621 get_terminal_width_height(0, &win_width, &win_height); 622 # endif623 624 # ifdef CONFIG_FEATURE_TELNET_TTYPE625 ttype = getenv("TERM"); 626 # endif627 628 memset(&G, 0, sizeof G); 566 INIT_G(); 567 568 #if ENABLE_FEATURE_AUTOWIDTH 569 get_terminal_width_height(0, &G.win_width, &G.win_height); 570 #endif 571 572 #if ENABLE_FEATURE_TELNET_TTYPE 573 G.ttype = getenv("TERM"); 574 #endif 629 575 630 576 if (tcgetattr(0, &G.termios_def) >= 0) { 631 577 G.do_termios = 1; 632 633 578 G.termios_raw = G.termios_def; 634 579 cfmakeraw(&G.termios_raw); … … 638 583 bb_show_usage(); 639 584 640 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 641 if (1 & bb_getopt_ulflags(argc, argv, "al:", &autologin)) 642 autologin = getenv("USER"); 643 644 if (optind < argc) { 645 bb_lookup_host(&s_in, argv[optind++]); 646 s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] : 647 "telnet", "tcp", 23); 648 if (optind < argc) 649 bb_show_usage(); 650 } else 585 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 586 if (1 & getopt32(argv, "al:", &G.autologin)) 587 G.autologin = getenv("USER"); 588 argv += optind; 589 #else 590 argv++; 591 #endif 592 if (!*argv) 651 593 bb_show_usage(); 652 #else 653 bb_lookup_host(&s_in, argv[1]);654 s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23);655 #endif 656 657 G.netfd = xconnect(&s_in);658 659 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, & one, sizeof one);594 host = *argv++; 595 port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23); 596 if (*argv) /* extra params?? */ 597 bb_show_usage(); 598 599 G.netfd = create_and_connect_stream_or_die(host, port); 600 601 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 660 602 661 603 signal(SIGINT, fgotsig); … … 671 613 #endif 672 614 673 while (1) 674 { 615 while (1) { 675 616 #ifndef USE_POLL 676 617 fd_set rfds = readfds; … … 699 640 { 700 641 len = read(0, G.buf, DATABUFSIZE); 701 702 642 if (len <= 0) 703 643 doexit(0); 704 705 644 TRACE(0, ("Read con: %d\n", len)); 706 707 645 handlenetoutput(len); 708 646 } … … 715 653 { 716 654 len = read(G.netfd, G.buf, DATABUFSIZE); 717 718 if (len <= 0) 719 { 720 WriteCS(1, "Connection closed by foreign host.\r\n"); 655 if (len <= 0) { 656 write_str(1, "Connection closed by foreign host\r\n"); 721 657 doexit(1); 722 658 } 723 659 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); 724 725 660 handlenetinput(len); 726 661 } -
branches/2.2.5/mindi-busybox/networking/telnetd.c
r821 r1765 22 22 */ 23 23 24 /*#define DEBUG 1 */ 25 #undef DEBUG 26 27 #include <sys/socket.h> 28 #include <sys/wait.h> 29 #include <sys/ioctl.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <errno.h> 34 #include <netinet/in.h> 35 #include <arpa/inet.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <signal.h> 39 #include <termios.h> 40 #ifdef DEBUG 24 #define DEBUG 0 25 26 #include "libbb.h" 27 28 #if DEBUG 41 29 #define TELCMDS 42 30 #define TELOPTS 43 31 #endif 44 32 #include <arpa/telnet.h> 45 #include <ctype.h>46 33 #include <sys/syslog.h> 47 34 48 #include "busybox.h" 49 50 #define BUFSIZE 4000 51 52 #ifdef CONFIG_FEATURE_IPV6 53 #define SOCKET_TYPE AF_INET6 54 typedef struct sockaddr_in6 sockaddr_type; 55 #else 56 #define SOCKET_TYPE AF_INET 57 typedef struct sockaddr_in sockaddr_type; 58 #endif 59 60 61 #ifdef CONFIG_LOGIN 35 36 #if ENABLE_LOGIN 62 37 static const char *loginpath = "/bin/login"; 63 38 #else 64 static const char *loginpath; 65 #endif 39 static const char *loginpath = DEFAULT_SHELL; 40 #endif 41 66 42 static const char *issuefile = "/etc/issue.net"; 67 43 68 /* shell name and arguments */69 70 static const char *argv_init[] = {NULL, NULL};71 72 44 /* structure that describes a session */ 73 45 74 46 struct tsession { 75 #ifdef CONFIG_FEATURE_TELNETD_INETD 47 struct tsession *next; 76 48 int sockfd_read, sockfd_write, ptyfd; 77 #else /* CONFIG_FEATURE_TELNETD_INETD */78 struct tsession *next;79 int sockfd, ptyfd;80 #endif /* CONFIG_FEATURE_TELNETD_INETD */81 49 int shell_pid; 82 50 /* two circular buffers */ … … 86 54 }; 87 55 56 /* Two buffers are directly after tsession in malloced memory. 57 * Make whole thing fit in 4k */ 58 enum { BUFSIZE = (4*1024 - sizeof(struct tsession)) / 2 }; 59 88 60 /* 89 90 61 This is how the buffers are used. The arrows indicate the movement 91 62 of data. … … 100 71 101 72 Each session has got two buffers. 102 103 73 */ 104 74 … … 109 79 110 80 /* 111 112 81 Remove all IAC's from the buffer pointed to by bf (received IACs are ignored 113 82 and must be removed so as to not be interpreted by the terminal). Make an … … 127 96 128 97 CR-LF ->'s CR mapping is also done here, for convenience 129 130 */ 98 */ 131 99 static char * 132 remove_iacs(struct tsession *ts, int *pnum_totty) { 100 remove_iacs(struct tsession *ts, int *pnum_totty) 101 { 133 102 unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1; 134 103 unsigned char *ptr = ptr0; … … 148 117 if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end) 149 118 ptr++; 150 } 151 else { 119 } else { 152 120 /* 153 121 * TELOPT_NAWS support! … … 169 137 ws.ws_col = (ptr[3] << 8) | ptr[4]; 170 138 ws.ws_row = (ptr[5] << 8) | ptr[6]; 171 (void)ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);139 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); 172 140 ptr += 9; 173 } 174 else { 141 } else { 175 142 /* skip 3-byte IAC non-SB cmd */ 176 #if defDEBUG143 #if DEBUG 177 144 fprintf(stderr, "Ignoring IAC %s,%s\n", 178 TELCMD( *(ptr+1)), TELOPT(*(ptr+2)));145 TELCMD(ptr[1]), TELOPT(ptr[2])); 179 146 #endif 180 147 ptr += 3; … … 198 165 199 166 static int 200 getpty(char *line )167 getpty(char *line, int size) 201 168 { 202 169 int p; 203 #if def CONFIG_FEATURE_DEVPTS204 p = open("/dev/ptmx", 2);170 #if ENABLE_FEATURE_DEVPTS 171 p = open("/dev/ptmx", O_RDWR); 205 172 if (p > 0) { 173 const char *name; 206 174 grantpt(p); 207 175 unlockpt(p); 208 strcpy(line, ptsname(p)); 209 return(p); 176 name = ptsname(p); 177 if (!name) { 178 bb_perror_msg("ptsname error (is /dev/pts mounted?)"); 179 return -1; 180 } 181 safe_strncpy(line, name, size); 182 return p; 210 183 } 211 184 #else … … 224 197 for (j = 0; j < 16; j++) { 225 198 line[9] = j < 10 ? j + '0' : j - 10 + 'a'; 226 #ifdef DEBUG 227 fprintf(stderr, "Trying to open device: %s\n", line);228 #endif 229 if ( (p = open(line, O_RDWR | O_NOCTTY))>= 0) {199 if (DEBUG) 200 fprintf(stderr, "Trying to open device: %s\n", line); 201 p = open(line, O_RDWR | O_NOCTTY); 202 if (p >= 0) { 230 203 line[5] = 't'; 231 204 return p; … … 233 206 } 234 207 } 235 #endif /* CONFIG_FEATURE_DEVPTS */208 #endif /* FEATURE_DEVPTS */ 236 209 return -1; 237 210 } … … 241 214 send_iac(struct tsession *ts, unsigned char command, int option) 242 215 { 243 /* We rely on that there is space in the buffer for now. 216 /* We rely on that there is space in the buffer for now. */ 244 217 char *b = ts->buf2 + ts->rdidx2; 245 218 *b++ = IAC; … … 252 225 253 226 static struct tsession * 254 #ifdef CONFIG_FEATURE_TELNETD_INETD 255 make_new_session(void) 256 #else /* CONFIG_FEATURE_TELNETD_INETD */ 257 make_new_session(int sockfd) 258 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 259 { 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]; 260 232 struct termios termbuf; 261 int pty, pid;233 int fd, pid; 262 234 char tty_name[32]; 263 235 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); … … 266 238 ts->buf2 = ts->buf1 + BUFSIZE; 267 239 268 #ifdef CONFIG_FEATURE_TELNETD_INETD 240 /* Got a new connection, set up a tty. */ 241 fd = getpty(tty_name, 32); 242 if (fd < 0) { 243 bb_error_msg("all terminals in use"); 244 return NULL; 245 } 246 if (fd > maxfd) maxfd = fd; 247 ndelay_on(ts->ptyfd = fd); 248 #if ENABLE_FEATURE_TELNETD_STANDALONE 249 if (sock_w > maxfd) maxfd = sock_w; 250 if (sock_r > maxfd) maxfd = sock_r; 251 ndelay_on(ts->sockfd_write = sock_w); 252 ndelay_on(ts->sockfd_read = sock_r); 253 #else 269 254 ts->sockfd_write = 1; 270 #else /* CONFIG_FEATURE_TELNETD_INETD */ 271 ts->sockfd = sockfd; 272 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 273 274 /* Got a new connection, set up a tty and spawn a shell. */ 275 276 pty = getpty(tty_name); 277 278 if (pty < 0) { 279 syslog(LOG_ERR, "All terminals in use!"); 280 return 0; 281 } 282 283 if (pty > maxfd) 284 maxfd = pty; 285 286 ts->ptyfd = pty; 287 255 /* xzalloc: ts->sockfd_read = 0; */ 256 ndelay_on(0); 257 ndelay_on(1); 258 #endif 288 259 /* Make the telnet client understand we will echo characters so it 289 260 * should not do it locally. We don't tell the client to run linemode, 290 261 * because we want to handle line editing and tab completion and other 291 * stuff that requires char-by-char support. 292 */ 293 262 * stuff that requires char-by-char support. */ 294 263 send_iac(ts, DO, TELOPT_ECHO); 295 264 send_iac(ts, DO, TELOPT_NAWS); … … 298 267 send_iac(ts, WILL, TELOPT_SGA); 299 268 300 if ((pid = fork()) < 0) {301 syslog(LOG_ERR, "Could not fork");302 }303 if (pid == 0) {304 /* In child, open the child's side of the tty. */305 int i;306 307 for(i = 0; i <= maxfd; i++)308 close(i);309 /* make new process group */310 setsid();311 312 if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) { 313 syslog(LOG_ERR, "Could not open tty");314 exit(1); 315 }316 dup(0);317 dup(0); 318 319 tcsetpgrp(0, getpid());320 321 /* The pseudo-terminal allocated to the client is configured to operate in322 * cooked mode, and with XTABS CRMOD enabled (see tty(4)).323 */324 325 tcgetattr(0, &termbuf);326 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */327 termbuf.c_oflag |= ONLCR|XTABS; 328 termbuf.c_iflag |= ICRNL;329 termbuf.c_iflag &= ~IXOFF;330 /*termbuf.c_lflag &= ~ICANON;*/331 tcsetattr(0, TCSANOW, &termbuf);332 333 print_login_issue(issuefile, NULL);334 335 /* exec shell, with correct argv and env*/336 execv(loginpath, (char *const *)argv_init);337 338 /* NOT REACHED */339 syslog(LOG_ERR, "execv error"); 340 exit(1);341 }342 343 ts->shell_pid = pid;344 345 return ts;269 pid = fork(); 270 if (pid < 0) { 271 free(ts); 272 close(fd); 273 bb_perror_msg("fork"); 274 return NULL; 275 } 276 if (pid > 0) { 277 /* parent */ 278 ts->shell_pid = pid; 279 return ts; 280 } 281 282 /* child */ 283 284 /* make new session and process group */ 285 setsid(); 286 287 /* open the child's side of the tty. */ 288 /* NB: setsid() disconnects from any previous ctty's. Therefore 289 * we must open child's side of the tty AFTER setsid! */ 290 fd = xopen(tty_name, O_RDWR); /* becomes our ctty */ 291 dup2(fd, 0); 292 dup2(fd, 1); 293 dup2(fd, 2); 294 while (fd > 2) close(fd--); 295 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */ 296 297 /* The pseudo-terminal allocated to the client is configured to operate in 298 * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */ 299 tcgetattr(0, &termbuf); 300 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ 301 termbuf.c_oflag |= ONLCR|XTABS; 302 termbuf.c_iflag |= ICRNL; 303 termbuf.c_iflag &= ~IXOFF; 304 /*termbuf.c_lflag &= ~ICANON;*/ 305 tcsetattr(0, TCSANOW, &termbuf); 306 307 print_login_issue(issuefile, NULL); 308 309 /* exec shell / login /whatever */ 310 login_argv[0] = loginpath; 311 login_argv[1] = NULL; 312 execv(loginpath, (char **)login_argv); 313 /* Hmmm... this gets sent to the client thru fd#2! Is it ok?? */ 314 bb_perror_msg_and_die("execv %s", loginpath); 346 315 } 347 316 348 #ifndef CONFIG_FEATURE_TELNETD_INETD 317 #if ENABLE_FEATURE_TELNETD_STANDALONE 318 349 319 static void 350 320 free_session(struct tsession *ts) … … 352 322 struct tsession *t = sessions; 353 323 354 /* Unlink this telnet session from the session list.*/324 /* unlink this telnet session from the session list */ 355 325 if (t == ts) 356 326 sessions = ts->next; 357 327 else { 358 while (t->next != ts)328 while (t->next != ts) 359 329 t = t->next; 360 330 t->next = ts->next; … … 362 332 363 333 kill(ts->shell_pid, SIGKILL); 364 365 334 wait4(ts->shell_pid, NULL, 0, NULL); 366 367 335 close(ts->ptyfd); 368 close(ts->sockfd); 369 370 if (ts->ptyfd == maxfd || ts->sockfd == maxfd) 371 maxfd--; 372 if (ts->ptyfd == maxfd || ts->sockfd == maxfd) 373 maxfd--; 374 336 close(ts->sockfd_read); 337 /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */ 338 close(ts->sockfd_write); 375 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 } 376 353 } 377 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 378 379 int 380 telnetd_main(int argc, char **argv) 354 355 #else /* !FEATURE_TELNETD_STANDALONE */ 356 357 /* Never actually called */ 358 void free_session(struct tsession *ts); 359 360 #endif 361 362 363 int telnetd_main(int argc, char **argv); 364 int telnetd_main(int argc, char **argv) 381 365 { 382 #ifndef CONFIG_FEATURE_TELNETD_INETD383 sockaddr_type sa;384 int master_fd;385 #endif /* CONFIG_FEATURE_TELNETD_INETD */386 366 fd_set rdfdset, wrfdset; 387 int selret;388 #ifndef CONFIG_FEATURE_TELNETD_INETD 389 int on = 1;390 int portnbr = 23; 391 struct in_addr bind_addr = { .s_addr = 0x0 }; 392 #endif /* CONFIG_FEATURE_TELNETD_INETD*/393 int c;394 static const char options[] =395 #ifdef CONFIG_FEATURE_TELNETD_INETD 396 "f:l:"; 397 #else /* CONFIG_EATURE_TELNETD_INETD */ 398 "f:l:p:b:";399 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 400 int maxlen, w, r;401 402 # ifndef CONFIG_LOGIN403 loginpath = DEFAULT_SHELL;404 #endif 405 406 for (;;) {407 c = getopt( argc, argv, options);408 if (c == EOF) break; 409 switch (c) {410 case 'f':411 issuefile = optarg;412 break;413 case 'l':414 loginpath = optarg;415 break;416 #ifndef CONFIG_FEATURE_TELNETD_INETD 417 case 'p':418 portnbr = atoi(optarg);419 break;420 case 'b':421 if (inet_aton(optarg, &bind_addr) == 0)422 bb_show_usage();423 break;424 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 425 default:426 bb_show_usage(); 427 }428 }429 430 if (access(loginpath, X_OK) < 0) { 431 bb_error_msg_and_die ("'%s' unavailable.", loginpath);432 }433 434 argv_init[0] = loginpath;435 436 openlog(bb_applet_name, 0, LOG_USER);437 438 #ifdef CONFIG_FEATURE_TELNETD_INETD 439 maxfd = 1; 367 unsigned opt; 368 int selret, maxlen, w, r; 369 struct tsession *ts; 370 #if ENABLE_FEATURE_TELNETD_STANDALONE 371 #define IS_INETD (opt & OPT_INETD) 372 int master_fd = -1; /* be happy, gcc */ 373 unsigned portnbr = 23; 374 char *opt_bindaddr = NULL; 375 char *opt_portnbr; 376 #else 377 enum { 378 IS_INETD = 1, 379 master_fd = -1, 380 portnbr = 23, 381 }; 382 #endif 383 enum { 384 OPT_PORT = 4 * ENABLE_FEATURE_TELNETD_STANDALONE, 385 OPT_FOREGROUND = 0x10 * ENABLE_FEATURE_TELNETD_STANDALONE, 386 OPT_INETD = 0x20 * ENABLE_FEATURE_TELNETD_STANDALONE, 387 }; 388 389 opt = getopt32(argv, "f:l:" USE_FEATURE_TELNETD_STANDALONE("p:b:Fi"), 390 &issuefile, &loginpath 391 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); 392 /* Redirect log to syslog early, if needed */ 393 if (IS_INETD || !(opt & OPT_FOREGROUND)) { 394 openlog(applet_name, 0, LOG_USER); 395 logmode = LOGMODE_SYSLOG; 396 } 397 //if (opt & 1) // -f 398 //if (opt & 2) // -l 399 USE_FEATURE_TELNETD_STANDALONE( 400 if (opt & OPT_PORT) // -p 401 portnbr = xatou16(opt_portnbr); 402 //if (opt & 8) // -b 403 //if (opt & 0x10) // -F 404 //if (opt & 0x20) // -i 405 ); 406 407 /* Used to check access(loginpath, X_OK) here. Pointless. 408 * exec will do this for us for free later. */ 409 410 #if ENABLE_FEATURE_TELNETD_STANDALONE 411 if (IS_INETD) { 412 sessions = make_new_session(0, 1); 413 } else { 414 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); 415 xlisten(master_fd, 1); 416 if (!(opt & OPT_FOREGROUND)) 417 bb_daemonize(DAEMON_CHDIR_ROOT); 418 } 419 #else 440 420 sessions = make_new_session(); 441 #else /* CONFIG_EATURE_TELNETD_INETD */ 442 sessions = 0; 443 444 /* Grab a TCP socket. */ 445 446 master_fd = bb_xsocket(SOCKET_TYPE, SOCK_STREAM, 0); 447 (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 448 449 /* Set it to listen to specified port. */ 450 451 memset((void *)&sa, 0, sizeof(sa)); 452 #ifdef CONFIG_FEATURE_IPV6 453 sa.sin6_family = AF_INET6; 454 sa.sin6_port = htons(portnbr); 455 /* sa.sin6_addr = bind_addr6; */ 456 #else 457 sa.sin_family = AF_INET; 458 sa.sin_port = htons(portnbr); 459 sa.sin_addr = bind_addr; 460 #endif 461 462 bb_xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa)); 463 bb_xlisten(master_fd, 1); 464 bb_xdaemon(0, 0); 465 466 maxfd = master_fd; 467 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 468 469 do { 470 struct tsession *ts; 471 472 FD_ZERO(&rdfdset); 473 FD_ZERO(&wrfdset); 474 475 /* select on the master socket, all telnet sockets and their 476 * ptys if there is room in their respective session buffers. 477 */ 478 479 #ifndef CONFIG_FEATURE_TELNETD_INETD 421 #endif 422 423 /* We don't want to die if just one session is broken */ 424 signal(SIGPIPE, SIG_IGN); 425 426 again: 427 FD_ZERO(&rdfdset); 428 FD_ZERO(&wrfdset); 429 if (!IS_INETD) { 480 430 FD_SET(master_fd, &rdfdset); 481 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 482 483 ts = sessions; 484 #ifndef CONFIG_FEATURE_TELNETD_INETD 485 while (ts) { 486 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 487 /* buf1 is used from socket to pty 488 * buf2 is used from pty to socket 489 */ 490 if (ts->size1 > 0) { 491 FD_SET(ts->ptyfd, &wrfdset); /* can write to pty */ 492 } 493 if (ts->size1 < BUFSIZE) { 494 #ifdef CONFIG_FEATURE_TELNETD_INETD 495 FD_SET(ts->sockfd_read, &rdfdset); /* can read from socket */ 496 #else /* CONFIG_FEATURE_TELNETD_INETD */ 497 FD_SET(ts->sockfd, &rdfdset); /* can read from socket */ 498 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 499 } 500 if (ts->size2 > 0) { 501 #ifdef CONFIG_FEATURE_TELNETD_INETD 502 FD_SET(ts->sockfd_write, &wrfdset); /* can write to socket */ 503 #else /* CONFIG_FEATURE_TELNETD_INETD */ 504 FD_SET(ts->sockfd, &wrfdset); /* can write to socket */ 505 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 506 } 507 if (ts->size2 < BUFSIZE) { 508 FD_SET(ts->ptyfd, &rdfdset); /* can read from pty */ 509 } 510 #ifndef CONFIG_FEATURE_TELNETD_INETD 511 ts = ts->next; 512 } 513 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 514 515 selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); 516 517 if (!selret) 518 break; 519 520 #ifndef CONFIG_FEATURE_TELNETD_INETD 521 /* First check for and accept new sessions. */ 522 if (FD_ISSET(master_fd, &rdfdset)) { 523 int fd; 524 socklen_t salen; 525 526 salen = sizeof(sa); 527 if ((fd = accept(master_fd, (struct sockaddr *)&sa, 528 &salen)) < 0) { 431 /* This is needed because free_session() does not 432 * take into account master_fd when it finds new 433 * maxfd among remaining fd's: */ 434 if (master_fd > maxfd) 435 maxfd = master_fd; 436 } 437 438 /* select on the master socket, all telnet sockets and their 439 * ptys if there is room in their session buffers. */ 440 ts = sessions; 441 while (ts) { 442 /* buf1 is used from socket to pty 443 * buf2 is used from pty to socket */ 444 if (ts->size1 > 0) /* can write to pty */ 445 FD_SET(ts->ptyfd, &wrfdset); 446 if (ts->size1 < BUFSIZE) /* can read from socket */ 447 FD_SET(ts->sockfd_read, &rdfdset); 448 if (ts->size2 > 0) /* can write to socket */ 449 FD_SET(ts->sockfd_write, &wrfdset); 450 if (ts->size2 < BUFSIZE) /* can read from pty */ 451 FD_SET(ts->ptyfd, &rdfdset); 452 ts = ts->next; 453 } 454 455 selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); 456 if (!selret) 457 return 0; 458 459 #if ENABLE_FEATURE_TELNETD_STANDALONE 460 /* First check for and accept new sessions. */ 461 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) { 462 int fd; 463 struct tsession *new_ts; 464 465 fd = accept(master_fd, NULL, 0); 466 if (fd < 0) 467 goto again; 468 /* Create a new session and link it into our active list */ 469 new_ts = make_new_session(fd, fd); 470 if (new_ts) { 471 new_ts->next = sessions; 472 sessions = new_ts; 473 } else { 474 close(fd); 475 } 476 } 477 #endif 478 479 /* Then check for data tunneling. */ 480 ts = sessions; 481 while (ts) { /* For all sessions... */ 482 struct tsession *next = ts->next; /* in case we free ts. */ 483 484 if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { 485 int num_totty; 486 char *ptr; 487 /* Write to pty from buffer 1. */ 488 ptr = remove_iacs(ts, &num_totty); 489 w = safe_write(ts->ptyfd, ptr, num_totty); 490 /* needed? if (w < 0 && errno == EAGAIN) continue; */ 491 if (w < 0) { 492 if (IS_INETD) 493 return 0; 494 free_session(ts); 495 ts = next; 529 496 continue; 530 } else { 531 /* Create a new session and link it into 532 our active list. */ 533 struct tsession *new_ts = make_new_session(fd); 534 if (new_ts) { 535 new_ts->next = sessions; 536 sessions = new_ts; 537 if (fd > maxfd) 538 maxfd = fd; 539 } else { 540 close(fd); 541 } 542 } 543 } 544 545 /* Then check for data tunneling. */ 546 547 ts = sessions; 548 while (ts) { /* For all sessions... */ 549 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 550 #ifndef CONFIG_FEATURE_TELNETD_INETD 551 struct tsession *next = ts->next; /* in case we free ts. */ 552 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 553 554 if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { 555 int num_totty; 556 char *ptr; 557 /* Write to pty from buffer 1. */ 558 559 ptr = remove_iacs(ts, &num_totty); 560 561 w = write(ts->ptyfd, ptr, num_totty); 562 if (w < 0) { 563 #ifdef CONFIG_FEATURE_TELNETD_INETD 564 exit(0); 565 #else /* CONFIG_FEATURE_TELNETD_INETD */ 566 free_session(ts); 567 ts = next; 497 } 498 ts->wridx1 += w; 499 ts->size1 -= w; 500 if (ts->wridx1 == BUFSIZE) 501 ts->wridx1 = 0; 502 } 503 504 if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) { 505 /* Write to socket from buffer 2. */ 506 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); 507 w = safe_write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen); 508 /* needed? if (w < 0 && errno == EAGAIN) continue; */ 509 if (w < 0) { 510 if (IS_INETD) 511 return 0; 512 free_session(ts); 513 ts = next; 514 continue; 515 } 516 ts->wridx2 += w; 517 ts->size2 -= w; 518 if (ts->wridx2 == BUFSIZE) 519 ts->wridx2 = 0; 520 } 521 522 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) { 523 /* Read from socket to buffer 1. */ 524 maxlen = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1); 525 r = safe_read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen); 526 if (r < 0 && errno == EAGAIN) continue; 527 if (r <= 0) { 528 if (IS_INETD) 529 return 0; 530 free_session(ts); 531 ts = next; 532 continue; 533 } 534 if (!ts->buf1[ts->rdidx1 + r - 1]) 535 if (!--r) 568 536 continue; 569 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 570 } 571 ts->wridx1 += w; 572 ts->size1 -= w; 573 if (ts->wridx1 == BUFSIZE) 574 ts->wridx1 = 0; 575 } 576 577 #ifdef CONFIG_FEATURE_TELNETD_INETD 578 if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) { 579 #else /* CONFIG_FEATURE_TELNETD_INETD */ 580 if (ts->size2 && FD_ISSET(ts->sockfd, &wrfdset)) { 581 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 582 /* Write to socket from buffer 2. */ 583 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); 584 #ifdef CONFIG_FEATURE_TELNETD_INETD 585 w = write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen); 586 if (w < 0) 587 exit(0); 588 #else /* CONFIG_FEATURE_TELNETD_INETD */ 589 w = write(ts->sockfd, ts->buf2 + ts->wridx2, maxlen); 590 if (w < 0) { 591 free_session(ts); 592 ts = next; 593 continue; 594 } 595 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 596 ts->wridx2 += w; 597 ts->size2 -= w; 598 if (ts->wridx2 == BUFSIZE) 599 ts->wridx2 = 0; 600 } 601 602 #ifdef CONFIG_FEATURE_TELNETD_INETD 603 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) { 604 #else /* CONFIG_FEATURE_TELNETD_INETD */ 605 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd, &rdfdset)) { 606 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 607 /* Read from socket to buffer 1. */ 608 maxlen = MIN(BUFSIZE - ts->rdidx1, 609 BUFSIZE - ts->size1); 610 #ifdef CONFIG_FEATURE_TELNETD_INETD 611 r = read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen); 612 if (!r || (r < 0 && errno != EINTR)) 613 exit(0); 614 #else /* CONFIG_FEATURE_TELNETD_INETD */ 615 r = read(ts->sockfd, ts->buf1 + ts->rdidx1, maxlen); 616 if (!r || (r < 0 && errno != EINTR)) { 617 free_session(ts); 618 ts = next; 619 continue; 620 } 621 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 622 if (!*(ts->buf1 + ts->rdidx1 + r - 1)) { 623 r--; 624 if (!r) 625 continue; 626 } 627 ts->rdidx1 += r; 628 ts->size1 += r; 629 if (ts->rdidx1 == BUFSIZE) 630 ts->rdidx1 = 0; 631 } 632 633 if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { 634 /* Read from pty to buffer 2. */ 635 maxlen = MIN(BUFSIZE - ts->rdidx2, 636 BUFSIZE - ts->size2); 637 r = read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); 638 if (!r || (r < 0 && errno != EINTR)) { 639 #ifdef CONFIG_FEATURE_TELNETD_INETD 640 exit(0); 641 #else /* CONFIG_FEATURE_TELNETD_INETD */ 642 free_session(ts); 643 ts = next; 644 continue; 645 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 646 } 647 ts->rdidx2 += r; 648 ts->size2 += r; 649 if (ts->rdidx2 == BUFSIZE) 650 ts->rdidx2 = 0; 651 } 652 653 if (ts->size1 == 0) { 537 ts->rdidx1 += r; 538 ts->size1 += r; 539 if (ts->rdidx1 == BUFSIZE) 654 540 ts->rdidx1 = 0; 655 ts->wridx1 = 0; 656 } 657 if (ts->size2 == 0) { 541 } 542 543 if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { 544 /* Read from pty to buffer 2. */ 545 maxlen = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2); 546 r = safe_read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); 547 if (r < 0 && errno == EAGAIN) continue; 548 if (r <= 0) { 549 if (IS_INETD) 550 return 0; 551 free_session(ts); 552 ts = next; 553 continue; 554 } 555 ts->rdidx2 += r; 556 ts->size2 += r; 557 if (ts->rdidx2 == BUFSIZE) 658 558 ts->rdidx2 = 0; 659 ts->wridx2 = 0; 660 } 661 #ifndef CONFIG_FEATURE_TELNETD_INETD 662 ts = next; 663 } 664 #endif /* CONFIG_FEATURE_TELNETD_INETD */ 665 666 } while (1); 667 668 return 0; 559 } 560 561 if (ts->size1 == 0) { 562 ts->rdidx1 = 0; 563 ts->wridx1 = 0; 564 } 565 if (ts->size2 == 0) { 566 ts->rdidx2 = 0; 567 ts->wridx2 = 0; 568 } 569 ts = next; 570 } 571 goto again; 669 572 } -
branches/2.2.5/mindi-busybox/networking/tftp.c
r821 r1765 20 20 * ------------------------------------------------------------------------- */ 21 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <sys/stat.h> 28 #include <netdb.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 #include <unistd.h> 32 #include <fcntl.h> 33 34 #include "busybox.h" 35 22 #include "libbb.h" 23 24 25 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT 36 26 37 27 #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ 38 28 #define TFTP_TIMEOUT 5 /* seconds */ 39 29 #define TFTP_NUM_RETRIES 5 /* number of retries */ 40 41 static const char * const MODE_OCTET = "octet";42 #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/43 44 static const char * const OPTION_BLOCKSIZE = "blksize";45 #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */46 30 47 31 /* opcodes we support */ … … 53 37 #define TFTP_OACK 6 54 38 55 static const char *const tftp_bb_error_msg[] = { 56 "Undefined error", 57 "File not found", 58 "Access violation", 59 "Disk full or allocation error", 60 "Illegal TFTP operation", 61 "Unknown transfer ID", 62 "File already exists", 63 "No such user" 64 }; 65 66 #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET 67 68 #if ENABLE_FEATURE_TFTP_PUT 69 # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT) 39 #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT 40 #define USE_GETPUT(...) 41 #define CMD_GET(cmd) 1 42 #define CMD_PUT(cmd) 0 43 #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT 44 #define USE_GETPUT(...) 45 #define CMD_GET(cmd) 0 46 #define CMD_PUT(cmd) 1 70 47 #else 71 # define tftp_cmd_put 0 72 #endif 73 74 75 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 48 #define USE_GETPUT(...) __VA_ARGS__ 49 /* masks coming from getpot32 */ 50 #define CMD_GET(cmd) ((cmd) & 1) 51 #define CMD_PUT(cmd) ((cmd) & 2) 52 #endif 53 /* NB: in the code below 54 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive 55 */ 56 57 58 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 76 59 77 60 static int tftp_blocksize_check(int blocksize, int bufsize) … … 83 66 */ 84 67 85 if ((bufsize && (blocksize > bufsize)) || 86 (blocksize < 8) || (blocksize > 65564)) { 68 if ((bufsize && (blocksize > bufsize)) 69 || (blocksize < 8) || (blocksize > 65564) 70 ) { 87 71 bb_error_msg("bad blocksize"); 88 72 return 0; … … 92 76 } 93 77 94 static char *tftp_option_get(char *buf, int len, const char * constoption)78 static char *tftp_option_get(char *buf, int len, const char *option) 95 79 { 96 80 int opt_val = 0; … … 99 83 100 84 while (len > 0) { 101 102 85 /* Make sure the options are terminated correctly */ 103 104 86 for (k = 0; k < len; k++) { 105 87 if (buf[k] == '\0') { 106 break; 107 } 108 } 109 110 if (k >= len) { 111 break; 112 } 113 88 goto nul_found; 89 } 90 } 91 return NULL; 92 nul_found: 114 93 if (opt_val == 0) { 115 94 if (strcasecmp(buf, option) == 0) { 116 95 opt_found = 1; 117 96 } 118 } else { 119 if (opt_found) { 120 return buf; 121 } 97 } else if (opt_found) { 98 return buf; 122 99 } 123 100 124 101 k++; 125 126 102 buf += k; 127 103 len -= k; 128 129 104 opt_val ^= 1; 130 105 } … … 135 110 #endif 136 111 137 static int tftp(const int cmd, const struct hostent *host, 138 const char *remotefile, const int localfd, 139 const unsigned short port, int tftp_bufsize) 112 static int tftp( USE_GETPUT(const int cmd,) 113 len_and_sockaddr *peer_lsa, 114 const char *remotefile, const int localfd, 115 unsigned port, int tftp_bufsize) 140 116 { 141 struct sockaddr_in sa;142 struct sockaddr_in from;143 117 struct timeval tv; 144 socklen_t fromlen;145 118 fd_set rfds; 146 119 int socketfd; 147 120 int len; 148 int opcode = 0; 149 int finished = 0; 121 int send_len; 122 USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;) 123 smallint finished = 0; 124 uint16_t opcode; 125 uint16_t block_nr = 1; 126 uint16_t recv_blk; 150 127 int timeout = TFTP_NUM_RETRIES; 151 unsigned short block_nr = 1;152 unsigned short tmp;153 128 char *cp; 154 129 155 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) 130 unsigned org_port; 131 len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len); 156 132 157 133 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 158 134 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 159 char *buf=xmalloc(tftp_bufsize += 4); 160 161 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 162 /* need to unlink the localfile, so don't use bb_xsocket here. */ 163 bb_perror_msg("socket"); 164 return EXIT_FAILURE; 165 } 166 167 len = sizeof(sa); 168 169 memset(&sa, 0, len); 170 bb_xbind(socketfd, (struct sockaddr *)&sa, len); 171 172 sa.sin_family = host->h_addrtype; 173 sa.sin_port = port; 174 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, 175 sizeof(sa.sin_addr)); 135 /* We must keep the transmit and receive buffers seperate */ 136 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */ 137 char *xbuf = xmalloc(tftp_bufsize += 4); 138 char *rbuf = xmalloc(tftp_bufsize); 139 140 port = org_port = htons(port); 141 142 socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); 176 143 177 144 /* build opcode */ 178 if (cmd & tftp_cmd_get) { 145 opcode = TFTP_WRQ; 146 if (CMD_GET(cmd)) { 179 147 opcode = TFTP_RRQ; 180 148 } 181 if (cmd & tftp_cmd_put) { 182 opcode = TFTP_WRQ; 183 } 149 cp = xbuf + 2; 150 /* add filename and mode */ 151 /* fill in packet if the filename fits into xbuf */ 152 len = strlen(remotefile) + 1; 153 if (2 + len + sizeof("octet") >= tftp_bufsize) { 154 bb_error_msg("remote filename is too long"); 155 goto ret; 156 } 157 strcpy(cp, remotefile); 158 cp += len; 159 /* add "mode" part of the package */ 160 strcpy(cp, "octet"); 161 cp += sizeof("octet"); 162 163 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 164 len = tftp_bufsize - 4; /* data block size */ 165 if (len != TFTP_BLOCKSIZE_DEFAULT) { 166 /* rfc2348 says that 65464 is a max allowed value */ 167 if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { 168 bb_error_msg("remote filename is too long"); 169 goto ret; 170 } 171 /* add "blksize", <nul>, blocksize */ 172 strcpy(cp, "blksize"); 173 cp += sizeof("blksize"); 174 cp += snprintf(cp, 6, "%d", len) + 1; 175 want_option_ack = 1; 176 } 177 #endif 178 /* First packet is built, so skip packet generation */ 179 goto send_pkt; 180 181 /* Using mostly goto's - continue/break will be less clear 182 * in where we actually jump to */ 184 183 185 184 while (1) { 186 187 cp = buf; 188 189 /* first create the opcode part */ 190 *((unsigned short *) cp) = htons(opcode); 185 /* Build ACK or DATA */ 186 cp = xbuf + 2; 187 *((uint16_t*)cp) = htons(block_nr); 191 188 cp += 2; 192 193 /* add filename and mode */ 194 if (((cmd & tftp_cmd_get) && (opcode == TFTP_RRQ)) || 195 ((cmd & tftp_cmd_put) && (opcode == TFTP_WRQ))) 196 { 197 int too_long = 0; 198 199 /* see if the filename fits into buf 200 * and fill in packet. */ 201 len = strlen(remotefile) + 1; 202 203 if ((cp + len) >= &buf[tftp_bufsize - 1]) { 204 too_long = 1; 205 } else { 206 safe_strncpy(cp, remotefile, len); 207 cp += len; 208 } 209 210 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) { 211 bb_error_msg("remote filename too long"); 212 break; 213 } 214 215 /* add "mode" part of the package */ 216 memcpy(cp, MODE_OCTET, MODE_OCTET_LEN); 217 cp += MODE_OCTET_LEN; 218 219 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 220 221 len = tftp_bufsize - 4; /* data block size */ 222 223 if (len != TFTP_BLOCKSIZE_DEFAULT) { 224 225 if ((&buf[tftp_bufsize - 1] - cp) < 15) { 226 bb_error_msg("remote filename too long"); 227 break; 189 block_nr++; 190 opcode = TFTP_ACK; 191 if (CMD_PUT(cmd)) { 192 opcode = TFTP_DATA; 193 len = full_read(localfd, cp, tftp_bufsize - 4); 194 if (len < 0) { 195 bb_perror_msg(bb_msg_read_error); 196 goto ret; 197 } 198 if (len != (tftp_bufsize - 4)) { 199 finished = 1; 200 } 201 cp += len; 202 } 203 send_pkt: 204 /* Send packet */ 205 *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */ 206 send_len = cp - xbuf; 207 /* NB: send_len value is preserved in code below 208 * for potential resend */ 209 send_again: 210 #if ENABLE_DEBUG_TFTP 211 fprintf(stderr, "sending %u bytes\n", send_len); 212 for (cp = xbuf; cp < &xbuf[send_len]; cp++) 213 fprintf(stderr, "%02x ", (unsigned char) *cp); 214 fprintf(stderr, "\n"); 215 #endif 216 xsendto(socketfd, xbuf, send_len, &peer_lsa->sa, peer_lsa->len); 217 /* Was it final ACK? then exit */ 218 if (finished && (opcode == TFTP_ACK)) 219 goto ret; 220 221 timeout = TFTP_NUM_RETRIES; /* re-initialize */ 222 recv_again: 223 /* Receive packet */ 224 tv.tv_sec = TFTP_TIMEOUT; 225 tv.tv_usec = 0; 226 FD_ZERO(&rfds); 227 FD_SET(socketfd, &rfds); 228 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 229 unsigned from_port; 230 case 1: 231 from->len = peer_lsa->len; 232 memset(&from->sa, 0, peer_lsa->len); 233 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, 234 &from->sa, &from->len); 235 if (len < 0) { 236 bb_perror_msg("recvfrom"); 237 goto ret; 238 } 239 from_port = get_nport(&from->sa); 240 if (port == org_port) { 241 /* Our first query went to port 69 242 * but reply will come from different one. 243 * Remember and use this new port */ 244 port = from_port; 245 set_nport(peer_lsa, from_port); 246 } 247 if (port != from_port) 248 goto recv_again; 249 goto process_pkt; 250 case 0: 251 timeout--; 252 if (timeout == 0) { 253 bb_error_msg("last timeout"); 254 goto ret; 255 } 256 bb_error_msg("last timeout" + 5); 257 goto send_again; /* resend last sent pkt */ 258 default: 259 bb_perror_msg("select"); 260 goto ret; 261 } 262 process_pkt: 263 /* Process recv'ed packet */ 264 opcode = ntohs( ((uint16_t*)rbuf)[0] ); 265 recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); 266 267 #if ENABLE_DEBUG_TFTP 268 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); 269 #endif 270 271 if (opcode == TFTP_ERROR) { 272 static const char *const errcode_str[] = { 273 "", 274 "file not found", 275 "access violation", 276 "disk full", 277 "illegal TFTP operation", 278 "unknown transfer id", 279 "file already exists", 280 "no such user", 281 "bad option" 282 }; 283 284 const char *msg = ""; 285 286 if (rbuf[4] != '\0') { 287 msg = &rbuf[4]; 288 rbuf[tftp_bufsize - 1] = '\0'; 289 } else if (recv_blk < ARRAY_SIZE(errcode_str)) { 290 msg = errcode_str[recv_blk]; 291 } 292 bb_error_msg("server error: (%u) %s", recv_blk, msg); 293 goto ret; 294 } 295 296 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 297 if (want_option_ack) { 298 want_option_ack = 0; 299 300 if (opcode == TFTP_OACK) { 301 /* server seems to support options */ 302 char *res; 303 304 res = tftp_option_get(&rbuf[2], len - 2, "blksize"); 305 if (res) { 306 int blksize = xatoi_u(res); 307 if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) { 308 /* send ERROR 8 to server... */ 309 /* htons can be impossible to use in const initializer: */ 310 /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/ 311 /* thus we open-code big-endian layout */ 312 static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 }; 313 xsendto(socketfd, error_8, 4, &peer_lsa->sa, peer_lsa->len); 314 bb_error_msg("server proposes bad blksize %d, exiting", blksize); 315 goto ret; 316 } 317 #if ENABLE_DEBUG_TFTP 318 fprintf(stderr, "using blksize %u\n", 319 blksize); 320 #endif 321 tftp_bufsize = blksize + 4; 322 /* Send ACK for OACK ("block" no: 0) */ 323 block_nr = 0; 324 continue; 228 325 } 229 230 /* add "blksize" + number of blocks */ 231 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN); 232 cp += OPTION_BLOCKSIZE_LEN; 233 cp += snprintf(cp, 6, "%d", len) + 1; 234 235 want_option_ack = 1; 236 } 237 #endif 238 } 239 240 /* add ack and data */ 241 242 if (((cmd & tftp_cmd_get) && (opcode == TFTP_ACK)) || 243 ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA))) { 244 245 *((unsigned short *) cp) = htons(block_nr); 246 247 cp += 2; 248 249 block_nr++; 250 251 if ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA)) { 252 len = bb_full_read(localfd, cp, tftp_bufsize - 4); 253 254 if (len < 0) { 255 bb_perror_msg(bb_msg_read_error); 256 break; 257 } 258 259 if (len != (tftp_bufsize - 4)) { 260 finished++; 261 } 262 263 cp += len; 264 } 265 } 266 267 268 /* send packet */ 269 270 271 timeout = TFTP_NUM_RETRIES; /* re-initialize */ 272 do { 273 274 len = cp - buf; 275 276 #ifdef CONFIG_DEBUG_TFTP 277 fprintf(stderr, "sending %u bytes\n", len); 278 for (cp = buf; cp < &buf[len]; cp++) 279 fprintf(stderr, "%02x ", (unsigned char) *cp); 280 fprintf(stderr, "\n"); 281 #endif 282 if (sendto(socketfd, buf, len, 0, 283 (struct sockaddr *) &sa, sizeof(sa)) < 0) { 284 bb_perror_msg("send"); 285 len = -1; 286 break; 287 } 288 289 290 if (finished && (opcode == TFTP_ACK)) { 291 break; 292 } 293 294 /* receive packet */ 295 296 memset(&from, 0, sizeof(from)); 297 fromlen = sizeof(from); 298 299 tv.tv_sec = TFTP_TIMEOUT; 300 tv.tv_usec = 0; 301 302 FD_ZERO(&rfds); 303 FD_SET(socketfd, &rfds); 304 305 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 306 case 1: 307 len = recvfrom(socketfd, buf, tftp_bufsize, 0, 308 (struct sockaddr *) &from, &fromlen); 309 310 if (len < 0) { 311 bb_perror_msg("recvfrom"); 312 break; 313 } 314 315 timeout = 0; 316 317 if (sa.sin_port == port) { 318 sa.sin_port = from.sin_port; 319 } 320 if (sa.sin_port == from.sin_port) { 321 break; 322 } 323 324 /* fall-through for bad packets! */ 325 /* discard the packet - treat as timeout */ 326 timeout = TFTP_NUM_RETRIES; 327 case 0: 328 bb_error_msg("timeout"); 329 330 timeout--; 331 if (timeout == 0) { 332 len = -1; 333 bb_error_msg("last timeout"); 334 } 335 break; 336 default: 337 bb_perror_msg("select"); 338 len = -1; 339 } 340 341 } while (timeout && (len >= 0)); 342 343 if ((finished) || (len < 0)) { 344 break; 345 } 346 347 /* process received packet */ 348 349 opcode = ntohs(*((unsigned short *) buf)); 350 tmp = ntohs(*((unsigned short *) &buf[2])); 351 352 #ifdef CONFIG_DEBUG_TFTP 353 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp); 354 #endif 355 356 if (opcode == TFTP_ERROR) { 357 const char *msg = NULL; 358 359 if (buf[4] != '\0') { 360 msg = &buf[4]; 361 buf[tftp_bufsize - 1] = '\0'; 362 } else if (tmp < (sizeof(tftp_bb_error_msg) 363 / sizeof(char *))) { 364 365 msg = tftp_bb_error_msg[tmp]; 366 } 367 368 if (msg) { 369 bb_error_msg("server says: %s", msg); 370 } 371 372 break; 373 } 374 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 375 if (want_option_ack) { 376 377 want_option_ack = 0; 378 379 if (opcode == TFTP_OACK) { 380 381 /* server seems to support options */ 382 383 char *res; 384 385 res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE); 386 387 if (res) { 388 int blksize = atoi(res); 389 390 if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { 391 392 if (cmd & tftp_cmd_put) { 393 opcode = TFTP_DATA; 394 } else { 395 opcode = TFTP_ACK; 396 } 397 #ifdef CONFIG_DEBUG_TFTP 398 fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE, 399 blksize); 400 #endif 401 tftp_bufsize = blksize + 4; 402 block_nr = 0; 403 continue; 404 } 405 } 406 /* FIXME: 407 * we should send ERROR 8 */ 408 bb_error_msg("bad server option"); 409 break; 410 } 411 412 bb_error_msg("warning: blksize not supported by server" 413 " - reverting to 512"); 414 326 /* rfc2347: 327 * "An option not acknowledged by the server 328 * must be ignored by the client and server 329 * as if it were never requested." */ 330 } 331 332 bb_error_msg("blksize is not supported by server" 333 " - reverting to 512"); 415 334 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; 416 335 } 417 336 #endif 418 419 if ((cmd & tftp_cmd_get) && (opcode == TFTP_DATA)) { 420 421 if (tmp == block_nr) { 422 423 len = bb_full_write(localfd, &buf[4], len - 4); 424 337 /* block_nr is already advanced to next block# we expect 338 * to get / block# we are about to send next time */ 339 340 if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { 341 if (recv_blk == block_nr) { 342 len = full_write(localfd, &rbuf[4], len - 4); 425 343 if (len < 0) { 426 344 bb_perror_msg(bb_msg_write_error); 427 break;345 goto ret; 428 346 } 429 430 347 if (len != (tftp_bufsize - 4)) { 431 finished ++;348 finished = 1; 432 349 } 433 434 opcode = TFTP_ACK; 350 continue; /* send ACK */ 351 } 352 if (recv_blk == (block_nr - 1)) { 353 /* Server lost our TFTP_ACK. Resend it */ 354 block_nr = recv_blk; 435 355 continue; 436 356 } 437 /* in case the last ack disappeared into the ether */ 438 if (tmp == (block_nr - 1)) { 439 --block_nr; 440 opcode = TFTP_ACK; 441 continue; 442 } else if (tmp + 1 == block_nr) { 443 /* Server lost our TFTP_ACK. Resend it */ 444 block_nr = tmp; 445 opcode = TFTP_ACK; 446 continue; 447 } 448 } 449 450 if ((cmd & tftp_cmd_put) && (opcode == TFTP_ACK)) { 451 452 if (tmp == (unsigned short) (block_nr - 1)) { 453 if (finished) { 454 break; 455 } 456 457 opcode = TFTP_DATA; 458 continue; 459 } 460 } 461 } 462 463 #ifdef CONFIG_FEATURE_CLEAN_UP 464 close(socketfd); 465 free(buf); 466 #endif 467 468 return finished ? EXIT_SUCCESS : EXIT_FAILURE; 357 } 358 359 if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { 360 /* did server ACK our last DATA pkt? */ 361 if (recv_blk == (uint16_t) (block_nr - 1)) { 362 if (finished) 363 goto ret; 364 continue; /* send next block */ 365 } 366 } 367 /* Awww... recv'd packet is not recognized! */ 368 goto recv_again; 369 /* why recv_again? - rfc1123 says: 370 * "The sender (i.e., the side originating the DATA packets) 371 * must never resend the current DATA packet on receipt 372 * of a duplicate ACK". 373 * DATA pkts are resent ONLY on timeout. 374 * Thus "goto send_again" will ba a bad mistake above. 375 * See: 376 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome 377 */ 378 } 379 ret: 380 if (ENABLE_FEATURE_CLEAN_UP) { 381 close(socketfd); 382 free(xbuf); 383 free(rbuf); 384 } 385 return finished == 0; /* returns 1 on failure */ 469 386 } 470 387 388 int tftp_main(int argc, char **argv); 471 389 int tftp_main(int argc, char **argv) 472 390 { 473 struct hostent *host = NULL;391 len_and_sockaddr *peer_lsa; 474 392 const char *localfile = NULL; 475 393 const char *remotefile = NULL; 394 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 395 const char *sblocksize = NULL; 396 #endif 476 397 int port; 477 int cmd = 0;398 USE_GETPUT(int cmd;) 478 399 int fd = -1; 479 400 int flags = 0; … … 481 402 int blocksize = TFTP_BLOCKSIZE_DEFAULT; 482 403 483 /* figure out what to pass to getopt */ 484 485 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 486 char *sblocksize = NULL; 487 488 #define BS "b:" 489 #define BS_ARG , &sblocksize 490 #else 491 #define BS 492 #define BS_ARG 493 #endif 494 495 #ifdef CONFIG_FEATURE_TFTP_GET 496 #define GET "g" 497 #define GET_COMPL ":g" 498 #else 499 #define GET 500 #define GET_COMPL 501 #endif 502 503 #ifdef CONFIG_FEATURE_TFTP_PUT 504 #define PUT "p" 505 #define PUT_COMPL ":p" 506 #else 507 #define PUT 508 #define PUT_COMPL 509 #endif 510 511 #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT) 512 bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g"; 513 #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) 514 bb_opt_complementally = GET_COMPL PUT_COMPL; 515 #endif 516 517 518 cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS, 519 &localfile, &remotefile BS_ARG); 520 521 cmd &= (tftp_cmd_get | tftp_cmd_put); 522 #ifdef CONFIG_FEATURE_TFTP_GET 523 if (cmd == tftp_cmd_get) 404 /* -p or -g is mandatory, and they are mutually exclusive */ 405 opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") 406 USE_GETPUT("?g--p:p--g"); 407 408 USE_GETPUT(cmd =) getopt32(argv, 409 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") 410 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), 411 &localfile, &remotefile 412 USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize)); 413 argv += optind; 414 415 flags = O_RDONLY; 416 if (CMD_GET(cmd)) 524 417 flags = O_WRONLY | O_CREAT | O_TRUNC; 525 #endif 526 #ifdef CONFIG_FEATURE_TFTP_PUT 527 if (cmd == tftp_cmd_put) 528 flags = O_RDONLY; 529 #endif 530 531 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 418 419 #if ENABLE_FEATURE_TFTP_BLOCKSIZE 532 420 if (sblocksize) { 533 blocksize = atoi(sblocksize);421 blocksize = xatoi_u(sblocksize); 534 422 if (!tftp_blocksize_check(blocksize, 0)) { 535 423 return EXIT_FAILURE; … … 538 426 #endif 539 427 540 if ( localfile == NULL)428 if (!localfile) 541 429 localfile = remotefile; 542 if ( remotefile == NULL)430 if (!remotefile) 543 431 remotefile = localfile; 544 if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL)) 432 /* Error if filename or host is not known */ 433 if (!remotefile || !argv[0]) 545 434 bb_show_usage(); 546 435 547 if (localfile == NULL || strcmp(localfile, "-") == 0) { 548 fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO; 549 } else { 550 fd = open(localfile, flags, 0644); /* fail below */ 551 } 552 if (fd < 0) { 553 bb_perror_msg_and_die("local file"); 554 } 555 556 host = xgethostbyname(argv[optind]); 557 port = bb_lookup_port(argv[optind + 1], "udp", 69); 558 559 #ifdef CONFIG_DEBUG_TFTP 560 fprintf(stderr, "using server \"%s\", remotefile \"%s\", " 561 "localfile \"%s\".\n", 562 inet_ntoa(*((struct in_addr *) host->h_addr)), 436 fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; 437 if (!LONE_DASH(localfile)) { 438 fd = xopen(localfile, flags); 439 } 440 441 port = bb_lookup_port(argv[1], "udp", 69); 442 peer_lsa = xhost2sockaddr(argv[0], port); 443 444 #if ENABLE_DEBUG_TFTP 445 fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n", 446 xmalloc_sockaddr2dotted(&peer_lsa->sa), 563 447 remotefile, localfile); 564 448 #endif 565 449 566 result = tftp(cmd, host, remotefile, fd, port, blocksize); 567 568 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) { 569 if (ENABLE_FEATURE_CLEAN_UP) 570 close(fd); 571 if (cmd == tftp_cmd_get && result != EXIT_SUCCESS) 572 unlink(localfile); 573 } 574 return (result); 450 result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize); 451 452 if (ENABLE_FEATURE_CLEAN_UP) 453 close(fd); 454 if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) { 455 unlink(localfile); 456 } 457 return result; 575 458 } 459 460 #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */ -
branches/2.2.5/mindi-busybox/networking/traceroute.c
r902 r1765 197 197 */ 198 198 199 #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE 199 #define TRACEROUTE_SO_DEBUG 0 200 201 /* TODO: undefs were uncommented - ??! we have config system for that! */ 202 /* probably ok to remove altogether */ 203 //#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE 200 204 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE 201 #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ 202 #undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 205 //#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 203 206 //#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 204 #undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP207 //#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP 205 208 //#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP 206 209 207 #include <errno.h>208 #include <stdio.h>209 #include <stdlib.h>210 #include <string.h>211 #include <unistd.h>212 #include <fcntl.h>213 #include <netdb.h>214 #include <endian.h>215 #include <getopt.h>216 217 #include <sys/param.h>218 #include <sys/file.h>219 #include <sys/ioctl.h>220 #include <sys/socket.h>221 #include <sys/select.h>222 #include "inet_common.h"223 210 224 211 #include <net/if.h> 212 #include <arpa/inet.h> 225 213 #include <netinet/in.h> 226 #include <arpa/inet.h>227 214 #include <netinet/udp.h> 228 215 #include <netinet/ip.h> 229 216 #include <netinet/ip_icmp.h> 230 217 231 #include "busybox.h" 218 #include "libbb.h" 219 #include "inet_common.h" 232 220 233 221 … … 236 224 * Per RFC 791, September 1981. 237 225 */ 238 #define IPVERSION 4 226 #define IPVERSION 4 227 228 #ifndef IPPROTO_ICMP 229 /* Grrrr.... */ 230 #define IPPROTO_ICMP 1 231 #endif 232 #ifndef IPPROTO_IP 233 #define IPPROTO_IP 0 234 #endif 239 235 240 236 /* … … 252 248 * UDP kernel structures and variables. 253 249 */ 254 struct 250 struct udpiphdr { 255 251 struct ipovly ui_i; /* overlaid ip structure */ 256 252 struct udphdr ui_u; /* udp header */ … … 273 269 char *name; 274 270 int n; 275 u _int32_t *addrs;271 uint32_t *addrs; 276 272 }; 277 273 … … 280 276 unsigned char seq; /* sequence number of this packet */ 281 277 unsigned char ttl; /* ttl packet left with */ 282 struct timeval tv ATTRIBUTE_PACKED; /* time packet left */ 278 // UNUSED. Retaining to have the same packet size. 279 struct timeval tv_UNUSED ATTRIBUTE_PACKED; /* time packet left */ 283 280 }; 284 281 285 282 struct IFADDRLIST { 286 u _int32_t addr;283 uint32_t addr; 287 284 char device[sizeof(struct ifreq)]; 288 285 }; 289 286 290 291 static const char route[] = "/proc/net/route";292 293 /* last inbound (icmp) packet */294 static unsigned char packet[512] ATTRIBUTE_ALIGNED(32);295 287 296 288 static struct ip *outip; /* last output (udp) packet */ … … 298 290 static struct outdata *outdata; /* last output (udp) packet */ 299 291 300 #if def CONFIG_FEATURE_TRACEROUTE_USE_ICMP292 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 301 293 static struct icmp *outicmp; /* last output (icmp) packet */ 302 #endif303 304 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE305 /* Maximum number of gateways (include room for one noop) */306 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))307 /* loose source route gateway list (including room for final destination) */308 static u_int32_t gwlist[NGATEWAYS + 1];309 294 #endif 310 295 … … 312 297 static int sndsock; /* send (udp/icmp) socket file descriptor */ 313 298 314 static struct sockaddr_storage whereto; /* Who to try to reach */315 static struct sockaddr_storage wherefrom; /* Who we are */316 299 static int packlen; /* total length of packet */ 317 300 static int minpacket; /* min ip packet size */ … … 321 304 static char *hostname; 322 305 323 static u _short ident;324 static u _short port = 32768 + 666; /* start udp dest port # for probe packets */306 static uint16_t ident; 307 static uint16_t port = 32768 + 666; /* start udp dest port # for probe packets */ 325 308 326 309 static int waittime = 5; /* time to wait for response (in seconds) */ 327 static int nflag; /* print addresses numerically */328 310 static int doipcksum = 1; /* calculate ip checksums by default */ 329 311 330 #if def CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE312 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 331 313 static int optlen; /* length of ip options */ 332 314 #else … … 334 316 #endif 335 317 336 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP 337 static int useicmp; /* use icmp echo instead of udp packets */ 338 #endif 339 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 340 static int verbose; 341 #endif 318 319 /* Keep in sync with getopt32 call! */ 320 #define OPT_DONT_FRAGMNT (1<<0) /* F */ 321 #define OPT_USE_ICMP (1<<1) /* I */ 322 #define OPT_TTL_FLAG (1<<2) /* l */ 323 #define OPT_ADDR_NUM (1<<3) /* n */ 324 #define OPT_BYPASS_ROUTE (1<<4) /* r */ 325 #define OPT_DEBUG (1<<5) /* d */ 326 #define OPT_VERBOSE (1<<6) /* v */ 327 #define OPT_IP_CHKSUM (1<<7) /* x */ 328 #define OPT_TOS (1<<8) /* t */ 329 #define OPT_DEVICE (1<<9) /* i */ 330 #define OPT_MAX_TTL (1<<10) /* m */ 331 #define OPT_PORT (1<<11) /* p */ 332 #define OPT_NPROBES (1<<12) /* q */ 333 #define OPT_SOURCE (1<<13) /* s */ 334 #define OPT_WAITTIME (1<<14) /* w */ 335 #define OPT_PAUSE_MS (1<<15) /* z */ 336 #define OPT_FIRST_TTL (1<<16) /* f */ 337 338 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 339 /* use icmp echo instead of udp packets */ 340 #define useicmp (option_mask32 & OPT_USE_ICMP) 341 #endif 342 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 343 #define verbose (option_mask32 & OPT_VERBOSE) 344 #endif 345 #define nflag (option_mask32 & OPT_ADDR_NUM) 346 347 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 */ 353 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 354 /* Maximum number of gateways (include room for one noop) */ 355 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t))) 356 /* loose source route gateway list (including room for final destination) */ 357 uint32_t gwlist[NGATEWAYS + 1]; 358 #endif 359 }; 360 361 #define G (*ptr_to_globals) 362 363 #define packet (G.packet ) 364 #define whereto (G.whereto ) 365 #define wherefrom (G.wherefrom) 366 #define gwlist (G.gwlist ) 367 342 368 343 369 /* … … 347 373 ifaddrlist(struct IFADDRLIST **ipaddrp) 348 374 { 375 enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) }; 376 349 377 int fd, nipaddr; 350 378 #ifdef HAVE_SOCKADDR_SA_LEN … … 355 383 struct IFADDRLIST *al; 356 384 struct ifconf ifc; 357 struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr; 385 struct ifreq ifr; 386 /* Was on stack, but 32k is a bit too much: */ 387 struct ifreq *ibuf = xmalloc(IFREQ_BUFSIZE * sizeof(ibuf[0])); 358 388 struct IFADDRLIST *st_ifaddrlist; 359 389 360 fd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);361 362 ifc.ifc_len = sizeof(ibuf);390 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 391 392 ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]); 363 393 ifc.ifc_buf = (caddr_t)ibuf; 364 394 365 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 366 ifc.ifc_len < sizeof(struct ifreq)) { 395 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 396 || ifc.ifc_len < sizeof(struct ifreq) 397 ) { 367 398 if (errno == EINVAL) 368 399 bb_error_msg_and_die( 369 "SIOCGIFCONF: ifreq struct too small (%d bytes)", 370 (int)sizeof(ibuf)); 371 else 372 bb_perror_msg_and_die("SIOCGIFCONF"); 400 "SIOCGIFCONF: ifreq struct too small (%u bytes)", 401 (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0]))); 402 bb_perror_msg_and_die("SIOCGIFCONF"); 373 403 } 374 404 ifrp = ibuf; … … 376 406 377 407 nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq)); 378 st_ifaddrlist = x calloc(nipaddr,sizeof(struct IFADDRLIST));408 st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST)); 379 409 al = st_ifaddrlist; 380 410 nipaddr = 0; … … 416 446 continue; 417 447 #endif 418 i f (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)419 bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);448 ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr, 449 "SIOCGIFADDR: %s", al->device); 420 450 421 451 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr; … … 424 454 ++nipaddr; 425 455 } 426 if(nipaddr == 0) 427 bb_error_msg_and_die ("Can't find any network interfaces"); 428 (void)close(fd); 429 456 if (nipaddr == 0) 457 bb_error_msg_and_die("can't find any network interfaces"); 458 459 free(ibuf); 460 close(fd); 430 461 *ipaddrp = st_ifaddrlist; 431 462 return nipaddr; … … 434 465 435 466 static void 436 setsin(struct sockaddr_in *addr_sin, u _int32_t addr)467 setsin(struct sockaddr_in *addr_sin, uint32_t addr) 437 468 { 438 469 memset(addr_sin, 0, sizeof(*addr_sin)); … … 453 484 int i, n; 454 485 FILE *f; 455 u _int32_t mask;456 u _int32_t dest, tmask;486 uint32_t mask; 487 uint32_t dest, tmask; 457 488 struct IFADDRLIST *al; 458 489 char buf[256], tdevice[256], device[256]; 459 490 460 f = bb_xfopen(route, "r");491 f = xfopen("/proc/net/route", "r"); 461 492 462 493 /* Find the appropriate interface */ … … 468 499 if (n == 1 && strncmp(buf, "Iface", 5) == 0) 469 500 continue; 470 if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x", 471 tdevice, &dest, &tmask)) != 3) 472 bb_error_msg_and_die ("junk in buffer"); 473 if ((to->sin_addr.s_addr & tmask) == dest && 474 (tmask > mask || mask == 0)) { 501 i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x", 502 tdevice, &dest, &tmask); 503 if (i != 3) 504 bb_error_msg_and_die("junk in buffer"); 505 if ((to->sin_addr.s_addr & tmask) == dest 506 && (tmask > mask || mask == 0) 507 ) { 475 508 mask = tmask; 476 509 strcpy(device, tdevice); … … 480 513 481 514 if (device[0] == '\0') 482 bb_error_msg_and_die ("Can't find interface");515 bb_error_msg_and_die("can't find interface"); 483 516 484 517 /* Get the interface address list */ … … 490 523 break; 491 524 if (i <= 0) 492 bb_error_msg_and_die(" Can't find interface %s", device);525 bb_error_msg_and_die("can't find interface %s", device); 493 526 494 527 setsin(from, al->addr); … … 502 535 */ 503 536 504 /* String to value with optional min and max. Handles decimal and hex. */505 537 static int 506 str2val(const char *str, const char *what, int mi, int ma) 507 { 508 const char *cp; 509 int val; 510 char *ep; 511 512 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 513 cp = str + 2; 514 val = (int)strtol(cp, &ep, 16); 515 } else 516 val = (int)strtol(str, &ep, 10); 517 if (*ep != '\0') { 518 bb_error_msg_and_die("\"%s\" bad value for %s \n", str, what); 519 } 520 if (val < mi && mi >= 0) { 521 if (mi == 0) 522 bb_error_msg_and_die("%s must be >= %d\n", what, mi); 523 else 524 bb_error_msg_and_die("%s must be > %d\n", what, mi - 1); 525 } 526 if (val > ma && ma >= 0) 527 bb_error_msg_and_die("%s must be <= %d\n", what, ma); 528 return val; 529 } 530 531 532 /* 533 * Subtract 2 timeval structs: out = out - in. 534 * Out is assumed to be >= in. 535 */ 536 static inline void 537 tvsub(struct timeval *out, struct timeval *in) 538 { 539 540 if ((out->tv_usec -= in->tv_usec) < 0) { 541 --out->tv_sec; 542 out->tv_usec += 1000000; 543 } 544 out->tv_sec -= in->tv_sec; 545 } 546 547 static int 548 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp) 538 wait_for_reply(int sock, struct sockaddr_in *fromp) 549 539 { 550 540 fd_set fds; 551 struct timeval now, wait; 552 struct timezone tz; 541 struct timeval tvwait; 553 542 int cc = 0; 554 543 socklen_t fromlen = sizeof(*fromp); … … 557 546 FD_SET(sock, &fds); 558 547 559 wait.tv_sec = tp->tv_sec + waittime; 560 wait.tv_usec = tp->tv_usec; 561 (void)gettimeofday(&now, &tz); 562 tvsub(&wait, &now); 563 564 if (select(sock + 1, &fds, NULL, NULL, &wait) > 0) 548 tvwait.tv_sec = waittime; 549 tvwait.tv_usec = 0; 550 551 if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0) 565 552 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, 566 553 (struct sockaddr *)fromp, &fromlen); … … 572 559 * Checksum routine for Internet Protocol family headers (C Version) 573 560 */ 574 static u _short575 in_cksum(u _short *addr, int len)561 static uint16_t 562 in_cksum(uint16_t *addr, int len) 576 563 { 577 564 int nleft = len; 578 u _short *w = addr;579 u _short answer;565 uint16_t *w = addr; 566 uint16_t answer; 580 567 int sum = 0; 581 568 … … 606 593 607 594 static void 608 send_probe(int seq, int ttl , struct timeval *tp)595 send_probe(int seq, int ttl) 609 596 { 610 597 int cc; … … 622 609 if (doipcksum) { 623 610 outip->ip_sum = 624 in_cksum((u _short *)outip, sizeof(*outip) + optlen);611 in_cksum((uint16_t *)outip, sizeof(*outip) + optlen); 625 612 if (outip->ip_sum == 0) 626 613 outip->ip_sum = 0xffff; … … 630 617 outdata->seq = seq; 631 618 outdata->ttl = ttl; 632 memcpy(&outdata->tv, tp, sizeof(outdata->tv)); 633 634 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP 619 // UNUSED: was storing gettimeofday's result there, but never ever checked it 620 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ 621 622 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 635 623 if (useicmp) 636 624 outicmp->icmp_seq = htons(seq); … … 639 627 outudp->dest = htons(port + seq); 640 628 641 #if def CONFIG_FEATURE_TRACEROUTE_USE_ICMP629 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 642 630 if (useicmp) { 643 631 /* Always calculate checksum for icmp packets */ 644 632 outicmp->icmp_cksum = 0; 645 outicmp->icmp_cksum = in_cksum((u _short *)outicmp,633 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, 646 634 packlen - (sizeof(*outip) + optlen)); 647 635 if (outicmp->icmp_cksum == 0) … … 649 637 } else 650 638 #endif 651 639 if (doipcksum) { 652 640 /* Checksum (we must save and restore ip header) */ 653 641 tip = *outip; … … 661 649 ui->ui_len = outudp->len; 662 650 outudp->check = 0; 663 outudp->check = in_cksum((u _short *)ui, packlen);651 outudp->check = in_cksum((uint16_t *)ui, packlen); 664 652 if (outudp->check == 0) 665 653 outudp->check = 0xffff; … … 667 655 } 668 656 669 #if def CONFIG_FEATURE_TRACEROUTE_VERBOSE657 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 670 658 /* XXX undocumented debugging hack */ 671 659 if (verbose > 1) { 672 const u _short *sp;660 const uint16_t *sp; 673 661 int nshorts, i; 674 662 675 sp = (u _short *)outip;676 nshorts = (u _int)packlen / sizeof(u_short);663 sp = (uint16_t *)outip; 664 nshorts = (unsigned)packlen / sizeof(uint16_t); 677 665 i = 0; 678 666 printf("[ %d bytes", packlen); … … 699 687 #endif 700 688 701 cc = sendto(sndsock, (char *)outip, 702 packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto)); 703 if (cc < 0 || cc != packlen) { 704 if (cc < 0) 705 bb_perror_msg_and_die("sendto"); 706 printf("%s: wrote %s %d chars, ret=%d\n", 707 bb_applet_name, hostname, packlen, cc); 708 (void)fflush(stdout); 709 } 710 } 711 712 static inline double 713 deltaT(struct timeval *t1p, struct timeval *t2p) 714 { 715 double dt; 716 717 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 718 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 719 return dt; 720 } 721 722 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 689 cc = xsendto(sndsock, (char *)outip, 690 packlen, (struct sockaddr *)&whereto, sizeof(whereto)); 691 if (cc != packlen) { 692 bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc); 693 } 694 } 695 696 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 723 697 /* 724 698 * Convert an ICMP "type" field to a printable string. … … 727 701 pr_type(unsigned char t) 728 702 { 729 static const char * 703 static const char *const ttab[] = { 730 704 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 731 705 "Source Quench", "Redirect", "ICMP 6", "ICMP 7", … … 753 727 hlen = ip->ip_hl << 2; 754 728 if (cc < hlen + ICMP_MINLEN) { 755 #if def CONFIG_FEATURE_TRACEROUTE_VERBOSE729 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 756 730 if (verbose) 757 731 printf("packet too short (%d bytes) from %s\n", cc, … … 777 751 hip = &icp->icmp_ip; 778 752 hlen = hip->ip_hl << 2; 779 #if def CONFIG_FEATURE_TRACEROUTE_USE_ICMP753 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 780 754 if (useicmp) { 781 755 struct icmp *hicmp; … … 796 770 } else 797 771 #endif 798 772 { 799 773 up = (struct udphdr *)((unsigned char *)hip + hlen); 800 774 /* XXX 8 is a magic number */ … … 806 780 } 807 781 } 808 #if def CONFIG_FEATURE_TRACEROUTE_VERBOSE782 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 809 783 if (verbose) { 810 784 int i; 811 u _int32_t *lp = (u_int32_t *)&icp->icmp_ip;785 uint32_t *lp = (uint32_t *)&icp->icmp_ip; 812 786 813 787 printf("\n%d bytes from %s to " … … 815 789 cc, inet_ntoa(from->sin_addr), 816 790 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); 817 for (i = 4; i < cc 791 for (i = 4; i < cc; i += sizeof(*lp)) 818 792 printf("%2d: x%8.8x\n", i, *lp++); 819 793 } … … 829 803 */ 830 804 static inline void 831 inetname(struct sockaddr_in *from) 832 { 833 const char *n = NULL; 805 print_inetname(struct sockaddr_in *from) 806 { 834 807 const char *ina; 835 char name[257]; 836 837 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) { 838 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) 839 n = name; 840 } 808 841 809 ina = inet_ntoa(from->sin_addr); 842 810 if (nflag) 843 811 printf(" %s", ina); 844 else 812 else { 813 char *n = NULL; 814 if (from->sin_addr.s_addr != INADDR_ANY) 815 n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); 845 816 printf(" %s (%s)", (n ? n : ina), ina); 817 free(n); 818 } 846 819 } 847 820 … … 856 829 cc -= hlen; 857 830 858 inetname(from);859 #if def CONFIG_FEATURE_TRACEROUTE_VERBOSE831 print_inetname(from); 832 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 860 833 if (verbose) 861 printf(" %d bytes to %s", cc, inet_ntoa 834 printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); 862 835 #endif 863 836 } … … 871 844 struct hostinfo *hi; 872 845 char **p; 873 u _int32_t addr, *ap;874 875 hi = x calloc(1,sizeof(*hi));846 uint32_t addr, *ap; 847 848 hi = xzalloc(sizeof(*hi)); 876 849 addr = inet_addr(host); 877 if ( (int32_t)addr != -1) {878 hi->name = bb_xstrdup(host);850 if (addr != 0xffffffff) { 851 hi->name = xstrdup(host); 879 852 hi->n = 1; 880 hi->addrs = x calloc(1,sizeof(hi->addrs[0]));853 hi->addrs = xzalloc(sizeof(hi->addrs[0])); 881 854 hi->addrs[0] = addr; 882 855 return hi; … … 886 859 if (hp->h_addrtype != AF_INET || hp->h_length != 4) 887 860 bb_perror_msg_and_die("bad host %s", host); 888 hi->name = bb_xstrdup(hp->h_name);861 hi->name = xstrdup(hp->h_name); 889 862 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) 890 863 continue; 891 864 hi->n = n; 892 hi->addrs = x calloc(n,sizeof(hi->addrs[0]));865 hi->addrs = xzalloc(n * sizeof(hi->addrs[0])); 893 866 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) 894 867 memcpy(ap, *p, sizeof(*ap)); … … 900 873 { 901 874 free(hi->name); 902 hi->name = NULL; 903 free((char *)hi->addrs); 904 free((char *)hi); 905 } 906 907 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 875 free(hi->addrs); 876 free(hi); 877 } 878 879 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 908 880 static void 909 getaddr(u _int32_t *ap, const char *host)881 getaddr(uint32_t *ap, const char *host) 910 882 { 911 883 struct hostinfo *hi; … … 917 889 #endif 918 890 919 920 int 921 traceroute_main(int argc, char *argv[]) 891 static void 892 print_delta_ms(unsigned t1p, unsigned t2p) 893 { 894 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) 922 900 { 923 901 int code, n; 924 char *cp;925 902 unsigned char *outp; 926 u _int32_t *ap;927 struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;928 struct sockaddr_in *to = (struct sockaddr_in *)&whereto;903 uint32_t *ap; 904 struct sockaddr_in *from; 905 struct sockaddr_in *to; 929 906 struct hostinfo *hi; 930 int on = 1;931 struct protoent *pe;932 907 int ttl, probe, i; 933 908 int seq = 0; 934 909 int tos = 0; 935 char *tos_str = NULL; 936 char *source = NULL; 937 unsigned long op; 938 939 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 910 char *tos_str; 911 char *source; 912 unsigned op; 913 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 940 914 int lsrr = 0; 941 915 #endif 942 u _short off = 0;916 uint16_t off = 0; 943 917 struct IFADDRLIST *al; 944 char *device = NULL;918 char *device; 945 919 int max_ttl = 30; 946 char *max_ttl_str = NULL;947 char *port_str = NULL;920 char *max_ttl_str; 921 char *port_str; 948 922 int nprobes = 3; 949 char *nprobes_str = NULL;950 char *waittime_str = NULL;951 u _intpausemsecs = 0;952 char *pausemsecs_str = NULL;923 char *nprobes_str; 924 char *waittime_str; 925 unsigned pausemsecs = 0; 926 char *pausemsecs_str; 953 927 int first_ttl = 1; 954 char *first_ttl_str = NULL; 955 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 956 llist_t *sourse_route_list = NULL; 957 #endif 958 959 opterr = 0; 960 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 961 bb_opt_complementally = "x-x:g::"; 928 char *first_ttl_str; 929 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 930 llist_t *source_route_list = NULL; 931 #endif 932 933 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 934 from = (struct sockaddr_in *)&wherefrom; 935 to = (struct sockaddr_in *)&whereto; 936 937 //opterr = 0; 938 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 939 opt_complementary = "x-x:g::"; 962 940 #else 963 bb_opt_complementally = "x-x"; 964 #endif 965 966 op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:" 967 #define USAGE_OP_DONT_FRAGMNT (1<<0) /* F */ 968 #define USAGE_OP_USE_ICMP (1<<1) /* I */ 969 #define USAGE_OP_TTL_FLAG (1<<2) /* l */ 970 #define USAGE_OP_ADDR_NUM (1<<3) /* n */ 971 #define USAGE_OP_BYPASS_ROUTE (1<<4) /* r */ 972 #define USAGE_OP_DEBUG (1<<5) /* d */ 973 #define USAGE_OP_VERBOSE (1<<6) /* v */ 974 #define USAGE_OP_IP_CHKSUM (1<<7) /* x */ 975 976 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 941 opt_complementary = "x-x"; 942 #endif 943 944 op = getopt32(argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:" 945 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 977 946 "g:" 978 947 #endif 979 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,980 &source, &waittime_str, &pausemsecs_str, &first_ttl_str981 #if def CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE982 , &sourse_route_list948 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str 949 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str 950 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 951 , &source_route_list 983 952 #endif 984 953 ); 985 954 986 if (op & USAGE_OP_DONT_FRAGMNT)955 if (op & OPT_DONT_FRAGMNT) 987 956 off = IP_DF; 988 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP 989 useicmp = op & USAGE_OP_USE_ICMP; 990 #endif 991 nflag = op & USAGE_OP_ADDR_NUM; 992 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 993 verbose = op & USAGE_OP_VERBOSE; 994 #endif 995 if(op & USAGE_OP_IP_CHKSUM) { 957 if (op & OPT_IP_CHKSUM) { 996 958 doipcksum = 0; 997 bb_error_msg("Warning: ip checksums disabled"); 998 } 999 if (tos_str) 1000 tos = str2val(tos_str, "tos", 0, 255); 1001 if(max_ttl_str) 1002 max_ttl = str2val(max_ttl_str, "max ttl", 1, 255); 1003 if(port_str) 1004 port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1); 1005 if(nprobes_str) 1006 nprobes = str2val(nprobes_str, "nprobes", 1, -1); 1007 if(source) { 1008 /* 1009 * set the ip source address of the outbound 1010 * probe (e.g., on a multi-homed host). 1011 */ 1012 if (getuid()) bb_error_msg_and_die("-s %s: Permission denied", source); 1013 } 1014 if(waittime_str) 1015 waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60); 1016 if(pausemsecs_str) 1017 pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000); 1018 if(first_ttl_str) 1019 first_ttl = str2val(first_ttl_str, "first ttl", 1, 255); 1020 1021 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 1022 if(sourse_route_list) { 959 bb_error_msg("warning: ip checksums disabled"); 960 } 961 if (op & OPT_TOS) 962 tos = xatou_range(tos_str, 0, 255); 963 if (op & OPT_MAX_TTL) 964 max_ttl = xatou_range(max_ttl_str, 1, 255); 965 if (op & OPT_PORT) 966 port = xatou16(port_str); 967 if (op & OPT_NPROBES) 968 nprobes = xatou_range(nprobes_str, 1, INT_MAX); 969 if (op & OPT_SOURCE) { 970 /* 971 * set the ip source address of the outbound 972 * probe (e.g., on a multi-homed host). 973 */ 974 if (getuid()) 975 bb_error_msg_and_die("-s %s: permission denied", source); 976 } 977 if (op & OPT_WAITTIME) 978 waittime = xatou_range(waittime_str, 2, 24 * 60 * 60); 979 if (op & OPT_PAUSE_MS) 980 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000); 981 if (op & OPT_FIRST_TTL) 982 first_ttl = xatou_range(first_ttl_str, 1, 255); 983 984 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 985 if (source_route_list) { 1023 986 llist_t *l_sr; 1024 987 1025 for(l_sr = sourse_route_list; l_sr; ) { 988 l_sr = source_route_list; 989 while (l_sr) { 1026 990 if (lsrr >= NGATEWAYS) 1027 bb_error_msg_and_die(" No more than %d gateways", NGATEWAYS);991 bb_error_msg_and_die("no more than %d gateways", NGATEWAYS); 1028 992 getaddr(gwlist + lsrr, l_sr->data); 1029 993 ++lsrr; 1030 994 l_sr = l_sr->link; 1031 free(sour se_route_list);1032 sour se_route_list = l_sr;995 free(source_route_list); 996 source_route_list = l_sr; 1033 997 } 1034 998 optlen = (lsrr + 1) * sizeof(gwlist[0]); … … 1044 1008 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen; 1045 1009 1046 #if def CONFIG_FEATURE_TRACEROUTE_USE_ICMP1010 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 1047 1011 if (useicmp) 1048 1012 minpacket += 8; /* XXX magic number */ … … 1056 1020 1057 1021 case 2: 1058 packlen = str2val(argv[optind + 1], 1059 "packet length", minpacket, maxpacket); 1022 packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket); 1060 1023 /* Fall through */ 1061 1024 … … 1065 1028 setsin(to, hi->addrs[0]); 1066 1029 if (hi->n > 1) 1067 bb_error_msg( 1068 "Warning: %s has multiple addresses; using %s", 1030 bb_error_msg("warning: %s has multiple addresses; using %s", 1069 1031 hostname, inet_ntoa(to->sin_addr)); 1070 1032 hostname = hi->name; … … 1077 1039 } 1078 1040 1079 cp = "icmp"; 1080 if ((pe = getprotobyname(cp)) == NULL) 1081 bb_perror_msg_and_die("unknown protocol %s", cp); 1082 1083 /* Insure the socket fds won't be 0, 1 or 2 */ 1084 do n = bb_xopen(bb_dev_null, O_RDONLY); while (n < 2); 1085 if (n > 2) 1086 close(n); 1087 1088 s = bb_xsocket(AF_INET, SOCK_RAW, pe->p_proto); 1089 1090 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG 1091 if (op & USAGE_OP_DEBUG) 1092 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, 1093 sizeof(on)); 1094 #endif 1095 if (op & USAGE_OP_BYPASS_ROUTE) 1096 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, 1097 sizeof(on)); 1098 1099 sndsock = bb_xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); 1100 1101 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 1041 /* Ensure the socket fds won't be 0, 1 or 2 */ 1042 bb_sanitize_stdio(); 1043 1044 s = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 1045 1046 #if TRACEROUTE_SO_DEBUG 1047 if (op & OPT_DEBUG) 1048 setsockopt(s, SOL_SOCKET, SO_DEBUG, 1049 &const_int_1, sizeof(const_int_1)); 1050 #endif 1051 if (op & OPT_BYPASS_ROUTE) 1052 setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 1053 &const_int_1, sizeof(const_int_1)); 1054 1055 sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); 1056 1057 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 1102 1058 #if defined(IP_OPTIONS) 1103 1059 if (lsrr > 0) { 1104 1060 unsigned char optlist[MAX_IPOPTLEN]; 1105 1106 cp = "ip";1107 if ((pe = getprotobyname(cp)) == NULL)1108 bb_perror_msg_and_die("unknown protocol");1109 1061 1110 1062 /* final hop */ … … 1122 1074 memcpy(optlist + 4, gwlist, i); 1123 1075 1124 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,1076 if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, 1125 1077 (char *)optlist, i + sizeof(gwlist[0]))) < 0) { 1126 1078 bb_perror_msg_and_die("IP_OPTIONS"); 1127 1079 } 1128 1080 } 1129 1081 #endif /* IP_OPTIONS */ … … 1131 1083 1132 1084 #ifdef SO_SNDBUF 1133 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, 1134 sizeof(packlen)) < 0) { 1085 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { 1135 1086 bb_perror_msg_and_die("SO_SNDBUF"); 1136 1087 } 1137 1088 #endif 1138 1089 #ifdef IP_HDRINCL 1139 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 1140 sizeof(on)) < 0 && errno != ENOPROTOOPT) { 1090 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 0 1091 && errno != ENOPROTOOPT 1092 ) { 1141 1093 bb_perror_msg_and_die("IP_HDRINCL"); 1142 1094 } 1143 1095 #else 1144 1096 #ifdef IP_TOS 1145 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS, 1146 (char *)&tos, sizeof(tos)) < 0) { 1097 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { 1147 1098 bb_perror_msg_and_die("setsockopt tos %d", tos); 1148 1099 } 1149 1100 #endif 1150 1101 #endif 1151 #if def CONFIG_FEATURE_TRACEROUTE_SO_DEBUG1152 if (op & USAGE_OP_DEBUG)1153 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,1154 sizeof(on));1155 #endif 1156 if (op & USAGE_OP_BYPASS_ROUTE)1157 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,1158 sizeof(on));1102 #if TRACEROUTE_SO_DEBUG 1103 if (op & OPT_DEBUG) 1104 setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 1105 &const_int_1, sizeof(const_int_1)); 1106 #endif 1107 if (op & OPT_BYPASS_ROUTE) 1108 setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 1109 &const_int_1, sizeof(const_int_1)); 1159 1110 1160 1111 /* Revert to non-privileged user after opening sockets */ … … 1162 1113 xsetuid(getuid()); 1163 1114 1164 outip = (struct ip *)xcalloc(1, (unsigned)packlen);1115 outip = xzalloc(packlen); 1165 1116 1166 1117 outip->ip_v = IPVERSION; … … 1174 1125 outip->ip_hl = (outp - (unsigned char *)outip) >> 2; 1175 1126 ident = (getpid() & 0xffff) | 0x8000; 1176 #if def CONFIG_FEATURE_TRACEROUTE_USE_ICMP1127 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 1177 1128 if (useicmp) { 1178 1129 outip->ip_p = IPPROTO_ICMP; 1179 1180 1130 outicmp = (struct icmp *)outp; 1181 1131 outicmp->icmp_type = ICMP_ECHO; 1182 1132 outicmp->icmp_id = htons(ident); 1183 1184 1133 outdata = (struct outdata *)(outp + 8); /* XXX magic number */ 1185 1134 } else 1186 1135 #endif 1187 1136 { 1188 1137 outip->ip_p = IPPROTO_UDP; 1189 1190 1138 outudp = (struct udphdr *)outp; 1191 1139 outudp->source = htons(ident); 1192 outudp->len = 1193 htons((u_short)(packlen - (sizeof(*outip) + optlen))); 1140 outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen))); 1194 1141 outdata = (struct outdata *)(outudp + 1); 1195 1142 } … … 1199 1146 1200 1147 /* Look for a specific device */ 1201 if ( device != NULL) {1148 if (op & OPT_DEVICE) { 1202 1149 for (i = n; i > 0; --i, ++al) 1203 1150 if (strcmp(device, al->device) == 0) 1204 break; 1205 if (i <= 0) { 1206 bb_error_msg_and_die("Can't find interface %s", device); 1207 } 1208 } 1151 goto found_dev; 1152 bb_error_msg_and_die("can't find interface %s", device); 1153 } 1154 found_dev: 1209 1155 1210 1156 /* Determine our source address */ 1211 if ( source == NULL) {1157 if (!(op & OPT_SOURCE)) { 1212 1158 /* 1213 1159 * If a device was specified, use the interface address. 1214 1160 * Otherwise, try to determine our source address. 1215 1161 */ 1216 if ( device != NULL)1162 if (op & OPT_DEVICE) 1217 1163 setsin(from, al->addr); 1218 1164 findsaddr(to, from); … … 1227 1173 * there are more than one). 1228 1174 */ 1229 if ( device != NULL) {1175 if (op & OPT_DEVICE) { 1230 1176 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) 1231 1177 if (*ap == al->addr) 1232 break; 1233 if (i <= 0) { 1234 bb_error_msg_and_die( 1235 "%s is not on interface %s", 1236 source, device); 1237 } 1178 goto found_dev2; 1179 bb_error_msg_and_die("%s is not on interface %s", 1180 source, device); 1181 found_dev2: 1238 1182 setsin(from, *ap); 1239 1183 } else { … … 1241 1185 if (hi->n > 1) 1242 1186 bb_error_msg( 1243 " Warning: %s has multiple addresses; using %s",1187 "warning: %s has multiple addresses; using %s", 1244 1188 source, inet_ntoa(from->sin_addr)); 1245 1189 } … … 1249 1193 outip->ip_src = from->sin_addr; 1250 1194 #ifndef IP_HDRINCL 1251 bb_xbind(sndsock, (struct sockaddr *)from, sizeof(*from));1252 #endif 1253 1254 fprintf(stderr,"traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));1255 if ( source)1256 fprintf(stderr," from %s", source);1257 fprintf(stderr,", %d hops max, %d byte packets\n", max_ttl, packlen);1258 (void)fflush(stderr);1195 xbind(sndsock, (struct sockaddr *)from, sizeof(*from)); 1196 #endif 1197 1198 printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr)); 1199 if (op & OPT_SOURCE) 1200 printf(" from %s", source); 1201 printf(", %d hops max, %d byte packets\n", max_ttl, packlen); 1202 fflush(stdout); 1259 1203 1260 1204 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 1261 u _int32_t lastaddr = 0;1205 uint32_t lastaddr = 0; 1262 1206 int gotlastaddr = 0; 1263 1207 int got_there = 0; … … 1268 1212 for (probe = 0; probe < nprobes; ++probe) { 1269 1213 int cc; 1270 struct timeval t1, t2;1271 struct timezone tz;1214 unsigned t1; 1215 unsigned t2; 1272 1216 struct ip *ip; 1273 1217 1274 1218 if (sentfirst && pausemsecs > 0) 1275 1219 usleep(pausemsecs * 1000); 1276 (void)gettimeofday(&t1, &tz);1277 send_probe(++seq, ttl , &t1);1220 t1 = monotonic_us(); 1221 send_probe(++seq, ttl); 1278 1222 ++sentfirst; 1279 while ((cc = wait_for_reply(s, from , &t1)) != 0) {1280 (void)gettimeofday(&t2, &tz);1223 while ((cc = wait_for_reply(s, from)) != 0) { 1224 t2 = monotonic_us(); 1281 1225 i = packet_ok(packet, cc, from, seq); 1282 1226 /* Skip short packet */ … … 1289 1233 ++gotlastaddr; 1290 1234 } 1291 print f(" %.3f ms", deltaT(&t1, &t2));1235 print_delta_ms(t1, t2); 1292 1236 ip = (struct ip *)packet; 1293 if (op & USAGE_OP_TTL_FLAG)1237 if (op & OPT_TTL_FLAG) 1294 1238 printf(" (%d)", ip->ip_ttl); 1295 1239 if (i == -2) { -
branches/2.2.5/mindi-busybox/networking/udhcp/Config.in
r821 r1765 4 4 # 5 5 6 menu "udhcp Server/Client" 7 8 config CONFIG_APP_UDHCPD 6 config APP_UDHCPD 9 7 bool "udhcp Server (udhcpd)" 10 8 default n … … 15 13 See http://udhcp.busybox.net for further details. 16 14 17 config CONFIG_APP_UDHCPC 15 config APP_DHCPRELAY 16 bool "dhcprelay" 17 default n 18 depends on APP_UDHCPD 19 help 20 dhcprelay listens for dhcp requests on one or more interfaces 21 and forwards these requests to a different interface or dhcp 22 server. 23 24 config APP_DUMPLEASES 25 bool "Lease display utility (dumpleases)" 26 default n 27 depends on APP_UDHCPD 28 help 29 dumpleases displays the leases written out by the udhcpd server. 30 Lease times are stored in the file by time remaining in lease, or 31 by the absolute time that it expires in seconds from epoch. 32 33 See http://udhcp.busybox.net for further details. 34 35 config FEATURE_UDHCPD_WRITE_LEASES_EARLY 36 bool "Rewrite the lease file at every new acknowledge" 37 default n 38 depends on APP_UDHCPD 39 help 40 If selected, udhcpd will write a new file with leases every 41 time a new lease has been accepted, thus eleminating the need 42 to send SIGUSR1 for the initial writing, or updating. Any timed 43 rewriting remains undisturbed 44 45 config APP_UDHCPC 18 46 bool "udhcp Client (udhcpc)" 19 47 default n … … 27 55 See http://udhcp.busybox.net for further details. 28 56 29 config CONFIG_APP_DUMPLEASES30 bool " Lease display utility (dumpleases)"57 config FEATURE_UDHCP_DEBUG 58 bool "Compile udhcp with noisy debugging messages" 31 59 default n 32 depends on CONFIG_APP_UDHCPD 33 help 34 dumpleases displays the leases written out by the udhcpd server. 35 Lease times are stored in the file by time remaining in lease, or 36 by the absolute time that it expires in seconds from epoch. 37 38 See http://udhcp.busybox.net for further details. 39 40 config CONFIG_FEATURE_UDHCP_SYSLOG 41 bool " Log udhcp messages to syslog (instead of stdout)" 42 default n 43 depends on CONFIG_APP_UDHCPD || CONFIG_APP_UDHCPC 44 help 45 If selected, udhcpd will log all its messages to syslog, otherwise, 46 it will attempt to log them to stdout. 47 48 See http://udhcp.busybox.net for further details. 49 50 config CONFIG_FEATURE_UDHCP_DEBUG 51 bool " Compile udhcp with noisy debugging messages" 52 default n 53 depends on CONFIG_APP_UDHCPD || CONFIG_APP_UDHCPC 60 depends on APP_UDHCPD || APP_UDHCPC 54 61 help 55 62 If selected, udhcpd will output extra debugging output. If using … … 59 66 See http://udhcp.busybox.net for further details. 60 67 61 endmenu 62 68 config FEATURE_RFC3397 69 bool "Support for RFC3397 domain search (experimental)" 70 default n 71 depends on APP_UDHCPD || APP_UDHCPC 72 help 73 If selected, both client and server will support passing of domain 74 search lists via option 119, specified in RFC3397. -
branches/2.2.5/mindi-busybox/networking/udhcp/arpping.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * arpping.c … … 6 7 */ 7 8 8 #include <time.h>9 #include <sys/socket.h>10 9 #include <netinet/if_ether.h> 11 10 #include <net/if_arp.h> 12 #include <netinet/in.h>13 #include <string.h>14 #include <unistd.h>15 #include <errno.h>16 11 12 #include "common.h" 17 13 #include "dhcpd.h" 18 #include "arpping.h"19 #include "common.h"20 21 /* args: yiaddr - what IP to ping22 * ip - our ip23 * mac - our arp address24 * interface - interface to use25 * retn: 1 addr free26 * 0 addr used27 * -1 error28 */29 30 /* FIXME: match response against chaddr */31 int arpping(uint32_t yiaddr, uint32_t ip, uint8_t *mac, char *interface)32 {33 34 int timeout = 2;35 int optval = 1;36 int s; /* socket */37 int rv = 1; /* return value */38 struct sockaddr addr; /* for interface name */39 struct arpMsg arp;40 fd_set fdset;41 struct timeval tm;42 time_t prevTime;43 14 44 15 45 if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) { 46 #ifdef IN_BUSYBOX 47 LOG(LOG_ERR, bb_msg_can_not_create_raw_socket); 48 #else 49 LOG(LOG_ERR, "Could not open raw socket"); 50 #endif 16 struct arpMsg { 17 /* Ethernet header */ 18 uint8_t h_dest[6]; /* 00 destination ether addr */ 19 uint8_t h_source[6]; /* 06 source ether addr */ 20 uint16_t h_proto; /* 0c packet type ID field */ 21 22 /* ARP packet */ 23 uint16_t htype; /* 0e hardware type (must be ARPHRD_ETHER) */ 24 uint16_t ptype; /* 10 protocol type (must be ETH_P_IP) */ 25 uint8_t hlen; /* 12 hardware address length (must be 6) */ 26 uint8_t plen; /* 13 protocol address length (must be 4) */ 27 uint16_t operation; /* 14 ARP opcode */ 28 uint8_t sHaddr[6]; /* 16 sender's hardware address */ 29 uint8_t sInaddr[4]; /* 1c sender's IP address */ 30 uint8_t tHaddr[6]; /* 20 target's hardware address */ 31 uint8_t tInaddr[4]; /* 26 target's IP address */ 32 uint8_t pad[18]; /* 2a pad for min. ethernet payload (60 bytes) */ 33 } ATTRIBUTE_PACKED; 34 35 36 /* Returns 1 if no reply received */ 37 38 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) 39 { 40 int timeout = 2; 41 int s; /* socket */ 42 int rv = 1; /* "no reply received" yet */ 43 struct sockaddr addr; /* for interface name */ 44 struct arpMsg arp; 45 fd_set fdset; 46 struct timeval tm; 47 unsigned prevTime; 48 49 s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); 50 if (s == -1) { 51 bb_perror_msg(bb_msg_can_not_create_raw_socket); 51 52 return -1; 52 53 } 53 54 54 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) { 55 LOG(LOG_ERR, "Could not setsocketopt on raw socket"); 56 close(s); 57 return -1; 55 if (setsockopt_broadcast(s) == -1) { 56 bb_perror_msg("cannot setsocketopt on raw socket"); 57 goto ret; 58 58 } 59 59 60 60 /* send arp request */ 61 61 memset(&arp, 0, sizeof(arp)); 62 memcpy(arp.h_dest, MAC_BCAST_ADDR, 6); /* MAC DA */ 63 memcpy(arp.h_source, mac, 6); /* MAC SA */ 64 arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */ 65 arp.htype = htons(ARPHRD_ETHER); /* hardware type */ 66 arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */ 67 arp.hlen = 6; /* hardware address length */ 68 arp.plen = 4; /* protocol address length */ 69 arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ 70 memcpy(arp.sInaddr, &ip, sizeof(ip)); /* source IP address */ 71 memcpy(arp.sHaddr, mac, 6); /* source hardware address */ 72 memcpy(arp.tInaddr, &yiaddr, sizeof(yiaddr)); /* target IP address */ 62 memset(arp.h_dest, 0xff, 6); /* MAC DA */ 63 memcpy(arp.h_source, from_mac, 6); /* MAC SA */ 64 arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */ 65 arp.htype = htons(ARPHRD_ETHER); /* hardware type */ 66 arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */ 67 arp.hlen = 6; /* hardware address length */ 68 arp.plen = 4; /* protocol address length */ 69 arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ 70 memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */ 71 memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */ 72 /* tHaddr */ /* target hardware address */ 73 memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */ 73 74 74 75 memset(&addr, 0, sizeof(addr)); 75 s trcpy(addr.sa_data, interface);76 safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data)); 76 77 if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) 77 rv = 0;78 goto ret; 78 79 79 /* wait arp reply, and check it */80 tm.tv_usec = 0;81 prevTime = uptime();82 while (timeout > 0) {80 /* wait for arp reply, and check it */ 81 do { 82 int r; 83 prevTime = monotonic_sec(); 83 84 FD_ZERO(&fdset); 84 85 FD_SET(s, &fdset); 85 86 tm.tv_sec = timeout; 86 if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) { 87 DEBUG(LOG_ERR, "Error on ARPING request: %m"); 88 if (errno != EINTR) rv = 0; 89 } else if (FD_ISSET(s, &fdset)) { 90 if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0; 91 if (arp.operation == htons(ARPOP_REPLY) && 92 memcmp(arp.tHaddr, mac, 6) == 0 && 93 *((uint32_t *) arp.sInaddr) == yiaddr) { 94 DEBUG(LOG_INFO, "Valid arp reply receved for this address"); 87 tm.tv_usec = 0; 88 r = select(s + 1, &fdset, NULL, NULL, &tm); 89 if (r < 0) { 90 bb_perror_msg("error on ARPING request"); 91 if (errno != EINTR) 92 break; 93 } else if (r) { 94 if (recv(s, &arp, sizeof(arp), 0) < 0) 95 break; 96 if (arp.operation == htons(ARPOP_REPLY) 97 && memcmp(arp.tHaddr, from_mac, 6) == 0 98 && *((uint32_t *) arp.sInaddr) == test_ip 99 ) { 95 100 rv = 0; 96 101 break; 97 102 } 98 103 } 99 timeout -= uptime() - prevTime; 100 prevTime = uptime(); 101 } 104 timeout -= monotonic_sec() - prevTime; 105 } while (timeout > 0); 106 107 ret: 102 108 close(s); 103 DEBUG( LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V");109 DEBUG("%srp reply received for this address", rv ? "No a" : "A"); 104 110 return rv; 105 111 } -
branches/2.2.5/mindi-busybox/networking/udhcp/clientpacket.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* clientpacket.c 2 3 * … … 8 9 */ 9 10 10 #include <string.h>11 #include <sys/socket.h>12 11 #include <features.h> 13 #if ( __GLIBC__ >= 2 && __GLIBC_MINOR>= 1) || defined _NEWLIB_VERSION12 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION 14 13 #include <netpacket/packet.h> 15 14 #include <net/ethernet.h> … … 19 18 #include <linux/if_ether.h> 20 19 #endif 21 #include <stdlib.h> 22 #include <time.h> 23 #include <unistd.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <fcntl.h> 27 28 20 21 #include "common.h" 29 22 #include "dhcpd.h" 30 #include " clientpacket.h"23 #include "dhcpc.h" 31 24 #include "options.h" 32 #include "dhcpc.h"33 #include "common.h"34 25 35 26 36 27 /* Create a random xid */ 37 unsigned long random_xid(void) 38 { 39 static int initialized; 28 uint32_t random_xid(void) 29 { 30 static smallint initialized; 31 40 32 if (!initialized) { 41 int fd; 42 unsigned long seed; 43 44 fd = open("/dev/urandom", 0); 45 if (fd < 0 || read(fd, &seed, sizeof(seed)) < 0) { 46 LOG(LOG_WARNING, "Could not load seed from /dev/urandom: %m"); 47 seed = time(0); 48 } 49 if (fd >= 0) close(fd); 50 srand(seed); 51 initialized++; 33 srand(monotonic_us()); 34 initialized = 1; 52 35 } 53 36 return rand(); … … 61 44 memcpy(packet->chaddr, client_config.arp, 6); 62 45 if (client_config.clientid) 63 add_option_string(packet->options, client_config.clientid); 64 if (client_config.hostname) add_option_string(packet->options, client_config.hostname); 65 if (client_config.fqdn) add_option_string(packet->options, client_config.fqdn); 46 add_option_string(packet->options, client_config.clientid); 47 if (client_config.hostname) 48 add_option_string(packet->options, client_config.hostname); 49 if (client_config.fqdn) 50 add_option_string(packet->options, client_config.fqdn); 66 51 add_option_string(packet->options, client_config.vendorclass); 67 52 } … … 87 72 88 73 /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ 89 int send_discover(u nsigned long xid, unsigned longrequested)74 int send_discover(uint32_t xid, uint32_t requested) 90 75 { 91 76 struct dhcpMessage packet; … … 97 82 98 83 add_requests(&packet); 99 LOG(LOG_DEBUG, "Sending discover..."); 84 bb_info_msg("Sending discover..."); 85 return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, 86 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); 87 } 88 89 90 /* Broadcasts a DHCP request message */ 91 int send_selecting(uint32_t xid, uint32_t server, uint32_t requested) 92 { 93 struct dhcpMessage packet; 94 struct in_addr addr; 95 96 init_packet(&packet, DHCPREQUEST); 97 packet.xid = xid; 98 99 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); 100 add_simple_option(packet.options, DHCP_SERVER_ID, server); 101 102 add_requests(&packet); 103 addr.s_addr = requested; 104 bb_info_msg("Sending select for %s...", inet_ntoa(addr)); 100 105 return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, 101 106 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); … … 103 108 104 109 105 /* Broadcasts a DHCP request message */106 int send_selecting(unsigned long xid, unsigned long server, unsigned long requested)107 {108 struct dhcpMessage packet;109 struct in_addr addr;110 111 init_packet(&packet, DHCPREQUEST);112 packet.xid = xid;113 114 add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);115 add_simple_option(packet.options, DHCP_SERVER_ID, server);116 117 add_requests(&packet);118 addr.s_addr = requested;119 LOG(LOG_DEBUG, "Sending select for %s...", inet_ntoa(addr));120 return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,121 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);122 }123 124 125 110 /* Unicasts or broadcasts a DHCP renew message */ 126 int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr) 127 { 128 struct dhcpMessage packet; 129 int ret = 0; 111 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) 112 { 113 struct dhcpMessage packet; 130 114 131 115 init_packet(&packet, DHCPREQUEST); … … 134 118 135 119 add_requests(&packet); 136 LOG(LOG_DEBUG,"Sending renew...");120 bb_info_msg("Sending renew..."); 137 121 if (server) 138 ret = udhcp_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); 139 else ret = udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, 122 return udhcp_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); 123 124 return udhcp_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, 140 125 SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); 141 return ret;142 126 } 143 127 144 128 145 129 /* Unicasts a DHCP release message */ 146 int send_release(u nsigned long server, unsigned longciaddr)130 int send_release(uint32_t server, uint32_t ciaddr) 147 131 { 148 132 struct dhcpMessage packet; … … 155 139 add_simple_option(packet.options, DHCP_SERVER_ID, server); 156 140 157 LOG(LOG_DEBUG,"Sending release...");141 bb_info_msg("Sending release..."); 158 142 return udhcp_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); 159 143 } … … 171 155 bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet)); 172 156 if (bytes < 0) { 173 DEBUG( LOG_INFO, "couldn't read on raw listening socket -- ignoring");157 DEBUG("Cannot read on raw listening socket - ignoring"); 174 158 usleep(500000); /* possible down interface, looping condition */ 175 159 return -1; … … 177 161 178 162 if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) { 179 DEBUG( LOG_INFO, "message too short, ignoring");163 DEBUG("Message too short, ignoring"); 180 164 return -2; 181 165 } 182 166 183 167 if (bytes < ntohs(packet.ip.tot_len)) { 184 DEBUG( LOG_INFO,"Truncated packet");168 DEBUG("Truncated packet"); 185 169 return -2; 186 170 } … … 190 174 191 175 /* Make sure its the right packet for us, and that it passes sanity checks */ 192 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION || 193 packet.ip.ihl != sizeof(packet.ip) >> 2 || packet.udp.dest != htons(CLIENT_PORT) || 194 bytes > (int) sizeof(struct udp_dhcp_packet) || 195 ntohs(packet.udp.len) != (uint16_t) (bytes - sizeof(packet.ip))) { 196 DEBUG(LOG_INFO, "unrelated/bogus packet"); 176 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION 177 || packet.ip.ihl != sizeof(packet.ip) >> 2 178 || packet.udp.dest != htons(CLIENT_PORT) 179 || bytes > (int) sizeof(struct udp_dhcp_packet) 180 || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip)) 181 ) { 182 DEBUG("Unrelated/bogus packet"); 197 183 return -2; 198 184 } … … 202 188 packet.ip.check = 0; 203 189 if (check != udhcp_checksum(&(packet.ip), sizeof(packet.ip))) { 204 DEBUG( LOG_INFO,"bad IP header checksum, ignoring");190 DEBUG("bad IP header checksum, ignoring"); 205 191 return -1; 206 192 } … … 218 204 packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */ 219 205 if (check && check != udhcp_checksum(&packet, bytes)) { 220 DEBUG(LOG_ERR,"packet with bad UDP checksum received, ignoring");206 bb_error_msg("packet with bad UDP checksum received, ignoring"); 221 207 return -2; 222 208 } … … 225 211 226 212 if (ntohl(payload->cookie) != DHCP_MAGIC) { 227 LOG(LOG_ERR, "received bogus message (bad magic) -- ignoring");228 return -2; 229 } 230 DEBUG( LOG_INFO,"oooooh!!! got some!");213 bb_error_msg("received bogus message (bad magic) - ignoring"); 214 return -2; 215 } 216 DEBUG("oooooh!!! got some!"); 231 217 return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); 232 233 } 218 } -
branches/2.2.5/mindi-busybox/networking/udhcp/clientsocket.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * clientsocket.c -- DHCP client socket creation … … 21 22 */ 22 23 23 #include <sys/types.h>24 #include <sys/socket.h>25 #include <unistd.h>26 #include <netinet/in.h>27 24 #include <features.h> 28 #if ( __GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION25 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION) 29 26 #include <netpacket/packet.h> 30 27 #include <net/ethernet.h> … … 35 32 #endif 36 33 37 #include "clientsocket.h"38 34 #include "common.h" 39 35 … … 44 40 struct sockaddr_ll sock; 45 41 46 DEBUG(LOG_INFO, "Opening raw socket on ifindex %d", ifindex); 47 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 48 DEBUG(LOG_ERR, "socket call failed: %m"); 49 return -1; 50 } 42 DEBUG("Opening raw socket on ifindex %d", ifindex); 43 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 51 44 52 45 sock.sll_family = AF_PACKET; 53 46 sock.sll_protocol = htons(ETH_P_IP); 54 47 sock.sll_ifindex = ifindex; 55 if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { 56 DEBUG(LOG_ERR, "bind call failed: %m"); 57 close(fd); 58 return -1; 59 } 48 xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); 60 49 61 50 return fd; -
branches/2.2.5/mindi-busybox/networking/udhcp/common.c
r821 r1765 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* common.c 3 *4 * Functions for debugging and logging as well as some other5 * simple helper functions.6 *7 * Russ Dill <Russ.Dill@asu.edu> 2001-20038 * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 20039 3 * 10 4 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 11 5 */ 12 6 13 #include <fcntl.h> 14 #include <unistd.h> 15 #include <errno.h> 16 #include <string.h> 17 #include <stdlib.h> 18 #include <signal.h> 19 #include <paths.h> 20 #include <sys/socket.h> 21 #include <stdarg.h> 7 #include "common.h" 22 8 23 #include "common.h" 24 #include "pidfile.h" 25 26 27 static int daemonized; 28 29 long uptime(void) 30 { 31 struct sysinfo info; 32 sysinfo(&info); 33 return info.uptime; 34 } 35 36 37 /* 38 * This function makes sure our first socket calls 39 * aren't going to fd 1 (printf badness...) and are 40 * not later closed by daemon() 41 */ 42 static inline void sanitize_fds(void) 43 { 44 int zero; 45 if ((zero = open(bb_dev_null, O_RDWR, 0)) < 0) 46 return; 47 while (zero < 3) 48 zero = dup(zero); 49 close(zero); 50 } 51 52 53 void udhcp_background(const char *pidfile) 54 { 55 #ifdef __uClinux__ 56 LOG(LOG_ERR, "Cannot background in uclinux (yet)"); 57 #else /* __uClinux__ */ 58 int pid_fd; 59 60 /* hold lock during fork. */ 61 pid_fd = pidfile_acquire(pidfile); 62 if (daemon(0, 0) == -1) { /* bb_xdaemon? */ 63 perror("fork"); 64 exit(1); 65 } 66 daemonized++; 67 pidfile_write_release(pid_fd); 68 #endif /* __uClinux__ */ 69 } 70 71 72 #ifdef CONFIG_FEATURE_UDHCP_SYSLOG 73 74 void udhcp_logging(int level, const char *fmt, ...) 75 { 76 va_list p; 77 va_list p2; 78 79 va_start(p, fmt); 80 __va_copy(p2, p); 81 if (!daemonized) { 82 vprintf(fmt, p); 83 putchar('\n'); 84 } 85 vsyslog(level, fmt, p2); 86 va_end(p); 87 } 88 89 #else 90 91 92 static char *syslog_level_msg[] = { 93 [LOG_EMERG] = "EMERGENCY!", 94 [LOG_ALERT] = "ALERT!", 95 [LOG_CRIT] = "critical!", 96 [LOG_WARNING] = "warning", 97 [LOG_ERR] = "error", 98 [LOG_INFO] = "info", 99 [LOG_DEBUG] = "debug" 9 const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = { 10 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 100 11 }; 101 102 103 void udhcp_logging(int level, const char *fmt, ...)104 {105 va_list p;106 107 va_start(p, fmt);108 if (!daemonized) {109 printf("%s, ", syslog_level_msg[level]);110 vprintf(fmt, p);111 putchar('\n');112 }113 va_end(p);114 }115 #endif116 117 118 void udhcp_start_log_and_pid(const char *client_server, const char *pidfile)119 {120 int pid_fd;121 122 /* Make sure our syslog fd isn't overwritten */123 sanitize_fds();124 125 /* do some other misc startup stuff while we are here to save bytes */126 pid_fd = pidfile_acquire(pidfile);127 pidfile_write_release(pid_fd);128 129 /* equivelent of doing a fflush after every \n */130 setlinebuf(stdout);131 132 if (ENABLE_FEATURE_UDHCP_SYSLOG)133 openlog(client_server, LOG_PID | LOG_CONS, LOG_LOCAL0);134 135 udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, BB_VER);136 } -
branches/2.2.5/mindi-busybox/networking/udhcp/common.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* common.h 2 3 * … … 10 11 #define _COMMON_H 11 12 12 #include "libbb_udhcp.h" 13 #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 #include <netinet/udp.h> 22 #include <netinet/ip.h> 23 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 { 44 struct iphdr ip; 45 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); 13 59 14 60 15 enum syslog_levels { 16 LOG_EMERG = 0, 17 LOG_ALERT, 18 LOG_CRIT, 19 LOG_WARNING, 20 LOG_ERR, 21 LOG_INFO, 22 LOG_DEBUG 23 }; 24 #include <syslog.h> 61 /**/ 25 62 26 long uptime(void);63 void udhcp_run_script(struct dhcpMessage *packet, const char *name); 27 64 28 #define LOG(level, str, args...) udhcp_logging(level, str, ## args) 65 // Still need to clean these up... 66 67 /* from options.h */ 68 #define get_option udhcp_get_option 69 #define end_option udhcp_end_option 70 #define add_option_string udhcp_add_option_string 71 #define add_simple_option udhcp_add_simple_option 72 #define option_lengths udhcp_option_lengths 73 /* from socket.h */ 74 #define listen_socket udhcp_listen_socket 75 #define read_interface udhcp_read_interface 76 /* from dhcpc.h */ 77 #define client_config udhcp_client_config 78 /* from dhcpd.h */ 79 #define server_config udhcp_server_config 80 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); 87 /* Returns 1 if no reply received */ 88 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface); 29 89 30 90 #if ENABLE_FEATURE_UDHCP_DEBUG 31 # define DEBUG( level, str, args...) LOG(level,str, ## args)91 # define DEBUG(str, args...) bb_info_msg(str, ## args) 32 92 #else 33 # define DEBUG( level, str, args...) do {;} while(0)93 # define DEBUG(str, args...) do {;} while (0) 34 94 #endif 35 95 -
branches/2.2.5/mindi-busybox/networking/udhcp/dhcpc.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* dhcpc.c 2 3 * … … 8 9 */ 9 10 10 #include <sys/file.h>11 #include <unistd.h>12 11 #include <getopt.h> 13 #include <stdlib.h> 14 #include <sys/socket.h> 15 #include <netinet/in.h> 16 #include <arpa/inet.h> 17 #include <signal.h> 18 #include <time.h> 19 #include <string.h> 20 #include <sys/ioctl.h> 21 #include <net/if.h> 22 #include <errno.h> 23 12 #include <syslog.h> 13 14 /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ 15 #define WANT_PIDFILE 1 24 16 #include "common.h" 25 17 #include "dhcpd.h" 26 18 #include "dhcpc.h" 27 19 #include "options.h" 28 #include "clientpacket.h" 29 #include "clientsocket.h" 30 #include "socket.h" 31 #include "signalpipe.h" 32 33 static int state; 34 static unsigned long requested_ip; /* = 0 */ 35 static unsigned long server_addr; 36 static unsigned long timeout; 20 21 22 /* Something is definitely wrong here. IPv4 addresses 23 * in variables of type long?? BTW, we use inet_ntoa() 24 * in the code. Manpage says that struct in_addr has a member of type long (!) 25 * which holds IPv4 address, and the struct is passed by value (!!) 26 */ 27 static unsigned timeout; 28 static uint32_t requested_ip; /* = 0 */ 29 static uint32_t server_addr; 37 30 static int packet_num; /* = 0 */ 38 static int fd = -1;31 static int sockfd = -1; 39 32 40 33 #define LISTEN_NONE 0 41 34 #define LISTEN_KERNEL 1 42 35 #define LISTEN_RAW 2 43 static int listen_mode; 44 45 struct client_config_t client_config = { 46 /* Default options. */ 47 .abort_if_no_lease = 0, 48 .foreground = 0, 49 .quit_after_lease = 0, 50 .background_if_no_lease = 0, 51 .interface = "eth0", 52 .pidfile = NULL, 53 .script = DEFAULT_SCRIPT, 54 .clientid = NULL, 55 .vendorclass = NULL, 56 .hostname = NULL, 57 .fqdn = NULL, 58 .ifindex = 0, 59 .retries = 3, 60 .timeout = 3, 61 .arp = "\0\0\0\0\0\0", /* appease gcc-3.0 */ 62 }; 36 static smallint listen_mode; 37 38 static smallint state; 39 40 struct client_config_t client_config; 41 63 42 64 43 /* just a little helper */ 65 44 static void change_mode(int new_mode) 66 45 { 67 DEBUG( LOG_INFO,"entering %s listen mode",46 DEBUG("entering %s listen mode", 68 47 new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); 69 if (fd >= 0) close(fd); 70 fd = -1; 48 if (sockfd >= 0) { 49 close(sockfd); 50 sockfd = -1; 51 } 71 52 listen_mode = new_mode; 72 53 } … … 76 57 static void perform_renew(void) 77 58 { 78 LOG(LOG_INFO,"Performing a DHCP renew");59 bb_info_msg("Performing a DHCP renew"); 79 60 switch (state) { 80 61 case BOUND: … … 106 87 static void perform_release(void) 107 88 { 108 char buffer[ 16];89 char buffer[sizeof("255.255.255.255")]; 109 90 struct in_addr temp_addr; 110 91 … … 112 93 if (state == BOUND || state == RENEWING || state == REBINDING) { 113 94 temp_addr.s_addr = server_addr; 114 s printf(buffer, "%s", inet_ntoa(temp_addr));95 strcpy(buffer, inet_ntoa(temp_addr)); 115 96 temp_addr.s_addr = requested_ip; 116 LOG(LOG_INFO,"Unicasting a release of %s to %s",97 bb_info_msg("Unicasting a release of %s to %s", 117 98 inet_ntoa(temp_addr), buffer); 118 99 send_release(server_addr, requested_ip); /* unicast */ 119 100 udhcp_run_script(NULL, "deconfig"); 120 101 } 121 LOG(LOG_INFO,"Entering released state");102 bb_info_msg("Entering released state"); 122 103 123 104 change_mode(LISTEN_NONE); 124 105 state = RELEASED; 125 timeout = 0x7fffffff;106 timeout = INT_MAX; 126 107 } 127 108 … … 129 110 static void client_background(void) 130 111 { 131 udhcp_background(client_config.pidfile); 132 client_config.foreground = 1; /* Do not fork again. */ 112 #if !BB_MMU 113 bb_error_msg("cannot background in uclinux (yet)"); 114 /* ... mainly because udhcpc calls client_background() 115 * in _the _middle _of _udhcpc _run_, not at the start! 116 * If that will be properly disabled for NOMMU, client_background() 117 * will work on NOMMU too */ 118 #else 119 bb_daemonize(0); 120 logmode &= ~LOGMODE_STDIO; 121 /* rewrite pidfile, as our pid is different now */ 122 write_pidfile(client_config.pidfile); 123 #endif 124 /* Do not fork again. */ 125 client_config.foreground = 1; 133 126 client_config.background_if_no_lease = 0; 134 127 } 135 128 136 129 137 int udhcpc_main(int argc, char *argv[]) 130 static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 131 { 132 uint8_t *storage; 133 int len = strlen(str); 134 if (len > 255) len = 255; 135 storage = xzalloc(len + extra + OPT_DATA); 136 storage[OPT_CODE] = code; 137 storage[OPT_LEN] = len + extra; 138 memcpy(storage + extra + OPT_DATA, str, len); 139 return storage; 140 } 141 142 143 int udhcpc_main(int argc, char **argv); 144 int udhcpc_main(int argc, char **argv) 138 145 { 139 146 uint8_t *temp, *message; 140 unsigned long t1 = 0, t2 = 0, xid = 0; 141 unsigned long start = 0, lease; 147 char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t; 148 uint32_t xid = 0; 149 uint32_t lease = 0; /* can be given as 32-bit quantity */ 150 unsigned t1 = 0, t2 = 0; /* what a wonderful names */ 151 unsigned start = 0; 152 unsigned now; 153 unsigned opt; 154 int max_fd; 155 int retval; 156 int len; 157 struct timeval tv; 158 struct in_addr temp_addr; 159 struct dhcpMessage packet; 142 160 fd_set rfds; 143 int retval; 144 struct timeval tv; 145 int c, len; 146 struct dhcpMessage packet; 147 struct in_addr temp_addr; 148 long now; 149 int max_fd; 150 int sig; 151 int no_clientid = 0; 152 153 static const struct option arg_options[] = { 154 {"clientid", required_argument, 0, 'c'}, 155 {"clientid-none", no_argument, 0, 'C'}, 156 {"vendorclass", required_argument, 0, 'V'}, 157 {"foreground", no_argument, 0, 'f'}, 158 {"background", no_argument, 0, 'b'}, 159 {"hostname", required_argument, 0, 'H'}, 160 {"hostname", required_argument, 0, 'h'}, 161 {"fqdn", required_argument, 0, 'F'}, 162 {"interface", required_argument, 0, 'i'}, 163 {"now", no_argument, 0, 'n'}, 164 {"pidfile", required_argument, 0, 'p'}, 165 {"quit", no_argument, 0, 'q'}, 166 {"request", required_argument, 0, 'r'}, 167 {"script", required_argument, 0, 's'}, 168 {"timeout", required_argument, 0, 'T'}, 169 {"version", no_argument, 0, 'v'}, 170 {"retries", required_argument, 0, 't'}, 171 {0, 0, 0, 0} 161 162 enum { 163 OPT_c = 1 << 0, 164 OPT_C = 1 << 1, 165 OPT_V = 1 << 2, 166 OPT_f = 1 << 3, 167 OPT_b = 1 << 4, 168 OPT_H = 1 << 5, 169 OPT_h = 1 << 6, 170 OPT_F = 1 << 7, 171 OPT_i = 1 << 8, 172 OPT_n = 1 << 9, 173 OPT_p = 1 << 10, 174 OPT_q = 1 << 11, 175 OPT_R = 1 << 12, 176 OPT_r = 1 << 13, 177 OPT_s = 1 << 14, 178 OPT_T = 1 << 15, 179 OPT_t = 1 << 16, 180 OPT_v = 1 << 17, 181 OPT_S = 1 << 18, 172 182 }; 173 174 /* get options */ 175 while (1) { 176 int option_index = 0; 177 c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qr:s:T:t:v", arg_options, &option_index); 178 if (c == -1) break; 179 180 switch (c) { 181 case 'c': 182 if (no_clientid) bb_show_usage(); 183 len = strlen(optarg) > 255 ? 255 : strlen(optarg); 184 free(client_config.clientid); 185 client_config.clientid = xmalloc(len + 2); 186 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; 187 client_config.clientid[OPT_LEN] = len; 188 client_config.clientid[OPT_DATA] = '\0'; 189 strncpy((char*)client_config.clientid + OPT_DATA, optarg, len); 190 break; 191 case 'C': 192 if (client_config.clientid) bb_show_usage(); 193 no_clientid = 1; 194 break; 195 case 'V': 196 len = strlen(optarg) > 255 ? 255 : strlen(optarg); 197 free(client_config.vendorclass); 198 client_config.vendorclass = xmalloc(len + 2); 199 client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; 200 client_config.vendorclass[OPT_LEN] = len; 201 strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len); 202 break; 203 case 'f': 204 client_config.foreground = 1; 205 break; 206 case 'b': 207 client_config.background_if_no_lease = 1; 208 break; 209 case 'h': 210 case 'H': 211 len = strlen(optarg) > 255 ? 255 : strlen(optarg); 212 free(client_config.hostname); 213 client_config.hostname = xmalloc(len + 2); 214 client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; 215 client_config.hostname[OPT_LEN] = len; 216 strncpy((char*)client_config.hostname + 2, optarg, len); 217 break; 218 case 'F': 219 len = strlen(optarg) > 255 ? 255 : strlen(optarg); 220 free(client_config.fqdn); 221 client_config.fqdn = xmalloc(len + 5); 222 client_config.fqdn[OPT_CODE] = DHCP_FQDN; 223 client_config.fqdn[OPT_LEN] = len + 3; 224 /* Flags: 0000NEOS 225 S: 1 => Client requests Server to update A RR in DNS as well as PTR 226 O: 1 => Server indicates to client that DNS has been updated regardless 227 E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" 228 N: 1 => Client requests Server to not update DNS 229 */ 230 client_config.fqdn[OPT_LEN + 1] = 0x1; 231 client_config.fqdn[OPT_LEN + 2] = 0; 232 client_config.fqdn[OPT_LEN + 3] = 0; 233 strncpy((char*)client_config.fqdn + 5, optarg, len); 234 break; 235 case 'i': 236 client_config.interface = optarg; 237 break; 238 case 'n': 239 client_config.abort_if_no_lease = 1; 240 break; 241 case 'p': 242 client_config.pidfile = optarg; 243 break; 244 case 'q': 245 client_config.quit_after_lease = 1; 246 break; 247 case 'r': 248 requested_ip = inet_addr(optarg); 249 break; 250 case 's': 251 client_config.script = optarg; 252 break; 253 case 'T': 254 client_config.timeout = atoi(optarg); 255 break; 256 case 't': 257 client_config.retries = atoi(optarg); 258 break; 259 case 'v': 260 printf("version %s\n\n", BB_VER); 261 return 0; 262 break; 263 default: 264 bb_show_usage(); 265 } 266 } 267 268 /* Start the log, sanitize fd's, and write a pid file */ 269 udhcp_start_log_and_pid("udhcpc", client_config.pidfile); 183 #if ENABLE_GETOPT_LONG 184 static const char udhcpc_longopts[] ALIGN1 = 185 "clientid\0" Required_argument "c" 186 "clientid-none\0" No_argument "C" 187 "vendorclass\0" Required_argument "V" 188 "foreground\0" No_argument "f" 189 "background\0" No_argument "b" 190 "hostname\0" Required_argument "H" 191 "hostname\0" Required_argument "h" 192 "fqdn\0" Required_argument "F" 193 "interface\0" Required_argument "i" 194 "now\0" No_argument "n" 195 "pidfile\0" Required_argument "p" 196 "quit\0" No_argument "q" 197 "release\0" No_argument "R" 198 "request\0" Required_argument "r" 199 "script\0" Required_argument "s" 200 "timeout\0" Required_argument "T" 201 "version\0" No_argument "v" 202 "retries\0" Required_argument "t" 203 "syslog\0" No_argument "S" 204 ; 205 #endif 206 /* Default options. */ 207 client_config.interface = "eth0"; 208 client_config.script = DEFAULT_SCRIPT; 209 client_config.retries = 3; 210 client_config.timeout = 3; 211 212 /* Parse command line */ 213 opt_complementary = "c--C:C--c" // mutually exclusive 214 ":hH:Hh"; // -h and -H are the same 215 #if ENABLE_GETOPT_LONG 216 applet_long_options = udhcpc_longopts; 217 #endif 218 opt = getopt32(argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:vS", 219 &str_c, &str_V, &str_h, &str_h, &str_F, 220 &client_config.interface, &client_config.pidfile, &str_r, 221 &client_config.script, &str_T, &str_t 222 ); 223 224 if (opt & OPT_c) 225 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0); 226 //if (opt & OPT_C) 227 if (opt & OPT_V) 228 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); 229 if (opt & OPT_f) 230 client_config.foreground = 1; 231 if (opt & OPT_b) 232 client_config.background_if_no_lease = 1; 233 if (opt & OPT_h) 234 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); 235 if (opt & OPT_F) { 236 client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); 237 /* Flags: 0000NEOS 238 S: 1 => Client requests Server to update A RR in DNS as well as PTR 239 O: 1 => Server indicates to client that DNS has been updated regardless 240 E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" 241 N: 1 => Client requests Server to not update DNS 242 */ 243 client_config.fqdn[OPT_DATA + 0] = 0x1; 244 /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */ 245 /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */ 246 } 247 // if (opt & OPT_i) client_config.interface = ... 248 if (opt & OPT_n) 249 client_config.abort_if_no_lease = 1; 250 // if (opt & OPT_p) client_config.pidfile = ... 251 if (opt & OPT_q) 252 client_config.quit_after_lease = 1; 253 if (opt & OPT_R) 254 client_config.release_on_quit = 1; 255 if (opt & OPT_r) 256 requested_ip = inet_addr(str_r); 257 // if (opt & OPT_s) client_config.script = ... 258 if (opt & OPT_T) 259 client_config.timeout = xatoi_u(str_T); 260 if (opt & OPT_t) 261 client_config.retries = xatoi_u(str_t); 262 if (opt & OPT_v) { 263 printf("version %s\n", BB_VER); 264 return 0; 265 } 266 267 if (opt & OPT_S) { 268 openlog(applet_name, LOG_PID, LOG_LOCAL0); 269 logmode |= LOGMODE_SYSLOG; 270 } 270 271 271 272 if (read_interface(client_config.interface, &client_config.ifindex, 272 NULL, client_config.arp) < 0)273 NULL, client_config.arp)) 273 274 return 1; 274 275 276 /* Make sure fd 0,1,2 are open */ 277 bb_sanitize_stdio(); 278 /* Equivalent of doing a fflush after every \n */ 279 setlinebuf(stdout); 280 281 /* Create pidfile */ 282 write_pidfile(client_config.pidfile); 283 /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */ 284 285 /* Goes to stdout and possibly syslog */ 286 bb_info_msg("%s (v%s) started", applet_name, BB_VER); 287 275 288 /* if not set, and not suppressed, setup the default client ID */ 276 if (!client_config.clientid && !no_clientid) { 277 client_config.clientid = xmalloc(6 + 3); 278 client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; 279 client_config.clientid[OPT_LEN] = 7; 289 if (!client_config.clientid && !(opt & OPT_C)) { 290 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); 280 291 client_config.clientid[OPT_DATA] = 1; 281 memcpy(client_config.clientid + 3, client_config.arp, 6); 282 } 283 284 if (!client_config.vendorclass) { 285 client_config.vendorclass = xmalloc(sizeof("udhcp "BB_VER) + 2); 286 client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; 287 client_config.vendorclass[OPT_LEN] = sizeof("udhcp "BB_VER) - 1; 288 client_config.vendorclass[OPT_DATA] = 1; 289 memcpy(&client_config.vendorclass[OPT_DATA], 290 "udhcp "BB_VER, sizeof("udhcp "BB_VER) - 1); 291 } 292 292 memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6); 293 } 294 295 if (!client_config.vendorclass) 296 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0); 293 297 294 298 /* setup the signal pipe */ … … 298 302 udhcp_run_script(NULL, "deconfig"); 299 303 change_mode(LISTEN_RAW); 304 tv.tv_sec = 0; 305 goto jump_in; 300 306 301 307 for (;;) { 302 303 tv.tv_sec = timeout - uptime(); 308 tv.tv_sec = timeout - monotonic_sec(); 309 jump_in: 304 310 tv.tv_usec = 0; 305 311 306 if (listen_mode != LISTEN_NONE && fd < 0) {312 if (listen_mode != LISTEN_NONE && sockfd < 0) { 307 313 if (listen_mode == LISTEN_KERNEL) 308 fd = listen_socket(INADDR_ANY,CLIENT_PORT, client_config.interface);314 sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); 309 315 else 310 fd = raw_socket(client_config.ifindex); 311 if (fd < 0) { 312 LOG(LOG_ERR, "FATAL: couldn't listen on socket, %m"); 313 return 0; 314 } 316 sockfd = raw_socket(client_config.ifindex); 315 317 } 316 max_fd = udhcp_sp_fd_set(&rfds, fd); 317 318 max_fd = udhcp_sp_fd_set(&rfds, sockfd); 319 320 retval = 0; /* If we already timed out, fall through, else... */ 318 321 if (tv.tv_sec > 0) { 319 DEBUG( LOG_INFO,"Waiting on select...");322 DEBUG("Waiting on select..."); 320 323 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 321 } else retval = 0; /* If we already timed out, fall through */ 322 323 now = uptime(); 324 if (retval == 0) { 324 } 325 326 now = monotonic_sec(); 327 if (retval < 0) { 328 /* EINTR? signal was caught, don't panic */ 329 if (errno != EINTR) { 330 /* Else: an error occured, panic! */ 331 bb_perror_msg_and_die("select"); 332 } 333 } else if (retval == 0) { 325 334 /* timeout dropped to zero */ 326 335 switch (state) { … … 338 347 udhcp_run_script(NULL, "leasefail"); 339 348 if (client_config.background_if_no_lease) { 340 LOG(LOG_INFO, "No lease, forking to background.");349 bb_info_msg("No lease, forking to background"); 341 350 client_background(); 342 351 } else if (client_config.abort_if_no_lease) { 343 LOG(LOG_INFO, "No lease, failing."); 344 return 1; 352 bb_info_msg("No lease, failing"); 353 retval = 1; 354 goto ret; 345 355 } 346 356 /* wait to try again */ … … 361 371 } else { 362 372 /* timed out, go back to init state */ 363 if (state == RENEW_REQUESTED) udhcp_run_script(NULL, "deconfig"); 373 if (state == RENEW_REQUESTED) 374 udhcp_run_script(NULL, "deconfig"); 364 375 state = INIT_SELECTING; 365 376 timeout = now; … … 372 383 state = RENEWING; 373 384 change_mode(LISTEN_KERNEL); 374 DEBUG( LOG_INFO,"Entering renew state");385 DEBUG("Entering renew state"); 375 386 /* fall right through */ 376 387 case RENEWING: … … 380 391 state = REBINDING; 381 392 timeout = now + (t2 - t1); 382 DEBUG( LOG_INFO,"Entering rebinding state");393 DEBUG("Entering rebinding state"); 383 394 } else { 384 395 /* send a request packet */ 385 396 send_renew(xid, server_addr, requested_ip); /* unicast */ 386 387 397 t1 = (t2 - t1) / 2 + t1; 388 timeout = t1 + start;398 timeout = start + t1; 389 399 } 390 400 break; … … 394 404 /* timed out, enter init state */ 395 405 state = INIT_SELECTING; 396 LOG(LOG_INFO,"Lease lost, entering init state");406 bb_info_msg("Lease lost, entering init state"); 397 407 udhcp_run_script(NULL, "deconfig"); 398 408 timeout = now; … … 402 412 /* send a request packet */ 403 413 send_renew(xid, 0, requested_ip); /* broadcast */ 404 405 414 t2 = (lease - t2) / 2 + t2; 406 timeout = t2 + start;415 timeout = start + t2; 407 416 } 408 417 break; 409 418 case RELEASED: 410 419 /* yah, I know, *you* say it would never happen */ 411 timeout = 0x7fffffff;412 break; 413 } 414 } else if ( retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) {420 timeout = INT_MAX; 421 break; 422 } 423 } else if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) { 415 424 /* a packet is ready, read it */ 416 425 417 426 if (listen_mode == LISTEN_KERNEL) 418 len = udhcp_get_packet(&packet, fd);419 else len = get_raw_packet(&packet, fd);427 len = udhcp_get_packet(&packet, sockfd); 428 else len = get_raw_packet(&packet, sockfd); 420 429 421 430 if (len == -1 && errno != EINTR) { 422 DEBUG( LOG_INFO, "error on read, %m, reopening socket");431 DEBUG("error on read, %s, reopening socket", strerror(errno)); 423 432 change_mode(listen_mode); /* just close and reopen */ 424 433 } … … 426 435 427 436 if (packet.xid != xid) { 428 DEBUG( LOG_INFO, "Ignoring XID %lx (our xid is %lx)",429 (unsigned long) packet.xid,xid);437 DEBUG("Ignoring XID %x (our xid is %x)", 438 (unsigned)packet.xid, (unsigned)xid); 430 439 continue; 431 440 } … … 433 442 /* Ignore packets that aren't for us */ 434 443 if (memcmp(packet.chaddr, client_config.arp, 6)) { 435 DEBUG( LOG_INFO, "packet does not have our chaddr -- ignoring");444 DEBUG("Packet does not have our chaddr - ignoring"); 436 445 continue; 437 446 } 438 447 439 if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { 440 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring"); 448 message = get_option(&packet, DHCP_MESSAGE_TYPE); 449 if (message == NULL) { 450 bb_error_msg("cannot get option from packet - ignoring"); 441 451 continue; 442 452 } … … 446 456 /* Must be a DHCPOFFER to one of our xid's */ 447 457 if (*message == DHCPOFFER) { 448 if ((temp = get_option(&packet, DHCP_SERVER_ID))) { 458 temp = get_option(&packet, DHCP_SERVER_ID); 459 if (temp) { 460 /* can be misaligned, thus memcpy */ 449 461 memcpy(&server_addr, temp, 4); 450 462 xid = packet.xid; … … 456 468 packet_num = 0; 457 469 } else { 458 DEBUG(LOG_ERR, "No server ID in message");470 bb_error_msg("no server ID in message"); 459 471 } 460 472 } … … 465 477 case REBINDING: 466 478 if (*message == DHCPACK) { 467 if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { 468 LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease"); 479 temp = get_option(&packet, DHCP_LEASE_TIME); 480 if (!temp) { 481 bb_error_msg("no lease time with ACK, using 1 hour lease"); 469 482 lease = 60 * 60; 470 483 } else { 484 /* can be misaligned, thus memcpy */ 471 485 memcpy(&lease, temp, 4); 472 486 lease = ntohl(lease); … … 477 491 478 492 /* little fixed point for n * .875 */ 479 t2 = (lease * 0x7) >> 3;493 t2 = (lease * 7) >> 3; 480 494 temp_addr.s_addr = packet.yiaddr; 481 LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",482 inet_ntoa(temp_addr), lease);495 bb_info_msg("Lease of %s obtained, lease time %u", 496 inet_ntoa(temp_addr), (unsigned)lease); 483 497 start = now; 484 timeout = t1 + start;498 timeout = start + t1; 485 499 requested_ip = packet.yiaddr; 486 500 udhcp_run_script(&packet, … … 489 503 state = BOUND; 490 504 change_mode(LISTEN_NONE); 491 if (client_config.quit_after_lease) 492 return 0; 505 if (client_config.quit_after_lease) { 506 if (client_config.release_on_quit) 507 perform_release(); 508 goto ret0; 509 } 493 510 if (!client_config.foreground) 494 511 client_background(); … … 496 513 } else if (*message == DHCPNAK) { 497 514 /* return to init state */ 498 LOG(LOG_INFO,"Received DHCP NAK");515 bb_info_msg("Received DHCP NAK"); 499 516 udhcp_run_script(&packet, "nak"); 500 517 if (state != REQUESTING) … … 510 527 /* case BOUND, RELEASED: - ignore all packets */ 511 528 } 512 } else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) { 513 switch (sig) { 529 } else { 530 int signo = udhcp_sp_read(&rfds); 531 switch (signo) { 514 532 case SIGUSR1: 515 533 perform_renew(); … … 519 537 break; 520 538 case SIGTERM: 521 LOG(LOG_INFO, "Received SIGTERM"); 522 return 0; 523 } 524 } else if (retval == -1 && errno == EINTR) { 525 /* a signal was caught */ 526 } else { 527 /* An error occured */ 528 DEBUG(LOG_ERR, "Error on select"); 539 bb_info_msg("Received SIGTERM"); 540 if (client_config.release_on_quit) 541 perform_release(); 542 goto ret0; 543 } 529 544 } 530 531 } 532 return 0; 545 } /* for (;;) */ 546 ret0: 547 retval = 0; 548 ret: 549 /*if (client_config.pidfile) - remove_pidfile has it's own check */ 550 remove_pidfile(client_config.pidfile); 551 return retval; 533 552 } -
branches/2.2.5/mindi-busybox/networking/udhcp/dhcpc.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* dhcpc.h */ 2 3 #ifndef _DHCPC_H 3 4 #define _DHCPC_H 4 5 /* grab define DEFAULT_SCRIPT */6 #include "libbb_udhcp.h"7 5 8 6 #define INIT_SELECTING 0 … … 15 13 #define RELEASED 7 16 14 17 18 15 struct client_config_t { 19 char foreground; /* Do not fork */ 20 char quit_after_lease; /* Quit after obtaining lease */ 21 char abort_if_no_lease; /* Abort if no lease */ 22 char background_if_no_lease; /* Fork to background if no lease */ 23 char *interface; /* The name of the interface to use */ 24 char *pidfile; /* Optionally store the process ID */ 25 char *script; /* User script to run at dhcp events */ 26 uint8_t *clientid; /* Optional client id to use */ 27 uint8_t *vendorclass; /* Optional vendor class-id to use */ 28 uint8_t *hostname; /* Optional hostname to use */ 29 uint8_t *fqdn; /* Optional fully qualified domain name to use */ 30 int ifindex; /* Index number of the interface to use */ 31 int retries; /* Max number of request packets */ 32 int timeout; /* Number of seconds to try to get a lease */ 33 uint8_t arp[6]; /* Our arp address */ 16 /* TODO: combine flag fields into single "unsigned opt" */ 17 /* (can be set directly to the result of getopt32) */ 18 char foreground; /* Do not fork */ 19 char quit_after_lease; /* Quit after obtaining lease */ 20 char release_on_quit; /* Perform release on quit */ 21 char abort_if_no_lease; /* Abort if no lease */ 22 char background_if_no_lease; /* Fork to background if no lease */ 23 const char *interface; /* The name of the interface to use */ 24 char *pidfile; /* Optionally store the process ID */ 25 const char *script; /* User script to run at dhcp events */ 26 uint8_t *clientid; /* Optional client id to use */ 27 uint8_t *vendorclass; /* Optional vendor class-id to use */ 28 uint8_t *hostname; /* Optional hostname to use */ 29 uint8_t *fqdn; /* Optional fully qualified domain name to use */ 30 int ifindex; /* Index number of the interface to use */ 31 int retries; /* Max number of request packets */ 32 int timeout; /* Number of seconds to try to get a lease */ 33 uint8_t arp[6]; /* Our arp address */ 34 34 }; 35 35 … … 37 37 38 38 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 49 39 50 #endif -
branches/2.2.5/mindi-busybox/networking/udhcp/dhcpd.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* dhcpd.c 2 3 * … … 10 11 */ 11 12 12 #include <fcntl.h> 13 #include <string.h> 14 #include <stdlib.h> 15 #include <sys/wait.h> 16 #include <arpa/inet.h> 17 #include <netdb.h> 18 #include <netinet/in.h> 19 #include <sys/socket.h> 20 #include <unistd.h> 21 #include <signal.h> 22 #include <errno.h> 23 #include <sys/ioctl.h> 24 #include <time.h> 25 13 #include <syslog.h> 14 #include "common.h" 26 15 #include "dhcpd.h" 27 #include "arpping.h"28 #include "socket.h"29 16 #include "options.h" 30 #include "files.h"31 #include "serverpacket.h"32 #include "common.h"33 #include "signalpipe.h"34 #include "static_leases.h"35 17 36 18 … … 40 22 41 23 42 int udhcpd_main(int argc, char *argv[]) 24 int udhcpd_main(int argc, char **argv); 25 int udhcpd_main(int argc, char **argv) 43 26 { 44 27 fd_set rfds; … … 48 31 uint8_t *state, *server_id, *requested; 49 32 uint32_t server_id_align, requested_align, static_lease_ip; 50 unsigned long timeout_end, num_ips; 33 unsigned timeout_end; 34 unsigned num_ips; 35 unsigned opt; 51 36 struct option_set *option; 52 37 struct dhcpOfferedAddr *lease, static_lease; 53 38 54 read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]); 55 56 /* Start the log, sanitize fd's, and write a pid file */ 57 udhcp_start_log_and_pid("udhcpd", server_config.pidfile); 58 59 if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) { 39 opt = getopt32(argv, "fS"); 40 argv += optind; 41 42 if (!(opt & 1)) { /* no -f */ 43 bb_daemonize_or_rexec(0, argv); 44 logmode &= ~LOGMODE_STDIO; 45 } 46 47 if (opt & 2) { /* -S */ 48 openlog(applet_name, LOG_PID, LOG_LOCAL0); 49 logmode |= LOGMODE_SYSLOG; 50 } 51 52 /* Would rather not do read_config before daemonization - 53 * otherwise NOMMU machines will parse config twice */ 54 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE); 55 56 /* Make sure fd 0,1,2 are open */ 57 bb_sanitize_stdio(); 58 /* Equivalent of doing a fflush after every \n */ 59 setlinebuf(stdout); 60 61 /* Create pidfile */ 62 write_pidfile(server_config.pidfile); 63 /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */ 64 65 bb_info_msg("%s (v%s) started", applet_name, BB_VER); 66 67 option = find_option(server_config.options, DHCP_LEASE_TIME); 68 server_config.lease = LEASE_TIME; 69 if (option) { 60 70 memcpy(&server_config.lease, option->data + 2, 4); 61 71 server_config.lease = ntohl(server_config.lease); 62 72 } 63 else server_config.lease = LEASE_TIME;64 73 65 74 /* Sanity check */ 66 num_ips = ntohl(server_config.end) - ntohl(server_config.start)+ 1;75 num_ips = server_config.end_ip - server_config.start_ip + 1; 67 76 if (server_config.max_leases > num_ips) { 68 LOG(LOG_ERR, "max_leases value (%lu) not sane, " 69 "setting to %lu instead", 70 server_config.max_leases, num_ips); 77 bb_error_msg("max_leases=%u is too big, setting to %u", 78 (unsigned)server_config.max_leases, num_ips); 71 79 server_config.max_leases = num_ips; 72 80 } 73 81 74 leases = xzalloc(server_config.max_leases * sizeof( struct dhcpOfferedAddr));82 leases = xzalloc(server_config.max_leases * sizeof(*leases)); 75 83 read_leases(server_config.lease_file); 76 84 77 85 if (read_interface(server_config.interface, &server_config.ifindex, 78 &server_config.server, server_config.arp) < 0) 79 return 1; 80 81 if (!ENABLE_FEATURE_UDHCP_DEBUG) 82 udhcp_background(server_config.pidfile); /* hold lock during fork. */ 86 &server_config.server, server_config.arp)) { 87 retval = 1; 88 goto ret; 89 } 83 90 84 91 /* Setup the signal pipe */ 85 92 udhcp_sp_setup(); 86 93 87 timeout_end = time(0) + server_config.auto_time; 88 while(1) { /* loop until universe collapses */ 89 90 if (server_socket < 0) 91 if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) { 92 LOG(LOG_ERR, "FATAL: couldn't create server socket, %m"); 93 return 2; 94 } 94 timeout_end = monotonic_sec() + server_config.auto_time; 95 while (1) { /* loop until universe collapses */ 96 97 if (server_socket < 0) { 98 server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT, 99 server_config.interface); 100 } 95 101 96 102 max_sock = udhcp_sp_fd_set(&rfds, server_socket); 97 103 if (server_config.auto_time) { 98 tv.tv_sec = timeout_end - time(0);104 tv.tv_sec = timeout_end - monotonic_sec(); 99 105 tv.tv_usec = 0; 100 106 } 107 retval = 0; 101 108 if (!server_config.auto_time || tv.tv_sec > 0) { 102 109 retval = select(max_sock + 1, &rfds, NULL, NULL, 103 110 server_config.auto_time ? &tv : NULL); 104 } else retval = 0; /* If we already timed out, fall through */ 105 111 } 106 112 if (retval == 0) { 107 113 write_leases(); 108 timeout_end = time(0) + server_config.auto_time; 109 continue; 110 } else if (retval < 0 && errno != EINTR) { 111 DEBUG(LOG_INFO, "error on select"); 114 timeout_end = monotonic_sec() + server_config.auto_time; 115 continue; 116 } 117 if (retval < 0 && errno != EINTR) { 118 DEBUG("error on select"); 112 119 continue; 113 120 } … … 115 122 switch (udhcp_sp_read(&rfds)) { 116 123 case SIGUSR1: 117 LOG(LOG_INFO,"Received a SIGUSR1");124 bb_info_msg("Received a SIGUSR1"); 118 125 write_leases(); 119 126 /* why not just reset the timeout, eh */ 120 timeout_end = time(0) + server_config.auto_time;127 timeout_end = monotonic_sec() + server_config.auto_time; 121 128 continue; 122 129 case SIGTERM: 123 LOG(LOG_INFO,"Received a SIGTERM");124 return0;130 bb_info_msg("Received a SIGTERM"); 131 goto ret0; 125 132 case 0: break; /* no signal */ 126 133 default: continue; /* signal or error (probably EINTR) */ 127 134 } 128 135 129 if ((bytes = udhcp_get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */ 136 bytes = udhcp_get_packet(&packet, server_socket); /* this waits for a packet - idle */ 137 if (bytes < 0) { 130 138 if (bytes == -1 && errno != EINTR) { 131 DEBUG( LOG_INFO, "error on read, %m, reopening socket");139 DEBUG("error on read, %s, reopening socket", strerror(errno)); 132 140 close(server_socket); 133 141 server_socket = -1; … … 136 144 } 137 145 138 if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { 139 DEBUG(LOG_ERR, "couldn't get option from packet, ignoring"); 146 state = get_option(&packet, DHCP_MESSAGE_TYPE); 147 if (state == NULL) { 148 bb_error_msg("cannot get option from packet, ignoring"); 140 149 continue; 141 150 } … … 144 153 static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); 145 154 146 if(static_lease_ip) 147 { 148 printf("Found static lease: %x\n", static_lease_ip); 155 if (static_lease_ip) { 156 bb_info_msg("Found static lease: %x", static_lease_ip); 149 157 150 158 memcpy(&static_lease.chaddr, &packet.chaddr, 16); … … 153 161 154 162 lease = &static_lease; 155 156 } 157 else 158 { 159 lease = find_lease_by_chaddr(packet.chaddr); 163 } else { 164 lease = find_lease_by_chaddr(packet.chaddr); 160 165 } 161 166 162 167 switch (state[0]) { 163 168 case DHCPDISCOVER: 164 DEBUG( LOG_INFO,"received DISCOVER");169 DEBUG("Received DISCOVER"); 165 170 166 171 if (sendOffer(&packet) < 0) { 167 LOG(LOG_ERR,"send OFFER failed");172 bb_error_msg("send OFFER failed"); 168 173 } 169 174 break; 170 175 case DHCPREQUEST: 171 DEBUG( LOG_INFO,"received REQUEST");176 DEBUG("received REQUEST"); 172 177 173 178 requested = get_option(&packet, DHCP_REQUESTED_IP); … … 180 185 if (server_id) { 181 186 /* SELECTING State */ 182 DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align)); 183 if (server_id_align == server_config.server && requested && 184 requested_align == lease->yiaddr) { 187 DEBUG("server_id = %08x", ntohl(server_id_align)); 188 if (server_id_align == server_config.server && requested 189 && requested_align == lease->yiaddr 190 ) { 185 191 sendACK(&packet, lease->yiaddr); 186 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); 187 202 } else { 188 if (requested) { 189 /* INIT-REBOOT State */ 190 if (lease->yiaddr == requested_align) 191 sendACK(&packet, lease->yiaddr); 192 else sendNAK(&packet); 193 } else { 194 /* RENEWING or REBINDING State */ 195 if (lease->yiaddr == packet.ciaddr) 196 sendACK(&packet, lease->yiaddr); 197 else { 198 /* don't know what to do!!!! */ 199 sendNAK(&packet); 200 } 201 } 203 /* don't know what to do!!!! */ 204 sendNAK(&packet); 202 205 } 203 206 … … 208 211 } else if (requested) { 209 212 /* INIT-REBOOT State */ 210 if ((lease = find_lease_by_yiaddr(requested_align))) { 213 lease = find_lease_by_yiaddr(requested_align); 214 if (lease) { 211 215 if (lease_expired(lease)) { 212 216 /* probably best if we drop this lease */ 213 217 memset(lease->chaddr, 0, 16); 214 218 /* make some contention for this address */ 215 } else sendNAK(&packet); 216 } else if (requested_align < server_config.start || 217 requested_align > server_config.end) { 218 sendNAK(&packet); 219 } /* else remain silent */ 219 } else 220 sendNAK(&packet); 221 } else { 222 uint32_t r = ntohl(requested_align); 223 if (r < server_config.start_ip 224 || r > server_config.end_ip 225 ) { 226 sendNAK(&packet); 227 } 228 /* else remain silent */ 229 } 220 230 221 231 } else { 222 232 /* RENEWING or REBINDING State */ 223 233 } 224 234 break; 225 235 case DHCPDECLINE: 226 DEBUG( LOG_INFO,"received DECLINE");236 DEBUG("Received DECLINE"); 227 237 if (lease) { 228 238 memset(lease->chaddr, 0, 16); … … 231 241 break; 232 242 case DHCPRELEASE: 233 DEBUG(LOG_INFO,"received RELEASE"); 234 if (lease) lease->expires = time(0); 243 DEBUG("Received RELEASE"); 244 if (lease) 245 lease->expires = time(0); 235 246 break; 236 247 case DHCPINFORM: 237 DEBUG( LOG_INFO,"received INFORM");248 DEBUG("Received INFORM"); 238 249 send_inform(&packet); 239 250 break; 240 251 default: 241 LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]); 242 } 243 } 244 245 return 0; 252 bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]); 253 } 254 } 255 ret0: 256 retval = 0; 257 ret: 258 /*if (server_config.pidfile) - server_config.pidfile is never NULL */ 259 remove_pidfile(server_config.pidfile); 260 return retval; 246 261 } 247 -
branches/2.2.5/mindi-busybox/networking/udhcp/dhcpd.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* dhcpd.h */ 2 3 #ifndef _DHCPD_H 3 4 #define _DHCPD_H 4 5 #include <netinet/ip.h>6 #include <netinet/udp.h>7 8 #include "libbb_udhcp.h"9 #include "leases.h"10 5 11 6 /************************************/ … … 20 15 #define DHCPD_CONF_FILE "/etc/udhcpd.conf" 21 16 22 /*****************************************************************/23 /* Do not modify below here unless you know what you are doing!! */24 /*****************************************************************/25 26 /* DHCP protocol -- see RFC 2131 */27 #define SERVER_PORT 6728 #define CLIENT_PORT 6829 30 #define DHCP_MAGIC 0x6382536331 32 /* DHCP option codes (partial list) */33 #define DHCP_PADDING 0x0034 #define DHCP_SUBNET 0x0135 #define DHCP_TIME_OFFSET 0x0236 #define DHCP_ROUTER 0x0337 #define DHCP_TIME_SERVER 0x0438 #define DHCP_NAME_SERVER 0x0539 #define DHCP_DNS_SERVER 0x0640 #define DHCP_LOG_SERVER 0x0741 #define DHCP_COOKIE_SERVER 0x0842 #define DHCP_LPR_SERVER 0x0943 #define DHCP_HOST_NAME 0x0c44 #define DHCP_BOOT_SIZE 0x0d45 #define DHCP_DOMAIN_NAME 0x0f46 #define DHCP_SWAP_SERVER 0x1047 #define DHCP_ROOT_PATH 0x1148 #define DHCP_IP_TTL 0x1749 #define DHCP_MTU 0x1a50 #define DHCP_BROADCAST 0x1c51 #define DHCP_NTP_SERVER 0x2a52 #define DHCP_WINS_SERVER 0x2c53 #define DHCP_REQUESTED_IP 0x3254 #define DHCP_LEASE_TIME 0x3355 #define DHCP_OPTION_OVER 0x3456 #define DHCP_MESSAGE_TYPE 0x3557 #define DHCP_SERVER_ID 0x3658 #define DHCP_PARAM_REQ 0x3759 #define DHCP_MESSAGE 0x3860 #define DHCP_MAX_SIZE 0x3961 #define DHCP_T1 0x3a62 #define DHCP_T2 0x3b63 #define DHCP_VENDOR 0x3c64 #define DHCP_CLIENT_ID 0x3d65 #define DHCP_FQDN 0x5166 67 #define DHCP_END 0xFF68 69 70 #define BOOTREQUEST 171 #define BOOTREPLY 272 73 #define ETH_10MB 174 #define ETH_10MB_LEN 675 76 #define DHCPDISCOVER 177 #define DHCPOFFER 278 #define DHCPREQUEST 379 #define DHCPDECLINE 480 #define DHCPACK 581 #define DHCPNAK 682 #define DHCPRELEASE 783 #define DHCPINFORM 884 85 #define BROADCAST_FLAG 0x800086 87 #define OPTION_FIELD 088 #define FILE_FIELD 189 #define SNAME_FIELD 290 91 /* miscellaneous defines */92 #define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff"93 #define OPT_CODE 094 #define OPT_LEN 195 #define OPT_DATA 296 97 17 struct option_set { 98 18 uint8_t *data; … … 101 21 102 22 struct static_lease { 23 struct static_lease *next; 103 24 uint8_t *mac; 104 25 uint32_t *ip; 105 struct static_lease *next;106 26 }; 107 27 108 28 struct server_config_t { 109 uint32_t server; /* Our IP, in network order */ 110 uint32_t start; /* Start address of leases, network order */ 111 uint32_t end; /* End of leases, network order */ 112 struct option_set *options; /* List of DHCP options loaded from the config file */ 113 char *interface; /* The name of the interface to use */ 114 int ifindex; /* Index number of the interface to use */ 115 uint8_t arp[6]; /* Our arp address */ 116 unsigned long lease; /* lease time in seconds (host order) */ 117 unsigned long max_leases; /* maximum number of leases (including reserved address) */ 118 char remaining; /* should the lease file be interpreted as lease time remaining, or 119 * as the time the lease expires */ 120 unsigned long auto_time; /* how long should udhcpd wait before writing a config file. 121 * if this is zero, it will only write one on SIGUSR1 */ 122 unsigned long decline_time; /* how long an address is reserved if a client returns a 123 * decline message */ 124 unsigned long conflict_time; /* how long an arp conflict offender is leased for */ 125 unsigned long offer_time; /* how long an offered address is reserved */ 126 unsigned long min_lease; /* minimum lease a client can request*/ 29 uint32_t server; /* Our IP, in network order */ 30 /* start,end are in host order: we need to compare start <= ip <= end */ 31 uint32_t start_ip; /* Start address of leases, in host order */ 32 uint32_t end_ip; /* End of leases, in host order */ 33 struct option_set *options; /* List of DHCP options loaded from the config file */ 34 char *interface; /* The name of the interface to use */ 35 int ifindex; /* Index number of the interface to use */ 36 uint8_t arp[6]; /* Our arp address */ 37 char remaining; /* should the lease file be interpreted as lease time remaining, or 38 * as the time the lease expires */ 39 uint32_t lease; /* lease time in seconds (host order) */ 40 uint32_t max_leases; /* maximum number of leases (including reserved address) */ 41 uint32_t auto_time; /* how long should udhcpd wait before writing a config file. 42 * if this is zero, it will only write one on SIGUSR1 */ 43 uint32_t decline_time; /* how long an address is reserved if a client returns a 44 * decline message */ 45 uint32_t conflict_time; /* how long an arp conflict offender is leased for */ 46 uint32_t offer_time; /* how long an offered address is reserved */ 47 uint32_t min_lease; /* minimum lease a client can request */ 127 48 char *lease_file; 128 49 char *pidfile; 129 char *notify_file; 130 uint32_t siaddr; 131 char *sname; 132 char *boot_file; 50 char *notify_file; /* What to run whenever leases are written */ 51 uint32_t siaddr; /* next server bootp option */ 52 char *sname; /* bootp server name */ 53 char *boot_file; /* bootp boot file option */ 133 54 struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */ 134 55 }; … … 138 59 139 60 61 /*** leases.h ***/ 62 63 struct dhcpOfferedAddr { 64 uint8_t chaddr[16]; 65 uint32_t yiaddr; /* network order */ 66 uint32_t expires; /* host order */ 67 }; 68 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); 74 75 76 /*** static_leases.h ***/ 77 78 /* Config file will pass static lease info to this function which will add it 79 * to a data structure that can be searched later */ 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); 85 /* Print out static leases just to check what's going on (debug code) */ 86 void printStaticLeases(struct static_lease **lease_struct); 87 88 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); 95 96 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 104 140 105 #endif -
branches/2.2.5/mindi-busybox/networking/udhcp/dumpleases.c
r821 r1765 3 3 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 4 4 */ 5 #include <fcntl.h>6 #include <string.h>7 #include <stdlib.h>8 #include <stdio.h>9 #include <sys/wait.h>10 #include <arpa/inet.h>11 #include <netdb.h>12 #include <netinet/in.h>13 #include <stdio.h>14 #include <sys/socket.h>15 #include <unistd.h>16 5 #include <getopt.h> 17 #include <time.h>18 6 7 #include "common.h" 19 8 #include "dhcpd.h" 20 #include "leases.h"21 #include "libbb_udhcp.h"22 9 23 #define REMAINING 0 24 #define ABSOLUTE 1 25 26 27 #ifndef IN_BUSYBOX 28 static void ATTRIBUTE_NORETURN show_usage(void) 10 int dumpleases_main(int argc, char **argv); 11 int dumpleases_main(int argc, char **argv) 29 12 { 30 printf( 31 "Usage: dumpleases -f <file> -[r|a]\n\n" 32 " -f, --file=FILENAME Leases file to load\n" 33 " -r, --remaining Interepret lease times as time remaining\n" 34 " -a, --absolute Interepret lease times as expire time\n"); 35 exit(0); 36 } 37 #else 38 #define show_usage bb_show_usage 39 #endif 40 41 42 #ifdef IN_BUSYBOX 43 int dumpleases_main(int argc, char *argv[]) 44 #else 45 int main(int argc, char *argv[]) 46 #endif 47 { 48 FILE *fp; 49 int i, c, mode = REMAINING; 50 long expires; 13 int fd; 14 int i; 15 unsigned opt; 16 time_t expires; 51 17 const char *file = LEASES_FILE; 52 18 struct dhcpOfferedAddr lease; 53 19 struct in_addr addr; 54 20 55 static const struct option options[] = { 56 {"absolute", 0, 0, 'a'}, 57 {"remaining", 0, 0, 'r'}, 58 {"file", 1, 0, 'f'}, 59 {0, 0, 0, 0} 21 enum { 22 OPT_a = 0x1, // -a 23 OPT_r = 0x2, // -r 24 OPT_f = 0x4, // -f 60 25 }; 26 #if ENABLE_GETOPT_LONG 27 static const char dumpleases_longopts[] ALIGN1 = 28 "absolute\0" No_argument "a" 29 "remaining\0" No_argument "r" 30 "file\0" Required_argument "f" 31 ; 61 32 62 while (1) {63 int option_index = 0; 64 c = getopt_long(argc, argv, "arf:", options, &option_index);65 if (c == -1) break;33 applet_long_options = dumpleases_longopts; 34 #endif 35 opt_complementary = "=0:a--r:r--a"; 36 opt = getopt32(argv, "arf:", &file); 66 37 67 switch (c) { 68 case 'a': mode = ABSOLUTE; break; 69 case 'r': mode = REMAINING; break; 70 case 'f': 71 file = optarg; 72 break; 73 default: 74 show_usage(); 75 } 76 } 38 fd = xopen(file, O_RDONLY); 77 39 78 fp = xfopen(file, "r"); 79 80 printf("Mac Address IP-Address Expires %s\n", mode == REMAINING ? "in" : "at"); 40 printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in"); 81 41 /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */ 82 while (fread(&lease, sizeof(lease), 1, fp)) { 83 84 for (i = 0; i < 6; i++) { 85 printf("%02x", lease.chaddr[i]); 86 if (i != 5) printf(":"); 42 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { 43 printf(":%02x"+1, lease.chaddr[0]); 44 for (i = 1; i < 6; i++) { 45 printf(":%02x", lease.chaddr[i]); 87 46 } 88 47 addr.s_addr = lease.yiaddr; 89 printf(" %-15s ", inet_ntoa(addr));48 printf(" %-15s ", inet_ntoa(addr)); 90 49 expires = ntohl(lease.expires); 91 printf(" ");92 if (mode == REMAINING) {93 if (!expires) printf("expired\n");50 if (!(opt & OPT_a)) { /* no -a */ 51 if (!expires) 52 puts("expired"); 94 53 else { 95 if (expires > 60*60*24) { 96 printf("%ld days, ", expires / (60*60*24)); 97 expires %= 60*60*24; 98 } 99 if (expires > 60*60) { 100 printf("%ld hours, ", expires / (60*60)); 101 expires %= 60*60; 102 } 103 if (expires > 60) { 104 printf("%ld minutes, ", expires / 60); 105 expires %= 60; 106 } 107 printf("%ld seconds\n", expires); 54 unsigned d, h, m; 55 d = expires / (24*60*60); expires %= (24*60*60); 56 h = expires / (60*60); expires %= (60*60); 57 m = expires / 60; expires %= 60; 58 if (d) printf("%u days ", d); 59 printf("%02u:%02u:%02u\n", h, m, (unsigned)expires); 108 60 } 109 } else printf("%s", ctime(&expires)); 61 } else /* -a */ 62 fputs(ctime(&expires), stdout); 110 63 } 111 fclose(fp);64 /* close(fd); */ 112 65 113 66 return 0; -
branches/2.2.5/mindi-busybox/networking/udhcp/files.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * files.c -- DHCP server file manipulation * … … 4 5 */ 5 6 6 #include <sys/socket.h>7 #include <arpa/inet.h>8 #include <string.h>9 #include <stdlib.h>10 #include <time.h>11 #include <ctype.h>12 #include <netdb.h>13 14 7 #include <netinet/ether.h> 15 #include "static_leases.h" 16 8 9 #include "common.h" 17 10 #include "dhcpd.h" 18 11 #include "options.h" 19 #include "files.h" 20 #include "common.h" 12 13 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) 41 { 42 char **dest = arg; 43 44 free(*dest); 45 *dest = xstrdup(line); 46 return 1; 47 } 48 49 50 static int read_u32(const char *line, void *arg) 51 { 52 *(uint32_t*)arg = bb_strtou32(line, NULL, 10); 53 return errno == 0; 54 } 55 56 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) 251 { 252 char *line; 253 char *mac_string; 254 char *ip_string; 255 uint8_t *mac_bytes; 256 uint32_t *ip; 257 258 /* Allocate memory for addresses */ 259 mac_bytes = xmalloc(sizeof(unsigned char) * 8); 260 ip = xmalloc(sizeof(uint32_t)); 261 262 /* Read mac */ 263 line = (char *) const_line; 264 mac_string = strtok(line, " \t"); 265 read_mac(mac_string, mac_bytes); 266 267 /* Read ip */ 268 ip_string = strtok(NULL, " \t"); 269 read_ip(ip_string, ip); 270 271 addStaticLease(arg, mac_bytes, ip); 272 273 if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg); 274 275 return 1; 276 } 277 278 279 struct config_keyword { 280 const char *keyword; 281 int (*handler)(const char *line, void *var); 282 void *var; 283 const char *def; 284 }; 285 286 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), ""}, 293 /* Avoid "max_leases value not sane" warning by setting default 294 * to default_end_ip - default_start_ip + 1: */ 295 {"max_leases", read_u32, &(server_config.max_leases), "235"}, 296 {"remaining", read_yn, &(server_config.remaining), "yes"}, 297 {"auto_time", read_u32, &(server_config.auto_time), "7200"}, 298 {"decline_time", read_u32, &(server_config.decline_time), "3600"}, 299 {"conflict_time",read_u32, &(server_config.conflict_time),"3600"}, 300 {"offer_time", read_u32, &(server_config.offer_time), "60"}, 301 {"min_lease", read_u32, &(server_config.min_lease), "60"}, 302 {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE}, 303 {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"}, 304 {"notify_file", read_str, &(server_config.notify_file), ""}, 305 {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"}, 306 {"sname", read_str, &(server_config.sname), ""}, 307 {"boot_file", read_str, &(server_config.boot_file), ""}, 308 {"static_lease", read_staticlease, &(server_config.static_leases), ""}, 309 /* ADDME: static lease */ 310 }; 311 21 312 22 313 /* … … 27 318 #define READ_CONFIG_BUF_SIZE 80 28 319 29 /* on these functions, make sure you datatype matches */30 static int read_ip(const char *line, void *arg)31 {32 struct in_addr *addr = arg;33 struct hostent *host;34 int retval = 1;35 36 if (!inet_aton(line, addr)) {37 if ((host = gethostbyname(line)))38 addr->s_addr = *((unsigned long *) host->h_addr_list[0]);39 else retval = 0;40 }41 return retval;42 }43 44 static int read_mac(const char *line, void *arg)45 {46 uint8_t *mac_bytes = arg;47 struct ether_addr *temp_ether_addr;48 int retval = 1;49 50 temp_ether_addr = ether_aton(line);51 52 if(temp_ether_addr == NULL)53 retval = 0;54 else55 memcpy(mac_bytes, temp_ether_addr, 6);56 57 return retval;58 }59 60 61 static int read_str(const char *line, void *arg)62 {63 char **dest = arg;64 65 free(*dest);66 *dest = strdup(line);67 68 return 1;69 }70 71 72 static int read_u32(const char *line, void *arg)73 {74 uint32_t *dest = arg;75 char *endptr;76 *dest = strtoul(line, &endptr, 0);77 return endptr[0] == '\0';78 }79 80 81 static int read_yn(const char *line, void *arg)82 {83 char *dest = arg;84 int retval = 1;85 86 if (!strcasecmp("yes", line))87 *dest = 1;88 else if (!strcasecmp("no", line))89 *dest = 0;90 else retval = 0;91 92 return retval;93 }94 95 96 /* find option 'code' in opt_list */97 struct option_set *find_option(struct option_set *opt_list, char code)98 {99 while (opt_list && opt_list->data[OPT_CODE] < code)100 opt_list = opt_list->next;101 102 if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;103 else return NULL;104 }105 106 107 /* add an option to the opt_list */108 static void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)109 {110 struct option_set *existing, *new, **curr;111 112 /* add it to an existing option */113 if ((existing = find_option(*opt_list, option->code))) {114 DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);115 if (option->flags & OPTION_LIST) {116 if (existing->data[OPT_LEN] + length <= 255) {117 existing->data = realloc(existing->data,118 existing->data[OPT_LEN] + length + 2);119 memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);120 existing->data[OPT_LEN] += length;121 } /* else, ignore the data, we could put this in a second option in the future */122 } /* else, ignore the new data */123 } else {124 DEBUG(LOG_INFO, "Attaching option %s to list", option->name);125 126 /* make a new option */127 new = xmalloc(sizeof(struct option_set));128 new->data = xmalloc(length + 2);129 new->data[OPT_CODE] = option->code;130 new->data[OPT_LEN] = length;131 memcpy(new->data + 2, buffer, length);132 133 curr = opt_list;134 while (*curr && (*curr)->data[OPT_CODE] < option->code)135 curr = &(*curr)->next;136 137 new->next = *curr;138 *curr = new;139 }140 }141 142 143 /* read a dhcp option and add it to opt_list */144 static int read_opt(const char *const_line, void *arg)145 {146 struct option_set **opt_list = arg;147 char *opt, *val, *endptr;148 struct dhcp_option *option;149 int retval = 0, length;150 char buffer[8];151 char *line;152 uint16_t *result_u16 = (uint16_t *) buffer;153 uint32_t *result_u32 = (uint32_t *) buffer;154 155 /* Cheat, the only const line we'll actually get is "" */156 line = (char *) const_line;157 if (!(opt = strtok(line, " \t="))) return 0;158 159 for (option = dhcp_options; option->code; option++)160 if (!strcasecmp(option->name, opt))161 break;162 163 if (!option->code) return 0;164 165 do {166 if (!(val = strtok(NULL, ", \t"))) break;167 length = option_lengths[option->flags & TYPE_MASK];168 retval = 0;169 opt = buffer; /* new meaning for variable opt */170 switch (option->flags & TYPE_MASK) {171 case OPTION_IP:172 retval = read_ip(val, buffer);173 break;174 case OPTION_IP_PAIR:175 retval = read_ip(val, buffer);176 if (!(val = strtok(NULL, ", \t/-"))) retval = 0;177 if (retval) retval = read_ip(val, buffer + 4);178 break;179 case OPTION_STRING:180 length = strlen(val);181 if (length > 0) {182 if (length > 254) length = 254;183 opt = val;184 retval = 1;185 }186 break;187 case OPTION_BOOLEAN:188 retval = read_yn(val, buffer);189 break;190 case OPTION_U8:191 buffer[0] = strtoul(val, &endptr, 0);192 retval = (endptr[0] == '\0');193 break;194 case OPTION_U16:195 *result_u16 = htons(strtoul(val, &endptr, 0));196 retval = (endptr[0] == '\0');197 break;198 case OPTION_S16:199 *result_u16 = htons(strtol(val, &endptr, 0));200 retval = (endptr[0] == '\0');201 break;202 case OPTION_U32:203 *result_u32 = htonl(strtoul(val, &endptr, 0));204 retval = (endptr[0] == '\0');205 break;206 case OPTION_S32:207 *result_u32 = htonl(strtol(val, &endptr, 0));208 retval = (endptr[0] == '\0');209 break;210 default:211 break;212 }213 if (retval)214 attach_option(opt_list, option, opt, length);215 } while (retval && option->flags & OPTION_LIST);216 return retval;217 }218 219 static int read_staticlease(const char *const_line, void *arg)220 {221 222 char *line;223 char *mac_string;224 char *ip_string;225 uint8_t *mac_bytes;226 uint32_t *ip;227 228 229 /* Allocate memory for addresses */230 mac_bytes = xmalloc(sizeof(unsigned char) * 8);231 ip = xmalloc(sizeof(uint32_t));232 233 /* Read mac */234 line = (char *) const_line;235 mac_string = strtok(line, " \t");236 read_mac(mac_string, mac_bytes);237 238 /* Read ip */239 ip_string = strtok(NULL, " \t");240 read_ip(ip_string, ip);241 242 addStaticLease(arg, mac_bytes, ip);243 244 if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg);245 246 return 1;247 248 }249 250 251 static const struct config_keyword keywords[] = {252 /* keyword handler variable address default */253 {"start", read_ip, &(server_config.start), "192.168.0.20"},254 {"end", read_ip, &(server_config.end), "192.168.0.254"},255 {"interface", read_str, &(server_config.interface), "eth0"},256 {"option", read_opt, &(server_config.options), ""},257 {"opt", read_opt, &(server_config.options), ""},258 {"max_leases", read_u32, &(server_config.max_leases), "254"},259 {"remaining", read_yn, &(server_config.remaining), "yes"},260 {"auto_time", read_u32, &(server_config.auto_time), "7200"},261 {"decline_time",read_u32, &(server_config.decline_time),"3600"},262 {"conflict_time",read_u32,&(server_config.conflict_time),"3600"},263 {"offer_time", read_u32, &(server_config.offer_time), "60"},264 {"min_lease", read_u32, &(server_config.min_lease), "60"},265 {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE},266 {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"},267 {"notify_file", read_str, &(server_config.notify_file), ""},268 {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"},269 {"sname", read_str, &(server_config.sname), ""},270 {"boot_file", read_str, &(server_config.boot_file), ""},271 {"static_lease",read_staticlease, &(server_config.static_leases), ""},272 /*ADDME: static lease */273 {"", NULL, NULL, ""}274 };275 276 277 320 int read_config(const char *file) 278 321 { … … 281 324 int i, lm = 0; 282 325 283 for (i = 0; keywords[i].keyword[0]; i++)326 for (i = 0; i < ARRAY_SIZE(keywords); i++) 284 327 if (keywords[i].def[0]) 285 328 keywords[i].handler(keywords[i].def, keywords[i].var); 286 329 287 i f (!(in = fopen(file, "r"))) {288 LOG(LOG_ERR, "unable to open config file: %s", file);330 in = fopen_or_warn(file, "r"); 331 if (!in) { 289 332 return 0; 290 333 } … … 292 335 while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) { 293 336 char debug_orig[READ_CONFIG_BUF_SIZE]; 337 char *p; 294 338 295 339 lm++; 296 if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0'; 340 p = strchr(buffer, '\n'); 341 if (p) *p = '\0'; 297 342 if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer); 298 if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0'; 343 p = strchr(buffer, '#'); 344 if (p) *p = '\0'; 299 345 300 346 if (!(token = strtok(buffer, " \t"))) continue; … … 302 348 303 349 /* eat leading whitespace */ 304 line = line + strspn(line, " \t=");350 line = skip_whitespace(line); 305 351 /* eat trailing whitespace */ 306 for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--); 307 line[i] = '\0'; 308 309 for (i = 0; keywords[i].keyword[0]; i++) 352 i = strlen(line) - 1; 353 while (i >= 0 && isspace(line[i])) 354 line[i--] = '\0'; 355 356 for (i = 0; i < ARRAY_SIZE(keywords); i++) 310 357 if (!strcasecmp(token, keywords[i].keyword)) 311 358 if (!keywords[i].handler(line, keywords[i].var)) { 312 LOG(LOG_ERR, "Failure parsing line %d of %s", lm, file); 313 DEBUG(LOG_ERR, "unable to parse '%s'", debug_orig); 359 bb_error_msg("cannot parse line %d of %s", lm, file); 360 if (ENABLE_FEATURE_UDHCP_DEBUG) 361 bb_error_msg("cannot parse '%s'", debug_orig); 314 362 /* reset back to the default value */ 315 363 keywords[i].handler(keywords[i].def, keywords[i].var); … … 317 365 } 318 366 fclose(in); 367 368 server_config.start_ip = ntohl(server_config.start_ip); 369 server_config.end_ip = ntohl(server_config.end_ip); 370 319 371 return 1; 320 372 } … … 323 375 void write_leases(void) 324 376 { 325 FILE *fp; 326 unsigned int i; 327 char buf[255]; 377 int fp; 378 unsigned i; 328 379 time_t curr = time(0); 329 380 unsigned long tmp_time; 330 381 331 if (!(fp = fopen(server_config.lease_file, "w"))) {332 LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);382 fp = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666); 383 if (fp < 0) { 333 384 return; 334 385 } … … 346 397 } /* else stick with the time we got */ 347 398 leases[i].expires = htonl(leases[i].expires); 348 fwrite(&leases[i], sizeof(struct dhcpOfferedAddr), 1, fp); 349 350 /* Then restore it when done. */ 399 // FIXME: error check?? 400 full_write(fp, &leases[i], sizeof(leases[i])); 401 402 /* then restore it when done */ 351 403 leases[i].expires = tmp_time; 352 404 } 353 405 } 354 fclose(fp);406 close(fp); 355 407 356 408 if (server_config.notify_file) { 357 sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file); 358 system(buf); 409 char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file); 410 system(cmd); 411 free(cmd); 359 412 } 360 413 } … … 363 416 void read_leases(const char *file) 364 417 { 365 FILE *fp;418 int fp; 366 419 unsigned int i = 0; 367 420 struct dhcpOfferedAddr lease; 368 421 369 if (!(fp = fopen(file, "r"))) {370 LOG(LOG_ERR, "Unable to open %s for reading", file);422 fp = open_or_warn(file, O_RDONLY); 423 if (fp < 0) { 371 424 return; 372 425 } 373 426 374 while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) { 427 while (i < server_config.max_leases 428 && full_read(fp, &lease, sizeof(lease)) == sizeof(lease) 429 ) { 375 430 /* ADDME: is it a static lease */ 376 if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) { 431 uint32_t y = ntohl(lease.yiaddr); 432 if (y >= server_config.start_ip && y <= server_config.end_ip) { 377 433 lease.expires = ntohl(lease.expires); 378 if (!server_config.remaining) lease.expires -= time(0); 434 if (!server_config.remaining) 435 lease.expires -= time(0); 379 436 if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) { 380 LOG(LOG_WARNING, "Too many leases while loading %s\n", file);437 bb_error_msg("too many leases while loading %s", file); 381 438 break; 382 439 } … … 384 441 } 385 442 } 386 DEBUG( LOG_INFO,"Read %d leases", i);387 fclose(fp);388 } 443 DEBUG("Read %d leases", i); 444 close(fp); 445 } -
branches/2.2.5/mindi-busybox/networking/udhcp/leases.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * leases.c -- tools to manage DHCP leases … … 4 5 */ 5 6 6 #include <time.h> 7 #include <string.h> 8 #include <sys/socket.h> 9 #include <netinet/in.h> 10 #include <arpa/inet.h> 11 7 #include "common.h" 12 8 #include "dhcpd.h" 13 #include "files.h"14 #include "options.h"15 #include "leases.h"16 #include "arpping.h"17 #include "common.h"18 19 #include "static_leases.h"20 9 21 10 22 uint8_t blank_chaddr[] = {[0 ... 15] = 0}; 11 /* Find the oldest expired lease, NULL if there are no expired leases */ 12 static struct dhcpOfferedAddr *oldest_expired_lease(void) 13 { 14 struct dhcpOfferedAddr *oldest = NULL; 15 // TODO: use monotonic_sec() 16 unsigned long oldest_lease = time(0); 17 unsigned i; 18 19 for (i = 0; i < server_config.max_leases; i++) 20 if (oldest_lease > leases[i].expires) { 21 oldest_lease = leases[i].expires; 22 oldest = &(leases[i]); 23 } 24 return oldest; 25 } 26 23 27 24 28 /* clear every lease out that chaddr OR yiaddr matches and is nonzero */ 25 void clear_lease(uint8_t *chaddr, uint32_t yiaddr)29 static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) 26 30 { 27 unsigned i nt i, j;31 unsigned i, j; 28 32 29 for (j = 0; j < 16 && !chaddr[j]; j++); 33 for (j = 0; j < 16 && !chaddr[j]; j++) 34 continue; 30 35 31 36 for (i = 0; i < server_config.max_leases; i++) 32 if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) || 33 (yiaddr && leases[i].yiaddr == yiaddr)) { 34 memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr)); 37 if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0) 38 || (yiaddr && leases[i].yiaddr == yiaddr) 39 ) { 40 memset(&(leases[i]), 0, sizeof(leases[i])); 35 41 } 36 42 } … … 38 44 39 45 /* add a lease into the table, clearing out any old ones */ 40 struct dhcpOfferedAddr *add_lease( uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)46 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease) 41 47 { 42 48 struct dhcpOfferedAddr *oldest; … … 64 70 65 71 66 /* Find the oldest expired lease, NULL if there are no expired leases*/67 struct dhcpOfferedAddr * oldest_expired_lease(void)72 /* Find the first lease that matches chaddr, NULL if no match */ 73 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) 68 74 { 69 struct dhcpOfferedAddr *oldest = NULL; 70 unsigned long oldest_lease = time(0); 71 unsigned int i; 72 75 unsigned i; 73 76 74 77 for (i = 0; i < server_config.max_leases; i++) 75 if (oldest_lease > leases[i].expires) { 76 oldest_lease = leases[i].expires; 77 oldest = &(leases[i]); 78 } 79 return oldest; 80 81 } 82 83 84 /* Find the first lease that matches chaddr, NULL if no match */ 85 struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr) 86 { 87 unsigned int i; 88 89 for (i = 0; i < server_config.max_leases; i++) 90 if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]); 78 if (!memcmp(leases[i].chaddr, chaddr, 16)) 79 return &(leases[i]); 91 80 92 81 return NULL; … … 97 86 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) 98 87 { 99 unsigned i nt i;88 unsigned i; 100 89 101 90 for (i = 0; i < server_config.max_leases; i++) 102 if (leases[i].yiaddr == yiaddr) return &(leases[i]); 91 if (leases[i].yiaddr == yiaddr) 92 return &(leases[i]); 103 93 104 94 return NULL; … … 107 97 108 98 /* check is an IP is taken, if it is, add it to the lease table */ 109 static int check_ip(uint32_t addr)99 static int nobody_responds_to_arp(uint32_t addr) 110 100 { 101 static const uint8_t blank_chaddr[16]; /* 16 zero bytes */ 102 111 103 struct in_addr temp; 104 int r; 112 105 113 if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) { 114 temp.s_addr = addr; 115 LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds", 116 inet_ntoa(temp), server_config.conflict_time); 117 add_lease(blank_chaddr, addr, server_config.conflict_time); 118 return 1; 119 } else return 0; 106 r = arpping(addr, server_config.server, server_config.arp, server_config.interface); 107 if (r) 108 return r; 109 110 temp.s_addr = addr; 111 bb_info_msg("%s belongs to someone, reserving it for %u seconds", 112 inet_ntoa(temp), (unsigned)server_config.conflict_time); 113 add_lease(blank_chaddr, addr, server_config.conflict_time); 114 return 0; 120 115 } 121 116 122 117 123 /* find an assignable address, i tcheck_expired is true, we check all the expired leases as well.118 /* find an assignable address, if check_expired is true, we check all the expired leases as well. 124 119 * Maybe this should try expired leases by age... */ 125 120 uint32_t find_address(int check_expired) … … 128 123 struct dhcpOfferedAddr *lease = NULL; 129 124 130 addr = ntohl(server_config.start); /* addr is in host order here */ 131 for (;addr <= ntohl(server_config.end); addr++) { 132 125 addr = server_config.start_ip; /* addr is in host order here */ 126 for (; addr <= server_config.end_ip; addr++) { 133 127 /* ie, 192.168.55.0 */ 134 if (!(addr & 0xFF)) continue;135 128 if (!(addr & 0xFF)) 129 continue; 136 130 /* ie, 192.168.55.255 */ 137 if ((addr & 0xFF) == 0xFF) continue; 138 139 /* Only do if it isn't an assigned as a static lease */ 140 if(!reservedIp(server_config.static_leases, htonl(addr))) 141 { 142 143 /* lease is not taken */ 131 if ((addr & 0xFF) == 0xFF) 132 continue; 133 /* Only do if it isn't assigned as a static lease */ 144 134 ret = htonl(addr); 145 if ( (!(lease = find_lease_by_yiaddr(ret)) ||146 147 /* or it expired and we are checking for expired leases */148 (check_expired && lease_expired(lease))) &&149 150 /* and it isn'ton the network */151 !check_ip(ret)) {152 return ret;153 break;135 if (!reservedIp(server_config.static_leases, ret)) { 136 /* lease is not taken */ 137 lease = find_lease_by_yiaddr(ret); 138 /* no lease or it expired and we are checking for expired leases */ 139 if ((!lease || (check_expired && lease_expired(lease))) 140 && nobody_responds_to_arp(ret) /* it isn't used on the network */ 141 ) { 142 return ret; 143 } 154 144 } 155 }156 145 } 157 146 return 0; -
branches/2.2.5/mindi-busybox/networking/udhcp/options.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * options.c -- DHCP server option packet tools … … 4 5 */ 5 6 6 #include <stdlib.h>7 #include <string.h>8 9 7 #include "common.h" 10 8 #include "dhcpd.h" 11 9 #include "options.h" 12 #include "files.h"13 10 14 11 15 12 /* supported options are easily added here */ 16 struct dhcp_option dhcp_options[] = { 17 /* name[10] flags code */ 18 {"subnet", OPTION_IP | OPTION_REQ, 0x01}, 19 {"timezone", OPTION_S32, 0x02}, 20 {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, 21 {"timesvr", OPTION_IP | OPTION_LIST, 0x04}, 22 {"namesvr", OPTION_IP | OPTION_LIST, 0x05}, 23 {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06}, 24 {"logsvr", OPTION_IP | OPTION_LIST, 0x07}, 25 {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08}, 26 {"lprsvr", OPTION_IP | OPTION_LIST, 0x09}, 27 {"hostname", OPTION_STRING | OPTION_REQ, 0x0c}, 28 {"bootsize", OPTION_U16, 0x0d}, 29 {"domain", OPTION_STRING | OPTION_REQ, 0x0f}, 30 {"swapsvr", OPTION_IP, 0x10}, 31 {"rootpath", OPTION_STRING, 0x11}, 32 {"ipttl", OPTION_U8, 0x17}, 33 {"mtu", OPTION_U16, 0x1a}, 34 {"broadcast", OPTION_IP | OPTION_REQ, 0x1c}, 35 {"nisdomain", OPTION_STRING | OPTION_REQ, 0x28}, 36 {"nissrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x29}, 37 {"ntpsrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a}, 38 {"wins", OPTION_IP | OPTION_LIST, 0x2c}, 39 {"requestip", OPTION_IP, 0x32}, 40 {"lease", OPTION_U32, 0x33}, 41 {"dhcptype", OPTION_U8, 0x35}, 42 {"serverid", OPTION_IP, 0x36}, 43 {"message", OPTION_STRING, 0x38}, 44 {"tftp", OPTION_STRING, 0x42}, 45 {"bootfile", OPTION_STRING, 0x43}, 46 {"", 0x00, 0x00} 13 const struct dhcp_option dhcp_options[] = { 14 /* name[12] flags code */ 15 {"subnet", OPTION_IP | OPTION_REQ, 0x01}, 16 {"timezone", OPTION_S32, 0x02}, 17 {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, 18 {"timesvr", OPTION_IP | OPTION_LIST, 0x04}, 19 {"namesvr", OPTION_IP | OPTION_LIST, 0x05}, 20 {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06}, 21 {"logsvr", OPTION_IP | OPTION_LIST, 0x07}, 22 {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08}, 23 {"lprsvr", OPTION_IP | OPTION_LIST, 0x09}, 24 {"hostname", OPTION_STRING | OPTION_REQ, 0x0c}, 25 {"bootsize", OPTION_U16, 0x0d}, 26 {"domain", OPTION_STRING | OPTION_LIST | OPTION_REQ, 0x0f}, 27 {"swapsvr", OPTION_IP, 0x10}, 28 {"rootpath", OPTION_STRING, 0x11}, 29 {"ipttl", OPTION_U8, 0x17}, 30 {"mtu", OPTION_U16, 0x1a}, 31 {"broadcast", OPTION_IP | OPTION_REQ, 0x1c}, 32 {"nisdomain", OPTION_STRING | OPTION_REQ, 0x28}, 33 {"nissrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x29}, 34 {"ntpsrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a}, 35 {"wins", OPTION_IP | OPTION_LIST, 0x2c}, 36 {"requestip", OPTION_IP, 0x32}, 37 {"lease", OPTION_U32, 0x33}, 38 {"dhcptype", OPTION_U8, 0x35}, 39 {"serverid", OPTION_IP, 0x36}, 40 {"message", OPTION_STRING, 0x38}, 41 {"vendorclass", OPTION_STRING, 0x3C}, 42 {"clientid", OPTION_STRING, 0x3D}, 43 {"tftp", OPTION_STRING, 0x42}, 44 {"bootfile", OPTION_STRING, 0x43}, 45 {"userclass", OPTION_STRING, 0x4D}, 46 #if ENABLE_FEATURE_RFC3397 47 {"search", OPTION_STR1035 | OPTION_LIST | OPTION_REQ, 0x77}, 48 #endif 49 /* MSIE's "Web Proxy Autodiscovery Protocol" support */ 50 {"wpad", OPTION_STRING, 0xfc}, 51 {"", 0x00, 0x00} 47 52 }; 48 53 49 54 /* Lengths of the different option types */ 50 int option_lengths[] = { 51 [OPTION_IP] = 4, 52 [OPTION_IP_PAIR] = 8, 53 [OPTION_BOOLEAN] = 1, 54 [OPTION_STRING] = 1, 55 [OPTION_U8] = 1, 56 [OPTION_U16] = 2, 57 [OPTION_S16] = 2, 58 [OPTION_U32] = 4, 59 [OPTION_S32] = 4 55 const unsigned char option_lengths[] ALIGN1 = { 56 [OPTION_IP] = 4, 57 [OPTION_IP_PAIR] = 8, 58 [OPTION_BOOLEAN] = 1, 59 [OPTION_STRING] = 1, 60 #if ENABLE_FEATURE_RFC3397 61 [OPTION_STR1035] = 1, 62 #endif 63 [OPTION_U8] = 1, 64 [OPTION_U16] = 2, 65 [OPTION_S16] = 2, 66 [OPTION_U32] = 4, 67 [OPTION_S32] = 4 60 68 }; 61 69 … … 73 81 while (!done) { 74 82 if (i >= length) { 75 LOG(LOG_WARNING, "bogus packet, option fields too long.");83 bb_error_msg("bogus packet, option fields too long"); 76 84 return NULL; 77 85 } 78 86 if (optionptr[i + OPT_CODE] == code) { 79 87 if (i + 1 + optionptr[i + OPT_LEN] >= length) { 80 LOG(LOG_WARNING, "bogus packet, option fields too long.");88 bb_error_msg("bogus packet, option fields too long"); 81 89 return NULL; 82 90 } … … 89 97 case DHCP_OPTION_OVER: 90 98 if (i + 1 + optionptr[i + OPT_LEN] >= length) { 91 LOG(LOG_WARNING, "bogus packet, option fields too long.");99 bb_error_msg("bogus packet, option fields too long"); 92 100 return NULL; 93 101 } … … 137 145 /* end position + string length + option code/length + end option */ 138 146 if (end + string[OPT_LEN] + 2 + 1 >= 308) { 139 LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]); 147 bb_error_msg("option 0x%02x did not fit into the packet", 148 string[OPT_CODE]); 140 149 return 0; 141 150 } 142 DEBUG( LOG_INFO,"adding option 0x%02x", string[OPT_CODE]);151 DEBUG("adding option 0x%02x", string[OPT_CODE]); 143 152 memcpy(optionptr + end, string, string[OPT_LEN] + 2); 144 153 optionptr[end + string[OPT_LEN] + 2] = DHCP_END; … … 150 159 int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) 151 160 { 152 struct dhcp_option *dh;161 const struct dhcp_option *dh; 153 162 154 for (dh =dhcp_options; dh->code; dh++) {163 for (dh = dhcp_options; dh->code; dh++) { 155 164 if (dh->code == code) { 156 165 uint8_t option[6], len; … … 167 176 } 168 177 169 DEBUG(LOG_ERR, "Couldnot add option 0x%02x", code);178 bb_error_msg("cannot add option 0x%02x", code); 170 179 return 0; 171 180 } -
branches/2.2.5/mindi-busybox/networking/udhcp/options.h
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* options.h */ 2 3 #ifndef _OPTIONS_H 3 4 #define _OPTIONS_H 4 5 #include "packet.h"6 5 7 6 #define TYPE_MASK 0x0F … … 11 10 OPTION_IP_PAIR, 12 11 OPTION_STRING, 12 #if ENABLE_FEATURE_RFC3397 13 OPTION_STR1035, /* RFC1035 compressed domain name list */ 14 #endif 13 15 OPTION_BOOLEAN, 14 16 OPTION_U8, … … 22 24 #define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ 23 25 26 /*****************************************************************/ 27 /* Do not modify below here unless you know what you are doing!! */ 28 /*****************************************************************/ 29 30 /* DHCP protocol -- see RFC 2131 */ 31 #define SERVER_PORT 67 32 #define CLIENT_PORT 68 33 34 #define DHCP_MAGIC 0x63825363 35 36 /* DHCP option codes (partial list) */ 37 #define DHCP_PADDING 0x00 38 #define DHCP_SUBNET 0x01 39 #define DHCP_TIME_OFFSET 0x02 40 #define DHCP_ROUTER 0x03 41 #define DHCP_TIME_SERVER 0x04 42 #define DHCP_NAME_SERVER 0x05 43 #define DHCP_DNS_SERVER 0x06 44 #define DHCP_LOG_SERVER 0x07 45 #define DHCP_COOKIE_SERVER 0x08 46 #define DHCP_LPR_SERVER 0x09 47 #define DHCP_HOST_NAME 0x0c 48 #define DHCP_BOOT_SIZE 0x0d 49 #define DHCP_DOMAIN_NAME 0x0f 50 #define DHCP_SWAP_SERVER 0x10 51 #define DHCP_ROOT_PATH 0x11 52 #define DHCP_IP_TTL 0x17 53 #define DHCP_MTU 0x1a 54 #define DHCP_BROADCAST 0x1c 55 #define DHCP_NTP_SERVER 0x2a 56 #define DHCP_WINS_SERVER 0x2c 57 #define DHCP_REQUESTED_IP 0x32 58 #define DHCP_LEASE_TIME 0x33 59 #define DHCP_OPTION_OVER 0x34 60 #define DHCP_MESSAGE_TYPE 0x35 61 #define DHCP_SERVER_ID 0x36 62 #define DHCP_PARAM_REQ 0x37 63 #define DHCP_MESSAGE 0x38 64 #define DHCP_MAX_SIZE 0x39 65 #define DHCP_T1 0x3a 66 #define DHCP_T2 0x3b 67 #define DHCP_VENDOR 0x3c 68 #define DHCP_CLIENT_ID 0x3d 69 #define DHCP_FQDN 0x51 70 71 #define DHCP_END 0xFF 72 73 74 #define BOOTREQUEST 1 75 #define BOOTREPLY 2 76 77 #define ETH_10MB 1 78 #define ETH_10MB_LEN 6 79 80 #define DHCPDISCOVER 1 81 #define DHCPOFFER 2 82 #define DHCPREQUEST 3 83 #define DHCPDECLINE 4 84 #define DHCPACK 5 85 #define DHCPNAK 6 86 #define DHCPRELEASE 7 87 #define DHCPINFORM 8 88 89 #define BROADCAST_FLAG 0x8000 90 91 #define OPTION_FIELD 0 92 #define FILE_FIELD 1 93 #define SNAME_FIELD 2 94 95 /* miscellaneous defines */ 96 #define OPT_CODE 0 97 #define OPT_LEN 1 98 #define OPT_DATA 2 99 24 100 struct dhcp_option { 25 char name[1 0];101 char name[12]; 26 102 char flags; 27 103 uint8_t code; 28 104 }; 29 105 30 extern struct dhcp_option dhcp_options[];31 extern intoption_lengths[];106 extern const struct dhcp_option dhcp_options[]; 107 extern const unsigned char option_lengths[]; 32 108 33 109 uint8_t *get_option(struct dhcpMessage *packet, int code); … … 35 111 int add_option_string(uint8_t *optionptr, uint8_t *string); 36 112 int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data); 113 #if ENABLE_FEATURE_RFC3397 114 char *dname_dec(const uint8_t *cstr, int clen, const char *pre); 115 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen); 116 #endif 37 117 38 118 #endif -
branches/2.2.5/mindi-busybox/networking/udhcp/packet.c
r821 r1765 1 #include <unistd.h> 2 #include <string.h> 1 /* vi: set sw=4 ts=4: */ 2 3 3 #include <netinet/in.h> 4 #include <sys/types.h> 5 #include <sys/socket.h> 6 #include <features.h> 7 #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION 4 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION 8 5 #include <netpacket/packet.h> 9 6 #include <net/ethernet.h> … … 13 10 #include <linux/if_ether.h> 14 11 #endif 15 #include <errno.h>16 12 17 13 #include "common.h" 18 #include "packet.h"19 14 #include "dhcpd.h" 20 15 #include "options.h" … … 47 42 int udhcp_get_packet(struct dhcpMessage *packet, int fd) 48 43 { 44 #if 0 49 45 static const char broken_vendors[][8] = { 50 46 "MSFT 98", 51 47 "" 52 48 }; 49 #endif 53 50 int bytes; 54 int i; 55 char unsigned *vendor; 56 57 memset(packet, 0, sizeof(struct dhcpMessage)); 58 bytes = read(fd, packet, sizeof(struct dhcpMessage)); 51 unsigned char *vendor; 52 53 memset(packet, 0, sizeof(*packet)); 54 bytes = read(fd, packet, sizeof(*packet)); 59 55 if (bytes < 0) { 60 DEBUG( LOG_INFO, "couldn't read on listening socket, ignoring");56 DEBUG("cannot read on listening socket, ignoring"); 61 57 return -1; 62 58 } 63 59 64 60 if (ntohl(packet->cookie) != DHCP_MAGIC) { 65 LOG(LOG_ERR,"received bogus message, ignoring");61 bb_error_msg("received bogus message, ignoring"); 66 62 return -2; 67 63 } 68 DEBUG(LOG_INFO, "Received a packet"); 69 70 if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) { 71 for (i = 0; broken_vendors[i][0]; i++) { 72 if (vendor[OPT_LEN - 2] == (uint8_t) strlen(broken_vendors[i]) && 73 !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])) { 74 DEBUG(LOG_INFO, "broken client (%s), forcing broadcast", 75 broken_vendors[i]); 64 DEBUG("Received a packet"); 65 66 if (packet->op == BOOTREQUEST) { 67 vendor = get_option(packet, DHCP_VENDOR); 68 if (vendor) { 69 #if 0 70 int i; 71 for (i = 0; broken_vendors[i][0]; i++) { 72 if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i]) 73 && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2]) 74 ) { 75 DEBUG("broken client (%s), forcing broadcast", 76 broken_vendors[i]); 77 packet->flags |= htons(BROADCAST_FLAG); 78 } 79 } 80 #else 81 if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1) 82 && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 83 ) { 84 DEBUG("broken client (%s), forcing broadcast", "MSFT 98"); 76 85 packet->flags |= htons(BROADCAST_FLAG); 77 86 } 87 #endif 78 88 } 79 89 } … … 88 98 * beginning at location "addr". 89 99 */ 90 registerint32_t sum = 0;100 int32_t sum = 0; 91 101 uint16_t *source = (uint16_t *) addr; 92 102 … … 114 124 115 125 /* Construct a ip/udp header for a packet, and specify the source and dest hardware address */ 116 int udhcp_raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, 117 uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex) 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) 118 130 { 119 131 int fd; … … 122 134 struct udp_dhcp_packet packet; 123 135 124 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { 125 DEBUG(LOG_ERR, "socket call failed: %m"); 136 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 137 if (fd < 0) { 138 bb_perror_msg("socket"); 126 139 return -1; 127 140 } … … 136 149 memcpy(dest.sll_addr, dest_arp, 6); 137 150 if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { 138 DEBUG(LOG_ERR, "bind call failed: %m");151 bb_perror_msg("bind"); 139 152 close(fd); 140 153 return -1; … … 157 170 packet.ip.check = udhcp_checksum(&(packet.ip), sizeof(packet.ip)); 158 171 159 result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest)); 172 if (sizeof(struct udp_dhcp_packet) != 576) 173 BUG_sizeof_struct_udp_dhcp_packet_must_be_576(); 174 175 result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, 176 (struct sockaddr *) &dest, sizeof(dest)); 160 177 if (result <= 0) { 161 DEBUG(LOG_ERR, "write on socket failed: %m");178 bb_perror_msg("sendto"); 162 179 } 163 180 close(fd); … … 167 184 168 185 /* Let the kernel do all the work for packet generation */ 169 int udhcp_kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,170 uint32_t dest_ip, int dest_port)171 { 172 int n = 1; 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 { 173 190 int fd, result; 174 191 struct sockaddr_in client; 175 192 176 if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 177 return -1; 178 179 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) { 180 close(fd); 181 return -1; 182 } 193 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 194 if (fd < 0) 195 return -1; 196 197 setsockopt_reuseaddr(fd); 183 198 184 199 memset(&client, 0, sizeof(client)); … … 187 202 client.sin_addr.s_addr = source_ip; 188 203 189 if (bind(fd, (struct sockaddr *)&client, sizeof( struct sockaddr)) == -1) {204 if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 190 205 close(fd); 191 206 return -1; -
branches/2.2.5/mindi-busybox/networking/udhcp/script.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* script.c 2 3 * … … 8 9 */ 9 10 10 #include <string.h>11 #include <unistd.h>12 #include <stdio.h>13 #include <stdlib.h>14 #include <sys/socket.h>15 #include <netinet/in.h>16 #include <arpa/inet.h>17 #include <sys/types.h>18 #include <sys/wait.h>19 20 11 #include "common.h" 12 #include "dhcpc.h" 21 13 #include "options.h" 22 #include "dhcpd.h" 23 #include "dhcpc.h" 14 24 15 25 16 /* get a rough idea of how long an option will be (rounding up...) */ 26 static const int max_option_length[] = {17 static const uint8_t max_option_length[] = { 27 18 [OPTION_IP] = sizeof("255.255.255.255 "), 28 19 [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2, 29 20 [OPTION_STRING] = 1, 21 #if ENABLE_FEATURE_RFC3397 22 [OPTION_STR1035] = 1, 23 #endif 30 24 [OPTION_BOOLEAN] = sizeof("yes "), 31 25 [OPTION_U8] = sizeof("255 "), … … 44 38 45 39 46 static int sprintip(char *dest, c har *pre,uint8_t *ip)40 static int sprintip(char *dest, const char *pre, const uint8_t *ip) 47 41 { 48 42 return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]); … … 62 56 63 57 64 /* Fill destwith the text of option 'option'. */65 static void fill_options(char *dest, uint8_t *option,struct dhcp_option *type_p)66 { 67 int type, optlen;58 /* Allocate and fill with the text of option 'option'. */ 59 static char *alloc_fill_opts(uint8_t *option, const struct dhcp_option *type_p) 60 { 61 int len, type, optlen; 68 62 uint16_t val_u16; 69 63 int16_t val_s16; 70 64 uint32_t val_u32; 71 65 int32_t val_s32; 72 int len = option[OPT_LEN - 2]; 73 74 dest += sprintf(dest, "%s=", type_p->name); 75 66 char *dest, *ret; 67 68 len = option[OPT_LEN - 2]; 76 69 type = type_p->flags & TYPE_MASK; 77 70 optlen = option_lengths[type]; 78 for(;;) { 71 72 dest = ret = xmalloc(upper_length(len, type) + strlen(type_p->name) + 2); 73 dest += sprintf(ret, "%s=", type_p->name); 74 75 for (;;) { 79 76 switch (type) { 80 77 case OPTION_IP_PAIR: 81 78 dest += sprintip(dest, "", option); 82 * (dest++)= '/';79 *dest++ = '/'; 83 80 option += 4; 84 81 optlen = 4; … … 111 108 memcpy(dest, option, len); 112 109 dest[len] = '\0'; 113 return; /* Short circuit this case */ 110 return ret; /* Short circuit this case */ 111 #if ENABLE_FEATURE_RFC3397 112 case OPTION_STR1035: 113 /* unpack option into dest; use ret for prefix (i.e., "optname=") */ 114 dest = dname_dec(option, len, ret); 115 free(ret); 116 return dest; 117 #endif 114 118 } 115 119 option += optlen; … … 118 122 dest += sprintf(dest, " "); 119 123 } 124 return ret; 120 125 } 121 126 … … 127 132 int i, j; 128 133 char **envp; 134 char *var; 129 135 uint8_t *temp; 130 136 struct in_addr subnet; 131 137 char over = 0; 132 138 133 if (packet == NULL) 134 num_options = 0; 135 else { 136 for (i = 0; dhcp_options[i].code; i++) 139 if (packet) { 140 for (i = 0; dhcp_options[i].code; i++) { 137 141 if (get_option(packet, dhcp_options[i].code)) { 138 142 num_options++; … … 140 144 num_options++; /* for mton */ 141 145 } 142 if (packet->siaddr) num_options++; 143 if ((temp = get_option(packet, DHCP_OPTION_OVER))) 146 } 147 if (packet->siaddr) 148 num_options++; 149 temp = get_option(packet, DHCP_OPTION_OVER); 150 if (temp) 144 151 over = *temp; 145 if (!(over & FILE_FIELD) && packet->file[0]) num_options++; 146 if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++; 152 if (!(over & FILE_FIELD) && packet->file[0]) 153 num_options++; 154 if (!(over & SNAME_FIELD) && packet->sname[0]) 155 num_options++; 147 156 } 148 157 149 158 envp = xzalloc(sizeof(char *) * (num_options + 5)); 150 159 j = 0; 151 envp[j++] = bb_xasprintf("interface=%s", client_config.interface); 152 envp[j++] = bb_xasprintf("PATH=%s", 153 getenv("PATH") ? : "/bin:/usr/bin:/sbin:/usr/sbin"); 154 envp[j++] = bb_xasprintf("HOME=%s", getenv("HOME") ? : "/"); 155 156 if (packet == NULL) return envp; 160 envp[j++] = xasprintf("interface=%s", client_config.interface); 161 var = getenv("PATH"); 162 if (var) 163 envp[j++] = xasprintf("PATH=%s", var); 164 var = getenv("HOME"); 165 if (var) 166 envp[j++] = xasprintf("HOME=%s", var); 167 168 if (packet == NULL) 169 return envp; 157 170 158 171 envp[j] = xmalloc(sizeof("ip=255.255.255.255")); 159 172 sprintip(envp[j++], "ip=", (uint8_t *) &packet->yiaddr); 160 173 161 162 174 for (i = 0; dhcp_options[i].code; i++) { 163 if (!(temp = get_option(packet, dhcp_options[i].code))) 175 temp = get_option(packet, dhcp_options[i].code); 176 if (!temp) 164 177 continue; 165 envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], 166 dhcp_options[i].flags & TYPE_MASK) + strlen(dhcp_options[i].name) + 2); 167 fill_options(envp[j++], temp, &dhcp_options[i]); 178 envp[j++] = alloc_fill_opts(temp, &dhcp_options[i]); 168 179 169 180 /* Fill in a subnet bits option for things like /24 */ 170 181 if (dhcp_options[i].code == DHCP_SUBNET) { 171 182 memcpy(&subnet, temp, 4); 172 envp[j++] = bb_xasprintf("mask=%d", mton(&subnet));183 envp[j++] = xasprintf("mask=%d", mton(&subnet)); 173 184 } 174 185 } … … 180 191 /* watch out for invalid packets */ 181 192 packet->file[sizeof(packet->file) - 1] = '\0'; 182 envp[j++] = bb_xasprintf("boot_file=%s", packet->file);193 envp[j++] = xasprintf("boot_file=%s", packet->file); 183 194 } 184 195 if (!(over & SNAME_FIELD) && packet->sname[0]) { 185 196 /* watch out for invalid packets */ 186 197 packet->sname[sizeof(packet->sname) - 1] = '\0'; 187 envp[j++] = bb_xasprintf("sname=%s", packet->sname);198 envp[j++] = xasprintf("sname=%s", packet->sname); 188 199 } 189 200 return envp; … … 200 211 return; 201 212 202 DEBUG( LOG_INFO, "vforking and execle'ing %s", client_config.script);213 DEBUG("vfork'ing and execle'ing %s", client_config.script); 203 214 204 215 envp = fill_envp(packet); 216 205 217 /* call script */ 218 // can we use wait4pid(spawn(...)) here? 206 219 pid = vfork(); 207 if (pid) { 208 waitpid(pid, NULL, 0); 209 for (curr = envp; *curr; curr++) free(*curr); 210 free(envp); 211 return; 212 } else if (pid == 0) { 220 if (pid < 0) return; 221 if (pid == 0) { 213 222 /* close fd's? */ 214 215 223 /* exec script */ 216 224 execle(client_config.script, client_config.script, 217 225 name, NULL, envp); 218 LOG(LOG_ERR, "script %s failed: %m", client_config.script); 219 exit(1); 220 } 221 } 226 bb_perror_msg_and_die("script %s failed", client_config.script); 227 } 228 waitpid(pid, NULL, 0); 229 for (curr = envp; *curr; curr++) 230 free(*curr); 231 free(envp); 232 } -
branches/2.2.5/mindi-busybox/networking/udhcp/serverpacket.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* serverpacket.c 2 3 * … … 20 21 */ 21 22 22 #include <sys/socket.h>23 #include <netinet/in.h>24 #include <arpa/inet.h>25 #include <string.h>26 #include <time.h>27 28 23 #include "common.h" 29 #include "serverpacket.h"30 24 #include "dhcpd.h" 31 25 #include "options.h" 32 #include "static_leases.h" 26 33 27 34 28 /* send a packet to giaddr using the kernel ip stack */ 35 29 static int send_packet_to_relay(struct dhcpMessage *payload) 36 30 { 37 DEBUG( LOG_INFO,"Forwarding packet to relay");31 DEBUG("Forwarding packet to relay"); 38 32 39 33 return udhcp_kernel_packet(payload, server_config.server, SERVER_PORT, … … 45 39 static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast) 46 40 { 47 uint8_t *chaddr;41 const uint8_t *chaddr; 48 42 uint32_t ciaddr; 49 43 50 44 if (force_broadcast) { 51 DEBUG( LOG_INFO,"broadcasting packet to client (NAK)");45 DEBUG("broadcasting packet to client (NAK)"); 52 46 ciaddr = INADDR_BROADCAST; 53 47 chaddr = MAC_BCAST_ADDR; 54 48 } else if (payload->ciaddr) { 55 DEBUG( LOG_INFO,"unicasting packet to client ciaddr");49 DEBUG("unicasting packet to client ciaddr"); 56 50 ciaddr = payload->ciaddr; 57 51 chaddr = payload->chaddr; 58 52 } else if (ntohs(payload->flags) & BROADCAST_FLAG) { 59 DEBUG( LOG_INFO,"broadcasting packet to client (requested)");53 DEBUG("broadcasting packet to client (requested)"); 60 54 ciaddr = INADDR_BROADCAST; 61 55 chaddr = MAC_BCAST_ADDR; 62 56 } else { 63 DEBUG( LOG_INFO,"unicasting packet to client yiaddr");57 DEBUG("unicasting packet to client yiaddr"); 64 58 ciaddr = payload->yiaddr; 65 59 chaddr = payload->chaddr; … … 122 116 123 117 /* ADDME: if static, short circuit */ 124 if(!static_lease_ip) 125 { 126 /* the client is in our lease/offered table */ 127 if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) { 128 if (!lease_expired(lease)) 129 lease_time_align = lease->expires - time(0); 130 packet.yiaddr = lease->yiaddr; 131 132 /* Or the client has a requested ip */ 133 } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) && 134 135 /* Don't look here (ugly hackish thing to do) */ 136 memcpy(&req_align, req, 4) && 137 138 /* and the ip is in the lease range */ 139 ntohl(req_align) >= ntohl(server_config.start) && 140 ntohl(req_align) <= ntohl(server_config.end) && 141 142 !static_lease_ip && /* Check that its not a static lease */ 143 /* and is not already taken/offered */ 144 ((!(lease = find_lease_by_yiaddr(req_align)) || 145 146 /* or its taken, but expired */ /* ADDME: or maybe in here */ 147 lease_expired(lease)))) { 148 packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ 149 118 if (!static_lease_ip) { 119 /* the client is in our lease/offered table */ 120 lease = find_lease_by_chaddr(oldpacket->chaddr); 121 if (lease) { 122 if (!lease_expired(lease)) 123 lease_time_align = lease->expires - time(0); 124 packet.yiaddr = lease->yiaddr; 125 /* Or the client has a requested ip */ 126 } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) 127 /* Don't look here (ugly hackish thing to do) */ 128 && memcpy(&req_align, req, 4) 129 /* and the ip is in the lease range */ 130 && ntohl(req_align) >= server_config.start_ip 131 && ntohl(req_align) <= server_config.end_ip 132 && !static_lease_ip /* Check that its not a static lease */ 133 /* and is not already taken/offered */ 134 && (!(lease = find_lease_by_yiaddr(req_align)) 135 /* or its taken, but expired */ /* ADDME: or maybe in here */ 136 || lease_expired(lease)) 137 ) { 138 packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ 150 139 /* otherwise, find a free IP */ 140 } else { 141 /* Is it a static lease? (No, because find_address skips static lease) */ 142 packet.yiaddr = find_address(0); 143 /* try for an expired lease */ 144 if (!packet.yiaddr) 145 packet.yiaddr = find_address(1); 146 } 147 148 if (!packet.yiaddr) { 149 bb_error_msg("no IP addresses to give - OFFER abandoned"); 150 return -1; 151 } 152 if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { 153 bb_error_msg("lease pool is full - OFFER abandoned"); 154 return -1; 155 } 156 lease_time = get_option(oldpacket, DHCP_LEASE_TIME); 157 if (lease_time) { 158 memcpy(&lease_time_align, lease_time, 4); 159 lease_time_align = ntohl(lease_time_align); 160 if (lease_time_align > server_config.lease) 161 lease_time_align = server_config.lease; 162 } 163 164 /* Make sure we aren't just using the lease time from the previous offer */ 165 if (lease_time_align < server_config.min_lease) 166 lease_time_align = server_config.lease; 167 /* ADDME: end of short circuit */ 151 168 } else { 152 /* Is it a static lease? (No, because find_address skips static lease) */153 packet.yiaddr = find_address(0);154 155 /* try for an expired lease */156 if (!packet.yiaddr) packet.yiaddr = find_address(1);157 }158 159 if(!packet.yiaddr) {160 LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned");161 return -1;162 }163 164 if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {165 LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned");166 return -1;167 }168 169 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {170 memcpy(&lease_time_align, lease_time, 4);171 lease_time_align = ntohl(lease_time_align);172 if (lease_time_align > server_config.lease)173 lease_time_align = server_config.lease;174 }175 176 /* Make sure we aren't just using the lease time from the previous offer */177 if (lease_time_align < server_config.min_lease)178 lease_time_align = server_config.lease;179 }180 /* ADDME: end of short circuit */181 else182 {183 169 /* It is a static lease... use it */ 184 170 packet.yiaddr = static_lease_ip; … … 197 183 198 184 addr.s_addr = packet.yiaddr; 199 LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr));185 bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); 200 186 return send_packet(&packet, 0); 201 187 } … … 208 194 init_packet(&packet, oldpacket, DHCPNAK); 209 195 210 DEBUG( LOG_INFO, "sending NAK");196 DEBUG("Sending NAK"); 211 197 return send_packet(&packet, 1); 212 198 } … … 224 210 packet.yiaddr = yiaddr; 225 211 226 if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { 212 lease_time = get_option(oldpacket, DHCP_LEASE_TIME); 213 if (lease_time) { 227 214 memcpy(&lease_time_align, lease_time, 4); 228 215 lease_time_align = ntohl(lease_time_align); … … 245 232 246 233 addr.s_addr = packet.yiaddr; 247 LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr));234 bb_info_msg("Sending ACK to %s", inet_ntoa(addr)); 248 235 249 236 if (send_packet(&packet, 0) < 0) … … 251 238 252 239 add_lease(packet.chaddr, packet.yiaddr, lease_time_align); 240 if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { 241 /* rewrite the file with leases at every new acceptance */ 242 write_leases(); 243 } 253 244 254 245 return 0; -
branches/2.2.5/mindi-busybox/networking/udhcp/signalpipe.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* signalpipe.c 2 3 * … … 20 21 */ 21 22 22 #include <unistd.h> 23 #include <fcntl.h> 24 #include <signal.h> 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <sys/select.h> 23 #include "common.h" 28 24 29 30 #include "signalpipe.h"31 #include "common.h"32 25 33 26 static int signal_pipe[2]; … … 35 28 static void signal_handler(int sig) 36 29 { 37 if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) 38 DEBUG(LOG_ERR, "Could not send signal: %m"); 30 unsigned char ch = sig; /* use char, avoid dealing with partial writes */ 31 if (write(signal_pipe[1], &ch, 1) != 1) 32 bb_perror_msg("cannot send signal"); 39 33 } 40 34 … … 44 38 void udhcp_sp_setup(void) 45 39 { 46 socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe); 40 /* was socketpair, but it needs AF_UNIX in kernel */ 41 xpipe(signal_pipe); 47 42 fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC); 48 43 fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC); 44 fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK); 49 45 signal(SIGUSR1, signal_handler); 50 46 signal(SIGUSR2, signal_handler); … … 73 69 int udhcp_sp_read(fd_set *rfds) 74 70 { 75 intsig;71 unsigned char sig; 76 72 77 73 if (!FD_ISSET(signal_pipe[0], rfds)) 78 74 return 0; 79 75 80 if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)76 if (read(signal_pipe[0], &sig, 1) != 1) 81 77 return -1; 82 78 -
branches/2.2.5/mindi-busybox/networking/udhcp/socket.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * socket.c -- DHCP server client/server socket creation … … 23 24 */ 24 25 25 #include <sys/types.h>26 #include <sys/socket.h>27 #include <sys/ioctl.h>28 #include <netinet/in.h>29 #include <unistd.h>30 #include <string.h>31 #include <arpa/inet.h>32 26 #include <net/if.h> 33 #include <errno.h>34 27 #include <features.h> 35 #if ( __GLIBC__ >= 2 && __GLIBC_MINOR>= 1) || defined _NEWLIB_VERSION28 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION 36 29 #include <netpacket/packet.h> 37 30 #include <net/ethernet.h> … … 43 36 44 37 #include "common.h" 45 #include "socket.h"46 38 47 int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) 39 40 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) 48 41 { 49 42 int fd; … … 51 44 struct sockaddr_in *our_ip; 52 45 53 memset(&ifr, 0, sizeof(struct ifreq)); 54 if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) { 55 ifr.ifr_addr.sa_family = AF_INET; 56 strcpy(ifr.ifr_name, interface); 46 memset(&ifr, 0, sizeof(ifr)); 47 fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); 57 48 58 if (addr) { 59 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { 60 our_ip = (struct sockaddr_in *) &ifr.ifr_addr; 61 *addr = our_ip->sin_addr.s_addr; 62 DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr)); 63 } else { 64 LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %m"); 65 close(fd); 66 return -1; 67 } 68 } 69 70 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) { 71 DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex); 72 *ifindex = ifr.ifr_ifindex; 73 } else { 74 LOG(LOG_ERR, "SIOCGIFINDEX failed!: %m"); 49 ifr.ifr_addr.sa_family = AF_INET; 50 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); 51 if (addr) { 52 if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr, 53 "is interface %s up and configured?", interface) 54 ) { 75 55 close(fd); 76 56 return -1; 77 57 } 78 if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) { 79 memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); 80 DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x", 81 arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); 82 } else { 83 LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %m"); 58 our_ip = (struct sockaddr_in *) &ifr.ifr_addr; 59 *addr = our_ip->sin_addr.s_addr; 60 DEBUG("%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr)); 61 } 62 63 if (ifindex) { 64 if (ioctl_or_warn(fd, SIOCGIFINDEX, &ifr) != 0) { 84 65 close(fd); 85 66 return -1; 86 67 } 87 } else { 88 LOG(LOG_ERR, "socket failed!: %m"); 89 return -1; 68 DEBUG("adapter index %d", ifr.ifr_ifindex); 69 *ifindex = ifr.ifr_ifindex; 90 70 } 71 72 if (arp) { 73 if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) { 74 close(fd); 75 return -1; 76 } 77 memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); 78 DEBUG("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x", 79 arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); 80 } 81 91 82 close(fd); 92 83 return 0; 93 84 } 94 85 86 /* 1. None of the callers expects it to ever fail */ 87 /* 2. ip was always INADDR_ANY */ 88 int listen_socket(/*uint32_t ip,*/ int port, const char *inf) 89 { 90 int fd; 91 struct ifreq interface; 92 struct sockaddr_in addr; 95 93 96 int listen_socket(uint32_t ip, int port, char *inf) 97 { 98 struct ifreq interface; 99 int fd; 100 struct sockaddr_in addr; 101 int n = 1; 94 DEBUG("Opening listen socket on *:%d %s", port, inf); 95 fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 102 96 103 DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s", ip, port, inf); 104 if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 105 DEBUG(LOG_ERR, "socket call failed: %m"); 106 return -1; 107 } 97 setsockopt_reuseaddr(fd); 98 if (setsockopt_broadcast(fd) == -1) 99 bb_perror_msg_and_die("SO_BROADCAST"); 100 101 strncpy(interface.ifr_name, inf, IFNAMSIZ); 102 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface)) == -1) 103 bb_perror_msg_and_die("SO_BINDTODEVICE"); 108 104 109 105 memset(&addr, 0, sizeof(addr)); 110 106 addr.sin_family = AF_INET; 111 107 addr.sin_port = htons(port); 112 addr.sin_addr.s_addr = ip; 113 114 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) { 115 close(fd); 116 return -1; 117 } 118 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) { 119 close(fd); 120 return -1; 121 } 122 123 strncpy(interface.ifr_name, inf, IFNAMSIZ); 124 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) { 125 close(fd); 126 return -1; 127 } 128 129 if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { 130 close(fd); 131 return -1; 132 } 108 /* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */ 109 xbind(fd, (struct sockaddr *)&addr, sizeof(addr)); 133 110 134 111 return fd; -
branches/2.2.5/mindi-busybox/networking/udhcp/static_leases.c
r821 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * static_leases.c -- Couple of functions to assist with storing and … … 7 8 */ 8 9 10 #include "common.h" 11 #include "dhcpd.h" 9 12 10 #include <stdlib.h>11 #include <stdio.h>12 #include <string.h>13 14 #include "static_leases.h"15 #include "dhcpd.h"16 13 17 14 /* Takes the address of the pointer to the static_leases linked list, … … 20 17 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip) 21 18 { 22 23 19 struct static_lease *cur; 24 20 struct static_lease *new_static_lease; … … 31 27 32 28 /* If it's the first node to be added... */ 33 if(*lease_struct == NULL) 34 { 29 if (*lease_struct == NULL) { 35 30 *lease_struct = new_static_lease; 36 } 37 else 38 { 31 } else { 39 32 cur = *lease_struct; 40 while(cur->next != NULL) 41 { 33 while (cur->next) { 42 34 cur = cur->next; 43 35 } … … 47 39 48 40 return 1; 49 50 41 } 51 42 … … 59 50 return_ip = 0; 60 51 61 while(cur != NULL) 62 { 52 while (cur) { 63 53 /* If the client has the correct mac */ 64 if(memcmp(cur->mac, mac, 6) == 0) 65 { 54 if (memcmp(cur->mac, mac, 6) == 0) { 66 55 return_ip = *(cur->ip); 67 56 } … … 71 60 72 61 return return_ip; 73 74 62 } 75 63 … … 81 69 uint32_t return_val = 0; 82 70 83 while(cur != NULL) 84 { 71 while (cur) { 85 72 /* If the client has the correct ip */ 86 if (*cur->ip == ip)73 if (*cur->ip == ip) 87 74 return_val = 1; 88 75 … … 91 78 92 79 return return_val; 93 94 80 } 95 81 96 #if def CONFIG_FEATURE_UDHCP_DEBUG82 #if ENABLE_FEATURE_UDHCP_DEBUG 97 83 /* Print out static leases just to check what's going on */ 98 84 /* Takes the address of the pointer to the static_leases linked list */ … … 102 88 struct static_lease *cur = *arg; 103 89 104 while(cur != NULL) 105 { 90 while (cur) { 106 91 /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */ 107 92 printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac)); … … 111 96 cur = cur->next; 112 97 } 113 114 115 98 } 116 99 #endif 117 118 119 -
branches/2.2.5/mindi-busybox/networking/vconfig.c
r821 r1765 10 10 /* BB_AUDIT SUSv3 N/A */ 11 11 12 #include <stdlib.h> 13 #include <unistd.h> 14 #include <fcntl.h> 15 #include <sys/ioctl.h> 12 #include "libbb.h" 16 13 #include <net/if.h> 17 #include <string.h>18 #include <limits.h>19 #include "busybox.h"20 14 21 15 /* Stuff from linux/if_vlan.h, kernel version 2.4.23 */ … … 70 64 } 71 65 72 static const char cmds[] = {66 static const char cmds[] ALIGN1 = { 73 67 4, ADD_VLAN_CMD, 7, 74 68 'a', 'd', 'd', 0, … … 79 73 'n', 'a', 'm', 'e', '_', 80 74 't', 'y', 'p', 'e', 0, 81 4, SET_VLAN_FLAG_CMD, 12,75 5, SET_VLAN_FLAG_CMD, 12, 82 76 's', 'e', 't', '_', 83 77 'f', 'l', 'a', 'g', 0, … … 92 86 }; 93 87 94 static const char name_types[] = {88 static const char name_types[] ALIGN1 = { 95 89 VLAN_NAME_TYPE_PLUS_VID, 16, 96 90 'V', 'L', 'A', 'N', … … 111 105 }; 112 106 113 static const char conf_file_name[] = "/proc/net/vlan/config";107 static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config"; 114 108 109 int vconfig_main(int argc, char **argv); 115 110 int vconfig_main(int argc, char **argv) 116 111 { … … 125 120 /* Don't bother closing the filedes. It will be closed on cleanup. */ 126 121 /* Will die if 802.1q is not present */ 127 bb_xopen3(conf_file_name, O_RDONLY, 0);122 xopen(conf_file_name, O_RDONLY); 128 123 129 124 memset(&ifr, 0, sizeof(struct vlan_ioctl_args)); … … 140 135 } else { 141 136 if (strlen(argv[1]) >= IF_NAMESIZE) { 142 bb_error_msg_and_die("if_name >= %d chars \n", IF_NAMESIZE);137 bb_error_msg_and_die("if_name >= %d chars", IF_NAMESIZE); 143 138 } 144 139 strcpy(ifr.device1, argv[1]); … … 151 146 * more of a pain. */ 152 147 if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */ 153 ifr.u.flag = bb_xgetularg10_bnd(p, 0, 1); 148 ifr.u.flag = xatoul_range(p, 0, 1); 149 /* DM: in order to set reorder header, qos must be set */ 150 ifr.vlan_qos = xatoul_range(argv[3], 0, 7); 154 151 } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */ 155 ifr.u.VID = bb_xgetularg10_bnd(p, 0, VLAN_GROUP_ARRAY_LEN-1);152 ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1); 156 153 } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */ 157 ifr.u.skb_priority = bb_xgetularg10_bnd(p, 0, ULONG_MAX);158 ifr.vlan_qos = bb_xgetularg10_bnd(argv[3], 0, 7);154 ifr.u.skb_priority = xatou(p); 155 ifr.vlan_qos = xatoul_range(argv[3], 0, 7); 159 156 } 160 157 } 161 158 162 fd = bb_xsocket(AF_INET, SOCK_STREAM, 0); 163 if (ioctl(fd, SIOCSIFVLAN, &ifr) < 0) { 164 bb_perror_msg_and_die("ioctl error for %s", *argv); 165 } 159 fd = xsocket(AF_INET, SOCK_STREAM, 0); 160 ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr, 161 "ioctl error for %s", *argv); 166 162 167 163 return 0; 168 164 } 169 -
branches/2.2.5/mindi-busybox/networking/wget.c
r821 r1765 7 7 */ 8 8 9 #include "busybox.h" 10 #include <errno.h> 11 #include <signal.h> 12 #include <sys/ioctl.h> 13 #include <getopt.h> 14 9 /* We want libc to give us xxx64 functions also */ 10 /* http://www.unix.org/version2/whatsnew/lfs20mar.html */ 11 //#define _LARGEFILE64_SOURCE 1 12 13 #include <getopt.h> /* for struct option */ 14 #include "libbb.h" 15 15 16 16 struct host_info { 17 // May be used if we ever will want to free() all xstrdup()s... 18 /* char *allocated; */ 17 19 char *host; 18 20 int port; … … 23 25 24 26 static void parse_url(char *url, struct host_info *h); 25 static FILE *open_socket( struct sockaddr_in *s_in);27 static FILE *open_socket(len_and_sockaddr *lsa); 26 28 static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); 27 static int ftpcmd(c har *s1,char *s2, FILE *fp, char *buf);29 static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf); 28 30 29 31 /* Globals (can be accessed from signal handlers */ 30 static off_t filesize; /* content-length of the file */ 31 static int chunked; /* chunked transfer encoding */ 32 #ifdef CONFIG_FEATURE_WGET_STATUSBAR 32 static off_t content_len; /* Content-length of the file */ 33 static off_t beg_range; /* Range at which continue begins */ 34 #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 */ 38 #if ENABLE_FEATURE_WGET_STATUSBAR 33 39 static void progressmeter(int flag); 34 static char *curfile; /* Name of current file being transferred. */ 35 static struct timeval start; /* Time a transfer started. */ 36 static off_t transferred; /* Number of bytes transferred so far. */ 37 /* For progressmeter() -- number of seconds before xfer considered "stalled" */ 40 static const char *curfile; /* Name of current file being transferred */ 38 41 enum { 39 STALLTIME = 5 42 STALLTIME = 5 /* Seconds when xfer considered "stalled" */ 40 43 }; 41 44 #else 42 static inline void progressmeter(int flag) {} 43 #endif 44 45 static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue) 46 { 47 if (output != stdout && do_continue==0) { 48 fclose(output); 49 unlink(fname_out); 50 } 51 } 52 53 /* Read NMEMB elements of SIZE bytes into PTR from STREAM. Returns the 54 * number of elements read, and a short count if an eof or non-interrupt 55 * error is encountered. */ 56 static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 57 { 58 size_t ret = 0; 45 static ALWAYS_INLINE void progressmeter(int flag) {} 46 #endif 47 48 /* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, 49 * and a short count if an eof or non-interrupt error is encountered. */ 50 static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) 51 { 52 size_t ret; 53 char *p = (char*)ptr; 59 54 60 55 do { 61 56 clearerr(stream); 62 ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream); 63 } while (ret < nmemb && ferror(stream) && errno == EINTR); 64 65 return ret; 66 } 67 68 /* Write NMEMB elements of SIZE bytes from PTR to STREAM. Returns the 69 * number of elements written, and a short count if an eof or non-interrupt 70 * error is encountered. */ 71 static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) 72 { 73 size_t ret = 0; 74 75 do { 76 clearerr(stream); 77 ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream); 78 } while (ret < nmemb && ferror(stream) && errno == EINTR); 79 80 return ret; 81 } 82 83 /* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM. 57 ret = fread(p, 1, nmemb, stream); 58 p += ret; 59 nmemb -= ret; 60 } while (nmemb && ferror(stream) && errno == EINTR); 61 62 return p - (char*)ptr; 63 } 64 65 /* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM. 84 66 * Returns S, or NULL if an eof or non-interrupt error is encountered. */ 85 67 static char *safe_fgets(char *s, int size, FILE *stream) … … 95 77 } 96 78 97 #define close_delete_and_die(s...) { \ 98 close_and_delete_outfile(output, fname_out, do_continue); \ 99 bb_error_msg_and_die(s); } 100 101 102 #ifdef CONFIG_FEATURE_WGET_AUTHENTICATION 103 /* 104 * Base64-encode character string 105 * oops... isn't something similar in uuencode.c? 106 * XXX: It would be better to use already existing code 107 */ 108 static char *base64enc(unsigned char *p, char *buf, int len) { 109 110 char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 111 "0123456789+/"; 112 char *s = buf; 113 114 while(*p) { 115 if (s >= buf+len-4) 116 bb_error_msg_and_die("buffer overflow"); 117 *(s++) = al[(*p >> 2) & 0x3F]; 118 *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)]; 119 *s = *(s+1) = '='; 120 *(s+2) = 0; 121 if (! *(++p)) break; 122 *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)]; 123 if (! *(++p)) break; 124 *(s++) = al[*(p++) & 0x3F]; 125 } 126 79 #if ENABLE_FEATURE_WGET_AUTHENTICATION 80 /* Base64-encode character string. buf is assumed to be char buf[512]. */ 81 static char *base64enc_512(char buf[512], const char *str) 82 { 83 unsigned len = strlen(str); 84 if (len > 512/4*3 - 10) /* paranoia */ 85 len = 512/4*3 - 10; 86 bb_uuencode(buf, str, len, bb_uuenc_tbl_base64); 127 87 return buf; 128 88 } 129 89 #endif 130 90 131 #define WGET_OPT_CONTINUE 1 132 #define WGET_OPT_QUIET 2 133 #define WGET_OPT_PASSIVE 4 134 #define WGET_OPT_OUTNAME 8 135 #define WGET_OPT_HEADER 16 136 #define WGET_OPT_PREFIX 32 137 #define WGET_OPT_PROXY 64 138 139 #if ENABLE_WGET_LONG_OPTIONS 140 static const struct option wget_long_options[] = { 141 { "continue", 0, NULL, 'c' }, 142 { "quiet", 0, NULL, 'q' }, 143 { "passive-ftp", 0, NULL, 139 }, 144 { "output-document", 1, NULL, 'O' }, 145 { "header", 1, NULL, 131 }, 146 { "directory-prefix",1, NULL, 'P' }, 147 { "proxy", 1, NULL, 'Y' }, 148 { 0, 0, 0, 0 } 149 }; 150 #endif 151 91 int wget_main(int argc, char **argv); 152 92 int wget_main(int argc, char **argv) 153 93 { 154 int n, try=5, status; 155 unsigned long opt; 94 char buf[512]; 95 struct host_info server, target; 96 len_and_sockaddr *lsa; 97 int n, status; 156 98 int port; 99 int try = 5; 100 unsigned opt; 101 char *str; 157 102 char *proxy = 0; 158 char *dir_prefix=NULL; 159 char *s, buf[512]; 160 struct stat sbuf; 161 char extra_headers[1024]; 162 char *extra_headers_ptr = extra_headers; 163 int extra_headers_left = sizeof(extra_headers); 164 struct host_info server, target; 165 struct sockaddr_in s_in; 103 char *dir_prefix = NULL; 104 #if ENABLE_FEATURE_WGET_LONG_OPTIONS 105 char *extra_headers = NULL; 166 106 llist_t *headers_llist = NULL; 167 168 FILE *sfp = NULL; /* socket to web/ftp server */ 169 FILE *dfp = NULL; /* socket to ftp server (data) */ 170 char *fname_out = NULL; /* where to direct output (-O) */ 171 int do_continue = 0; /* continue a prev transfer (-c) */ 172 long beg_range = 0L; /* range at which continue begins */ 173 int got_clen = 0; /* got content-length: from server */ 174 FILE *output; /* socket to web server */ 175 int quiet_flag = FALSE; /* Be verry, verry quiet... */ 176 int use_proxy = 1; /* Use proxies if env vars are set */ 177 char *proxy_flag = "on"; /* Use proxies if env vars are set */ 178 179 /* 180 * Crack command line. 181 */ 182 bb_opt_complementally = "-1:\203::"; 183 #if ENABLE_WGET_LONG_OPTIONS 184 bb_applet_long_options = wget_long_options; 185 #endif 186 opt = bb_getopt_ulflags(argc, argv, "cq\213O:\203:P:Y:", 187 &fname_out, &headers_llist, 188 &dir_prefix, &proxy_flag); 189 if (opt & WGET_OPT_CONTINUE) { 190 ++do_continue; 191 } 192 if (opt & WGET_OPT_QUIET) { 193 quiet_flag = TRUE; 194 } 107 #endif 108 109 FILE *sfp = NULL; /* socket to web/ftp server */ 110 FILE *dfp = NULL; /* socket to ftp server (data) */ 111 char *fname_out = NULL; /* where to direct output (-O) */ 112 bool got_clen = 0; /* got content-length: from server */ 113 int output_fd = -1; 114 bool use_proxy = 1; /* Use proxies if env vars are set */ 115 const char *proxy_flag = "on"; /* Use proxies if env vars are set */ 116 const char *user_agent = "Wget";/* "User-Agent" header field */ 117 static const char keywords[] ALIGN1 = 118 "content-length\0""transfer-encoding\0""chunked\0""location\0"; 119 enum { 120 KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location 121 }; 122 enum { 123 WGET_OPT_CONTINUE = 0x1, 124 WGET_OPT_SPIDER = 0x2, 125 WGET_OPT_QUIET = 0x4, 126 WGET_OPT_OUTNAME = 0x8, 127 WGET_OPT_PREFIX = 0x10, 128 WGET_OPT_PROXY = 0x20, 129 WGET_OPT_USER_AGENT = 0x40, 130 WGET_OPT_PASSIVE = 0x80, 131 WGET_OPT_HEADER = 0x100, 132 }; 133 #if ENABLE_FEATURE_WGET_LONG_OPTIONS 134 static const char wget_longopts[] ALIGN1 = 135 /* name, has_arg, val */ 136 "continue\0" No_argument "c" 137 "spider\0" No_argument "s" 138 "quiet\0" No_argument "q" 139 "output-document\0" Required_argument "O" 140 "directory-prefix\0" Required_argument "P" 141 "proxy\0" Required_argument "Y" 142 "user-agent\0" Required_argument "U" 143 "passive-ftp\0" No_argument "\xff" 144 "header\0" Required_argument "\xfe" 145 ; 146 applet_long_options = wget_longopts; 147 #endif 148 /* server.allocated = target.allocated = NULL; */ 149 opt_complementary = "-1" USE_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); 150 opt = getopt32(argv, "csqO:P:Y:U:", 151 &fname_out, &dir_prefix, 152 &proxy_flag, &user_agent 153 USE_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) 154 ); 195 155 if (strcmp(proxy_flag, "off") == 0) { 196 /* Use the proxy if necessary .*/156 /* Use the proxy if necessary */ 197 157 use_proxy = 0; 198 158 } 199 if (opt & WGET_OPT_HEADER) { 159 #if ENABLE_FEATURE_WGET_LONG_OPTIONS 160 if (headers_llist) { 161 int size = 1; 162 char *cp; 163 llist_t *ll = headers_llist; 164 while (ll) { 165 size += strlen(ll->data) + 2; 166 ll = ll->link; 167 } 168 extra_headers = cp = xmalloc(size); 200 169 while (headers_llist) { 201 int arglen = strlen(headers_llist->data); 202 if (extra_headers_left - arglen - 2 <= 0) 203 bb_error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen); 204 strcpy(extra_headers_ptr, headers_llist->data); 205 extra_headers_ptr += arglen; 206 extra_headers_left -= ( arglen + 2 ); 207 *extra_headers_ptr++ = '\r'; 208 *extra_headers_ptr++ = '\n'; 209 *(extra_headers_ptr + 1) = 0; 170 cp += sprintf(cp, "%s\r\n", headers_llist->data); 210 171 headers_llist = headers_llist->link; 211 172 } 212 173 } 174 #endif 213 175 214 176 parse_url(argv[optind], &target); … … 216 178 server.port = target.port; 217 179 218 /* 219 * Use the proxy if necessary. 220 */ 180 /* Use the proxy if necessary */ 221 181 if (use_proxy) { 222 182 proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); 223 183 if (proxy && *proxy) { 224 parse_url( bb_xstrdup(proxy), &server);184 parse_url(proxy, &server); 225 185 } else { 226 186 use_proxy = 0; … … 232 192 // Dirty hack. Needed because bb_get_last_path_component 233 193 // will destroy trailing / by storing '\0' in last byte! 234 if (*target.path && target.path[strlen(target.path)-1]!='/') {235 fname_out = 236 #if def CONFIG_FEATURE_WGET_STATUSBAR237 curfile =238 #endif 239 bb_get_last_path_component(target.path);240 }241 if (fname_out==NULL || strlen(fname_out)<1) {242 fname_out =243 #ifdef CONFIG_FEATURE_WGET_STATUSBAR 244 curfile = 245 #endif 246 "index.html"; 194 if (!last_char_is(target.path, '/')) { 195 fname_out = bb_get_last_path_component(target.path); 196 #if ENABLE_FEATURE_WGET_STATUSBAR 197 curfile = fname_out; 198 #endif 199 } 200 if (!fname_out || !fname_out[0]) { 201 /* bb_get_last_path_component writes 202 * to last '/' only. We don't have one here... */ 203 fname_out = (char*)"index.html"; 204 #if ENABLE_FEATURE_WGET_STATUSBAR 205 curfile = fname_out; 206 #endif 247 207 } 248 208 if (dir_prefix != NULL) 249 209 fname_out = concat_path_file(dir_prefix, fname_out); 250 #if def CONFIG_FEATURE_WGET_STATUSBAR210 #if ENABLE_FEATURE_WGET_STATUSBAR 251 211 } else { 252 212 curfile = bb_get_last_path_component(fname_out); 253 213 #endif 254 214 } 255 if (do_continue && !fname_out) 256 bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); 257 258 259 /* 260 * Open the output file stream. 261 */ 262 if (strcmp(fname_out, "-") == 0) { 263 output = stdout; 264 quiet_flag = TRUE; 265 } else { 266 output = bb_xfopen(fname_out, (do_continue ? "a" : "w")); 267 } 268 269 /* 270 * Determine where to start transfer. 271 */ 272 if (do_continue) { 273 if (fstat(fileno(output), &sbuf) < 0) 274 bb_perror_msg_and_die("fstat()"); 275 if (sbuf.st_size > 0) 276 beg_range = sbuf.st_size; 277 else 278 do_continue = 0; 215 /* Impossible? 216 if ((opt & WGET_OPT_CONTINUE) && !fname_out) 217 bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); */ 218 219 /* Determine where to start transfer */ 220 if (LONE_DASH(fname_out)) { 221 output_fd = 1; 222 opt &= ~WGET_OPT_CONTINUE; 223 } 224 if (opt & WGET_OPT_CONTINUE) { 225 output_fd = open(fname_out, O_WRONLY); 226 if (output_fd >= 0) { 227 beg_range = xlseek(output_fd, 0, SEEK_END); 228 } 229 /* File doesn't exist. We do not create file here yet. 230 We are not sure it exists on remove side */ 279 231 } 280 232 … … 282 234 * sites (i.e. ftp.us.debian.org) use round-robin DNS 283 235 * and we want to connect to only one IP... */ 284 bb_lookup_host(&s_in, server.host);285 s_in.sin_port = server.port;286 if (quiet_flag==FALSE) {287 fprintf(stdout, "Connecting to %s[%s]:%d\n",288 server.host, inet_ntoa(s_in.sin_addr), ntohs(server.port));236 lsa = xhost2sockaddr(server.host, server.port); 237 if (!(opt & WGET_OPT_QUIET)) { 238 fprintf(stderr, "Connecting to %s (%s)\n", server.host, 239 xmalloc_sockaddr2dotted(&lsa->sa)); 240 /* We leak result of xmalloc_sockaddr2dotted */ 289 241 } 290 242 … … 296 248 got_clen = chunked = 0; 297 249 298 if (! --try) 299 close_delete_and_die("too many redirections"); 300 301 /* 302 * Open socket to http server 303 */ 250 if (!--try) 251 bb_error_msg_and_die("too many redirections"); 252 253 /* Open socket to http server */ 304 254 if (sfp) fclose(sfp); 305 sfp = open_socket(&s_in); 306 307 /* 308 * Send HTTP request. 309 */ 255 sfp = open_socket(lsa); 256 257 /* Send HTTP request. */ 310 258 if (use_proxy) { 311 const char *format = "GET %stp://%s:%d/%s HTTP/1.1\r\n"; 312 #ifdef CONFIG_FEATURE_WGET_IP6_LITERAL 313 if (strchr(target.host, ':')) 314 format = "GET %stp://[%s]:%d/%s HTTP/1.1\r\n"; 315 #endif 316 fprintf(sfp, format, 259 fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", 317 260 target.is_ftp ? "f" : "ht", target.host, 318 ntohs(target.port),target.path);261 target.path); 319 262 } else { 320 263 fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); 321 264 } 322 265 323 fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host); 324 325 #ifdef CONFIG_FEATURE_WGET_AUTHENTICATION 266 fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", 267 target.host, user_agent); 268 269 #if ENABLE_FEATURE_WGET_AUTHENTICATION 326 270 if (target.user) { 327 fprintf(sfp, " Authorization: Basic %s\r\n",328 base64enc ((unsigned char*)target.user, buf, sizeof(buf)));271 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, 272 base64enc_512(buf, target.user)); 329 273 } 330 274 if (use_proxy && server.user) { 331 275 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", 332 base64enc ((unsigned char*)server.user, buf, sizeof(buf)));276 base64enc_512(buf, server.user)); 333 277 } 334 278 #endif 335 279 336 if (do_continue) 337 fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range); 338 if(extra_headers_left < sizeof(extra_headers)) 339 fputs(extra_headers,sfp); 340 fprintf(sfp,"Connection: close\r\n\r\n"); 280 if (beg_range) 281 fprintf(sfp, "Range: bytes=%"OFF_FMT"d-\r\n", beg_range); 282 #if ENABLE_FEATURE_WGET_LONG_OPTIONS 283 if (extra_headers) 284 fputs(extra_headers, sfp); 285 #endif 286 fprintf(sfp, "Connection: close\r\n\r\n"); 341 287 342 288 /* 343 289 * Retrieve HTTP response line and check for "200" status code. 344 290 */ 345 read_response:291 read_response: 346 292 if (fgets(buf, sizeof(buf), sfp) == NULL) 347 close_delete_and_die("no response from server"); 348 349 for (s = buf ; *s != '\0' && !isspace(*s) ; ++s) 350 ; 351 for ( ; isspace(*s) ; ++s) 352 ; 353 switch (status = atoi(s)) { 354 case 0: 355 case 100: 356 while (gethdr(buf, sizeof(buf), sfp, &n) != NULL); 357 goto read_response; 358 case 200: 359 if (do_continue && output != stdout) 360 output = freopen(fname_out, "w", output); 361 do_continue = 0; 293 bb_error_msg_and_die("no response from server"); 294 295 str = buf; 296 str = skip_non_whitespace(str); 297 str = skip_whitespace(str); 298 // FIXME: no error check 299 // xatou wouldn't work: "200 OK" 300 status = atoi(str); 301 switch (status) { 302 case 0: 303 case 100: 304 while (gethdr(buf, sizeof(buf), sfp, &n) != NULL) 305 /* eat all remaining headers */; 306 goto read_response; 307 case 200: 308 break; 309 case 300: /* redirection */ 310 case 301: 311 case 302: 312 case 303: 313 break; 314 case 206: 315 if (beg_range) 362 316 break; 363 case 300: /* redirection */ 364 case 301: 365 case 302: 366 case 303: 367 break; 368 case 206: 369 if (do_continue) 370 break; 371 /*FALLTHRU*/ 372 default: 373 chomp(buf); 374 close_delete_and_die("server returned error %d: %s", atoi(s), buf); 317 /*FALLTHRU*/ 318 default: 319 /* Show first line only and kill any ESC tricks */ 320 buf[strcspn(buf, "\n\r\x1b")] = '\0'; 321 bb_error_msg_and_die("server returned error: %s", buf); 375 322 } 376 323 … … 378 325 * Retrieve HTTP headers. 379 326 */ 380 while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { 381 if (strcasecmp(buf, "content-length") == 0) { 382 unsigned long value; 383 if (safe_strtoul(s, &value)) { 384 close_delete_and_die("content-length %s is garbage", s); 327 while ((str = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { 328 /* gethdr did already convert the "FOO:" string to lowercase */ 329 smalluint key = index_in_strings(keywords, *&buf) + 1; 330 if (key == KEY_content_length) { 331 content_len = BB_STRTOOFF(str, NULL, 10); 332 if (errno || content_len < 0) { 333 bb_error_msg_and_die("content-length %s is garbage", str); 385 334 } 386 filesize = value;387 335 got_clen = 1; 388 336 continue; 389 337 } 390 if (strcasecmp(buf, "transfer-encoding") == 0) { 391 if (strcasecmp(s, "chunked") == 0) { 392 chunked = got_clen = 1; 393 } else { 394 close_delete_and_die("server wants to do %s transfer encoding", s); 395 } 338 if (key == KEY_transfer_encoding) { 339 if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) 340 bb_error_msg_and_die("server wants to do %s transfer encoding", str); 341 chunked = got_clen = 1; 396 342 } 397 if (strcasecmp(buf, "location") == 0) { 398 if (s[0] == '/') 399 target.path = bb_xstrdup(s+1); 343 if (key == KEY_location) { 344 if (str[0] == '/') 345 /* free(target.allocated); */ 346 target.path = /* target.allocated = */ xstrdup(str+1); 400 347 else { 401 parse_url( bb_xstrdup(s), &target);348 parse_url(str, &target); 402 349 if (use_proxy == 0) { 403 350 server.host = target.host; 404 351 server.port = target.port; 405 352 } 406 bb_lookup_host(&s_in, server.host);407 s_in.sin_port = server.port;353 free(lsa); 354 lsa = xhost2sockaddr(server.host, server.port); 408 355 break; 409 356 } 410 357 } 411 358 } 412 } while (status >= 300);359 } while (status >= 300); 413 360 414 361 dfp = sfp; 415 } 416 else417 { 362 363 } else { 364 418 365 /* 419 366 * FTP session 420 367 */ 421 if (! 422 target.user = bb_xstrdup("anonymous:busybox@");423 424 sfp = open_socket( &s_in);368 if (!target.user) 369 target.user = xstrdup("anonymous:busybox@"); 370 371 sfp = open_socket(lsa); 425 372 if (ftpcmd(NULL, NULL, sfp, buf) != 220) 426 close_delete_and_die("%s", buf+4);373 bb_error_msg_and_die("%s", buf+4); 427 374 428 375 /* … … 430 377 * trying to log in 431 378 */ 432 s = strchr(target.user, ':'); 433 if (s) 434 *(s++) = '\0'; 435 switch(ftpcmd("USER ", target.user, sfp, buf)) { 436 case 230: 379 str = strchr(target.user, ':'); 380 if (str) 381 *(str++) = '\0'; 382 switch (ftpcmd("USER ", target.user, sfp, buf)) { 383 case 230: 384 break; 385 case 331: 386 if (ftpcmd("PASS ", str, sfp, buf) == 230) 437 387 break; 438 case 331: 439 if (ftpcmd("PASS ", s, sfp, buf) == 230) 440 break; 441 /* FALLTHRU (failed login) */ 442 default: 443 close_delete_and_die("ftp login: %s", buf+4); 388 /* FALLTHRU (failed login) */ 389 default: 390 bb_error_msg_and_die("ftp login: %s", buf+4); 444 391 } 445 392 … … 450 397 */ 451 398 if (ftpcmd("SIZE ", target.path, sfp, buf) == 213) { 452 unsigned long value;453 if ( safe_strtoul(buf+4, &value)) {454 close_delete_and_die("SIZE value is garbage");399 content_len = BB_STRTOOFF(buf+4, NULL, 10); 400 if (errno || content_len < 0) { 401 bb_error_msg_and_die("SIZE value is garbage"); 455 402 } 456 filesize = value;457 403 got_clen = 1; 458 404 } … … 461 407 * Entering passive mode 462 408 */ 463 if (ftpcmd("PASV", NULL, sfp, buf) != 227) 464 close_delete_and_die("PASV: %s", buf+4); 465 s = strrchr(buf, ','); 466 *s = 0; 467 port = atoi(s+1); 468 s = strrchr(buf, ','); 469 port += atoi(s+1) * 256; 470 s_in.sin_port = htons(port); 471 dfp = open_socket(&s_in); 472 473 if (do_continue) { 474 sprintf(buf, "REST %ld", beg_range); 475 if (ftpcmd(buf, NULL, sfp, buf) != 350) { 476 if (output != stdout) 477 output = freopen(fname_out, "w", output); 478 do_continue = 0; 479 } else 480 filesize -= beg_range; 409 if (ftpcmd("PASV", NULL, sfp, buf) != 227) { 410 pasv_error: 411 bb_error_msg_and_die("bad response to %s: %s", "PASV", buf); 412 } 413 // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage] 414 // Server's IP is N1.N2.N3.N4 (we ignore it) 415 // Server's port for data connection is P1*256+P2 416 str = strrchr(buf, ')'); 417 if (str) str[0] = '\0'; 418 str = strrchr(buf, ','); 419 if (!str) goto pasv_error; 420 port = xatou_range(str+1, 0, 255); 421 *str = '\0'; 422 str = strrchr(buf, ','); 423 if (!str) goto pasv_error; 424 port += xatou_range(str+1, 0, 255) * 256; 425 set_nport(lsa, htons(port)); 426 dfp = open_socket(lsa); 427 428 if (beg_range) { 429 sprintf(buf, "REST %"OFF_FMT"d", beg_range); 430 if (ftpcmd(buf, NULL, sfp, buf) == 350) 431 content_len -= beg_range; 481 432 } 482 433 483 434 if (ftpcmd("RETR ", target.path, sfp, buf) > 150) 484 close_delete_and_die("RETR: %s", buf+4); 485 } 486 435 bb_error_msg_and_die("bad response to RETR: %s", buf); 436 } 437 if (opt & WGET_OPT_SPIDER) { 438 if (ENABLE_FEATURE_CLEAN_UP) 439 fclose(sfp); 440 goto done; 441 } 487 442 488 443 /* … … 491 446 if (chunked) { 492 447 fgets(buf, sizeof(buf), dfp); 493 filesize = strtol(buf, (char **) NULL, 16); 494 } 495 496 if (quiet_flag==FALSE) 448 content_len = STRTOOFF(buf, NULL, 16); 449 /* FIXME: error check?? */ 450 } 451 452 /* Do it before progressmeter (want to have nice error message) */ 453 if (output_fd < 0) 454 output_fd = xopen(fname_out, 455 O_WRONLY|O_CREAT|O_EXCL|O_TRUNC); 456 457 if (!(opt & WGET_OPT_QUIET)) 497 458 progressmeter(-1); 498 459 499 460 do { 500 while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, ((chunked || got_clen) && (filesize < sizeof(buf)) ? filesize : sizeof(buf)), dfp)) > 0) { 501 if (safe_fwrite(buf, 1, n, output) != n) { 461 while (content_len > 0 || !got_clen) { 462 unsigned rdsz = sizeof(buf); 463 if (content_len < sizeof(buf) && (chunked || got_clen)) 464 rdsz = (unsigned)content_len; 465 n = safe_fread(buf, rdsz, dfp); 466 if (n <= 0) 467 break; 468 if (full_write(output_fd, buf, n) != n) { 502 469 bb_perror_msg_and_die(bb_msg_write_error); 503 470 } 504 #if def CONFIG_FEATURE_WGET_STATUSBAR471 #if ENABLE_FEATURE_WGET_STATUSBAR 505 472 transferred += n; 506 473 #endif 507 474 if (got_clen) { 508 filesize-= n;475 content_len -= n; 509 476 } 510 477 } … … 513 480 safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ 514 481 safe_fgets(buf, sizeof(buf), dfp); 515 filesize = strtol(buf, (char **) NULL, 16); 516 if (filesize==0) { 482 content_len = STRTOOFF(buf, NULL, 16); 483 /* FIXME: error check? */ 484 if (content_len == 0) { 517 485 chunked = 0; /* all done! */ 518 486 } … … 524 492 } while (chunked); 525 493 526 if ( quiet_flag==FALSE)494 if (!(opt & WGET_OPT_QUIET)) 527 495 progressmeter(1); 528 496 … … 533 501 ftpcmd("QUIT", NULL, sfp, buf); 534 502 } 503 done: 535 504 exit(EXIT_SUCCESS); 536 505 } 537 506 538 507 539 void parse_url(char *url, struct host_info *h) 540 { 541 char *cp, *sp, *up, *pp; 508 static void parse_url(char *src_url, struct host_info *h) 509 { 510 char *url, *p, *sp; 511 512 /* h->allocated = */ url = xstrdup(src_url); 542 513 543 514 if (strncmp(url, "http://", 7) == 0) { … … 546 517 h->is_ftp = 0; 547 518 } else if (strncmp(url, "ftp://", 6) == 0) { 548 h->port = bb_lookup_port("ftp", "t fp", 21);519 h->port = bb_lookup_port("ftp", "tcp", 21); 549 520 h->host = url + 6; 550 521 h->is_ftp = 1; … … 552 523 bb_error_msg_and_die("not an http or ftp url: %s", url); 553 524 525 // FYI: 526 // "Real" wget 'http://busybox.net?var=a/b' sends this request: 527 // 'GET /?var=a/b HTTP 1.0' 528 // and saves 'index.html?var=a%2Fb' (we save 'b') 529 // wget 'http://busybox.net?login=john@doe': 530 // request: 'GET /?login=john@doe HTTP/1.0' 531 // saves: 'index.html?login=john@doe' (we save '?login=john@doe') 532 // wget 'http://busybox.net#test/test': 533 // request: 'GET / HTTP/1.0' 534 // saves: 'index.html' (we save 'test') 535 // 536 // We also don't add unique .N suffix if file exists... 554 537 sp = strchr(h->host, '/'); 555 if (sp) { 556 *sp++ = '\0'; 538 p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p; 539 p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p; 540 if (!sp) { 541 /* must be writable because of bb_get_last_path_component() */ 542 static char nullstr[] ALIGN1 = ""; 543 h->path = nullstr; 544 } else if (*sp == '/') { 545 *sp = '\0'; 546 h->path = sp + 1; 547 } else { // '#' or '?' 548 // http://busybox.net?login=john@doe is a valid URL 549 // memmove converts to: 550 // http:/busybox.nett?login=john@doe... 551 memmove(h->host-1, h->host, sp - h->host); 552 h->host--; 553 sp[-1] = '\0'; 557 554 h->path = sp; 558 } else559 h->path = bb_xstrdup(""); 560 561 up = strrchr(h->host, '@');562 if ( up != NULL) {555 } 556 557 sp = strrchr(h->host, '@'); 558 h->user = NULL; 559 if (sp != NULL) { 563 560 h->user = h->host; 564 *up++ = '\0'; 565 h->host = up; 566 } else 567 h->user = NULL; 568 569 pp = h->host; 570 571 #ifdef CONFIG_FEATURE_WGET_IP6_LITERAL 572 if (h->host[0] == '[') { 573 char *ep; 574 575 ep = h->host + 1; 576 while (*ep == ':' || isxdigit (*ep)) 577 ep++; 578 if (*ep == ']') { 579 h->host++; 580 *ep = '\0'; 581 pp = ep + 1; 582 } 583 } 584 #endif 585 586 cp = strchr(pp, ':'); 587 if (cp != NULL) { 588 *cp++ = '\0'; 589 h->port = htons(atoi(cp)); 590 } 591 } 592 593 594 FILE *open_socket(struct sockaddr_in *s_in) 561 *sp = '\0'; 562 h->host = sp + 1; 563 } 564 565 sp = h->host; 566 } 567 568 569 static FILE *open_socket(len_and_sockaddr *lsa) 595 570 { 596 571 FILE *fp; 597 572 598 fp = fdopen(xconnect(s_in), "r+"); 573 /* glibc 2.4 seems to try seeking on it - ??! */ 574 /* hopefully it understands what ESPIPE means... */ 575 fp = fdopen(xconnect_stream(lsa), "r+"); 599 576 if (fp == NULL) 600 bb_perror_msg_and_die("fdopen ()");577 bb_perror_msg_and_die("fdopen"); 601 578 602 579 return fp; … … 604 581 605 582 606 char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)583 static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc) 607 584 { 608 585 char *s, *hdrval; … … 616 593 617 594 /* see if we are at the end of the headers */ 618 for (s = buf ; *s == '\r'; ++s)595 for (s = buf; *s == '\r'; ++s) 619 596 ; 620 597 if (s[0] == '\n') … … 622 599 623 600 /* convert the header name to lower case */ 624 for (s = buf ; isalnum(*s) || *s == '-'; ++s)601 for (s = buf; isalnum(*s) || *s == '-'; ++s) 625 602 *s = tolower(*s); 626 603 … … 630 607 631 608 /* locate the start of the header value */ 632 for (*s++ = '\0' ; *s == ' ' || *s == '\t'; ++s)609 for (*s++ = '\0'; *s == ' ' || *s == '\t'; ++s) 633 610 ; 634 611 hdrval = s; … … 651 628 } 652 629 653 static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf) 654 { 630 static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) 631 { 632 int result; 655 633 if (s1) { 656 if (!s2) s2 ="";634 if (!s2) s2 = ""; 657 635 fprintf(fp, "%s%s\r\n", s1, s2); 658 636 fflush(fp); … … 663 641 664 642 if (fgets(buf, 510, fp) == NULL) { 665 bb_perror_msg_and_die(" fgets()");643 bb_perror_msg_and_die("error getting response"); 666 644 } 667 645 buf_ptr = strstr(buf, "\r\n"); … … 669 647 *buf_ptr = '\0'; 670 648 } 671 } while (! isdigit(buf[0]) || buf[3] != ' '); 672 673 return atoi(buf); 674 } 675 676 #ifdef CONFIG_FEATURE_WGET_STATUSBAR 649 } while (!isdigit(buf[0]) || buf[3] != ' '); 650 651 buf[3] = '\0'; 652 result = xatoi_u(buf); 653 buf[3] = ' '; 654 return result; 655 } 656 657 #if ENABLE_FEATURE_WGET_STATUSBAR 677 658 /* Stuff below is from BSD rcp util.c, as added to openshh. 678 659 * Original copyright notice is retained at the end of this file. 679 *680 660 */ 681 682 683 661 static int 684 662 getttywidth(void) 685 663 { 686 int width =0;664 int width; 687 665 get_terminal_width_height(0, &width, NULL); 688 return (width);666 return width; 689 667 } 690 668 … … 698 676 } 699 677 700 static void 701 alarmtimer(int wait) 678 static void alarmtimer(int iwait) 702 679 { 703 680 struct itimerval itv; 704 681 705 itv.it_value.tv_sec = wait;682 itv.it_value.tv_sec = iwait; 706 683 itv.it_value.tv_usec = 0; 707 684 itv.it_interval = itv.it_value; … … 709 686 } 710 687 711 712 688 static void 713 689 progressmeter(int flag) 714 690 { 715 static struct timeval lastupdate; 691 static unsigned lastupdate_sec; 692 static unsigned start_sec; 716 693 static off_t lastsize, totalsize; 717 694 718 struct timeval now, td, wait;719 695 off_t abbrevsize; 720 int elapsed, ratio, barlength, i; 721 char buf[256]; 722 723 if (flag == -1) { 724 (void) gettimeofday(&start, (struct timezone *) 0); 725 lastupdate = start; 696 unsigned since_last_update, elapsed; 697 unsigned ratio; 698 int barlength, i; 699 700 if (flag == -1) { /* first call to progressmeter */ 701 start_sec = monotonic_sec(); 702 lastupdate_sec = start_sec; 726 703 lastsize = 0; 727 totalsize = filesize; /* as filesize changes.. */ 728 } 729 730 (void) gettimeofday(&now, (struct timezone *) 0); 704 totalsize = content_len + beg_range; /* as content_len changes.. */ 705 } 706 731 707 ratio = 100; 732 708 if (totalsize != 0 && !chunked) { 733 ratio = (int) (100 * transferred / totalsize); 734 ratio = MIN(ratio, 100); 709 /* long long helps to have it working even if !LFS */ 710 ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize); 711 if (ratio > 100) ratio = 100; 735 712 } 736 713 737 714 fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio); 738 715 739 barlength = getttywidth() - 51; 740 if (barlength > 0 && barlength < sizeof(buf)) { 716 barlength = getttywidth() - 49; 717 if (barlength > 0) { 718 /* god bless gcc for variable arrays :) */ 741 719 i = barlength * ratio / 100; 742 memset(buf, '*', i); 743 memset(buf + i, ' ', barlength - i); 744 buf[barlength] = '\0'; 745 fprintf(stderr, "|%s|", buf); 720 { 721 char buf[i+1]; 722 memset(buf, '*', i); 723 buf[i] = '\0'; 724 fprintf(stderr, "|%s%*s|", buf, barlength - i, ""); 725 } 746 726 } 747 727 i = 0; 748 abbrevsize = transferred ;728 abbrevsize = transferred + beg_range; 749 729 while (abbrevsize >= 100000) { 750 730 i++; 751 731 abbrevsize >>= 10; 752 732 } 753 /* See http://en.wikipedia.org/wiki/Tera */ 754 fprintf(stderr, "%6d %c%c ", (int)abbrevsize, " KMGTPEZY"[i], i?'B':' '); 755 756 timersub(&now, &lastupdate, &wait); 733 /* see http://en.wikipedia.org/wiki/Tera */ 734 fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]); 735 736 // Nuts! Ain't it easier to update progress meter ONLY when we transferred++? 737 // FIXME: get rid of alarmtimer + updateprogressmeter mess 738 739 elapsed = monotonic_sec(); 740 since_last_update = elapsed - lastupdate_sec; 757 741 if (transferred > lastsize) { 758 lastupdate = now;742 lastupdate_sec = elapsed; 759 743 lastsize = transferred; 760 if (wait.tv_sec >= STALLTIME) 761 timeradd(&start, &wait, &start); 762 wait.tv_sec = 0; 763 } 764 timersub(&now, &start, &td); 765 elapsed = td.tv_sec; 766 767 if (wait.tv_sec >= STALLTIME) { 744 if (since_last_update >= STALLTIME) { 745 /* We "cut off" these seconds from elapsed time 746 * by adjusting start time */ 747 start_sec += since_last_update; 748 } 749 since_last_update = 0; /* we are un-stalled now */ 750 } 751 elapsed -= start_sec; /* now it's "elapsed since start" */ 752 753 if (since_last_update >= STALLTIME) { 768 754 fprintf(stderr, " - stalled -"); 769 } else if (transferred <= 0 || elapsed <= 0 || transferred > totalsize || chunked) {770 fprintf(stderr, "--:--:-- ETA");771 755 } else { 772 /* totalsize / (transferred/elapsed) - elapsed: */ 773 int eta = (int) (totalsize*elapsed/transferred - elapsed); 774 i = eta % 3600; 775 fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60); 776 } 777 778 if (flag == -1) { 756 off_t to_download = totalsize - beg_range; 757 if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) { 758 fprintf(stderr, "--:--:-- ETA"); 759 } else { 760 /* to_download / (transferred/elapsed) - elapsed: */ 761 int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed); 762 /* (long long helps to have working ETA even if !LFS) */ 763 i = eta % 3600; 764 fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60); 765 } 766 } 767 768 if (flag == -1) { /* first call to progressmeter */ 779 769 struct sigaction sa; 780 770 sa.sa_handler = updateprogressmeter; … … 783 773 sigaction(SIGALRM, &sa, NULL); 784 774 alarmtimer(1); 785 } else if (flag == 1) { 775 } else if (flag == 1) { /* last call to progressmeter */ 786 776 alarmtimer(0); 787 777 transferred = 0; … … 789 779 } 790 780 } 791 #endif 781 #endif /* FEATURE_WGET_STATUSBAR */ 792 782 793 783 /* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff, … … 826 816 * SUCH DAMAGE. 827 817 * 828 * $Id: wget.c,v 1.75 2004/10/08 08:27:40 andersen Exp $829 818 */ -
branches/2.2.5/mindi-busybox/networking/zcip.c
r902 r1765 1 /* vi: set sw=4 ts=4: */ 1 2 /* 2 3 * RFC3927 ZeroConf IPv4 Link-Local addressing … … 23 24 // - link status monitoring (restart on link-up; stop on link-down) 24 25 25 #include "busybox.h"26 #include <errno.h>27 #include <string.h>28 26 #include <syslog.h> 29 27 #include <poll.h> 30 #include <time.h>31 32 28 #include <sys/wait.h> 33 34 29 #include <netinet/ether.h> 35 30 #include <net/ethernet.h> 36 31 #include <net/if.h> 37 32 #include <net/if_arp.h> 38 39 33 #include <linux/if_packet.h> 40 34 #include <linux/sockios.h> 41 35 36 #include "libbb.h" 37 38 /* We don't need more than 32 bits of the counter */ 39 #define MONOTONIC_US() ((unsigned)monotonic_us()) 42 40 43 41 struct arp_packet { … … 72 70 }; 73 71 74 /* Implicitly zero-initialized */ 75 static const struct in_addr null_ip; 76 static const struct ether_addr null_addr; 77 static int verbose; 78 79 #define DBG(fmt,args...) \ 72 #define VDBG(fmt,args...) \ 80 73 do { } while (0) 81 #define VDBG DBG82 74 83 75 /** … … 87 79 static void pick(struct in_addr *ip) 88 80 { 89 unsigned tmp; 90 91 /* use cheaper math than lrand48() mod N */ 81 unsigned tmp; 82 92 83 do { 93 tmp = (lrand48() >> 16) & IN_CLASSB_HOST;84 tmp = rand() & IN_CLASSB_HOST; 94 85 } while (tmp > (IN_CLASSB_HOST - 0x0200)); 95 86 ip->s_addr = htonl((LINKLOCAL_ADDR + 0x0100) + tmp); … … 99 90 * Broadcast an ARP packet. 100 91 */ 101 static intarp(int fd, struct sockaddr *saddr, int op,92 static void arp(int fd, struct sockaddr *saddr, int op, 102 93 const struct ether_addr *source_addr, struct in_addr source_ip, 103 94 const struct ether_addr *target_addr, struct in_addr target_ip) … … 118 109 p.arp.arp_op = htons(op); 119 110 memcpy(&p.arp.arp_sha, source_addr, ETH_ALEN); 120 memcpy(&p.arp.arp_spa, &source_ip, sizeof 111 memcpy(&p.arp.arp_spa, &source_ip, sizeof(p.arp.arp_spa)); 121 112 memcpy(&p.arp.arp_tha, target_addr, ETH_ALEN); 122 memcpy(&p.arp.arp_tpa, &target_ip, sizeof 113 memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa)); 123 114 124 115 // send it 125 if (sendto(fd, &p, sizeof (p), 0, saddr, sizeof (*saddr)) < 0) { 126 perror("sendto"); 116 xsendto(fd, &p, sizeof(p), saddr, sizeof(*saddr)); 117 118 // Currently all callers ignore errors, that's why returns are 119 // commented out... 120 //return 0; 121 } 122 123 /** 124 * Run a script. argv[2] is already NULL. 125 */ 126 static int run(char *argv[3], const char *intf, struct in_addr *ip) 127 { 128 int status; 129 130 VDBG("%s run %s %s\n", intf, argv[0], argv[1]); 131 132 if (ip) { 133 char *addr = inet_ntoa(*ip); 134 setenv("ip", addr, 1); 135 bb_info_msg("%s %s %s", argv[1], intf, addr); 136 } 137 138 status = wait4pid(spawn(argv)); 139 if (status < 0) { 140 bb_perror_msg("%s %s", argv[1], intf); 127 141 return -errno; 128 142 } 129 return 0; 143 if (status != 0) 144 bb_error_msg("script %s %s failed, exitcode=%d", argv[0], argv[1], status); 145 return status; 130 146 } 131 147 132 148 /** 133 * R un a script.134 */ 135 static int run(char *script, char *arg, char *intf, struct in_addr *ip)149 * Return milliseconds of random delay, up to "secs" seconds. 150 */ 151 static unsigned ALWAYS_INLINE ms_rdelay(unsigned secs) 136 152 { 137 int pid, status; 138 char *why; 139 140 if (script != NULL) { 141 VDBG("%s run %s %s\n", intf, script, arg); 142 if (ip != NULL) { 143 char *addr = inet_ntoa(*ip); 144 setenv("ip", addr, 1); 145 syslog(LOG_INFO, "%s %s %s", arg, intf, addr); 146 } 147 148 pid = vfork(); 149 if (pid < 0) { // error 150 why = "vfork"; 151 goto bad; 152 } else if (pid == 0) { // child 153 execl(script, script, arg, NULL); 154 perror("execl"); 155 _exit(EXIT_FAILURE); 156 } 157 158 if (waitpid(pid, &status, 0) <= 0) { 159 why = "waitpid"; 160 goto bad; 161 } 162 if (WEXITSTATUS(status) != 0) { 163 bb_error_msg("script %s failed, exit=%d\n", 164 script, WEXITSTATUS(status)); 165 return -errno; 153 return rand() % (secs * 1000); 154 } 155 156 /** 157 * main program 158 */ 159 int zcip_main(int argc, char **argv); 160 int zcip_main(int argc, char **argv) 161 { 162 int state = PROBE; 163 struct ether_addr eth_addr; 164 const char *why; 165 int fd; 166 char *r_opt; 167 unsigned opts; 168 169 /* Ugly trick, but I want these zeroed in one go */ 170 struct { 171 const struct in_addr null_ip; 172 const struct ether_addr null_addr; 173 struct sockaddr saddr; 174 struct in_addr ip; 175 struct ifreq ifr; 176 char *intf; 177 char *script_av[3]; 178 int timeout_ms; /* must be signed */ 179 unsigned conflicts; 180 unsigned nprobes; 181 unsigned nclaims; 182 int ready; 183 int verbose; 184 } L; 185 #define null_ip (L.null_ip ) 186 #define null_addr (L.null_addr ) 187 #define saddr (L.saddr ) 188 #define ip (L.ip ) 189 #define ifr (L.ifr ) 190 #define intf (L.intf ) 191 #define script_av (L.script_av ) 192 #define timeout_ms (L.timeout_ms) 193 #define conflicts (L.conflicts ) 194 #define nprobes (L.nprobes ) 195 #define nclaims (L.nclaims ) 196 #define ready (L.ready ) 197 #define verbose (L.verbose ) 198 199 memset(&L, 0, sizeof(L)); 200 201 #define FOREGROUND (opts & 1) 202 #define QUIT (opts & 2) 203 // parse commandline: prog [options] ifname script 204 // exactly 2 args; -v accumulates and implies -f 205 opt_complementary = "=2:vv:vf"; 206 opts = getopt32(argv, "fqr:v", &r_opt, &verbose); 207 if (!FOREGROUND) { 208 /* Do it early, before all bb_xx_msg calls */ 209 openlog(applet_name, 0, LOG_DAEMON); 210 logmode |= LOGMODE_SYSLOG; 211 } 212 if (opts & 4) { // -r n.n.n.n 213 if (inet_aton(r_opt, &ip) == 0 214 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR 215 ) { 216 bb_error_msg_and_die("invalid link address"); 166 217 } 167 218 } 168 return 0; 169 bad: 170 status = -errno; 171 syslog(LOG_ERR, "%s %s, %s error: %s", 172 arg, intf, why, strerror(errno)); 173 return status; 174 } 175 176 177 /** 178 * Return milliseconds of random delay, up to "secs" seconds. 179 */ 180 static inline unsigned ms_rdelay(unsigned secs) 181 { 182 return lrand48() % (secs * 1000); 183 } 184 185 /** 186 * main program 187 */ 188 189 int zcip_main(int argc, char *argv[]) 190 { 191 char *intf = NULL; 192 char *script = NULL; 193 int quit = 0; 194 int foreground = 0; 195 196 char *why; 197 struct sockaddr saddr; 198 struct ether_addr addr; 199 struct in_addr ip = { 0 }; 200 int fd; 201 int ready = 0; 202 suseconds_t timeout = 0; // milliseconds 203 unsigned conflicts = 0; 204 unsigned nprobes = 0; 205 unsigned nclaims = 0; 206 int t; 207 int state = PROBE; 208 209 // parse commandline: prog [options] ifname script 210 while ((t = getopt(argc, argv, "fqr:v")) != EOF) { 211 switch (t) { 212 case 'f': 213 foreground = 1; 214 continue; 215 case 'q': 216 quit = 1; 217 continue; 218 case 'r': 219 if (inet_aton(optarg, &ip) == 0 220 || (ntohl(ip.s_addr) & IN_CLASSB_NET) 221 != LINKLOCAL_ADDR) { 222 bb_error_msg_and_die("invalid link address"); 223 } 224 continue; 225 case 'v': 226 verbose++; 227 foreground = 1; 228 continue; 229 default: 230 bb_error_msg_and_die("bad option"); 231 } 232 } 233 if (optind < argc - 1) { 234 intf = argv[optind++]; 235 setenv("interface", intf, 1); 236 script = argv[optind++]; 237 } 238 if (optind != argc || !intf) 239 bb_show_usage(); 240 openlog(bb_applet_name, 0, LOG_DAEMON); 219 // On NOMMU reexec early (or else we will rerun things twice) 220 #if !BB_MMU 221 if (!FOREGROUND) 222 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); 223 #endif 224 argc -= optind; 225 argv += optind; 226 227 intf = argv[0]; 228 script_av[0] = argv[1]; 229 setenv("interface", intf, 1); 241 230 242 231 // initialize the interface (modprobe, ifup, etc) 243 if (run(script, "init", intf, NULL) < 0) 232 script_av[1] = (char*)"init"; 233 if (run(script_av, intf, NULL)) 244 234 return EXIT_FAILURE; 245 235 246 236 // initialize saddr 247 memset(&saddr, 0, sizeof(saddr));248 safe_strncpy(saddr.sa_data, intf, sizeof 237 //memset(&saddr, 0, sizeof(saddr)); 238 safe_strncpy(saddr.sa_data, intf, sizeof(saddr.sa_data)); 249 239 250 240 // open an ARP socket 251 if ((fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) < 0) { 252 why = "open"; 253 fail: 254 foreground = 1; 255 goto bad; 256 } 241 fd = xsocket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); 257 242 // bind to the interface's ARP socket 258 if (bind(fd, &saddr, sizeof (saddr)) < 0) { 259 why = "bind"; 260 goto fail; 261 } else { 262 struct ifreq ifr; 263 unsigned short seed[3]; 264 265 // get the interface's ethernet address 266 memset(&ifr, 0, sizeof (ifr)); 267 strncpy(ifr.ifr_name, intf, sizeof (ifr.ifr_name)); 268 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { 269 why = "get ethernet address"; 270 goto fail; 271 } 272 memcpy(&addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 273 274 // start with some stable ip address, either a function of 275 // the hardware address or else the last address we used. 276 // NOTE: the sequence of addresses we try changes only 277 // depending on when we detect conflicts. 278 memcpy(seed, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 279 seed48(seed); 280 if (ip.s_addr == 0) 281 pick(&ip); 282 } 243 xbind(fd, &saddr, sizeof(saddr)); 244 245 // get the interface's ethernet address 246 //memset(&ifr, 0, sizeof(ifr)); 247 strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name)); 248 xioctl(fd, SIOCGIFHWADDR, &ifr); 249 memcpy(ð_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 250 251 // start with some stable ip address, either a function of 252 // the hardware address or else the last address we used. 253 // NOTE: the sequence of addresses we try changes only 254 // depending on when we detect conflicts. 255 srand(*(unsigned*)&ifr.ifr_hwaddr.sa_data); 256 if (ip.s_addr == 0) 257 pick(&ip); 283 258 284 259 // FIXME cases to handle: … … 287 262 288 263 // daemonize now; don't delay system startup 289 if (!foreground) { 290 if (daemon(0, verbose) < 0) { 291 why = "daemon"; 292 goto bad; 293 } 294 syslog(LOG_INFO, "start, interface %s", intf); 264 if (!FOREGROUND) { 265 #if BB_MMU 266 bb_daemonize(DAEMON_CHDIR_ROOT); 267 #endif 268 bb_info_msg("start, interface %s", intf); 295 269 } 296 270 … … 305 279 while (1) { 306 280 struct pollfd fds[1]; 307 struct timeval tv1;281 unsigned deadline_us; 308 282 struct arp_packet p; 283 284 int source_ip_conflict = 0; 285 int target_ip_conflict = 0; 309 286 310 287 fds[0].fd = fd; … … 312 289 fds[0].revents = 0; 313 290 314 int source_ip_conflict = 0;315 int target_ip_conflict = 0;316 317 291 // poll, being ready to adjust current timeout 318 if (!timeout ) {319 timeout = ms_rdelay(PROBE_WAIT);292 if (!timeout_ms) { 293 timeout_ms = ms_rdelay(PROBE_WAIT); 320 294 // FIXME setsockopt(fd, SO_ATTACH_FILTER, ...) to 321 295 // make the kernel filter out all packets except 322 296 // ones we'd care about. 323 297 } 324 // set tv1 to the point in time when we timeout 325 gettimeofday(&tv1, NULL); 326 tv1.tv_usec += (timeout % 1000) * 1000; 327 while (tv1.tv_usec > 1000000) { 328 tv1.tv_usec -= 1000000; 329 tv1.tv_sec++; 330 } 331 tv1.tv_sec += timeout / 1000; 332 333 VDBG("...wait %ld %s nprobes=%d, nclaims=%d\n", 334 timeout, intf, nprobes, nclaims); 335 switch (poll(fds, 1, timeout)) { 298 // set deadline_us to the point in time when we timeout 299 deadline_us = MONOTONIC_US() + timeout_ms * 1000; 300 301 VDBG("...wait %d %s nprobes=%u, nclaims=%u\n", 302 timeout_ms, intf, nprobes, nclaims); 303 switch (poll(fds, 1, timeout_ms)) { 336 304 337 305 // timeout … … 340 308 switch (state) { 341 309 case PROBE: 342 // timeouts in the PROBE state mean sno conflicting ARP packets310 // timeouts in the PROBE state mean no conflicting ARP packets 343 311 // have been received, so we can progress through the states 344 312 if (nprobes < PROBE_NUM) { 345 313 nprobes++; 346 VDBG("probe/% d%s@%s\n",314 VDBG("probe/%u %s@%s\n", 347 315 nprobes, intf, inet_ntoa(ip)); 348 (void)arp(fd, &saddr, ARPOP_REQUEST,349 & addr, null_ip,316 arp(fd, &saddr, ARPOP_REQUEST, 317 ð_addr, null_ip, 350 318 &null_addr, ip); 351 timeout = PROBE_MIN * 1000; 352 timeout += ms_rdelay(PROBE_MAX 353 - PROBE_MIN); 319 timeout_ms = PROBE_MIN * 1000; 320 timeout_ms += ms_rdelay(PROBE_MAX - PROBE_MIN); 354 321 } 355 322 else { … … 357 324 state = ANNOUNCE; 358 325 nclaims = 0; 359 VDBG("announce/% d%s@%s\n",326 VDBG("announce/%u %s@%s\n", 360 327 nclaims, intf, inet_ntoa(ip)); 361 (void)arp(fd, &saddr, ARPOP_REQUEST,362 & addr, ip,363 & addr, ip);364 timeout = ANNOUNCE_INTERVAL * 1000;328 arp(fd, &saddr, ARPOP_REQUEST, 329 ð_addr, ip, 330 ð_addr, ip); 331 timeout_ms = ANNOUNCE_INTERVAL * 1000; 365 332 } 366 333 break; 367 334 case RATE_LIMIT_PROBE: 368 // timeouts in the RATE_LIMIT_PROBE state mean sno conflicting ARP packets335 // timeouts in the RATE_LIMIT_PROBE state mean no conflicting ARP packets 369 336 // have been received, so we can move immediately to the announce state 370 337 state = ANNOUNCE; 371 338 nclaims = 0; 372 VDBG("announce/% d%s@%s\n",339 VDBG("announce/%u %s@%s\n", 373 340 nclaims, intf, inet_ntoa(ip)); 374 (void)arp(fd, &saddr, ARPOP_REQUEST,375 & addr, ip,376 & addr, ip);377 timeout = ANNOUNCE_INTERVAL * 1000;341 arp(fd, &saddr, ARPOP_REQUEST, 342 ð_addr, ip, 343 ð_addr, ip); 344 timeout_ms = ANNOUNCE_INTERVAL * 1000; 378 345 break; 379 346 case ANNOUNCE: 380 // timeouts in the ANNOUNCE state mean sno conflicting ARP packets347 // timeouts in the ANNOUNCE state mean no conflicting ARP packets 381 348 // have been received, so we can progress through the states 382 349 if (nclaims < ANNOUNCE_NUM) { 383 350 nclaims++; 384 VDBG("announce/% d%s@%s\n",351 VDBG("announce/%u %s@%s\n", 385 352 nclaims, intf, inet_ntoa(ip)); 386 (void)arp(fd, &saddr, ARPOP_REQUEST,387 & addr, ip,388 & addr, ip);389 timeout = ANNOUNCE_INTERVAL * 1000;353 arp(fd, &saddr, ARPOP_REQUEST, 354 ð_addr, ip, 355 ð_addr, ip); 356 timeout_ms = ANNOUNCE_INTERVAL * 1000; 390 357 } 391 358 else { … … 394 361 // link is ok to use earlier 395 362 // FIXME update filters 396 run(script, "config", intf, &ip); 363 script_av[1] = (char*)"config"; 364 run(script_av, intf, &ip); 397 365 ready = 1; 398 366 conflicts = 0; 399 timeout = -1; // Never timeout in the monitor state.400 401 // NOTE: 367 timeout_ms = -1; // Never timeout in the monitor state. 368 369 // NOTE: all other exit paths 402 370 // should deconfig ... 403 if ( quit)371 if (QUIT) 404 372 return EXIT_SUCCESS; 405 373 } … … 408 376 // We won! No ARP replies, so just go back to monitor. 409 377 state = MONITOR; 410 timeout = -1;378 timeout_ms = -1; 411 379 conflicts = 0; 412 380 break; … … 415 383 state = PROBE; 416 384 pick(&ip); 417 timeout = 0;385 timeout_ms = 0; 418 386 nprobes = 0; 419 387 nclaims = 0; … … 425 393 // We need to adjust the timeout in case we didn't receive 426 394 // a conflicting packet. 427 if (timeout > 0) { 428 struct timeval tv2; 429 430 gettimeofday(&tv2, NULL); 431 if (timercmp(&tv1, &tv2, <)) { 395 if (timeout_ms > 0) { 396 unsigned diff = deadline_us - MONOTONIC_US(); 397 if ((int)(diff) < 0) { 432 398 // Current time is greater than the expected timeout time. 433 399 // Should never happen. 434 400 VDBG("missed an expected timeout\n"); 435 timeout = 0;401 timeout_ms = 0; 436 402 } else { 437 403 VDBG("adjusting timeout\n"); 438 timersub(&tv1, &tv2, &tv1); 439 timeout = 1000 * tv1.tv_sec 440 + tv1.tv_usec / 1000; 404 timeout_ms = diff / 1000; 405 if (!timeout_ms) timeout_ms = 1; 441 406 } 442 407 } … … 446 411 // FIXME: links routinely go down; 447 412 // this shouldn't necessarily exit. 448 bb_error_msg("%s: poll error \n", intf);413 bb_error_msg("%s: poll error", intf); 449 414 if (ready) { 450 run(script, "deconfig",451 415 script_av[1] = (char*)"deconfig"; 416 run(script_av, intf, &ip); 452 417 } 453 418 return EXIT_FAILURE; … … 457 422 458 423 // read ARP packet 459 if (recv(fd, &p, sizeof 424 if (recv(fd, &p, sizeof(p), 0) < 0) { 460 425 why = "recv"; 461 426 goto bad; … … 486 451 487 452 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 488 memcmp(& addr, &p.arp.arp_sha, ETH_ALEN) != 0) {453 memcmp(ð_addr, &p.arp.arp_sha, ETH_ALEN) != 0) { 489 454 source_ip_conflict = 1; 490 455 } 491 456 if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 492 457 p.arp.arp_op == htons(ARPOP_REQUEST) && 493 memcmp(& addr, &p.arp.arp_tha, ETH_ALEN) != 0) {458 memcmp(ð_addr, &p.arp.arp_tha, ETH_ALEN) != 0) { 494 459 target_ip_conflict = 1; 495 460 } 496 461 497 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", 462 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", 498 463 state, source_ip_conflict, target_ip_conflict); 499 464 switch (state) { … … 506 471 if (conflicts >= MAX_CONFLICTS) { 507 472 VDBG("%s ratelimit\n", intf); 508 timeout = RATE_LIMIT_INTERVAL * 1000;473 timeout_ms = RATE_LIMIT_INTERVAL * 1000; 509 474 state = RATE_LIMIT_PROBE; 510 475 } … … 512 477 // restart the whole protocol 513 478 pick(&ip); 514 timeout = 0;479 timeout_ms = 0; 515 480 nprobes = 0; 516 481 nclaims = 0; … … 522 487 VDBG("monitor conflict -- defending\n"); 523 488 state = DEFEND; 524 timeout = DEFEND_INTERVAL * 1000;525 (void)arp(fd, &saddr,489 timeout_ms = DEFEND_INTERVAL * 1000; 490 arp(fd, &saddr, 526 491 ARPOP_REQUEST, 527 & addr, ip,528 & addr, ip);492 ð_addr, ip, 493 ð_addr, ip); 529 494 } 530 495 break; … … 535 500 VDBG("defend conflict -- starting over\n"); 536 501 ready = 0; 537 run(script, "deconfig", intf, &ip); 502 script_av[1] = (char*)"deconfig"; 503 run(script_av, intf, &ip); 538 504 539 505 // restart the whole protocol 540 506 pick(&ip); 541 timeout = 0;507 timeout_ms = 0; 542 508 nprobes = 0; 543 509 nclaims = 0; … … 549 515 state = PROBE; 550 516 pick(&ip); 551 timeout = 0;517 timeout_ms = 0; 552 518 nprobes = 0; 553 519 nclaims = 0; … … 561 527 } // switch poll 562 528 } 563 bad: 564 if (foreground) 565 perror(why); 566 else 567 syslog(LOG_ERR, "%s %s, %s error: %s", 568 bb_applet_name, intf, why, strerror(errno)); 529 bad: 530 bb_perror_msg("%s, %s", intf, why); 569 531 return EXIT_FAILURE; 570 532 }
Note:
See TracChangeset
for help on using the changeset viewer.