]> git.proxmox.com Git - qemu.git/blame - slirp/slirp.c
slirp: fix CVE 2007-5729
[qemu.git] / slirp / slirp.c
CommitLineData
d75a0b97
FB
1/*
2 * libslirp glue
3 *
4 * Copyright (c) 2004-2008 Fabrice Bellard
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 */
f0cbd3ec
FB
24#include "slirp.h"
25
26/* host address */
27struct in_addr our_addr;
28/* host dns address */
29struct in_addr dns_addr;
30/* host loopback address */
31struct in_addr loopback_addr;
32
33/* address for slirp virtual addresses */
34struct in_addr special_addr;
8dbca8dd
FB
35/* virtual address alias for host */
36struct in_addr alias_addr;
f0cbd3ec 37
9634d903 38static const uint8_t special_ethaddr[6] = {
f0cbd3ec
FB
39 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
40};
41
de806f07 42/* ARP cache for the guest IP addresses (XXX: allow many entries) */
f0cbd3ec 43uint8_t client_ethaddr[6];
de806f07
FB
44static struct in_addr client_ipaddr;
45
46static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
f0cbd3ec
FB
47
48int do_slowtimo;
49int link_up;
50struct timeval tt;
51FILE *lfd;
a3d4af03 52struct ex_list *exec_list;
f0cbd3ec
FB
53
54/* XXX: suppress those select globals */
55fd_set *global_readfds, *global_writefds, *global_xfds;
56
3f423c9c 57char slirp_hostname[33];
115defd1 58
f0cbd3ec
FB
59#ifdef _WIN32
60
61static int get_dns_addr(struct in_addr *pdns_addr)
62{
379ff53d
FB
63 FIXED_INFO *FixedInfo=NULL;
64 ULONG BufLen;
65 DWORD ret;
66 IP_ADDR_STRING *pIPAddr;
67 struct in_addr tmp_addr;
3b46e624 68
379ff53d
FB
69 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
70 BufLen = sizeof(FIXED_INFO);
3b46e624 71
379ff53d
FB
72 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
73 if (FixedInfo) {
74 GlobalFree(FixedInfo);
75 FixedInfo = NULL;
76 }
77 FixedInfo = GlobalAlloc(GPTR, BufLen);
78 }
5fafdf24 79
379ff53d
FB
80 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
81 printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
82 if (FixedInfo) {
83 GlobalFree(FixedInfo);
84 FixedInfo = NULL;
85 }
86 return -1;
87 }
3b46e624 88
379ff53d
FB
89 pIPAddr = &(FixedInfo->DnsServerList);
90 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
91 *pdns_addr = tmp_addr;
92#if 0
93 printf( "DNS Servers:\n" );
94 printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
3b46e624 95
379ff53d
FB
96 pIPAddr = FixedInfo -> DnsServerList.Next;
97 while ( pIPAddr ) {
98 printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
99 pIPAddr = pIPAddr ->Next;
100 }
101#endif
102 if (FixedInfo) {
103 GlobalFree(FixedInfo);
104 FixedInfo = NULL;
105 }
106 return 0;
f0cbd3ec
FB
107}
108
109#else
110
111static int get_dns_addr(struct in_addr *pdns_addr)
112{
113 char buff[512];
363a37d5 114 char buff2[257];
f0cbd3ec
FB
115 FILE *f;
116 int found = 0;
117 struct in_addr tmp_addr;
3b46e624 118
f0cbd3ec
FB
119 f = fopen("/etc/resolv.conf", "r");
120 if (!f)
121 return -1;
122
31a60e22 123#ifdef DEBUG
f0cbd3ec 124 lprint("IP address of your DNS(s): ");
31a60e22 125#endif
f0cbd3ec
FB
126 while (fgets(buff, 512, f) != NULL) {
127 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
128 if (!inet_aton(buff2, &tmp_addr))
129 continue;
130 if (tmp_addr.s_addr == loopback_addr.s_addr)
131 tmp_addr = our_addr;
132 /* If it's the first one, set it to dns_addr */
133 if (!found)
134 *pdns_addr = tmp_addr;
31a60e22 135#ifdef DEBUG
f0cbd3ec
FB
136 else
137 lprint(", ");
31a60e22 138#endif
f0cbd3ec 139 if (++found > 3) {
31a60e22 140#ifdef DEBUG
f0cbd3ec 141 lprint("(more)");
31a60e22 142#endif
f0cbd3ec 143 break;
31a60e22
BS
144 }
145#ifdef DEBUG
146 else
f0cbd3ec 147 lprint("%s", inet_ntoa(tmp_addr));
31a60e22 148#endif
f0cbd3ec
FB
149 }
150 }
1d43a717 151 fclose(f);
f0cbd3ec
FB
152 if (!found)
153 return -1;
154 return 0;
155}
156
157#endif
158
379ff53d 159#ifdef _WIN32
9634d903 160static void slirp_cleanup(void)
379ff53d
FB
161{
162 WSACleanup();
163}
164#endif
165
f0cbd3ec
FB
166void slirp_init(void)
167{
512176db 168 // debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
3b46e624 169
379ff53d
FB
170#ifdef _WIN32
171 {
172 WSADATA Data;
173 WSAStartup(MAKEWORD(2,0), &Data);
174 atexit(slirp_cleanup);
175 }
176#endif
177
f0cbd3ec
FB
178 link_up = 1;
179
180 if_init();
181 ip_init();
182
183 /* Initialise mbufs *after* setting the MTU */
184 m_init();
185
186 /* set default addresses */
f0cbd3ec
FB
187 inet_aton("127.0.0.1", &loopback_addr);
188
189 if (get_dns_addr(&dns_addr) < 0) {
0f8134bf
PB
190 dns_addr = loopback_addr;
191 fprintf (stderr, "Warning: No DNS servers found\n");
f0cbd3ec
FB
192 }
193
194 inet_aton(CTL_SPECIAL, &special_addr);
8dbca8dd 195 alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
f4e15b4b 196 getouraddr();
f0cbd3ec
FB
197}
198
199#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
200#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
201#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
202
203/*
204 * curtime kept to an accuracy of 1ms
205 */
379ff53d
FB
206#ifdef _WIN32
207static void updtime(void)
208{
209 struct _timeb tb;
210
211 _ftime(&tb);
212 curtime = (u_int)tb.time * (u_int)1000;
213 curtime += (u_int)tb.millitm;
214}
215#else
f0cbd3ec
FB
216static void updtime(void)
217{
218 gettimeofday(&tt, 0);
5fafdf24 219
f0cbd3ec
FB
220 curtime = (u_int)tt.tv_sec * (u_int)1000;
221 curtime += (u_int)tt.tv_usec / (u_int)1000;
5fafdf24 222
f0cbd3ec
FB
223 if ((tt.tv_usec % 1000) >= 500)
224 curtime++;
225}
379ff53d 226#endif
f0cbd3ec 227
5fafdf24 228void slirp_select_fill(int *pnfds,
f0cbd3ec
FB
229 fd_set *readfds, fd_set *writefds, fd_set *xfds)
230{
231 struct socket *so, *so_next;
232 struct timeval timeout;
233 int nfds;
234 int tmp_time;
235
236 /* fail safe */
237 global_readfds = NULL;
238 global_writefds = NULL;
239 global_xfds = NULL;
3b46e624 240
f0cbd3ec
FB
241 nfds = *pnfds;
242 /*
243 * First, TCP sockets
244 */
245 do_slowtimo = 0;
246 if (link_up) {
5fafdf24 247 /*
f0cbd3ec
FB
248 * *_slowtimo needs calling if there are IP fragments
249 * in the fragment queue, or there are TCP connections active
250 */
251 do_slowtimo = ((tcb.so_next != &tcb) ||
252 ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
3b46e624 253
f0cbd3ec
FB
254 for (so = tcb.so_next; so != &tcb; so = so_next) {
255 so_next = so->so_next;
3b46e624 256
f0cbd3ec
FB
257 /*
258 * See if we need a tcp_fasttimo
259 */
260 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
261 time_fasttimo = curtime; /* Flag when we want a fasttimo */
3b46e624 262
f0cbd3ec
FB
263 /*
264 * NOFDREF can include still connecting to local-host,
265 * newly socreated() sockets etc. Don't want to select these.
266 */
267 if (so->so_state & SS_NOFDREF || so->s == -1)
268 continue;
3b46e624 269
f0cbd3ec
FB
270 /*
271 * Set for reading sockets which are accepting
272 */
273 if (so->so_state & SS_FACCEPTCONN) {
274 FD_SET(so->s, readfds);
275 UPD_NFDS(so->s);
276 continue;
277 }
3b46e624 278
f0cbd3ec
FB
279 /*
280 * Set for writing sockets which are connecting
281 */
282 if (so->so_state & SS_ISFCONNECTING) {
283 FD_SET(so->s, writefds);
284 UPD_NFDS(so->s);
285 continue;
286 }
3b46e624 287
f0cbd3ec
FB
288 /*
289 * Set for writing if we are connected, can send more, and
290 * we have something to send
291 */
292 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
293 FD_SET(so->s, writefds);
294 UPD_NFDS(so->s);
295 }
3b46e624 296
f0cbd3ec
FB
297 /*
298 * Set for reading (and urgent data) if we are connected, can
299 * receive more, and we have room for it XXX /2 ?
300 */
301 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
302 FD_SET(so->s, readfds);
303 FD_SET(so->s, xfds);
304 UPD_NFDS(so->s);
305 }
306 }
3b46e624 307
f0cbd3ec
FB
308 /*
309 * UDP sockets
310 */
311 for (so = udb.so_next; so != &udb; so = so_next) {
312 so_next = so->so_next;
3b46e624 313
f0cbd3ec
FB
314 /*
315 * See if it's timed out
316 */
317 if (so->so_expire) {
318 if (so->so_expire <= curtime) {
319 udp_detach(so);
320 continue;
321 } else
322 do_slowtimo = 1; /* Let socket expire */
323 }
3b46e624 324
f0cbd3ec
FB
325 /*
326 * When UDP packets are received from over the
327 * link, they're sendto()'d straight away, so
328 * no need for setting for writing
329 * Limit the number of packets queued by this session
330 * to 4. Note that even though we try and limit this
331 * to 4 packets, the session could have more queued
332 * if the packets needed to be fragmented
333 * (XXX <= 4 ?)
334 */
335 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
336 FD_SET(so->s, readfds);
337 UPD_NFDS(so->s);
338 }
339 }
340 }
5fafdf24 341
f0cbd3ec
FB
342 /*
343 * Setup timeout to use minimum CPU usage, especially when idle
344 */
5fafdf24
TS
345
346 /*
f0cbd3ec
FB
347 * First, see the timeout needed by *timo
348 */
349 timeout.tv_sec = 0;
350 timeout.tv_usec = -1;
351 /*
352 * If a slowtimo is needed, set timeout to 500ms from the last
353 * slow timeout. If a fast timeout is needed, set timeout within
354 * 200ms of when it was requested.
355 */
356 if (do_slowtimo) {
357 /* XXX + 10000 because some select()'s aren't that accurate */
358 timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
359 if (timeout.tv_usec < 0)
360 timeout.tv_usec = 0;
361 else if (timeout.tv_usec > 510000)
362 timeout.tv_usec = 510000;
3b46e624 363
f0cbd3ec
FB
364 /* Can only fasttimo if we also slowtimo */
365 if (time_fasttimo) {
366 tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
367 if (tmp_time < 0)
368 tmp_time = 0;
3b46e624 369
f0cbd3ec
FB
370 /* Choose the smallest of the 2 */
371 if (tmp_time < timeout.tv_usec)
372 timeout.tv_usec = (u_int)tmp_time;
373 }
374 }
375 *pnfds = nfds;
5fafdf24 376}
f0cbd3ec
FB
377
378void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
379{
380 struct socket *so, *so_next;
381 int ret;
382
383 global_readfds = readfds;
384 global_writefds = writefds;
385 global_xfds = xfds;
386
387 /* Update time */
388 updtime();
5fafdf24 389
f0cbd3ec 390 /*
5fafdf24 391 * See if anything has timed out
f0cbd3ec
FB
392 */
393 if (link_up) {
df5f8956 394 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
f0cbd3ec
FB
395 tcp_fasttimo();
396 time_fasttimo = 0;
397 }
398 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
399 ip_slowtimo();
400 tcp_slowtimo();
401 last_slowtimo = curtime;
402 }
403 }
5fafdf24 404
f0cbd3ec
FB
405 /*
406 * Check sockets
407 */
408 if (link_up) {
409 /*
410 * Check TCP sockets
411 */
412 for (so = tcb.so_next; so != &tcb; so = so_next) {
413 so_next = so->so_next;
3b46e624 414
f0cbd3ec
FB
415 /*
416 * FD_ISSET is meaningless on these sockets
417 * (and they can crash the program)
418 */
419 if (so->so_state & SS_NOFDREF || so->s == -1)
420 continue;
3b46e624 421
f0cbd3ec
FB
422 /*
423 * Check for URG data
424 * This will soread as well, so no need to
425 * test for readfds below if this succeeds
426 */
427 if (FD_ISSET(so->s, xfds))
428 sorecvoob(so);
429 /*
430 * Check sockets for reading
431 */
432 else if (FD_ISSET(so->s, readfds)) {
433 /*
434 * Check for incoming connections
435 */
436 if (so->so_state & SS_FACCEPTCONN) {
437 tcp_connect(so);
438 continue;
439 } /* else */
440 ret = soread(so);
3b46e624 441
f0cbd3ec
FB
442 /* Output it if we read something */
443 if (ret > 0)
444 tcp_output(sototcpcb(so));
445 }
3b46e624 446
f0cbd3ec
FB
447 /*
448 * Check sockets for writing
449 */
450 if (FD_ISSET(so->s, writefds)) {
451 /*
452 * Check for non-blocking, still-connecting sockets
453 */
454 if (so->so_state & SS_ISFCONNECTING) {
455 /* Connected */
456 so->so_state &= ~SS_ISFCONNECTING;
3b46e624 457
02d2c54c 458 ret = send(so->s, &ret, 0, 0);
f0cbd3ec
FB
459 if (ret < 0) {
460 /* XXXXX Must fix, zero bytes is a NOP */
461 if (errno == EAGAIN || errno == EWOULDBLOCK ||
462 errno == EINPROGRESS || errno == ENOTCONN)
463 continue;
3b46e624 464
f0cbd3ec
FB
465 /* else failed */
466 so->so_state = SS_NOFDREF;
467 }
468 /* else so->so_state &= ~SS_ISFCONNECTING; */
3b46e624 469
f0cbd3ec
FB
470 /*
471 * Continue tcp_input
472 */
473 tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
474 /* continue; */
475 } else
476 ret = sowrite(so);
477 /*
5fafdf24 478 * XXXXX If we wrote something (a lot), there
f0cbd3ec
FB
479 * could be a need for a window update.
480 * In the worst case, the remote will send
481 * a window probe to get things going again
482 */
483 }
3b46e624 484
f0cbd3ec
FB
485 /*
486 * Probe a still-connecting, non-blocking socket
487 * to check if it's still alive
488 */
489#ifdef PROBE_CONN
490 if (so->so_state & SS_ISFCONNECTING) {
02d2c54c 491 ret = recv(so->s, (char *)&ret, 0,0);
3b46e624 492
f0cbd3ec
FB
493 if (ret < 0) {
494 /* XXX */
495 if (errno == EAGAIN || errno == EWOULDBLOCK ||
496 errno == EINPROGRESS || errno == ENOTCONN)
497 continue; /* Still connecting, continue */
3b46e624 498
f0cbd3ec
FB
499 /* else failed */
500 so->so_state = SS_NOFDREF;
3b46e624 501
f0cbd3ec
FB
502 /* tcp_input will take care of it */
503 } else {
02d2c54c 504 ret = send(so->s, &ret, 0,0);
f0cbd3ec
FB
505 if (ret < 0) {
506 /* XXX */
507 if (errno == EAGAIN || errno == EWOULDBLOCK ||
508 errno == EINPROGRESS || errno == ENOTCONN)
509 continue;
510 /* else failed */
511 so->so_state = SS_NOFDREF;
512 } else
513 so->so_state &= ~SS_ISFCONNECTING;
3b46e624 514
f0cbd3ec
FB
515 }
516 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
517 } /* SS_ISFCONNECTING */
518#endif
519 }
3b46e624 520
f0cbd3ec
FB
521 /*
522 * Now UDP sockets.
523 * Incoming packets are sent straight away, they're not buffered.
524 * Incoming UDP data isn't buffered either.
525 */
526 for (so = udb.so_next; so != &udb; so = so_next) {
527 so_next = so->so_next;
3b46e624 528
f0cbd3ec
FB
529 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
530 sorecvfrom(so);
531 }
532 }
533 }
5fafdf24 534
f0cbd3ec
FB
535 /*
536 * See if we can start outputting
537 */
538 if (if_queued && link_up)
539 if_start();
02d2c54c
FB
540
541 /* clear global file descriptor sets.
542 * these reside on the stack in vl.c
543 * so they're unusable if we're not in
544 * slirp_select_fill or slirp_select_poll.
545 */
546 global_readfds = NULL;
547 global_writefds = NULL;
548 global_xfds = NULL;
f0cbd3ec
FB
549}
550
551#define ETH_ALEN 6
552#define ETH_HLEN 14
553
554#define ETH_P_IP 0x0800 /* Internet Protocol packet */
555#define ETH_P_ARP 0x0806 /* Address Resolution packet */
556
557#define ARPOP_REQUEST 1 /* ARP request */
558#define ARPOP_REPLY 2 /* ARP reply */
559
5fafdf24 560struct ethhdr
f0cbd3ec
FB
561{
562 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
563 unsigned char h_source[ETH_ALEN]; /* source ether addr */
564 unsigned short h_proto; /* packet type ID field */
565};
566
567struct arphdr
568{
569 unsigned short ar_hrd; /* format of hardware address */
570 unsigned short ar_pro; /* format of protocol address */
571 unsigned char ar_hln; /* length of hardware address */
572 unsigned char ar_pln; /* length of protocol address */
573 unsigned short ar_op; /* ARP opcode (command) */
574
575 /*
576 * Ethernet looks like this : This bit is variable sized however...
577 */
578 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
579 unsigned char ar_sip[4]; /* sender IP address */
580 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
581 unsigned char ar_tip[4]; /* target IP address */
582};
583
8fcd3692 584static void arp_input(const uint8_t *pkt, int pkt_len)
f0cbd3ec
FB
585{
586 struct ethhdr *eh = (struct ethhdr *)pkt;
587 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
588 uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
589 struct ethhdr *reh = (struct ethhdr *)arp_reply;
590 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
591 int ar_op;
a3d4af03 592 struct ex_list *ex_ptr;
f0cbd3ec
FB
593
594 ar_op = ntohs(ah->ar_op);
595 switch(ar_op) {
596 case ARPOP_REQUEST:
a3d4af03 597 if (!memcmp(ah->ar_tip, &special_addr, 3)) {
5fafdf24 598 if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
a3d4af03
FB
599 goto arp_ok;
600 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
601 if (ex_ptr->ex_addr == ah->ar_tip[3])
602 goto arp_ok;
603 }
604 return;
605 arp_ok:
f0cbd3ec
FB
606 /* XXX: make an ARP request to have the client address */
607 memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
608
609 /* ARP request for alias/dns mac address */
610 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
611 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
612 reh->h_source[5] = ah->ar_tip[3];
613 reh->h_proto = htons(ETH_P_ARP);
614
615 rah->ar_hrd = htons(1);
616 rah->ar_pro = htons(ETH_P_IP);
617 rah->ar_hln = ETH_ALEN;
618 rah->ar_pln = 4;
619 rah->ar_op = htons(ARPOP_REPLY);
620 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
621 memcpy(rah->ar_sip, ah->ar_tip, 4);
622 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
623 memcpy(rah->ar_tip, ah->ar_sip, 4);
624 slirp_output(arp_reply, sizeof(arp_reply));
625 }
626 break;
de806f07
FB
627 case ARPOP_REPLY:
628 /* reply to request of client mac address ? */
629 if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
630 !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
631 memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
632 }
633 break;
f0cbd3ec
FB
634 default:
635 break;
636 }
637}
638
639void slirp_input(const uint8_t *pkt, int pkt_len)
640{
641 struct mbuf *m;
642 int proto;
643
644 if (pkt_len < ETH_HLEN)
645 return;
3b46e624 646
f0cbd3ec
FB
647 proto = ntohs(*(uint16_t *)(pkt + 12));
648 switch(proto) {
649 case ETH_P_ARP:
650 arp_input(pkt, pkt_len);
651 break;
652 case ETH_P_IP:
653 m = m_get();
654 if (!m)
655 return;
38f3e7c2 656 /* Note: we add to align the IP header */
e8e880a7
AJ
657 if (M_FREEROOM(m) < pkt_len + 2) {
658 m_inc(m, pkt_len + 2);
659 }
38f3e7c2
FB
660 m->m_len = pkt_len + 2;
661 memcpy(m->m_data + 2, pkt, pkt_len);
f0cbd3ec 662
38f3e7c2
FB
663 m->m_data += 2 + ETH_HLEN;
664 m->m_len -= 2 + ETH_HLEN;
f0cbd3ec
FB
665
666 ip_input(m);
667 break;
668 default:
669 break;
670 }
671}
672
673/* output the IP packet to the ethernet device */
674void if_encap(const uint8_t *ip_data, int ip_data_len)
675{
676 uint8_t buf[1600];
677 struct ethhdr *eh = (struct ethhdr *)buf;
678
679 if (ip_data_len + ETH_HLEN > sizeof(buf))
680 return;
de806f07
FB
681
682 if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
683 uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
684 struct ethhdr *reh = (struct ethhdr *)arp_req;
685 struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
686 const struct ip *iph = (const struct ip *)ip_data;
687
688 /* If the client addr is not known, there is no point in
689 sending the packet to it. Normally the sender should have
690 done an ARP request to get its MAC address. Here we do it
691 in place of sending the packet and we hope that the sender
692 will retry sending its packet. */
693 memset(reh->h_dest, 0xff, ETH_ALEN);
694 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
695 reh->h_source[5] = CTL_ALIAS;
696 reh->h_proto = htons(ETH_P_ARP);
697 rah->ar_hrd = htons(1);
698 rah->ar_pro = htons(ETH_P_IP);
699 rah->ar_hln = ETH_ALEN;
700 rah->ar_pln = 4;
701 rah->ar_op = htons(ARPOP_REQUEST);
702 /* source hw addr */
703 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
704 rah->ar_sha[5] = CTL_ALIAS;
705 /* source IP */
706 memcpy(rah->ar_sip, &alias_addr, 4);
707 /* target hw addr (none) */
708 memset(rah->ar_tha, 0, ETH_ALEN);
709 /* target IP */
710 memcpy(rah->ar_tip, &iph->ip_dst, 4);
711 client_ipaddr = iph->ip_dst;
712 slirp_output(arp_req, sizeof(arp_req));
713 } else {
714 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
715 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
716 /* XXX: not correct */
717 eh->h_source[5] = CTL_ALIAS;
718 eh->h_proto = htons(ETH_P_IP);
719 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
720 slirp_output(buf, ip_data_len + ETH_HLEN);
721 }
f0cbd3ec 722}
9bf05444 723
5fafdf24 724int slirp_redir(int is_udp, int host_port,
9bf05444
FB
725 struct in_addr guest_addr, int guest_port)
726{
727 if (is_udp) {
5fafdf24 728 if (!udp_listen(htons(host_port), guest_addr.s_addr,
9bf05444
FB
729 htons(guest_port), 0))
730 return -1;
731 } else {
5fafdf24 732 if (!solisten(htons(host_port), guest_addr.s_addr,
9bf05444
FB
733 htons(guest_port), 0))
734 return -1;
735 }
736 return 0;
737}
a3d4af03 738
5fafdf24 739int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
a3d4af03
FB
740 int guest_port)
741{
5fafdf24 742 return add_exec(&exec_list, do_pty, (char *)args,
a3d4af03
FB
743 addr_low_byte, htons(guest_port));
744}