Statistics
| Branch: | Revision:

root / slirp / slirp.c @ 115defd1

History | View | Annotate | Download (16.2 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
struct ex_list *exec_list;
24

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

    
28
const char slirp_hostname[33];
29

    
30
#ifdef _WIN32
31

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

    
80
#else
81

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

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

    
119
#endif
120

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

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

    
140
    link_up = 1;
141

    
142
    if_init();
143
    ip_init();
144

    
145
    /* Initialise mbufs *after* setting the MTU */
146
    m_init();
147

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

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

    
157
    inet_aton(CTL_SPECIAL, &special_addr);
158
}
159

    
160
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
161
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
162
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
163

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

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

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

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

    
339
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
340
{
341
    struct socket *so, *so_next;
342
    int ret;
343

    
344
    global_readfds = readfds;
345
    global_writefds = writefds;
346
    global_xfds = xfds;
347

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

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

    
512
#define ETH_ALEN 6
513
#define ETH_HLEN 14
514

    
515
#define ETH_P_IP        0x0800                /* Internet Protocol packet        */
516
#define ETH_P_ARP        0x0806                /* Address Resolution packet        */
517

    
518
#define        ARPOP_REQUEST        1                /* ARP request                        */
519
#define        ARPOP_REPLY        2                /* ARP reply                        */
520

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

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

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

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

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

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

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

    
593
void slirp_input(const uint8_t *pkt, int pkt_len)
594
{
595
    struct mbuf *m;
596
    int proto;
597

    
598
    if (pkt_len < ETH_HLEN)
599
        return;
600
    
601
    proto = ntohs(*(uint16_t *)(pkt + 12));
602
    switch(proto) {
603
    case ETH_P_ARP:
604
        arp_input(pkt, pkt_len);
605
        break;
606
    case ETH_P_IP:
607
        m = m_get();
608
        if (!m)
609
            return;
610
        m->m_len = pkt_len;
611
        memcpy(m->m_data, pkt, pkt_len);
612

    
613
        m->m_data += ETH_HLEN;
614
        m->m_len -= ETH_HLEN;
615

    
616
        ip_input(m);
617
        break;
618
    default:
619
        break;
620
    }
621
}
622

    
623
/* output the IP packet to the ethernet device */
624
void if_encap(const uint8_t *ip_data, int ip_data_len)
625
{
626
    uint8_t buf[1600];
627
    struct ethhdr *eh = (struct ethhdr *)buf;
628

    
629
    if (ip_data_len + ETH_HLEN > sizeof(buf))
630
        return;
631

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

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

    
656
int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, 
657
                  int guest_port)
658
{
659
    return add_exec(&exec_list, do_pty, (char *)args, 
660
                    addr_low_byte, htons(guest_port));
661
}