Statistics
| Branch: | Revision:

root / slirp / slirp.c @ 5fafdf24

History | View | Annotate | Download (16.3 kB)

1
#include "slirp.h"
2

    
3
/* host address */
4
struct in_addr our_addr;
5
/* host dns address */
6
struct in_addr dns_addr;
7
/* host loopback address */
8
struct in_addr loopback_addr;
9

    
10
/* address for slirp virtual addresses */
11
struct in_addr special_addr;
12
/* virtual address alias for host */
13
struct in_addr alias_addr;
14

    
15
const uint8_t special_ethaddr[6] = {
16
    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
17
};
18

    
19
uint8_t client_ethaddr[6];
20

    
21
int do_slowtimo;
22
int link_up;
23
struct timeval tt;
24
FILE *lfd;
25
struct ex_list *exec_list;
26

    
27
/* XXX: suppress those select globals */
28
fd_set *global_readfds, *global_writefds, *global_xfds;
29

    
30
char slirp_hostname[33];
31

    
32
#ifdef _WIN32
33

    
34
static int get_dns_addr(struct in_addr *pdns_addr)
35
{
36
    FIXED_INFO *FixedInfo=NULL;
37
    ULONG    BufLen;
38
    DWORD    ret;
39
    IP_ADDR_STRING *pIPAddr;
40
    struct in_addr tmp_addr;
41
   
42
    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
43
    BufLen = sizeof(FIXED_INFO);
44
  
45
    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
46
        if (FixedInfo) {
47
            GlobalFree(FixedInfo);
48
            FixedInfo = NULL;
49
        }
50
        FixedInfo = GlobalAlloc(GPTR, BufLen);
51
    }
52

    
53
    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
54
        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
55
        if (FixedInfo) {
56
            GlobalFree(FixedInfo);
57
            FixedInfo = NULL;
58
        }
59
        return -1;
60
    }
61
    
62
    pIPAddr = &(FixedInfo->DnsServerList);
63
    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
64
    *pdns_addr = tmp_addr;
65
#if 0
66
    printf( "DNS Servers:\n" );
67
    printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
68
   
69
    pIPAddr = FixedInfo -> DnsServerList.Next;
70
    while ( pIPAddr ) {
71
            printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
72
            pIPAddr = pIPAddr ->Next;
73
    }
74
#endif
75
    if (FixedInfo) {
76
        GlobalFree(FixedInfo);
77
        FixedInfo = NULL;
78
    }
79
    return 0;
80
}
81

    
82
#else
83

    
84
static int get_dns_addr(struct in_addr *pdns_addr)
85
{
86
    char buff[512];
87
    char buff2[256];
88
    FILE *f;
89
    int found = 0;
90
    struct in_addr tmp_addr;
91
   
92
    f = fopen("/etc/resolv.conf", "r");
93
    if (!f)
94
        return -1;
95

    
96
    lprint("IP address of your DNS(s): ");
97
    while (fgets(buff, 512, f) != NULL) {
98
        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
99
            if (!inet_aton(buff2, &tmp_addr))
100
                continue;
101
            if (tmp_addr.s_addr == loopback_addr.s_addr)
102
                tmp_addr = our_addr;
103
            /* If it's the first one, set it to dns_addr */
104
            if (!found)
105
                *pdns_addr = tmp_addr;
106
            else
107
                lprint(", ");
108
            if (++found > 3) {
109
                lprint("(more)");
110
                break;
111
            } else
112
                lprint("%s", inet_ntoa(tmp_addr));
113
        }
114
    }
115
    fclose(f);
116
    if (!found)
117
        return -1;
118
    return 0;
119
}
120

    
121
#endif
122

    
123
#ifdef _WIN32
124
void slirp_cleanup(void)
125
{
126
    WSACleanup();
127
}
128
#endif
129

    
130
void slirp_init(void)
131
{
132
    //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
133
   
134
#ifdef _WIN32
135
    {
136
        WSADATA Data;
137
        WSAStartup(MAKEWORD(2,0), &Data);
138
        atexit(slirp_cleanup);
139
    }
140
#endif
141

    
142
    link_up = 1;
143

    
144
    if_init();
145
    ip_init();
146

    
147
    /* Initialise mbufs *after* setting the MTU */
148
    m_init();
149

    
150
    /* set default addresses */
151
    inet_aton("127.0.0.1", &loopback_addr);
152

    
153
    if (get_dns_addr(&dns_addr) < 0) {
154
        dns_addr = loopback_addr;
155
        fprintf (stderr, "Warning: No DNS servers found\n");
156
    }
157

    
158
    inet_aton(CTL_SPECIAL, &special_addr);
159
    alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
160
    getouraddr();
161
}
162

    
163
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
164
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
165
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
166

    
167
/*
168
 * curtime kept to an accuracy of 1ms
169
 */
170
#ifdef _WIN32
171
static void updtime(void)
172
{
173
    struct _timeb tb;
174

    
175
    _ftime(&tb);
176
    curtime = (u_int)tb.time * (u_int)1000;
177
    curtime += (u_int)tb.millitm;
178
}
179
#else
180
static void updtime(void)
181
{
182
        gettimeofday(&tt, 0);
183

    
184
        curtime = (u_int)tt.tv_sec * (u_int)1000;
185
        curtime += (u_int)tt.tv_usec / (u_int)1000;
186

    
187
        if ((tt.tv_usec % 1000) >= 500)
188
           curtime++;
189
}
190
#endif
191

    
192
void slirp_select_fill(int *pnfds,
193
                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
194
{
195
    struct socket *so, *so_next;
196
    struct timeval timeout;
197
    int nfds;
198
    int tmp_time;
199

    
200
    /* fail safe */
201
    global_readfds = NULL;
202
    global_writefds = NULL;
203
    global_xfds = NULL;
204
   
205
    nfds = *pnfds;
206
        /*
207
         * First, TCP sockets
208
         */
209
        do_slowtimo = 0;
210
        if (link_up) {
211
                /*
212
                 * *_slowtimo needs calling if there are IP fragments
213
                 * in the fragment queue, or there are TCP connections active
214
                 */
215
                do_slowtimo = ((tcb.so_next != &tcb) ||
216
                               ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
217
        
218
                for (so = tcb.so_next; so != &tcb; so = so_next) {
219
                        so_next = so->so_next;
220
                
221
                        /*
222
                         * See if we need a tcp_fasttimo
223
                         */
224
                        if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
225
                           time_fasttimo = curtime; /* Flag when we want a fasttimo */
226
                
227
                        /*
228
                         * NOFDREF can include still connecting to local-host,
229
                         * newly socreated() sockets etc. Don't want to select these.
230
                          */
231
                        if (so->so_state & SS_NOFDREF || so->s == -1)
232
                           continue;
233
                
234
                        /*
235
                         * Set for reading sockets which are accepting
236
                         */
237
                        if (so->so_state & SS_FACCEPTCONN) {
238
                                FD_SET(so->s, readfds);
239
                                UPD_NFDS(so->s);
240
                                continue;
241
                        }
242
                
243
                        /*
244
                         * Set for writing sockets which are connecting
245
                         */
246
                        if (so->so_state & SS_ISFCONNECTING) {
247
                                FD_SET(so->s, writefds);
248
                                UPD_NFDS(so->s);
249
                                continue;
250
                        }
251
                
252
                        /*
253
                         * Set for writing if we are connected, can send more, and
254
                         * we have something to send
255
                         */
256
                        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
257
                                FD_SET(so->s, writefds);
258
                                UPD_NFDS(so->s);
259
                        }
260
                
261
                        /*
262
                         * Set for reading (and urgent data) if we are connected, can
263
                         * receive more, and we have room for it XXX /2 ?
264
                         */
265
                        if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
266
                                FD_SET(so->s, readfds);
267
                                FD_SET(so->s, xfds);
268
                                UPD_NFDS(so->s);
269
                        }
270
                }
271
        
272
                /*
273
                 * UDP sockets
274
                 */
275
                for (so = udb.so_next; so != &udb; so = so_next) {
276
                        so_next = so->so_next;
277
                
278
                        /*
279
                         * See if it's timed out
280
                         */
281
                        if (so->so_expire) {
282
                                if (so->so_expire <= curtime) {
283
                                        udp_detach(so);
284
                                        continue;
285
                                } else
286
                                        do_slowtimo = 1; /* Let socket expire */
287
                        }
288
                
289
                        /*
290
                         * When UDP packets are received from over the
291
                         * link, they're sendto()'d straight away, so
292
                         * no need for setting for writing
293
                         * Limit the number of packets queued by this session
294
                         * to 4.  Note that even though we try and limit this
295
                         * to 4 packets, the session could have more queued
296
                         * if the packets needed to be fragmented
297
                         * (XXX <= 4 ?)
298
                         */
299
                        if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
300
                                FD_SET(so->s, readfds);
301
                                UPD_NFDS(so->s);
302
                        }
303
                }
304
        }
305

    
306
        /*
307
         * Setup timeout to use minimum CPU usage, especially when idle
308
         */
309

    
310
        /*
311
         * First, see the timeout needed by *timo
312
         */
313
        timeout.tv_sec = 0;
314
        timeout.tv_usec = -1;
315
        /*
316
         * If a slowtimo is needed, set timeout to 500ms from the last
317
         * slow timeout. If a fast timeout is needed, set timeout within
318
         * 200ms of when it was requested.
319
         */
320
        if (do_slowtimo) {
321
                /* XXX + 10000 because some select()'s aren't that accurate */
322
                timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
323
                if (timeout.tv_usec < 0)
324
                   timeout.tv_usec = 0;
325
                else if (timeout.tv_usec > 510000)
326
                   timeout.tv_usec = 510000;
327
        
328
                /* Can only fasttimo if we also slowtimo */
329
                if (time_fasttimo) {
330
                        tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
331
                        if (tmp_time < 0)
332
                           tmp_time = 0;
333
                
334
                        /* Choose the smallest of the 2 */
335
                        if (tmp_time < timeout.tv_usec)
336
                           timeout.tv_usec = (u_int)tmp_time;
337
                }
338
        }
339
        *pnfds = nfds;
340
}
341

    
342
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
343
{
344
    struct socket *so, *so_next;
345
    int ret;
346

    
347
    global_readfds = readfds;
348
    global_writefds = writefds;
349
    global_xfds = xfds;
350

    
351
        /* Update time */
352
        updtime();
353

    
354
        /*
355
         * See if anything has timed out
356
         */
357
        if (link_up) {
358
                if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
359
                        tcp_fasttimo();
360
                        time_fasttimo = 0;
361
                }
362
                if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
363
                        ip_slowtimo();
364
                        tcp_slowtimo();
365
                        last_slowtimo = curtime;
366
                }
367
        }
368

    
369
        /*
370
         * Check sockets
371
         */
