VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/tftp.c@ 1033

最後變更 在這個檔案從1033是 1033,由 vboxsync 提交於 18 年 前

Big change to make slirp fully instantiatable (replace all global
variables with local ones, passing a reference to the state/config
structure to all places which are interested). You can now have as many
cards in the guest configured for NAT networking as you want.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 13.4 KB
 
1/*
2 * tftp.c - a simple, read-only tftp server for qemu
3 *
4 * Copyright (c) 2004 Magnus Damm <[email protected]>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include <slirp.h>
26
27#ifndef VBOX
28struct tftp_session {
29 int in_use;
30 unsigned char filename[TFTP_FILENAME_MAX];
31
32 struct in_addr client_ip;
33 u_int16_t client_port;
34
35 int timestamp;
36};
37
38struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
39
40const char *tftp_prefix;
41#endif /* !VBOX */
42
43#ifdef VBOX
44static void tftp_session_update(PNATState pData, struct tftp_session *spt)
45#else /* !VBOX */
46static void tftp_session_update(struct tftp_session *spt)
47#endif /* !VBOX */
48{
49 spt->timestamp = curtime;
50 spt->in_use = 1;
51}
52
53static void tftp_session_terminate(struct tftp_session *spt)
54{
55 spt->in_use = 0;
56}
57
58#ifdef VBOX
59static int tftp_session_allocate(PNATState pData, struct tftp_t *tp)
60#else /* !VBOX */
61static int tftp_session_allocate(struct tftp_t *tp)
62#endif /* !VBOX */
63{
64 struct tftp_session *spt;
65 int k;
66
67 for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
68 spt = &tftp_sessions[k];
69
70 if (!spt->in_use)
71 goto found;
72
73 /* sessions time out after 5 inactive seconds */
74 if ((int)(curtime - spt->timestamp) > 5000)
75 goto found;
76 }
77
78 return -1;
79
80 found:
81 memset(spt, 0, sizeof(*spt));
82 memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
83 spt->client_port = tp->udp.uh_sport;
84
85#ifdef VBOX
86 tftp_session_update(pData, spt);
87#else /* !VBOX */
88 tftp_session_update(spt);
89#endif /* !VBOX */
90
91 return k;
92}
93
94#ifdef VBOX
95static int tftp_session_find(PNATState pData, struct tftp_t *tp)
96#else /* !VBOX */
97static int tftp_session_find(struct tftp_t *tp)
98#endif /* !VBOX */
99{
100 struct tftp_session *spt;
101 int k;
102
103 for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
104 spt = &tftp_sessions[k];
105
106 if (spt->in_use) {
107 if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
108 if (spt->client_port == tp->udp.uh_sport) {
109 return k;
110 }
111 }
112 }
113 }
114
115 return -1;
116}
117
118#ifdef VBOX
119static int tftp_read_data(PNATState pData, struct tftp_session *spt, u_int16_t block_nr,
120 u_int8_t *buf, int len)
121#else /* !VBOX */
122static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr,
123 u_int8_t *buf, int len)
124#endif /* !VBOX */
125{
126 int fd;
127 int bytes_read = 0;
128 char buffer[1024];
129 int n;
130
131#ifndef VBOX
132 n = snprintf(buffer, sizeof(buffer), "%s/%s",
133 tftp_prefix, spt->filename);
134#else
135 n = RTStrPrintf(buffer, sizeof(buffer), "%s/%s",
136 tftp_prefix, spt->filename);
137#endif
138 if (n >= sizeof(buffer))
139 return -1;
140
141 fd = open(buffer, O_RDONLY | O_BINARY);
142
143 if (fd < 0) {
144 return -1;
145 }
146
147 if (len) {
148 lseek(fd, block_nr * 512, SEEK_SET);
149
150 bytes_read = read(fd, buf, len);
151 }
152
153 close(fd);
154
155 return bytes_read;
156}
157
158#ifdef VBOX
159static int tftp_send_oack(PNATState pData,
160 struct tftp_session *spt,
161 const char *key, uint32_t value,
162 struct tftp_t *recv_tp)
163#else /* !VBOX */
164static int tftp_send_oack(struct tftp_session *spt,
165 const char *key, uint32_t value,
166 struct tftp_t *recv_tp)
167#endif /* !VBOX */
168{
169 struct sockaddr_in saddr, daddr;
170 struct mbuf *m;
171 struct tftp_t *tp;
172 int n = 0;
173
174#ifdef VBOX
175 m = m_get(pData);
176#else /* !VBOX */
177 m = m_get();
178#endif /* !VBOX */
179
180 if (!m)
181 return -1;
182
183 memset(m->m_data, 0, m->m_size);
184
185 m->m_data += if_maxlinkhdr;
186 tp = (void *)m->m_data;
187 m->m_data += sizeof(struct udpiphdr);
188
189 tp->tp_op = htons(TFTP_OACK);
190#ifdef VBOX
191 n += sprintf((char *)tp->x.tp_buf + n, "%s", key) + 1;
192 n += sprintf((char *)tp->x.tp_buf + n, "%u", value) + 1;
193#else /* !VBOX */
194 n += sprintf(tp->x.tp_buf + n, "%s", key) + 1;
195 n += sprintf(tp->x.tp_buf + n, "%u", value) + 1;
196#endif /* !VBOX */
197
198 saddr.sin_addr = recv_tp->ip.ip_dst;
199 saddr.sin_port = recv_tp->udp.uh_dport;
200
201 daddr.sin_addr = spt->client_ip;
202 daddr.sin_port = spt->client_port;
203
204 m->m_len = sizeof(struct tftp_t) - 514 + n -
205 sizeof(struct ip) - sizeof(struct udphdr);
206#ifdef VBOX
207 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
208#else /* !VBOX */
209 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
210#endif /* !VBOX */
211
212 return 0;
213}
214
215
216
217#ifdef VBOX
218static int tftp_send_error(PNATState pData,
219 struct tftp_session *spt,
220 u_int16_t errorcode, const char *msg,
221 struct tftp_t *recv_tp)
222#else /* !VBOX */
223static int tftp_send_error(struct tftp_session *spt,
224 u_int16_t errorcode, const char *msg,
225 struct tftp_t *recv_tp)
226#endif /* !VBOX */
227{
228 struct sockaddr_in saddr, daddr;
229 struct mbuf *m;
230 struct tftp_t *tp;
231 int nobytes;
232
233#ifdef VBOX
234 m = m_get(pData);
235#else /* !VBOX */
236 m = m_get();
237#endif /* !VBOX */
238
239 if (!m) {
240 return -1;
241 }
242
243 memset(m->m_data, 0, m->m_size);
244
245 m->m_data += if_maxlinkhdr;
246 tp = (void *)m->m_data;
247 m->m_data += sizeof(struct udpiphdr);
248
249 tp->tp_op = htons(TFTP_ERROR);
250 tp->x.tp_error.tp_error_code = htons(errorcode);
251#ifndef VBOX
252 strcpy(tp->x.tp_error.tp_msg, msg);
253#else /* VBOX */
254 strcpy((char *)tp->x.tp_error.tp_msg, msg);
255#endif /* VBOX */
256
257 saddr.sin_addr = recv_tp->ip.ip_dst;
258 saddr.sin_port = recv_tp->udp.uh_dport;
259
260 daddr.sin_addr = spt->client_ip;
261 daddr.sin_port = spt->client_port;
262
263 nobytes = 2;
264
265 m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
266 sizeof(struct ip) - sizeof(struct udphdr);
267
268#ifdef VBOX
269 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
270#else /* !VBOX */
271 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
272#endif /* !VBOX */
273
274 tftp_session_terminate(spt);
275
276 return 0;
277}
278
279#ifdef VBOX
280static int tftp_send_data(PNATState pData,
281 struct tftp_session *spt,
282 u_int16_t block_nr,
283 struct tftp_t *recv_tp)
284#else /* !VBOX */
285static int tftp_send_data(struct tftp_session *spt,
286 u_int16_t block_nr,
287 struct tftp_t *recv_tp)
288#endif /* !VBOX */
289{
290 struct sockaddr_in saddr, daddr;
291 struct mbuf *m;
292 struct tftp_t *tp;
293 int nobytes;
294
295 if (block_nr < 1) {
296 return -1;
297 }
298
299#ifdef VBOX
300 m = m_get(pData);
301#else /* !VBOX */
302 m = m_get();
303#endif /* !VBOX */
304
305 if (!m) {
306 return -1;
307 }
308
309 memset(m->m_data, 0, m->m_size);
310
311 m->m_data += if_maxlinkhdr;
312 tp = (void *)m->m_data;
313 m->m_data += sizeof(struct udpiphdr);
314
315 tp->tp_op = htons(TFTP_DATA);
316 tp->x.tp_data.tp_block_nr = htons(block_nr);
317
318 saddr.sin_addr = recv_tp->ip.ip_dst;
319 saddr.sin_port = recv_tp->udp.uh_dport;
320
321 daddr.sin_addr = spt->client_ip;
322 daddr.sin_port = spt->client_port;
323
324#ifdef VBOX
325 nobytes = tftp_read_data(pData, spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
326#else /* !VBOX */
327 nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
328#endif /* !VBOX */
329
330 if (nobytes < 0) {
331#ifdef VBOX
332 m_free(pData, m);
333#else /* !VBOX */
334 m_free(m);
335#endif /* !VBOX */
336
337 /* send "file not found" error back */
338
339#ifdef VBOX
340 tftp_send_error(pData, spt, 1, "File not found", tp);
341#else /* !VBOX */
342 tftp_send_error(spt, 1, "File not found", tp);
343#endif /* !VBOX */
344
345 return -1;
346 }
347
348 m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
349 sizeof(struct ip) - sizeof(struct udphdr);
350
351#ifdef VBOX
352 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
353#else /* !VBOX */
354 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
355#endif /* !VBOX */
356
357 if (nobytes == 512) {
358#ifdef VBOX
359 tftp_session_update(pData, spt);
360#else /* !VBOX */
361 tftp_session_update(spt);
362#endif /* !VBOX */
363 }
364 else {
365 tftp_session_terminate(spt);
366 }
367
368 return 0;
369}
370
371#ifdef VBOX
372static void tftp_handle_rrq(PNATState pData, struct tftp_t *tp, int pktlen)
373#else /* !VBOX */
374static void tftp_handle_rrq(struct tftp_t *tp, int pktlen)
375#endif /* !VBOX */
376{
377 struct tftp_session *spt;
378 int s, k, n;
379 u_int8_t *src, *dst;
380
381#ifdef VBOX
382 s = tftp_session_allocate(pData, tp);
383#else /* !VBOX */
384 s = tftp_session_allocate(tp);
385#endif /* !VBOX */
386
387 if (s < 0) {
388 return;
389 }
390
391 spt = &tftp_sessions[s];
392
393 src = tp->x.tp_buf;
394 dst = spt->filename;
395 n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp);
396
397 /* get name */
398
399 for (k = 0; k < n; k++) {
400 if (k < TFTP_FILENAME_MAX) {
401 dst[k] = src[k];
402 }
403 else {
404 return;
405 }
406
407 if (src[k] == '\0') {
408 break;
409 }
410 }
411
412 if (k >= n) {
413 return;
414 }
415
416 k++;
417
418 /* check mode */
419 if ((n - k) < 6) {
420 return;
421 }
422
423 if (memcmp(&src[k], "octet\0", 6) != 0) {
424#ifdef VBOX
425 tftp_send_error(pData, spt, 4, "Unsupported transfer mode", tp);
426#else /* !VBOX */
427 tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
428#endif /* !VBOX */
429 return;
430 }
431
432 k += 6; /* skipping octet */
433
434 /* do sanity checks on the filename */
435
436#ifndef VBOX
437 if ((spt->filename[0] != '/')
438 || (spt->filename[strlen(spt->filename) - 1] == '/')
439 || strstr(spt->filename, "/../")) {
440 tftp_send_error(spt, 2, "Access violation", tp);
441#else /* VBOX */
442 if ((spt->filename[0] != '/')
443 || (spt->filename[strlen((const char *)spt->filename) - 1] == '/')
444 || strstr((char *)spt->filename, "/../")) {
445 tftp_send_error(pData, spt, 2, "Access violation", tp);
446#endif /* VBOX */
447 return;
448 }
449
450 /* only allow exported prefixes */
451
452 if (!tftp_prefix) {
453#ifdef VBOX
454 tftp_send_error(pData, spt, 2, "Access violation", tp);
455#else /* !VBOX */
456 tftp_send_error(spt, 2, "Access violation", tp);
457#endif /* !VBOX */
458 return;
459 }
460
461 /* check if the file exists */
462
463#ifdef VBOX
464 if (tftp_read_data(pData, spt, 0, spt->filename, 0) < 0) {
465 tftp_send_error(pData, spt, 1, "File not found", tp);
466#else /* !VBOX */
467 if (tftp_read_data(spt, 0, spt->filename, 0) < 0) {
468 tftp_send_error(spt, 1, "File not found", tp);
469#endif /* !VBOX */
470 return;
471 }
472
473 if (src[n - 1] != 0) {
474#ifdef VBOX
475 tftp_send_error(pData, spt, 2, "Access violation", tp);
476#else /* !VBOX */
477 tftp_send_error(spt, 2, "Access violation", tp);
478#endif /* !VBOX */
479 return;
480 }
481
482 while (k < n) {
483 const char *key, *value;
484
485#ifdef VBOX
486 key = (const char *)src + k;
487#else /* !VBOX */
488 key = src + k;
489#endif /* !VBOX */
490 k += strlen(key) + 1;
491
492 if (k >= n) {
493#ifdef VBOX
494 tftp_send_error(pData, spt, 2, "Access violation", tp);
495#else /* !VBOX */
496 tftp_send_error(spt, 2, "Access violation", tp);
497#endif /* !VBOX */
498 return;
499 }
500
501#ifdef VBOX
502 value = (const char *)src + k;
503#else /* !VBOX */
504 value = src + k;
505#endif /* !VBOX */
506 k += strlen(value) + 1;
507
508 if (strcmp(key, "tsize") == 0) {
509 int tsize = atoi(value);
510 struct stat stat_p;
511
512 if (tsize == 0 && tftp_prefix) {
513 char buffer[1024];
514 int len;
515
516#ifndef VBOX
517 len = snprintf(buffer, sizeof(buffer), "%s/%s",
518 tftp_prefix, spt->filename);
519#else
520 len = RTStrPrintf(buffer, sizeof(buffer), "%s/%s",
521 tftp_prefix, spt->filename);
522#endif
523
524 if (stat(buffer, &stat_p) == 0)
525 tsize = stat_p.st_size;
526 else {
527#ifdef VBOX
528 tftp_send_error(pData, spt, 1, "File not found", tp);
529#else /* !VBOX */
530 tftp_send_error(spt, 1, "File not found", tp);
531#endif /* !VBOX */
532 return;
533 }
534 }
535
536#ifdef VBOX
537 tftp_send_oack(pData, spt, "tsize", tsize, tp);
538#else /* !VBOX */
539 tftp_send_oack(spt, "tsize", tsize, tp);
540#endif /* !VBOX */
541 }
542 }
543
544#ifdef VBOX
545 tftp_send_data(pData, spt, 1, tp);
546#else /* !VBOX */
547 tftp_send_data(spt, 1, tp);
548#endif /* !VBOX */
549}
550
551#ifdef VBOX
552static void tftp_handle_ack(PNATState pData, struct tftp_t *tp, int pktlen)
553#else /* !VBOX */
554static void tftp_handle_ack(struct tftp_t *tp, int pktlen)
555#endif /* !VBOX */
556{
557 int s;
558
559#ifdef VBOX
560 s = tftp_session_find(pData, tp);
561#else /* !VBOX */
562 s = tftp_session_find(tp);
563#endif /* !VBOX */
564
565 if (s < 0) {
566 return;
567 }
568
569#ifdef VBOX
570 if (tftp_send_data(pData, &tftp_sessions[s],
571 ntohs(tp->x.tp_data.tp_block_nr) + 1,
572 tp) < 0) {
573#else /* !VBOX */
574 if (tftp_send_data(&tftp_sessions[s],
575 ntohs(tp->x.tp_data.tp_block_nr) + 1,
576 tp) < 0) {
577#endif /* !VBOX */
578 return;
579 }
580}
581
582#ifdef VBOX
583void tftp_input(PNATState pData, struct mbuf *m)
584#else /* !VBOX */
585void tftp_input(struct mbuf *m)
586#endif /* !VBOX */
587{
588 struct tftp_t *tp = (struct tftp_t *)m->m_data;
589
590 switch(ntohs(tp->tp_op)) {
591 case TFTP_RRQ:
592#ifdef VBOX
593 tftp_handle_rrq(pData, tp, m->m_len);
594#else /* !VBOX */
595 tftp_handle_rrq(tp, m->m_len);
596#endif /* !VBOX */
597 break;
598
599 case TFTP_ACK:
600#ifdef VBOX
601 tftp_handle_ack(pData, tp, m->m_len);
602#else /* !VBOX */
603 tftp_handle_ack(tp, m->m_len);
604#endif /* !VBOX */
605 break;
606 }
607}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette