Statistics
| Branch: | Revision:

root / slirp / slirp.c @ c4dfa5b7

History | View | Annotate | Download (15.4 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

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

    
17
uint8_t client_ethaddr[6];
18

    
19
int do_slowtimo;
20
int link_up;
21
struct timeval tt;
22
FILE *lfd;
23

    
24
/* XXX: suppress those select globals */
25
fd_set *global_readfds, *global_writefds, *global_xfds;
26

    
27
#ifdef _WIN32
28

    
29
static int get_dns_addr(struct in_addr *pdns_addr)
30
{
31
    FIXED_INFO *FixedInfo=NULL;
32
    ULONG    BufLen;
33
    DWORD    ret;
34
    IP_ADDR_STRING *pIPAddr;
35
    struct in_addr tmp_addr;
36
    
37
    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
38
    BufLen = sizeof(FIXED_INFO);
39
   
40
    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
41
        if (FixedInfo) {
42
            GlobalFree(FixedInfo);
43
            FixedInfo = NULL;
44
        }
45
        FixedInfo = GlobalAlloc(GPTR, BufLen);
46
    }
47
        
48
    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
49
        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
50
        if (FixedInfo) {
51
            GlobalFree(FixedInfo);
52
            FixedInfo = NULL;
53
        }
54
        return -1;
55
    }
56
     
57
    pIPAddr = &(FixedInfo->DnsServerList);
58
    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
59
    *pdns_addr = tmp_addr;
60
#if 0
61
    printf( "DNS Servers:\n" );
62
    printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
63
    
64
    pIPAddr = FixedInfo -> DnsServerList.Next;
65
    while ( pIPAddr ) {
66
            printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
67
            pIPAddr = pIPAddr ->Next;
68
    }
69
#endif
70
    if (FixedInfo) {
71
        GlobalFree(FixedInfo);
72
        FixedInfo = NULL;
73
    }
74
    return 0;
75
}
76

    
77
#else
78

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

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

    
116
#endif
117

    
118
#ifdef _WIN32
119
void slirp_cleanup(void)
120
{
121
    WSACleanup();
122
}
123
#endif
124

    
125
void slirp_init(void)
126
{
127
    //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
128
    
129
#ifdef _WIN32
130
    {
131
        WSADATA Data;
132
        WSAStartup(MAKEWORD(2,0), &Data);
133
        atexit(slirp_cleanup);
134
    }
135
#endif
136

    
137
    link_up = 1;
138

    
139
    if_init();
140
    ip_init();
141

    
142
    /* Initialise mbufs *after* setting the MTU */
143
    m_init();
144

    
145
    /* set default addresses */
146
    getouraddr();
147
    inet_aton("127.0.0.1", &loopback_addr);
148

    
149
    if (get_dns_addr(&dns_addr) < 0) {
150
        fprintf(stderr, "Could not get DNS address\n");
151
        exit(1);
152
    }
153

    
154
    inet_aton(CTL_SPECIAL, &special_addr);
155
}
156

    
157
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
158
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
159
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
160

    
161
/*
162
 * curtime kept to an accuracy of 1ms
163
 */
