diff options
author | Ron Yorston <rmy@pobox.com> | 2016-10-19 17:07:41 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-10-19 17:07:41 +0100 |
commit | 03aa1e26b8885cd0ae28b676bed0e646e93433fb (patch) | |
tree | 6ea4dd81cc9fb84c7da3a42731363144ee7ff0c3 | |
parent | 2e04fb569646e1882496f7175a1f5da6f33e36e1 (diff) | |
parent | 6bbb48fadf2265c7ed806027781da8039e561865 (diff) | |
download | busybox-w32-03aa1e26b8885cd0ae28b676bed0e646e93433fb.tar.gz busybox-w32-03aa1e26b8885cd0ae28b676bed0e646e93433fb.tar.bz2 busybox-w32-03aa1e26b8885cd0ae28b676bed0e646e93433fb.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | archival/libarchive/init_handle.c | 4 | ||||
-rw-r--r-- | examples/var_service/README | 218 | ||||
-rw-r--r-- | networking/ifupdown.c | 43 | ||||
-rw-r--r-- | networking/tcpudp.c | 69 | ||||
-rw-r--r-- | networking/telnet.c | 7 | ||||
-rw-r--r-- | networking/telnetd.IAC_test.sh | 87 | ||||
-rw-r--r-- | networking/telnetd.c | 289 | ||||
-rw-r--r-- | util-linux/more.c | 11 |
8 files changed, 564 insertions, 164 deletions
diff --git a/archival/libarchive/init_handle.c b/archival/libarchive/init_handle.c index cbae06ac3..dcba6666f 100644 --- a/archival/libarchive/init_handle.c +++ b/archival/libarchive/init_handle.c | |||
@@ -17,6 +17,10 @@ archive_handle_t* FAST_FUNC init_handle(void) | |||
17 | archive_handle->action_data = data_skip; | 17 | archive_handle->action_data = data_skip; |
18 | archive_handle->filter = filter_accept_all; | 18 | archive_handle->filter = filter_accept_all; |
19 | archive_handle->seek = seek_by_jump; | 19 | archive_handle->seek = seek_by_jump; |
20 | #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM | ||
21 | archive_handle->cpio__owner.uid = (uid_t)-1L; | ||
22 | archive_handle->cpio__owner.gid = (gid_t)-1L; | ||
23 | #endif | ||
20 | 24 | ||
21 | return archive_handle; | 25 | return archive_handle; |
22 | } | 26 | } |
diff --git a/examples/var_service/README b/examples/var_service/README index d096ad0b9..938cce91d 100644 --- a/examples/var_service/README +++ b/examples/var_service/README | |||
@@ -1,54 +1,158 @@ | |||
1 | In many cases, network configuration makes it necessary to run several daemons: | 1 | Daemontools and runit |
2 | dhcp, zeroconf, ppp, openvpn and such. They need to be controlled, | 2 | |
3 | and in many cases you also want to babysit them. runsvdir is a good tool for this. | 3 | Tired of PID files, needing root access, and writing init scripts just |
4 | examples/var_service directory provides a few examples. It is meant to be used | 4 | to have your UNIX apps start when your server boots? Want a simpler, |
5 | this way: copy it somewhere (say, /var/service) and run something like | 5 | better alternative that will also restart them if they crash? If so, |
6 | this is an introduction to process supervision with runit/daemontools. | ||
7 | |||
8 | |||
9 | Background | ||
10 | |||
11 | Classic init scripts, e.g. /etc/init.d/apache, are widely used for | ||
12 | starting processes at system boot time, when they are executed by init. | ||
13 | Sadly, init scripts are cumbersome and error-prone to write, they must | ||
14 | typically be edited and run as root, and the processes they launch do | ||
15 | not get restarted automatically if they crash. | ||
16 | |||
17 | In an alternative scheme called "process supervision", each important | ||
18 | process is looked after by a tiny supervising process, which deals with | ||
19 | starting and stopping the important process on request, and re-starting | ||
20 | it when it exits unexpectedly. Those supervising processes can in turn | ||
21 | be supervised by other supervising processes. | ||
22 | |||
23 | Dan Bernstein wrote the process supervision toolkit, "daemontools", | ||
24 | which is a set of small, reliable programs that cooperate in the | ||
25 | UNIX tradition to manage process supervision trees. | ||
26 | |||
27 | Runit is a more conveniently licensed and more actively maintained | ||
28 | reimplementation of daemontools, written by Gerrit Pape. | ||
29 | |||
30 | Here I’ll use runit, however, the ideas are the same for other | ||
31 | daemontools-like projects (there are several). | ||
32 | |||
33 | |||
34 | Service directories and scripts | ||
35 | |||
36 | In runit parlance a "service" is simply a directory containing a script | ||
37 | named "run". | ||
6 | 38 | ||
7 | env - PATH=... <other vars=...> runsvdir /var/service & | 39 | There are just two key programs in runit. Firstly, runsv supervises the |
40 | process for an individual service. Service directories themselves sit | ||
41 | inside a containing directory, and the runsvdir program supervises that | ||
42 | directory, running one child runsv process for the service in each | ||
43 | subdirectory. A typical choice is to start an instance of runsvdir | ||
44 | which supervises services in subdirectories of /var/service/. | ||
8 | 45 | ||
9 | from one of system startup scripts. (Google "man runsvdir" and "man runsv" | 46 | If /var/service/log/ exists, runsv will supervise two services, |
10 | for more info about these tools). | 47 | and will connect stdout of main service to the stdin of log service. |
48 | This is primarily used for logging. | ||
11 | 49 | ||
12 | You can try or debug an individual service by running its SERVICE_DIR/run script. | 50 | You can debug an individual service by running its SERVICE_DIR/run script. |
13 | In this case, its stdout and stderr go to your terminal. | 51 | In this case, its stdout and stderr go to your terminal. |
14 | 52 | ||
15 | You can also run "runsv SERVICE_DIR", which runs both the service | 53 | You can also run "runsv SERVICE_DIR", which runs both the service |
16 | and its logger service (SERVICE_DIR/log/run) if logger service exists. | 54 | and its logger service (SERVICE_DIR/log/run) if logger service exists. |
17 | If logger service exists, the output will go to it instead of the terminal. | 55 | If logger service exists, the output will go to it instead of the terminal. |
18 | 56 | ||
19 | "runsvdir DIR" merely runs "runsv SERVICE_DIR" for every subdirectory in DIR. | 57 | "runsvdir /var/service" merely runs "runsv SERVICE_DIR" for every subdirectory |
58 | in /var/service. | ||
59 | |||
60 | |||
61 | Examples | ||
62 | |||
63 | This directory contains some examples of services: | ||
64 | |||
65 | var_service/getty_<tty> | ||
66 | |||
67 | Runs a getty on <tty>. (run script looks at $PWD and extracts suffix | ||
68 | after "_" as tty name). Create copies (or symlinks) of this directory | ||
69 | with different names to run many gettys on many ttys. | ||
70 | |||
71 | var_service/gpm | ||
72 | |||
73 | Runs gpm, the cut and paste utility and mouse server for text consoles. | ||
74 | |||
75 | var_service/inetd | ||
76 | |||
77 | Runs inetd. This is an example of a service with log. Log service | ||
78 | writes timestamped, rotated log data to /var/log/service/inetd/* | ||
79 | using "svlogd -tt". p_log and w_log scripts demonstrage how you can | ||
80 | "page log" and "watch log". | ||
81 | |||
82 | Other services which have logs handle them in the same way. | ||
83 | |||
84 | var_service/nmeter | ||
85 | |||
86 | Runs nmeter '%t %c ....' with output to /dev/tty9. This gives you | ||
87 | a 1-second sampling of server load and health on a dedicated text console. | ||
88 | |||
20 | 89 | ||
21 | Some existing examples: | 90 | Networking examples |
91 | |||
92 | In many cases, network configuration makes it necessary to run several daemons: | ||
93 | dhcp, zeroconf, ppp, openvpn and such. They need to be controlled, | ||
94 | and in many cases you also want to babysit them. | ||
95 | |||
96 | They present a case where different services need to control (start, stop, | ||
97 | restart) each other. | ||
98 | |||
99 | var_service/dhcp_if | ||
22 | 100 | ||
23 | var_service/dhcp_if - | ||
24 | controls a udhcpc instance which provides dhpc-assigned IP | 101 | controls a udhcpc instance which provides dhpc-assigned IP |
25 | address on interface named "if". Copy/rename this directory as needed to run | 102 | address on interface named "if". Copy/rename this directory as needed to run |
26 | udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix | 103 | udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix |
27 | of the parent directory as interface name). When IP address is obtained or lost, | 104 | of the parent directory as interface name). |
28 | var_service/dhcp_if/dhcp_handler is run. It saves new config data to | 105 | |
29 | /var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service. | 106 | When IP address is obtained or lost, var_service/dhcp_if/dhcp_handler is run. |
30 | This example can be used as a template for other dynamic network link services | 107 | It saves new config data to /var/run/service/fw/dhcp_if.ipconf and (re)starts |
31 | (ppp/vpn/zcip). | 108 | /var/service/fw service. This example can be used as a template for other |
32 | 109 | dynamic network link services (ppp/vpn/zcip). | |
33 | var_service/ifplugd_if - | 110 | |
34 | watches link status of interface if. Downs and ups /var/service/dhcp_if | 111 | This is an example of service with has a "finish" script. If downed ("sv d"), |
112 | "finish" is executed. For this service, it removes DHCP address from | ||
113 | the interface. This is useful when ifplugd detects that the the link is dead | ||
114 | (cable is no longer attached anywhere) and downs us - keeping DHCP configured | ||
115 | addresses on the interface would make kernel still try to use it. | ||
116 | |||
117 | var_service/zcip_if | ||
118 | |||
119 | Zeroconf IP service: assigns a 169.254.x.y/16 address to interface "if". | ||
120 | This allows to talk to other devices on a network without DHCP server | ||
121 | (if they also assign 169.254 addresses to themselves). | ||
122 | |||
123 | var_service/ifplugd_if | ||
124 | |||
125 | Watches link status of interface "if". Downs and ups /var/service/dhcp_if | ||
35 | service accordingly. In effect, it allows you to unplug/plug-to-different-network | 126 | service accordingly. In effect, it allows you to unplug/plug-to-different-network |
36 | and have your IP properly re-negotiated at once. | 127 | and have your IP properly re-negotiated at once. |
37 | 128 | ||
38 | var_service/dhcp_if_pinger - | 129 | var_service/dhcp_if_pinger |
130 | |||
39 | Uses var_service/dhcp_if's data to determine router IP. Pings it. | 131 | Uses var_service/dhcp_if's data to determine router IP. Pings it. |
40 | If ping fails, restarts /var/service/dhcp_if service. | 132 | If ping fails, restarts /var/service/dhcp_if service. |
41 | Basically, an example of watchdog service for networks which are not reliable | 133 | Basically, an example of watchdog service for networks which are not reliable |
42 | and need babysitting. | 134 | and need babysitting. |
43 | 135 | ||
44 | var_service/fw - | 136 | var_service/supplicant_if |
45 | A *one-shot* service which reconfigures network based on current known state | 137 | |
46 | of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf | 138 | Wireless supplicant (wifi association and encryption daemon) service for |
139 | interface "if". | ||
140 | |||
141 | var_service/fw | ||
142 | |||
143 | "Firewall" script, although it is tasked with much more than setting up firewall. | ||
144 | It is responsible for all aspects of network configuration. | ||
145 | |||
146 | This is an example of *one-shot* service. | ||
147 | |||
148 | It reconfigures network based on current known state of ALL interfaces. | ||
149 | Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf | ||
47 | (dynamic config from dhcp/ppp/vpn/etc) to determine what to do. | 150 | (dynamic config from dhcp/ppp/vpn/etc) to determine what to do. |
151 | |||
48 | One-shot-ness of this service means that it shuts itself off after single run. | 152 | One-shot-ness of this service means that it shuts itself off after single run. |
49 | IOW: it is not a constantly running daemon sort of thing. | 153 | IOW: it is not a constantly running daemon sort of thing. |
50 | It starts, it configures the network, it shuts down, all done | 154 | It starts, it configures the network, it shuts down, all done |
51 | (unlike infamous NetworkManagers which sit in RAM forever, doing hell knows what). | 155 | (unlike infamous NetworkManagers which sit in RAM forever). |
52 | 156 | ||
53 | However, any dhcp/ppp/vpn or similar service can restart it anytime | 157 | However, any dhcp/ppp/vpn or similar service can restart it anytime |
54 | when it senses the change in network configuration. | 158 | when it senses the change in network configuration. |
@@ -59,10 +163,74 @@ This is achieved very simply by having | |||
59 | # Make ourself one-shot | 163 | # Make ourself one-shot |
60 | sv o . | 164 | sv o . |
61 | at the very beginning of fw/run script, not at the end. | 165 | at the very beginning of fw/run script, not at the end. |
166 | |||
62 | Therefore, any "sv u /var/run/service/fw" command by any other | 167 | Therefore, any "sv u /var/run/service/fw" command by any other |
63 | script "undoes" o(ne-shot) command if fw still runs, thus | 168 | script "undoes" o(ne-shot) command if fw still runs, thus |
64 | runsv will rerun it; or start it in a normal way if fw is not running. | 169 | runsv will rerun it; or start it in a normal way if fw is not running. |
65 | 170 | ||
171 | This mechanism is the reason why fw is a service, not just a script. | ||
172 | |||
66 | System administrators are expected to edit fw/run script, since | 173 | System administrators are expected to edit fw/run script, since |
67 | network configuration needs are likely to be very complex and different | 174 | network configuration needs are likely to be very complex and different |
68 | for non-trivial installations. | 175 | for non-trivial installations. |
176 | |||
177 | var_service/ftpd | ||
178 | var_service/httpd | ||
179 | var_service/tftpd | ||
180 | var_service/ntpd | ||
181 | |||
182 | Examples of typical network daemons. | ||
183 | |||
184 | |||
185 | Process tree | ||
186 | |||
187 | Here is an example of the process tree from a live system with these services | ||
188 | (and a few others). An interesting detail are ftpd and vpnc services, where | ||
189 | you can see only logger process. These services are "downed" at the moment: | ||
190 | their daemons are not launched. | ||
191 | |||
192 | PID TIME COMMAND | ||
193 | 553 0:04 runsvdir -P /var/service | ||
194 | 561 0:00 runsv sshd | ||
195 | 576 0:00 svlogd -tt /var/log/service/sshd | ||
196 | 589 0:00 /usr/sbin/sshd -D -e -p22 -u0 -h /var/service/sshd/ssh_host_rsa_key | ||
197 | 562 0:00 runsv dhcp_eth0 | ||
198 | 568 0:00 svlogd -tt /var/log/service/dhcp_eth0 | ||
199 | 850 0:00 udhcpc -vv --foreground --interface=eth0 | ||
200 | --pidfile=/var/service/dhcp_eth0/udhcpc.pid | ||
201 | --script=/var/service/dhcp_eth0/dhcp_handler -x hostname bbox | ||
202 | 563 0:00 runsv ntpd | ||
203 | 573 0:01 svlogd -tt /var/log/service/ntpd | ||
204 | 845 0:00 busybox ntpd -dddnNl -S ./ntp.script -p 10.x.x.x -p 10.x.x.x | ||
205 | 564 0:00 runsv ifplugd_wlan0 | ||
206 | 598 0:00 svlogd -tt /var/log/service/ifplugd_wlan0 | ||
207 | 614 0:05 ifplugd -apqns -t3 -u0 -d0 -i wlan0 | ||
208 | -r /var/service/ifplugd_wlan0/ifplugd_handler | ||
209 | 565 0:08 runsv dhcp_wlan0_pinger | ||
210 | 911 0:00 sleep 67 | ||
211 | 566 0:00 runsv unscd | ||
212 | 583 0:03 svlogd -tt /var/log/service/unscd | ||
213 | 599 0:02 nscd -dddd | ||
214 | 567 0:00 runsv dhcp_wlan0 | ||
215 | 591 0:00 svlogd -tt /var/log/service/dhcp_wlan0 | ||
216 | 802 0:00 udhcpc -vv -C -o -V --foreground --interface=wlan0 | ||
217 | --pidfile=/var/service/dhcp_wlan0/udhcpc.pid | ||
218 | --script=/var/service/dhcp_wlan0/dhcp_handler | ||
219 | 569 0:00 runsv fw | ||
220 | 570 0:00 runsv ifplugd_eth0 | ||
221 | 597 0:00 svlogd -tt /var/log/service/ifplugd_eth0 | ||
222 | 612 0:05 ifplugd -apqns -t3 -u8 -d8 -i eth0 | ||
223 | -r /var/service/ifplugd_eth0/ifplugd_handler | ||
224 | 571 0:00 runsv zcip_eth0 | ||
225 | 590 0:00 svlogd -tt /var/log/service/zcip_eth0 | ||
226 | 607 0:01 zcip -fvv eth0 /var/service/zcip_eth0/zcip_handler | ||
227 | 572 0:00 runsv ftpd | ||
228 | 604 0:00 svlogd -tt /var/log/service/ftpd | ||
229 | 574 0:00 runsv vpnc | ||
230 | 603 0:00 svlogd -tt /var/log/service/vpnc | ||
231 | 575 0:00 runsv httpd | ||
232 | 602 0:00 svlogd -tt /var/log/service/httpd | ||
233 | 622 0:00 busybox httpd -p80 -vvv -f -h /home/httpd_root | ||
234 | 577 0:00 runsv supplicant_wlan0 | ||
235 | 627 0:00 svlogd -tt /var/log/service/supplicant_wlan0 | ||
236 | 638 0:03 wpa_supplicant -i wlan0 -c /var/service/supplicant_wlan0/wpa_supplicant.conf -d | ||
diff --git a/networking/ifupdown.c b/networking/ifupdown.c index b0bc0d70f..1d0fc53cf 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | #define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS | 58 | #define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS |
59 | #define IFSTATE_FILE_PATH CONFIG_IFUPDOWN_IFSTATE_PATH | ||
59 | 60 | ||
60 | #define debug_noise(args...) /*fprintf(stderr, args)*/ | 61 | #define debug_noise(args...) /*fprintf(stderr, args)*/ |
61 | 62 | ||
@@ -1200,7 +1201,7 @@ static llist_t *find_iface_state(llist_t *state_list, const char *iface) | |||
1200 | static llist_t *read_iface_state(void) | 1201 | static llist_t *read_iface_state(void) |
1201 | { | 1202 | { |
1202 | llist_t *state_list = NULL; | 1203 | llist_t *state_list = NULL; |
1203 | FILE *state_fp = fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH); | 1204 | FILE *state_fp = fopen_for_read(IFSTATE_FILE_PATH); |
1204 | 1205 | ||
1205 | if (state_fp) { | 1206 | if (state_fp) { |
1206 | char *start, *end_ptr; | 1207 | char *start, *end_ptr; |
@@ -1215,6 +1216,38 @@ static llist_t *read_iface_state(void) | |||
1215 | return state_list; | 1216 | return state_list; |
1216 | } | 1217 | } |
1217 | 1218 | ||
1219 | /* read the previous state from the state file */ | ||
1220 | static FILE *open_new_state_file(void) | ||
1221 | { | ||
1222 | int fd, flags, cnt; | ||
1223 | |||
1224 | cnt = 0; | ||
1225 | flags = (O_WRONLY | O_CREAT | O_EXCL); | ||
1226 | for (;;) { | ||
1227 | fd = open(IFSTATE_FILE_PATH".new", flags, 0666); | ||
1228 | if (fd >= 0) | ||
1229 | break; | ||
1230 | if (errno != EEXIST | ||
1231 | || flags == (O_WRONLY | O_CREAT | O_TRUNC) | ||
1232 | ) { | ||
1233 | bb_perror_msg_and_die("can't open '%s'", | ||
1234 | IFSTATE_FILE_PATH".new"); | ||
1235 | } | ||
1236 | /* Someone else created the .new file */ | ||
1237 | if (cnt > 30 * 1000) { | ||
1238 | /* Waited for 30*30/2 = 450 milliseconds, still EEXIST. | ||
1239 | * Assuming a stale file, rewriting it. | ||
1240 | */ | ||
1241 | flags = (O_WRONLY | O_CREAT | O_TRUNC); | ||
1242 | continue; | ||
1243 | } | ||
1244 | usleep(cnt); | ||
1245 | cnt += 1000; | ||
1246 | } | ||
1247 | |||
1248 | return xfdopen_for_write(fd); | ||
1249 | } | ||
1250 | |||
1218 | 1251 | ||
1219 | int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1252 | int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1220 | int ifupdown_main(int argc UNUSED_PARAM, char **argv) | 1253 | int ifupdown_main(int argc UNUSED_PARAM, char **argv) |
@@ -1348,7 +1381,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) | |||
1348 | any_failures = 1; | 1381 | any_failures = 1; |
1349 | } else if (!NO_ACT) { | 1382 | } else if (!NO_ACT) { |
1350 | /* update the state file */ | 1383 | /* update the state file */ |
1351 | FILE *state_fp; | 1384 | FILE *new_state_fp = open_new_state_file(); |
1352 | llist_t *state; | 1385 | llist_t *state; |
1353 | llist_t *state_list = read_iface_state(); | 1386 | llist_t *state_list = read_iface_state(); |
1354 | llist_t *iface_state = find_iface_state(state_list, iface); | 1387 | llist_t *iface_state = find_iface_state(state_list, iface); |
@@ -1368,15 +1401,15 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) | |||
1368 | } | 1401 | } |
1369 | 1402 | ||
1370 | /* Actually write the new state */ | 1403 | /* Actually write the new state */ |
1371 | state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH); | ||
1372 | state = state_list; | 1404 | state = state_list; |
1373 | while (state) { | 1405 | while (state) { |
1374 | if (state->data) { | 1406 | if (state->data) { |
1375 | fprintf(state_fp, "%s\n", state->data); | 1407 | fprintf(new_state_fp, "%s\n", state->data); |
1376 | } | 1408 | } |
1377 | state = state->link; | 1409 | state = state->link; |
1378 | } | 1410 | } |
1379 | fclose(state_fp); | 1411 | fclose(new_state_fp); |
1412 | xrename(IFSTATE_FILE_PATH".new", IFSTATE_FILE_PATH); | ||
1380 | llist_free(state_list, free); | 1413 | llist_free(state_list, free); |
1381 | } | 1414 | } |
1382 | next: | 1415 | next: |
diff --git a/networking/tcpudp.c b/networking/tcpudp.c index fbd1f1c45..b27cf3ea9 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c | |||
@@ -34,37 +34,56 @@ | |||
34 | /* with not-implemented options: */ | 34 | /* with not-implemented options: */ |
35 | /* //usage: "[-hpEvv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] [-i DIR|-x CDB] [-t SEC] IP PORT PROG" */ | 35 | /* //usage: "[-hpEvv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] [-i DIR|-x CDB] [-t SEC] IP PORT PROG" */ |
36 | //usage:#define tcpsvd_full_usage "\n\n" | 36 | //usage:#define tcpsvd_full_usage "\n\n" |
37 | //usage: "Create TCP socket, bind to IP:PORT and listen\n" | 37 | //usage: "Create TCP socket, bind to IP:PORT and listen for incoming connections.\n" |
38 | //usage: "for incoming connection. Run PROG for each connection.\n" | 38 | //usage: "Run PROG for each connection.\n" |
39 | //usage: "\n IP IP to listen on, 0 = all" | 39 | //usage: "\n IP PORT IP:PORT to listen on" |
40 | //usage: "\n PORT Port to listen on" | ||
41 | //usage: "\n PROG ARGS Program to run" | 40 | //usage: "\n PROG ARGS Program to run" |
42 | //usage: "\n -l NAME Local hostname (else looks up local hostname in DNS)" | ||
43 | //usage: "\n -u USER[:GRP] Change to user/group after bind" | 41 | //usage: "\n -u USER[:GRP] Change to user/group after bind" |
44 | //usage: "\n -c N Handle up to N connections simultaneously" | 42 | //usage: "\n -c N Up to N connections simultaneously (default 30)" |
45 | //usage: "\n -b N Allow a backlog of approximately N TCP SYNs" | 43 | //usage: "\n -b N Allow backlog of approximately N TCP SYNs (default 20)" |
46 | //usage: "\n -C N[:MSG] Allow only up to N connections from the same IP" | 44 | //usage: "\n -C N[:MSG] Allow only up to N connections from the same IP:" |
47 | //usage: "\n New connections from this IP address are closed" | 45 | //usage: "\n new connections from this IP address are closed" |
48 | //usage: "\n immediately. MSG is written to the peer before close" | 46 | //usage: "\n immediately, MSG is written to the peer before close" |
47 | //usage: "\n -E Don't set up environment" | ||
49 | //usage: "\n -h Look up peer's hostname" | 48 | //usage: "\n -h Look up peer's hostname" |
50 | //usage: "\n -E Don't set up environment variables" | 49 | //usage: "\n -l NAME Local hostname (else look up local hostname in DNS)" |
51 | //usage: "\n -v Verbose" | 50 | //usage: "\n -v Verbose" |
51 | //usage: "\n" | ||
52 | //usage: "\nEnvironment if no -E:" | ||
53 | //usage: "\nPROTO='TCP'" | ||
54 | //usage: "\nTCPREMOTEADDR='ip:port'" IF_FEATURE_IPV6(" ('[ip]:port' for IPv6)") | ||
55 | //usage: "\nTCPLOCALADDR='ip:port'" | ||
56 | //usage: "\nTCPORIGDSTADDR='ip:port' of destination before firewall" | ||
57 | //usage: "\n Useful for REDIRECTed-to-local connections:" | ||
58 | //usage: "\n iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080" | ||
59 | //usage: "\nTCPCONCURRENCY=num_of_connects_from_this_ip" | ||
60 | //usage: "\nIf -h:" | ||
61 | //usage: "\nTCPLOCALHOST='hostname' (-l NAME is used if specified)" | ||
62 | //usage: "\nTCPREMOTEHOST='hostname'" | ||
63 | |||
52 | //usage: | 64 | //usage: |
53 | //usage:#define udpsvd_trivial_usage | 65 | //usage:#define udpsvd_trivial_usage |
54 | //usage: "[-hEv] [-c N] [-u USER] [-l NAME] IP PORT PROG" | 66 | //usage: "[-hEv] [-c N] [-u USER] [-l NAME] IP PORT PROG" |
55 | //usage:#define udpsvd_full_usage "\n\n" | 67 | //usage:#define udpsvd_full_usage "\n\n" |
56 | //usage: "Create UDP socket, bind to IP:PORT and wait\n" | 68 | //usage: "Create UDP socket, bind to IP:PORT and wait for incoming packets.\n" |
57 | //usage: "for incoming packets. Run PROG for each packet,\n" | 69 | //usage: "Run PROG for each packet, redirecting all further packets with same\n" |
58 | //usage: "redirecting all further packets with same peer ip:port to it.\n" | 70 | //usage: "peer ip:port to it.\n" |
59 | //usage: "\n IP IP to listen on, 0 = all" | 71 | //usage: "\n IP PORT IP:PORT to listen on" |
60 | //usage: "\n PORT Port to listen on" | ||
61 | //usage: "\n PROG ARGS Program to run" | 72 | //usage: "\n PROG ARGS Program to run" |
62 | //usage: "\n -l NAME Local hostname (else looks up local hostname in DNS)" | ||
63 | //usage: "\n -u USER[:GRP] Change to user/group after bind" | 73 | //usage: "\n -u USER[:GRP] Change to user/group after bind" |
64 | //usage: "\n -c N Handle up to N connections simultaneously" | 74 | //usage: "\n -c N Up to N connections simultaneously (default 30)" |
75 | //usage: "\n -E Don't set up environment" | ||
65 | //usage: "\n -h Look up peer's hostname" | 76 | //usage: "\n -h Look up peer's hostname" |
66 | //usage: "\n -E Don't set up environment variables" | 77 | //usage: "\n -l NAME Local hostname (else look up local hostname in DNS)" |
67 | //usage: "\n -v Verbose" | 78 | //usage: "\n -v Verbose" |
79 | //usage: "\n" | ||
80 | //usage: "\nEnvironment if no -E:" | ||
81 | //usage: "\nPROTO='UDP'" | ||
82 | //usage: "\nUDPREMOTEADDR='ip:port'" IF_FEATURE_IPV6(" ('[ip]:port' for IPv6)") | ||
83 | //usage: "\nUDPLOCALADDR='ip:port'" | ||
84 | //usage: "\nIf -h:" | ||
85 | //usage: "\nUDPLOCALHOST='hostname' (-l NAME is used if specified)" | ||
86 | //usage: "\nUDPREMOTEHOST='hostname'" | ||
68 | 87 | ||
69 | #include "libbb.h" | 88 | #include "libbb.h" |
70 | #include "common_bufsiz.h" | 89 | #include "common_bufsiz.h" |
@@ -240,7 +259,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
240 | ); | 259 | ); |
241 | #else | 260 | #else |
242 | /* "+": stop on first non-option */ | 261 | /* "+": stop on first non-option */ |
243 | opts = getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v", | 262 | opts = getopt32(argv, "+c:+C:i:x:u:l:Eb:hpt:v", |
244 | &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, | 263 | &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, |
245 | &backlog, &str_t, &verbose | 264 | &backlog, &str_t, &verbose |
246 | ); | 265 | ); |
@@ -349,16 +368,20 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
349 | again: | 368 | again: |
350 | hccp = NULL; | 369 | hccp = NULL; |
351 | 370 | ||
371 | again1: | ||
372 | close(0); | ||
373 | /* It's important to close(0) _before_ wait loop: | ||
374 | * fd#0 can be a shared connection fd. | ||
375 | * If kept open by us, peer can't detect PROG closing it. | ||
376 | */ | ||
352 | while (cnum >= cmax) | 377 | while (cnum >= cmax) |
353 | wait_for_any_sig(); /* expecting SIGCHLD */ | 378 | wait_for_any_sig(); /* expecting SIGCHLD */ |
354 | 379 | ||
355 | /* Accept a connection to fd #0 */ | ||
356 | again1: | ||
357 | close(0); | ||
358 | again2: | 380 | again2: |
359 | sig_unblock(SIGCHLD); | 381 | sig_unblock(SIGCHLD); |
360 | local.len = remote.len = sa_len; | 382 | local.len = remote.len = sa_len; |
361 | if (tcp) { | 383 | if (tcp) { |
384 | /* Accept a connection to fd #0 */ | ||
362 | conn = accept(sock, &remote.u.sa, &remote.len); | 385 | conn = accept(sock, &remote.u.sa, &remote.len); |
363 | } else { | 386 | } else { |
364 | /* In case recv_from_to won't be able to recover local addr. | 387 | /* In case recv_from_to won't be able to recover local addr. |
diff --git a/networking/telnet.c b/networking/telnet.c index d2daf5c8c..1a6986b94 100644 --- a/networking/telnet.c +++ b/networking/telnet.c | |||
@@ -311,15 +311,16 @@ static void put_iac(int c) | |||
311 | G.iacbuf[G.iaclen++] = c; | 311 | G.iacbuf[G.iaclen++] = c; |
312 | } | 312 | } |
313 | 313 | ||
314 | static void put_iac2(byte wwdd, byte c) | 314 | static void put_iac2_merged(unsigned wwdd_and_c) |
315 | { | 315 | { |
316 | if (G.iaclen + 3 > IACBUFSIZE) | 316 | if (G.iaclen + 3 > IACBUFSIZE) |
317 | iac_flush(); | 317 | iac_flush(); |
318 | 318 | ||
319 | put_iac(IAC); | 319 | put_iac(IAC); |
320 | put_iac(wwdd); | 320 | put_iac(wwdd_and_c >> 8); |
321 | put_iac(c); | 321 | put_iac(wwdd_and_c & 0xff); |
322 | } | 322 | } |
323 | #define put_iac2(wwdd,c) put_iac2_merged(((wwdd)<<8) + (c)) | ||
323 | 324 | ||
324 | #if ENABLE_FEATURE_TELNET_TTYPE | 325 | #if ENABLE_FEATURE_TELNET_TTYPE |
325 | static void put_iac_subopt(byte c, char *str) | 326 | static void put_iac_subopt(byte c, char *str) |
diff --git a/networking/telnetd.IAC_test.sh b/networking/telnetd.IAC_test.sh new file mode 100644 index 000000000..a36ee3aa0 --- /dev/null +++ b/networking/telnetd.IAC_test.sh | |||
@@ -0,0 +1,87 @@ | |||
1 | #!/bin/sh | ||
2 | # Testcase for IAC input processing. | ||
3 | # The bug also required a small and odd BUFSIZE ("enum { BUFSIZE = 37 };") | ||
4 | # in telnetd.c to trigger easily. | ||
5 | |||
6 | echo "\ | ||
7 | Run telnetd like this: | ||
8 | busybox telnetd -l./save.sh -F | ||
9 | where save.sh is | ||
10 | #!/bin/sh | ||
11 | stty -echo | ||
12 | exec cat >save.dat | ||
13 | Now I'll try to connect to it and feed it 2048 0xff bytes. | ||
14 | Check that save.dat does contain 2048 0xff bytes. | ||
15 | " | ||
16 | |||
17 | ff() | ||
18 | { | ||
19 | echo -en \ | ||
20 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
21 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
22 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
23 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
24 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
25 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
26 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
27 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
28 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
29 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
30 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
31 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
32 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
33 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
34 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
35 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
36 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
37 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
38 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
39 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
40 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
41 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
42 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
43 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
44 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
45 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
46 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
47 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
48 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
49 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
50 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
51 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
52 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
53 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
54 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
55 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
56 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
57 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
58 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
59 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
60 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
61 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
62 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
63 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
64 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
65 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
66 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
67 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
68 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
69 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
70 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
71 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
72 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
73 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
74 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
75 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
76 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
77 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
78 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
79 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
80 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
81 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
82 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
83 | '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'\ | ||
84 | '\r\n'; } | ||
85 | |||
86 | ff | wc -c | ||
87 | { ff; sleep 2; } | busybox telnet 127.0.0.1 | ||
diff --git a/networking/telnetd.c b/networking/telnetd.c index 2fbdc3bb3..303ef1be7 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -60,6 +60,7 @@ struct tsession { | |||
60 | int sockfd_read; | 60 | int sockfd_read; |
61 | int sockfd_write; | 61 | int sockfd_write; |
62 | int ptyfd; | 62 | int ptyfd; |
63 | smallint buffered_IAC_for_pty; | ||
63 | 64 | ||
64 | /* two circular buffers */ | 65 | /* two circular buffers */ |
65 | /*char *buf1, *buf2;*/ | 66 | /*char *buf1, *buf2;*/ |
@@ -91,107 +92,197 @@ struct globals { | |||
91 | } while (0) | 92 | } while (0) |
92 | 93 | ||
93 | 94 | ||
94 | /* | 95 | /* Write some buf1 data to pty, processing IACs. |
95 | Remove all IAC's from buf1 (received IACs are ignored and must be removed | 96 | * Update wridx1 and size1. Return < 0 on error. |
96 | so as to not be interpreted by the terminal). Make an uninterrupted | 97 | * Buggy if IAC is present but incomplete: skips them. |
97 | string of characters fit for the terminal. Do this by packing | ||
98 | all characters meant for the terminal sequentially towards the end of buf. | ||
99 | |||
100 | Return a pointer to the beginning of the characters meant for the terminal | ||
101 | and make *num_totty the number of characters that should be sent to | ||
102 | the terminal. | ||
103 | |||
104 | Note - if an IAC (3 byte quantity) starts before (bf + len) but extends | ||
105 | past (bf + len) then that IAC will be left unprocessed and *processed | ||
106 | will be less than len. | ||
107 | |||
108 | CR-LF ->'s CR mapping is also done here, for convenience. | ||
109 | |||
110 | NB: may fail to remove iacs which wrap around buffer! | ||
111 | */ | 98 | */ |
112 | static unsigned char * | 99 | static ssize_t |
113 | remove_iacs(struct tsession *ts, int *pnum_totty) | 100 | safe_write_to_pty_decode_iac(struct tsession *ts) |
114 | { | 101 | { |
115 | unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1; | 102 | unsigned wr; |
116 | unsigned char *ptr = ptr0; | 103 | ssize_t rc; |
117 | unsigned char *totty = ptr; | 104 | unsigned char *buf; |
118 | unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1); | 105 | unsigned char *found; |
119 | int num_totty; | 106 | |
120 | 107 | buf = TS_BUF1(ts) + ts->wridx1; | |
121 | while (ptr < end) { | 108 | wr = MIN(BUFSIZE - ts->wridx1, ts->size1); |
122 | if (*ptr != IAC) { | 109 | /* wr is at least 1 here */ |
123 | char c = *ptr; | 110 | |
124 | 111 | if (ts->buffered_IAC_for_pty) { | |
125 | *totty++ = c; | 112 | /* Last time we stopped on a "dangling" IAC byte. |
126 | ptr++; | 113 | * We removed it from the buffer back then. |
127 | /* We map \r\n ==> \r for pragmatic reasons. | 114 | * Now pretend it's still there, and jump to IAC processing. |
128 | * Many client implementations send \r\n when | 115 | */ |
129 | * the user hits the CarriageReturn key. | 116 | ts->buffered_IAC_for_pty = 0; |
130 | * See RFC 1123 3.3.1 Telnet End-of-Line Convention. | 117 | wr++; |
131 | */ | 118 | ts->size1++; |
132 | if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0')) | 119 | buf--; /* Yes, this can point before the buffer. It's ok */ |
133 | ptr++; | 120 | ts->wridx1--; |
134 | continue; | 121 | goto handle_iac; |
135 | } | 122 | } |
136 | 123 | ||
137 | if ((ptr+1) >= end) | 124 | found = memchr(buf, IAC, wr); |
138 | break; | 125 | if (found != buf) { |
139 | if (ptr[1] == NOP) { /* Ignore? (putty keepalive, etc.) */ | 126 | /* There is a "prefix" of non-IAC chars. |
140 | ptr += 2; | 127 | * Write only them, and return. |
141 | continue; | 128 | */ |
142 | } | 129 | if (found) |
143 | if (ptr[1] == IAC) { /* Literal IAC? (emacs M-DEL) */ | 130 | wr = found - buf; |
144 | *totty++ = ptr[1]; | ||
145 | ptr += 2; | ||
146 | continue; | ||
147 | } | ||
148 | 131 | ||
149 | /* | 132 | /* We map \r\n ==> \r for pragmatic reasons: |
150 | * TELOPT_NAWS support! | 133 | * many client implementations send \r\n when |
134 | * the user hits the CarriageReturn key. | ||
135 | * See RFC 1123 3.3.1 Telnet End-of-Line Convention. | ||
151 | */ | 136 | */ |
152 | if ((ptr+2) >= end) { | 137 | rc = wr; |
153 | /* Only the beginning of the IAC is in the | 138 | found = memchr(buf, '\r', wr); |
154 | buffer we were asked to process, we can't | 139 | if (found) |
155 | process this char */ | 140 | rc = found - buf + 1; |
156 | break; | 141 | rc = safe_write(ts->ptyfd, buf, rc); |
142 | if (rc <= 0) | ||
143 | return rc; | ||
144 | if (rc < wr /* don't look past available data */ | ||
145 | && buf[rc-1] == '\r' /* need this: imagine that write was _short_ */ | ||
146 | && (buf[rc] == '\n' || buf[rc] == '\0') | ||
147 | ) { | ||
148 | rc++; | ||
157 | } | 149 | } |
150 | goto update_and_return; | ||
151 | } | ||
152 | |||
153 | /* buf starts with IAC char. Process that sequence. | ||
154 | * Example: we get this from our own (bbox) telnet client: | ||
155 | * read(5, "\377\374\1""\377\373\37""\377\372\37\0\262\0@\377\360""\377\375\1""\377\375\3"): | ||
156 | * IAC WONT ECHO, IAC WILL NAWS, IAC SB NAWS <cols> <rows> IAC SE, IAC DO SGA | ||
157 | * Another example (telnet-0.17 from old-netkit): | ||
158 | * read(4, "\377\375\3""\377\373\30""\377\373\37""\377\373 ""\377\373!""\377\373\"""\377\373'" | ||
159 | * "\377\375\5""\377\373#""\377\374\1""\377\372\37\0\257\0I\377\360""\377\375\1"): | ||
160 | * IAC DO SGA, IAC WILL TTYPE, IAC WILL NAWS, IAC WILL TSPEED, IAC WILL LFLOW, IAC WILL LINEMODE, IAC WILL NEW_ENVIRON, | ||
161 | * IAC DO STATUS, IAC WILL XDISPLOC, IAC WONT ECHO, IAC SB NAWS <cols> <rows> IAC SE, IAC DO ECHO | ||
162 | */ | ||
163 | if (wr <= 1) { | ||
164 | /* Only the single IAC byte is in the buffer, eat it | ||
165 | * and set a flag "process the rest of the sequence | ||
166 | * next time we are here". | ||
167 | */ | ||
168 | //bb_error_msg("dangling IAC!"); | ||
169 | ts->buffered_IAC_for_pty = 1; | ||
170 | rc = 1; | ||
171 | goto update_and_return; | ||
172 | } | ||
173 | |||
174 | handle_iac: | ||
175 | /* 2-byte commands (240..250 and 255): | ||
176 | * IAC IAC (255) Literal 255. Supported. | ||
177 | * IAC SE (240) End of subnegotiation. Treated as NOP. | ||
178 | * IAC NOP (241) NOP. Supported. | ||
179 | * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()? | ||
180 | * IAC AYT (246) Are you there. Send back evidence that AYT was seen. TODO (send NOP back)? | ||
181 | * These don't look useful: | ||
182 | * IAC DM (242) Data mark. What is this? | ||
183 | * IAC IP (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C). | ||
184 | * IAC AO (245) Abort output. "You can continue running, but do not send me the output". | ||
185 | * IAC EC (247) Erase character. The receiver should delete the last received char. | ||
186 | * IAC EL (248) Erase line. The receiver should delete everything up tp last newline. | ||
187 | * IAC GA (249) Go ahead. For half-duplex lines: "now you talk". | ||
188 | * Implemented only as part of NAWS: | ||
189 | * IAC SB (250) Subnegotiation of an option follows. | ||
190 | */ | ||
191 | if (buf[1] == IAC) { | ||
192 | /* Literal 255 (emacs M-DEL) */ | ||
193 | //bb_error_msg("255!"); | ||
194 | rc = safe_write(ts->ptyfd, &buf[1], 1); | ||
158 | /* | 195 | /* |
159 | * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE | 196 | * If we went through buffered_IAC_for_pty==1 path, |
197 | * bailing out on error like below messes up the buffer. | ||
198 | * EAGAIN is highly unlikely here, other errors will be | ||
199 | * repeated on next write, let's just skip error check. | ||
160 | */ | 200 | */ |
161 | if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { | 201 | #if 0 |
202 | if (rc <= 0) | ||
203 | return rc; | ||
204 | #endif | ||
205 | rc = 2; | ||
206 | goto update_and_return; | ||
207 | } | ||
208 | if (buf[1] >= 240 && buf[1] <= 249) { | ||
209 | /* NOP (241). Ignore (putty keepalive, etc) */ | ||
210 | /* All other 2-byte commands also treated as NOPs here */ | ||
211 | rc = 2; | ||
212 | goto update_and_return; | ||
213 | } | ||
214 | |||
215 | if (wr <= 2) { | ||
216 | /* BUG: only 2 bytes of the IAC is in the buffer, we just eat them. | ||
217 | * This is not a practical problem since >2 byte IACs are seen only | ||
218 | * in initial negotiation, when buffer is empty | ||
219 | */ | ||
220 | rc = 2; | ||
221 | goto update_and_return; | ||
222 | } | ||
223 | |||
224 | if (buf[1] == SB) { | ||
225 | if (buf[2] == TELOPT_NAWS) { | ||
226 | /* IAC SB, TELOPT_NAWS, 4-byte, IAC SE */ | ||
162 | struct winsize ws; | 227 | struct winsize ws; |
163 | if ((ptr+8) >= end) | 228 | if (wr <= 6) { |
164 | break; /* incomplete, can't process */ | 229 | /* BUG: incomplete, can't process */ |
165 | ws.ws_col = (ptr[3] << 8) | ptr[4]; | 230 | rc = wr; |
166 | ws.ws_row = (ptr[5] << 8) | ptr[6]; | 231 | goto update_and_return; |
232 | } | ||
233 | memset(&ws, 0, sizeof(ws)); /* pixel sizes are set to 0 */ | ||
234 | ws.ws_col = (buf[3] << 8) | buf[4]; | ||
235 | ws.ws_row = (buf[5] << 8) | buf[6]; | ||
167 | ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); | 236 | ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); |
168 | ptr += 9; | 237 | rc = 7; |
169 | continue; | 238 | /* trailing IAC SE will be eaten separately, as 2-byte NOP */ |
239 | goto update_and_return; | ||
170 | } | 240 | } |
171 | /* skip 3-byte IAC non-SB cmd */ | 241 | /* else: other subnegs not supported yet */ |
242 | } | ||
243 | |||
244 | /* Assume it is a 3-byte WILL/WONT/DO/DONT 251..254 command and skip it */ | ||
172 | #if DEBUG | 245 | #if DEBUG |
173 | fprintf(stderr, "Ignoring IAC %s,%s\n", | 246 | fprintf(stderr, "Ignoring IAC %s,%s\n", |
174 | TELCMD(ptr[1]), TELOPT(ptr[2])); | 247 | TELCMD(buf[1]), TELOPT(buf[2])); |
175 | #endif | 248 | #endif |
176 | ptr += 3; | 249 | rc = 3; |
250 | |||
251 | update_and_return: | ||
252 | ts->wridx1 += rc; | ||
253 | if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */ | ||
254 | ts->wridx1 = 0; | ||
255 | ts->size1 -= rc; | ||
256 | /* | ||
257 | * Hack. We cannot process IACs which wrap around buffer's end. | ||
258 | * Since properly fixing it requires writing bigger code, | ||
259 | * we rely instead on this code making it virtually impossible | ||
260 | * to have wrapped IAC (people don't type at 2k/second). | ||
261 | * It also allows for bigger reads in common case. | ||
262 | */ | ||
263 | if (ts->size1 == 0) { /* very typical */ | ||
264 | //bb_error_msg("zero size1"); | ||
265 | ts->rdidx1 = 0; | ||
266 | ts->wridx1 = 0; | ||
267 | return rc; | ||
177 | } | 268 | } |
178 | 269 | wr = ts->wridx1; | |
179 | num_totty = totty - ptr0; | 270 | if (wr != 0 && wr < ts->rdidx1) { |
180 | *pnum_totty = num_totty; | 271 | /* Buffer is not wrapped yet. |
181 | /* The difference between ptr and totty is number of iacs | 272 | * We can easily move it to the beginning. |
182 | we removed from the stream. Adjust buf1 accordingly */ | 273 | */ |
183 | if ((ptr - totty) == 0) /* 99.999% of cases */ | 274 | //bb_error_msg("moved %d", wr); |
184 | return ptr0; | 275 | memmove(TS_BUF1(ts), TS_BUF1(ts) + wr, ts->size1); |
185 | ts->wridx1 += ptr - totty; | 276 | ts->rdidx1 -= wr; |
186 | ts->size1 -= ptr - totty; | 277 | ts->wridx1 = 0; |
187 | /* Move chars meant for the terminal towards the end of the buffer */ | 278 | } |
188 | return memmove(ptr - num_totty, ptr0, num_totty); | 279 | return rc; |
189 | } | 280 | } |
190 | 281 | ||
191 | /* | 282 | /* |
192 | * Converting single IAC into double on output | 283 | * Converting single IAC into double on output |
193 | */ | 284 | */ |
194 | static size_t iac_safe_write(int fd, const char *buf, size_t count) | 285 | static size_t safe_write_double_iac(int fd, const char *buf, size_t count) |
195 | { | 286 | { |
196 | const char *IACptr; | 287 | const char *IACptr; |
197 | size_t wr, rc, total; | 288 | size_t wr, rc, total; |
@@ -203,6 +294,7 @@ static size_t iac_safe_write(int fd, const char *buf, size_t count) | |||
203 | if (*buf == (char)IAC) { | 294 | if (*buf == (char)IAC) { |
204 | static const char IACIAC[] ALIGN1 = { IAC, IAC }; | 295 | static const char IACIAC[] ALIGN1 = { IAC, IAC }; |
205 | rc = safe_write(fd, IACIAC, 2); | 296 | rc = safe_write(fd, IACIAC, 2); |
297 | /* BUG: if partial write was only 1 byte long, we end up emitting just one IAC */ | ||
206 | if (rc != 2) | 298 | if (rc != 2) |
207 | break; | 299 | break; |
208 | buf++; | 300 | buf++; |
@@ -298,7 +390,7 @@ make_new_session( | |||
298 | IAC, WILL, TELOPT_ECHO, | 390 | IAC, WILL, TELOPT_ECHO, |
299 | IAC, WILL, TELOPT_SGA | 391 | IAC, WILL, TELOPT_SGA |
300 | }; | 392 | }; |
301 | /* This confuses iac_safe_write(), it will try to duplicate | 393 | /* This confuses safe_write_double_iac(), it will try to duplicate |
302 | * each IAC... */ | 394 | * each IAC... */ |
303 | //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send)); | 395 | //memcpy(TS_BUF2(ts), iacs_to_send, sizeof(iacs_to_send)); |
304 | //ts->rdidx2 = sizeof(iacs_to_send); | 396 | //ts->rdidx2 = sizeof(iacs_to_send); |
@@ -649,51 +741,34 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
649 | struct tsession *next = ts->next; /* in case we free ts */ | 741 | struct tsession *next = ts->next; /* in case we free ts */ |
650 | 742 | ||
651 | if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) { | 743 | if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) { |
652 | int num_totty; | ||
653 | unsigned char *ptr; | ||
654 | /* Write to pty from buffer 1 */ | 744 | /* Write to pty from buffer 1 */ |
655 | ptr = remove_iacs(ts, &num_totty); | 745 | count = safe_write_to_pty_decode_iac(ts); |
656 | count = safe_write(ts->ptyfd, ptr, num_totty); | ||
657 | if (count < 0) { | 746 | if (count < 0) { |
658 | if (errno == EAGAIN) | 747 | if (errno == EAGAIN) |
659 | goto skip1; | 748 | goto skip1; |
660 | goto kill_session; | 749 | goto kill_session; |
661 | } | 750 | } |
662 | ts->size1 -= count; | ||
663 | ts->wridx1 += count; | ||
664 | if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */ | ||
665 | ts->wridx1 = 0; | ||
666 | } | 751 | } |
667 | skip1: | 752 | skip1: |
668 | if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { | 753 | if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { |
669 | /* Write to socket from buffer 2 */ | 754 | /* Write to socket from buffer 2 */ |
670 | count = MIN(BUFSIZE - ts->wridx2, ts->size2); | 755 | count = MIN(BUFSIZE - ts->wridx2, ts->size2); |
671 | count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count); | 756 | count = safe_write_double_iac(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count); |
672 | if (count < 0) { | 757 | if (count < 0) { |
673 | if (errno == EAGAIN) | 758 | if (errno == EAGAIN) |
674 | goto skip2; | 759 | goto skip2; |
675 | goto kill_session; | 760 | goto kill_session; |
676 | } | 761 | } |
677 | ts->size2 -= count; | ||
678 | ts->wridx2 += count; | 762 | ts->wridx2 += count; |
679 | if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */ | 763 | if (ts->wridx2 >= BUFSIZE) /* actually == BUFSIZE */ |
680 | ts->wridx2 = 0; | 764 | ts->wridx2 = 0; |
765 | ts->size2 -= count; | ||
766 | if (ts->size2 == 0) { | ||
767 | ts->rdidx2 = 0; | ||
768 | ts->wridx2 = 0; | ||
769 | } | ||
681 | } | 770 | } |
682 | skip2: | 771 | skip2: |
683 | /* Should not be needed, but... remove_iacs is actually buggy | ||
684 | * (it cannot process iacs which wrap around buffer's end)! | ||
685 | * Since properly fixing it requires writing bigger code, | ||
686 | * we rely instead on this code making it virtually impossible | ||
687 | * to have wrapped iac (people don't type at 2k/second). | ||
688 | * It also allows for bigger reads in common case. */ | ||
689 | if (ts->size1 == 0) { | ||
690 | ts->rdidx1 = 0; | ||
691 | ts->wridx1 = 0; | ||
692 | } | ||
693 | if (ts->size2 == 0) { | ||
694 | ts->rdidx2 = 0; | ||
695 | ts->wridx2 = 0; | ||
696 | } | ||
697 | 772 | ||
698 | if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) { | 773 | if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) { |
699 | /* Read from socket to buffer 1 */ | 774 | /* Read from socket to buffer 1 */ |
diff --git a/util-linux/more.c b/util-linux/more.c index 4812f1bc5..f6923efda 100644 --- a/util-linux/more.c +++ b/util-linux/more.c | |||
@@ -76,7 +76,16 @@ int more_main(int argc UNUSED_PARAM, char **argv) | |||
76 | 76 | ||
77 | INIT_G(); | 77 | INIT_G(); |
78 | 78 | ||
79 | argv++; | 79 | /* Parse options */ |
80 | /* Accepted but ignored: */ | ||
81 | /* -d Display help instead of ringing bell is pressed */ | ||
82 | /* -f Count logical lines (IOW: long lines are not folded) */ | ||
83 | /* -l Do not pause after any line containing a ^L (form feed) */ | ||
84 | /* -s Squeeze blank lines into one */ | ||
85 | /* -u Suppress underlining */ | ||
86 | getopt32(argv, "dflsu"); | ||
87 | argv += optind; | ||
88 | |||
80 | /* Another popular pager, most, detects when stdout | 89 | /* Another popular pager, most, detects when stdout |
81 | * is not a tty and turns into cat. This makes sense. */ | 90 | * is not a tty and turns into cat. This makes sense. */ |
82 | if (!isatty(STDOUT_FILENO)) | 91 | if (!isatty(STDOUT_FILENO)) |