372
        if (link_up) {
373
                /*
374
                 * Check TCP sockets
375
                 */
376
                for (so = tcb.so_next; so != &tcb; so = so_next) {
377
                        so_next = so->so_next;
378
                
379
                        /*
380
                         * FD_ISSET is meaningless on these sockets
381
                         * (and they can crash the program)
382
                         */
383
                        if (so->so_state & SS_NOFDREF || so->s == -1)
384
                           continue;
385
                
386
                        /*
387
                         * Check for URG data
388
                         * This will soread as well, so no need to
389
                         * test for readfds below if this succeeds
390
                         */
391
                        if (FD_ISSET(so->s, xfds))
392
                           sorecvoob(so);
393
                        /*
394
                         * Check sockets for reading
395
                         */
396
                        else if (FD_ISSET(so->s, readfds)) {
397
                                /*
398
                                 * Check for incoming connections
399
                                 */
400
                                if (so->so_state & SS_FACCEPTCONN) {
401
                                        tcp_connect(so);
402
                                        continue;
403
                                } /* else */
404
                                ret = soread(so);
405
                        
406
                                /* Output it if we read something */
407
                                if (ret > 0)
408
                                   tcp_output(sototcpcb(so));
409
                        }
410
                
411
                        /*
412
                         * Check sockets for writing
413
                         */
414
                        if (FD_ISSET(so->s, writefds)) {
415
                          /*
416
                           * Check for non-blocking, still-connecting sockets
417
                           */
418
                          if (so->so_state & SS_ISFCONNECTING) {
419
                            /* Connected */
420
                            so->so_state &= ~SS_ISFCONNECTING;
421
                           
422
                            ret = send(so->s, &ret, 0, 0);
423
                            if (ret < 0) {
424
                              /* XXXXX Must fix, zero bytes is a NOP */
425
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
426
                                  errno == EINPROGRESS || errno == ENOTCONN)
427
                                continue;
428
                             
429
                              /* else failed */
430
                              so->so_state = SS_NOFDREF;
431
                            }
432
                            /* else so->so_state &= ~SS_ISFCONNECTING; */
433
                           
434
                            /*
435
                             * Continue tcp_input
436
                             */
437
                            tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
438
                            /* continue; */
439
                          } else
440
                            ret = sowrite(so);
441
                          /*
442
                           * XXXXX If we wrote something (a lot), there
443
                           * could be a need for a window update.
444
                           * In the worst case, the remote will send
445
                           * a window probe to get things going again
446
                           */
447
                        }
448
                
449
                        /*
450
                         * Probe a still-connecting, non-blocking socket
451
                         * to check if it's still alive
452
                           */
453
#ifdef PROBE_CONN
454
                        if (so->so_state & SS_ISFCONNECTING) {
455
                          ret = recv(so->s, (char *)&ret, 0,0);
456
                         
457
                          if (ret < 0) {
458
                            /* XXX */
459
                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
460
                                errno == EINPROGRESS || errno == ENOTCONN)
461
                              continue; /* Still connecting, continue */
462
                           
463
                            /* else failed */
464
                            so->so_state = SS_NOFDREF;
465
                           
466
                            /* tcp_input will take care of it */
467
                          } else {
468
                            ret = send(so->s, &ret, 0,0);
469
                            if (ret < 0) {
470
                              /* XXX */
471
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
472
                                  errno == EINPROGRESS || errno == ENOTCONN)
473
                                continue;
474
                              /* else failed */
475
                              so->so_state = SS_NOFDREF;
476
                            } else
477
                              so->so_state &= ~SS_ISFCONNECTING;
478
                           
479
                          }
480
                          tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
481
                        } /* SS_ISFCONNECTING */
482
#endif
483
                }
484
        
485
                /*
486
                 * Now UDP sockets.
487
                 * Incoming packets are sent straight away, they're not buffered.
488
                 * Incoming UDP data isn't buffered either.
489
                 */
490
                for (so = udb.so_next; so != &udb; so = so_next) {
491
                        so_next = so->so_next;
492
                
493
                        if (so->s != -1 && FD_ISSET(so->s, readfds)) {
494
                            sorecvfrom(so);
495
                        }
496
                }
497
        }
498

    
499
        /*
500
         * See if we can start outputting
501
         */
502
        if (if_queued && link_up)
503
           if_start();
504

    
505
        /* clear global file descriptor sets.
506
         * these reside on the stack in vl.c
507
         * so they're unusable if we're not in
508
         * slirp_select_fill or slirp_select_poll.
509
         */
510
         global_readfds = NULL;
511
         global_writefds = NULL;
512
         global_xfds = NULL;