164
#ifdef _WIN32
165
static void updtime(void)
166
{
167
    struct _timeb tb;
168

    
169
    _ftime(&tb);
170
    curtime = (u_int)tb.time * (u_int)1000;
171
    curtime += (u_int)tb.millitm;
172
}
173
#else
174
static void updtime(void)
175
{
176
        gettimeofday(&tt, 0);
177
        
178
        curtime = (u_int)tt.tv_sec * (u_int)1000;
179
        curtime += (u_int)tt.tv_usec / (u_int)1000;
180
        
181
        if ((tt.tv_usec % 1000) >= 500)
182
           curtime++;
183
}
184
#endif
185

    
186
void slirp_select_fill(int *pnfds, 
187
                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
188
{
189
    struct socket *so, *so_next;
190
    struct timeval timeout;
191
    int nfds;
192
    int tmp_time;
193

    
194
    /* fail safe */
195
    global_readfds = NULL;
196
    global_writefds = NULL;
197
    global_xfds = NULL;
198
    
199
    nfds = *pnfds;
200
        /*
201
         * First, TCP sockets
202
         */
203
        do_slowtimo = 0;
204
        if (link_up) {
205
                /* 
206
                 * *_slowtimo needs calling if there are IP fragments
207
                 * in the fragment queue, or there are TCP connections active
208
                 */
209
                do_slowtimo = ((tcb.so_next != &tcb) ||
210
                               ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
211
                
212
                for (so = tcb.so_next; so != &tcb; so = so_next) {
213
                        so_next = so->so_next;
214
                        
215
                        /*
216
                         * See if we need a tcp_fasttimo
217
                         */
218
                        if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
219
                           time_fasttimo = curtime; /* Flag when we want a fasttimo */
220
                        
221
                        /*
222
                         * NOFDREF can include still connecting to local-host,
223
                         * newly socreated() sockets etc. Don't want to select these.
224
                          */
225
                        if (so->so_state & SS_NOFDREF || so->s == -1)
226
                           continue;
227
                        
228
                        /*
229
                         * Set for reading sockets which are accepting
230
                         */
231
                        if (so->so_state & SS_FACCEPTCONN) {
232
                                FD_SET(so->s, readfds);
233
                                UPD_NFDS(so->s);
234
                                continue;
235
                        }
236
                        
237
                        /*
238
                         * Set for writing sockets which are connecting
239
                         */
240
                        if (so->so_state & SS_ISFCONNECTING) {
241
                                FD_SET(so->s, writefds);
242
                                UPD_NFDS(so->s);
243
                                continue;
244
                        }
245
                        
246
                        /*
247
                         * Set for writing if we are connected, can send more, and
248
                         * we have something to send
249
                         */
250
                        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
251
                                FD_SET(so->s, writefds);
252
                                UPD_NFDS(so->s);
253
                        }
254
                        
255
                        /*
256
                         * Set for reading (and urgent data) if we are connected, can
257
                         * receive more, and we have room for it XXX /2 ?
258
                         */
259
                        if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
260
                                FD_SET(so->s, readfds);
261
                                FD_SET(so->s, xfds);
262
                                UPD_NFDS(so->s);
263
                        }
264
                }
265
                
266
                /*
267
                 * UDP sockets
268
                 */
269
                for (so = udb.so_next; so != &udb; so = so_next) {
270
                        so_next = so->so_next;
271
                        
272
                        /*
273
                         * See if it's timed out
274
                         */
275
                        if (so->so_expire) {
276
                                if (so->so_expire <= curtime) {
277
                                        udp_detach(so);
278
                                        continue;
279
                                } else
280
                                        do_slowtimo = 1; /* Let socket expire */
281
                        }
282
                        
283
                        /*
284
                         * When UDP packets are received from over the
285
                         * link, they're sendto()'d straight away, so
286
                         * no need for setting for writing
287
                         * Limit the number of packets queued by this session
288
                         * to 4.  Note that even though we try and limit this
289
                         * to 4 packets, the session could have more queued
290
                         * if the packets needed to be fragmented
291
                         * (XXX <= 4 ?)
292
                         */
293
                        if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
294
                                FD_SET(so->s, readfds);
295
                                UPD_NFDS(so->s);
296
                        }
297
                }
298
        }
299
        
300
        /*
301
         * Setup timeout to use minimum CPU usage, especially when idle
302
         */
303
        
304
        /* 
305
         * First, see the timeout needed by *timo
306
         */
307
        timeout.tv_sec = 0;
308
        timeout.tv_usec = -1;
309
        /*
310
         * If a slowtimo is needed, set timeout to 500ms from the last
311
         * slow timeout. If a fast timeout is needed, set timeout within
312
         * 200ms of when it was requested.
313
         */
314
        if (do_slowtimo) {
315
                /* XXX + 10000 because some select()'s aren't that accurate */
316
                timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
317
                if (timeout.tv_usec < 0)
318
                   timeout.tv_usec = 0;
319
                else if (timeout.tv_usec > 510000)
320
                   timeout.tv_usec = 510000;
321
                
322
                /* Can only fasttimo if we also slowtimo */
323
                if (time_fasttimo) {
324
                        tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
325
                        if (tmp_time < 0)
326
                           tmp_time = 0;
327
                        
328
                        /* Choose the smallest of the 2 */
329
                        if (tmp_time < timeout.tv_usec)
330
                           timeout.tv_usec = (u_int)tmp_time;
331
                }
332
        }
333
        *pnfds = nfds;
