Statistics
| Branch: | Revision:

root / slirp / slirp.c @ c94c8d64

History | View | Annotate | Download (15.9 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
#ifdef _WIN32
29

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

    
78
#else
79

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

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

    
117
#endif
118

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

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

    
138
    link_up = 1;
139

    
140
    if_init();
141
    ip_init();
142

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

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

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

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

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

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

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

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

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

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

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

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

    
501
#define ETH_ALEN 6
502
#define ETH_HLEN 14
503

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

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

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

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

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

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

    
544
    ar_op = ntohs(ah->ar_op);
545
    switch(ar_op) {
546
    case ARPOP_REQUEST:
547
        if (!memcmp(ah->ar_tip, &special_addr, 3)) {
548
            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) 
549
                goto arp_ok;
550
            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
551
                if (ex_ptr->ex_addr == ah->ar_tip[3])
552
                    goto arp_ok;
553
            }
554
            return;
555
        arp_ok:
556
            /* XXX: make an ARP request to have the client address */
557
            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
558

    
559
            /* ARP request for alias/dns mac address */
560
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
561
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
562
            reh->h_source[5] = ah->ar_tip[3];
563
            reh->h_proto = htons(ETH_P_ARP);
564

    
565
            rah->ar_hrd = htons(1);
566
            rah->ar_pro = htons(ETH_P_IP);
567
            rah->ar_hln = ETH_ALEN;
568
            rah->ar_pln = 4;
569
            rah->ar_op = htons(ARPOP_REPLY);
570
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
571
            memcpy(rah->ar_sip, ah->ar_tip, 4);
572
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
573
            memcpy(rah->ar_tip, ah->ar_sip, 4);
574
            slirp_output(arp_reply, sizeof(arp_reply));
575
        }
576
        break;
577
    default:
578
        break;
579
    }
580
}
581

    
582
void slirp_input(const uint8_t *pkt, int pkt_len)
583
{
584
    struct mbuf *m;
585
    int proto;
586

    
587
    if (pkt_len < ETH_HLEN)
588
        return;
589
    
590
    proto = ntohs(*(uint16_t *)(pkt + 12));
591
    switch(proto) {
592
    case ETH_P_ARP:
593
        arp_input(pkt, pkt_len);
594
        break;
595
    case ETH_P_IP:
596
        m = m_get();
597
        if (!m)
598
            return;
599
        m->m_len = pkt_len;
600
        memcpy(m->m_data, pkt, pkt_len);
601

    
602
        m->m_data += ETH_HLEN;
603
        m->m_len -= ETH_HLEN;
604

    
605
        ip_input(m);
606
        break;
607
    default:
608
        break;
609
    }
610
}
611

    
612
/* output the IP packet to the ethernet device */
613
void if_encap(const uint8_t *ip_data, int ip_data_len)
614
{
615
    uint8_t buf[1600];
616
    struct ethhdr *eh = (struct ethhdr *)buf;
617

    
618
    if (ip_data_len + ETH_HLEN > sizeof(buf))
619
        return;
620

    
621
    memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
622
    memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
623
    /* XXX: not correct */
624
    eh->h_source[5] = CTL_ALIAS;
625
    eh->h_proto = htons(ETH_P_IP);
626
    memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
627
    slirp_output(buf, ip_data_len + ETH_HLEN);
628
}
629

    
630
int slirp_redir(int is_udp, int host_port, 
631
                struct in_addr guest_addr, int guest_port)
632
{
633
    if (is_udp) {
634
        if (!udp_listen(htons(host_port), guest_addr.s_addr, 
635
                        htons(guest_port), 0))
636
            return -1;
637
    } else {
638
        if (!solisten(htons(host_port), guest_addr.s_addr, 
639
                      htons(guest_port), 0))
640
            return -1;
641
    }
642
    return 0;
643
}
644

    
645
int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, 
646
                  int guest_port)
647
{
648
    return add_exec(&exec_list, do_pty, (char *)args, 
649
                    addr_low_byte, htons(guest_port));
650
}