513
}
514

    
515
#define ETH_ALEN 6
516
#define ETH_HLEN 14
517

    
518
#define ETH_P_IP        0x0800                /* Internet Protocol packet        */
519
#define ETH_P_ARP        0x0806                /* Address Resolution packet        */
520

    
521
#define        ARPOP_REQUEST        1                /* ARP request                        */
522
#define        ARPOP_REPLY        2                /* ARP reply                        */
523

    
524
struct ethhdr
525
{
526
        unsigned char        h_dest[ETH_ALEN];        /* destination eth addr        */
527
        unsigned char        h_source[ETH_ALEN];        /* source ether addr        */
528
        unsigned short        h_proto;                /* packet type ID field        */
529
};
530

    
531
struct arphdr
532
{
533
        unsigned short        ar_hrd;                /* format of hardware address        */
534
        unsigned short        ar_pro;                /* format of protocol address        */
535
        unsigned char        ar_hln;                /* length of hardware address        */
536
        unsigned char        ar_pln;                /* length of protocol address        */
537
        unsigned short        ar_op;                /* ARP opcode (command)                */
538

    
539
         /*
540
          *         Ethernet looks like this : This bit is variable sized however...
541
          */
542
        unsigned char                ar_sha[ETH_ALEN];        /* sender hardware address        */
543
        unsigned char                ar_sip[4];                /* sender IP address                */
544
        unsigned char                ar_tha[ETH_ALEN];        /* target hardware address        */
545
        unsigned char                ar_tip[4];                /* target IP address                */
546
};
547

    
548
void arp_input(const uint8_t *pkt, int pkt_len)
549
{
550
    struct ethhdr *eh = (struct ethhdr *)pkt;
551
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
552
    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
553
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
554
    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
555
    int ar_op;
556
    struct ex_list *ex_ptr;
557

    
558
    ar_op = ntohs(ah->ar_op);
559
    switch(ar_op) {
560
    case ARPOP_REQUEST:
561
        if (!memcmp(ah->ar_tip, &special_addr, 3)) {
562
            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
563
                goto arp_ok;
564
            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
565
                if (ex_ptr->ex_addr == ah->ar_tip[3])
566
                    goto arp_ok;
567
            }
568
            return;
569
        arp_ok:
570
            /* XXX: make an ARP request to have the client address */
571
            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
572

    
573
            /* ARP request for alias/dns mac address */
574
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
575
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
576
            reh->h_source[5] = ah->ar_tip[3];
577
            reh->h_proto = htons(ETH_P_ARP);
578

    
579
            rah->ar_hrd = htons(1);
580
            rah->ar_pro = htons(ETH_P_IP);
581
            rah->ar_hln = ETH_ALEN;
582
            rah->ar_pln = 4;
583
            rah->ar_op = htons(ARPOP_REPLY);
584
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
585
            memcpy(rah->ar_sip, ah->ar_tip, 4);
586
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
587
            memcpy(rah->ar_tip, ah->ar_sip, 4);
588
            slirp_output(arp_reply, sizeof(arp_reply));
589
        }
590
        break;
591
    default:
592
        break;
593
    }
594
}
595

    
596
void slirp_input(const uint8_t *pkt, int pkt_len)
597
{
598
    struct mbuf *m;
599
    int proto;
600

    
601
    if (pkt_len < ETH_HLEN)
602
        return;
603
   
604
    proto = ntohs(*(uint16_t *)(pkt + 12));
605
    switch(proto) {
606
    case ETH_P_ARP:
607
        arp_input(pkt, pkt_len);
608
        break;
609
    case ETH_P_IP:
610
        m = m_get();
611
        if (!m)
612
            return;
613
        /* Note: we add to align the IP header */
614
        m->m_len = pkt_len + 2;
615
        memcpy(m->m_data + 2, pkt, pkt_len);
616

    
617
        m->m_data += 2 + ETH_HLEN;
618
        m->m_len -= 2 + ETH_HLEN;
619

    
620
        ip_input(m);
621
        break;
622
    default:
623
        break;
624
    }
625
}
626

    
627
/* output the IP packet to the ethernet device */
628
void if_encap(const uint8_t *ip_data, int ip_data_len)
629
{
630
    uint8_t buf[1600];
631
    struct ethhdr *eh = (struct ethhdr *)buf;
632

    
633
    if (ip_data_len + ETH_HLEN > sizeof(buf))
634
        return;
635

    
636
    memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
637
    memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
638
    /* XXX: not correct */
639
    eh->h_source[5] = CTL_ALIAS;
640
    eh->h_proto = htons(ETH_P_IP);
641
    memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
642
    slirp_output(buf, ip_data_len + ETH_HLEN);
643
}
644

    
645
int slirp_redir(int is_udp, int host_port,
646
                struct in_addr guest_addr, int guest_port)
647
{
648
    if (is_udp) {
649
        if (!udp_listen(htons(host_port), guest_addr.s_addr,
650
                        htons(guest_port), 0))
651
            return -1;
652
    } else {
653
        if (!solisten(htons(host_port), guest_addr.s_addr,
654
                      htons(guest_port), 0))
655
            return -1;
656
    }
657
    return 0;
658
}
659

    
660
int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
661
                  int guest_port)
662
{
663
    return add_exec(&exec_list, do_pty, (char *)args,
664
                    addr_low_byte, htons(guest_port));
665
}