334
}        
335

    
336
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
337
{
338
    struct socket *so, *so_next;
339
    int ret;
340

    
341
    global_readfds = readfds;
342
    global_writefds = writefds;
343
    global_xfds = xfds;
344

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

    
500
#define ETH_ALEN 6
501
#define ETH_HLEN 14
502

    
503
#define ETH_P_IP        0x0800                /* Internet Protocol packet        */
504
#define ETH_P_ARP        0x0806                /* Address Resolution packet        */
505

    
506
#define        ARPOP_REQUEST        1                /* ARP request                        */
507
#define        ARPOP_REPLY        2                /* ARP reply                        */
508

    
509
struct ethhdr 
510
{
511
        unsigned char        h_dest[ETH_ALEN];        /* destination eth addr        */
512
        unsigned char        h_source[ETH_ALEN];        /* source ether addr        */
513
        unsigned short        h_proto;                /* packet type ID field        */
514
};
515

    
516
struct arphdr
517
{
518
        unsigned short        ar_hrd;                /* format of hardware address        */
519
        unsigned short        ar_pro;                /* format of protocol address        */
520
        unsigned char        ar_hln;                /* length of hardware address        */
521
        unsigned char        ar_pln;                /* length of protocol address        */
522
        unsigned short        ar_op;                /* ARP opcode (command)                */
523

    
524
         /*
525
          *         Ethernet looks like this : This bit is variable sized however...
526
          */
527
        unsigned char                ar_sha[ETH_ALEN];        /* sender hardware address        */
528
        unsigned char                ar_sip[4];                /* sender IP address                */
529
        unsigned char                ar_tha[ETH_ALEN];        /* target hardware address        */
530
        unsigned char                ar_tip[4];                /* target IP address                */
531
};
532

    
533
void arp_input(const uint8_t *pkt, int pkt_len)
534
{
535
    struct ethhdr *eh = (struct ethhdr *)pkt;
536
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
537
    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
538
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
539
    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
540
    int ar_op;
541

    
542
    ar_op = ntohs(ah->ar_op);
543
    switch(ar_op) {
544
    case ARPOP_REQUEST:
545
        if (!memcmp(ah->ar_tip, &special_addr, 3) &&
546
            (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)) {
547

    
548
            /* XXX: make an ARP request to have the client address */
549
            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
550

    
551
            /* ARP request for alias/dns mac address */
552
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
553
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
554
            reh->h_source[5] = ah->ar_tip[3];
555
            reh->h_proto = htons(ETH_P_ARP);
556

    
557
            rah->ar_hrd = htons(1);
558
            rah->ar_pro = htons(ETH_P_IP);
559
            rah->ar_hln = ETH_ALEN;
560
            rah->ar_pln = 4;
561
            rah->ar_op = htons(ARPOP_REPLY);
562
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
563
            memcpy(rah->ar_sip, ah->ar_tip, 4);
564
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
565
            memcpy(rah->ar_tip, ah->ar_sip, 4);
566
            slirp_output(arp_reply, sizeof(arp_reply));
567
        }
568
        break;
569
    default:
570
        break;
571
    }
572
}
573

    
574
void slirp_input(const uint8_t *pkt, int pkt_len)
575
{
576
    struct mbuf *m;
577
    int proto;
578

    
579
    if (pkt_len < ETH_HLEN)
580
        return;
581
    
582
    proto = ntohs(*(uint16_t *)(pkt + 12));
583
    switch(proto) {
584
    case ETH_P_ARP:
585
        arp_input(pkt, pkt_len);
586
        break;
587
    case ETH_P_IP:
588
        m = m_get();
589
        if (!m)
590
            return;
591
        m->m_len = pkt_len;
592
        memcpy(m->m_data, pkt, pkt_len);
593

    
594
        m->m_data += ETH_HLEN;
595
        m->m_len -= ETH_HLEN;
596

    
597
        ip_input(m);
598
        break;
599
    default:
600
        break;
601
    }
602
}
603

    
604
/* output the IP packet to the ethernet device */
605
void if_encap(const uint8_t *ip_data, int ip_data_len)
606
{
607
    uint8_t buf[1600];
608
    struct ethhdr *eh = (struct ethhdr *)buf;
609

    
610
    if (ip_data_len + ETH_HLEN > sizeof(buf))
611
        return;
612

    
613
    memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
614
    memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
615
    eh->h_source[5] = CTL_ALIAS;
616
    eh->h_proto = htons(ETH_P_IP);
617
    memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
618
    slirp_output(buf, ip_data_len + ETH_HLEN);
619
}
620

    
621
int slirp_redir(int is_udp, int host_port, 
622
                struct in_addr guest_addr, int guest_port)
623
{
624
    if (is_udp) {
625
        if (!udp_listen(htons(host_port), guest_addr.s_addr, 
626
                        htons(guest_port), 0))
627
            return -1;
628
    } else {
629
        if (!solisten(htons(host_port), guest_addr.s_addr, 
630
                      htons(guest_port), 0))
631
            return -1;
632
    }
633
    return 0;
634
}