2
* Copyright (c) 1982, 1986, 1988, 1990, 1993
3
* The Regents of the University of California. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. All advertising materials mentioning features or use of this software
14
* must display the following acknowledgement:
15
* This product includes software developed by the University of
16
* California, Berkeley and its contributors.
17
* 4. Neither the name of the University nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
21
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
* @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
34
* udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
38
* Changes and additions relating to SLiRP
39
* Copyright (c) 1995 Danny Gasparovski.
41
* Please read the file COPYRIGHT for the
42
* terms and conditions of the copyright.
50
* UDP protocol implementation.
51
* Per RFC 768, August, 1980.
56
udp_init(PNATState pData)
59
udb.so_next = udb.so_prev = &udb;
62
/* m->m_data points at ip packet header
63
* m->m_len length ip packet
64
* ip->ip_len length data (IPDU)
67
udp_input(PNATState pData, register struct mbuf *m, int iphlen)
69
register struct ip *ip;
70
register struct udphdr *uh;
71
/* struct mbuf *opts = 0;*/
76
DEBUG_CALL("udp_input");
77
DEBUG_ARG("m = %lx", (long)m);
78
DEBUG_ARG("iphlen = %d", iphlen);
80
udpstat.udps_ipackets++;
83
* Strip IP options, if any; should skip this,
84
* make available to user, and use on returned packets,
85
* but we don't yet have a way to check the checksum
86
* with options still present.
88
if(iphlen > sizeof(struct ip)) {
89
ip_stripoptions(m, (struct mbuf *)0);
90
iphlen = sizeof(struct ip);
94
* Get IP and UDP header together in first mbuf.
96
ip = mtod(m, struct ip *);
97
uh = (struct udphdr *)((caddr_t)ip + iphlen);
100
* Make mbuf data length reflect UDP length.
101
* If not enough data to reflect UDP length, drop.
103
len = ntohs((u_int16_t)uh->uh_ulen);
105
if (ip->ip_len != len) {
106
if (len > ip->ip_len) {
107
udpstat.udps_badlen++;
110
m_adj(m, len - ip->ip_len);
115
* Save a copy of the IP header in case we want restore it
116
* for sending an ICMP error message in response.
119
save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
122
* Checksum extended UDP header and data.
124
if (udpcksum && uh->uh_sum) {
125
((struct ipovly *)ip)->ih_next = 0;
126
((struct ipovly *)ip)->ih_prev = 0;
127
((struct ipovly *)ip)->ih_x1 = 0;
128
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
129
/* keep uh_sum for ICMP reply
130
* uh->uh_sum = cksum(m, len + sizeof (struct ip));
133
if(cksum(m, len + sizeof(struct ip))) {
134
udpstat.udps_badsum++;
142
if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
143
bootp_input(pData, m);
150
if (ntohs(uh->uh_dport) == TFTP_SERVER) {
151
tftp_input(pData, m);
156
* Locate pcb for datagram.
159
if (so->so_lport != uh->uh_sport ||
160
so->so_laddr.s_addr != ip->ip_src.s_addr) {
163
for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
164
if (tmp->so_lport == uh->uh_sport &&
165
tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
173
udpstat.udpps_pcbcachemiss++;
180
* If there's no socket for this packet,
183
if ((so = socreate()) == NULL) goto bad;
184
if(udp_attach(pData, so) == -1) {
185
DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
186
errno,strerror(errno)));
194
/* udp_last_so = so; */
195
so->so_laddr = ip->ip_src;
196
so->so_lport = uh->uh_sport;
198
if ((so->so_iptos = udp_tos(so)) == 0)
199
so->so_iptos = ip->ip_tos;
202
* XXXXX Here, check if it's in udpexec_list,
203
* and if it is, do the fork_exec() etc.
207
so->so_faddr = ip->ip_dst; /* XXX */
208
so->so_fport = uh->uh_dport; /* XXX */
210
iphlen += sizeof(struct udphdr);
215
* Now we sendto() the packet.
218
udp_emu(pData, so, m);
220
if(sosendto(pData, so,m) == -1) {
224
DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
225
icmp_error(pData, m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
228
m_free(pData, so->so_m); /* used for ICMP if error on sorecvfrom */
230
/* restore the orig mbuf packet */
234
so->so_m=m; /* ICMP backup */
239
/* if (opts) m_freem(opts); */
243
int udp_output2(PNATState pData, struct socket *so, struct mbuf *m,
244
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
247
register struct udpiphdr *ui;
250
DEBUG_CALL("udp_output");
251
DEBUG_ARG("so = %lx", (long)so);
252
DEBUG_ARG("m = %lx", (long)m);
253
DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
254
DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
259
m->m_data -= sizeof(struct udpiphdr);
260
m->m_len += sizeof(struct udpiphdr);
263
* Fill in mbuf with extended UDP header
264
* and addresses and length put into network format.
266
ui = mtod(m, struct udpiphdr *);
267
ui->ui_next = ui->ui_prev = 0;
269
ui->ui_pr = IPPROTO_UDP;
270
ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
271
/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
272
ui->ui_src = saddr->sin_addr;
273
ui->ui_dst = daddr->sin_addr;
274
ui->ui_sport = saddr->sin_port;
275
ui->ui_dport = daddr->sin_port;
276
ui->ui_ulen = ui->ui_len;
279
* Stuff checksum and output datagram.
283
if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
286
((struct ip *)ui)->ip_len = m->m_len;
288
((struct ip *)ui)->ip_ttl = ip_defttl;
289
((struct ip *)ui)->ip_tos = iptos;
291
udpstat.udps_opackets++;
293
error = ip_output(pData, so, m);
298
int udp_output(PNATState pData, struct socket *so, struct mbuf *m,
299
struct sockaddr_in *addr)
301
struct sockaddr_in saddr, daddr;
304
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
305
saddr.sin_addr.s_addr = so->so_faddr.s_addr;
306
if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
307
saddr.sin_addr.s_addr = alias_addr.s_addr;
309
daddr.sin_addr = so->so_laddr;
310
daddr.sin_port = so->so_lport;
312
return udp_output2(pData, so, m, &saddr, &daddr, so->so_iptos);
316
udp_attach(PNATState pData, struct socket *so)
318
struct sockaddr_in addr;
320
if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
322
* Here, we bind() the socket. Although not really needed
323
* (sendto() on an unbound socket will bind it), it's done
324
* here so that emulation of ytalk etc. don't have to do it
326
addr.sin_family = AF_INET;
328
addr.sin_addr.s_addr = INADDR_ANY;
329
if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
334
WSASetLastError(lasterrno);
340
/* success, insert in queue */
341
so->so_expire = curtime + SO_EXPIRE;
342
/* enable broadcast for later use */
343
setsockopt(so->s, SOL_SOCKET, SO_BROADCAST, (const char *)&opt, sizeof(opt));
344
insque(pData, so,&udb);
351
udp_detach(PNATState pData, struct socket *so)
353
/* Correctly update list if detaching last socket in list. */
354
if (so == udp_last_so) udp_last_so = &udb;
356
/* if (so->so_m) m_free(so->so_m); done by sofree */
361
static const struct tos_t udptos[] = {
362
{0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
363
{517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */
364
{518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */
365
{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
375
while(udptos[i].tos) {
376
if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
377
(udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
378
so->so_emu = udptos[i].emu;
379
return udptos[i].tos;
392
* Here, talk/ytalk/ntalk requests must be emulated
395
udp_emu(PNATState pData, struct socket *so, struct mbuf *m)
397
struct sockaddr_in addr;
398
socklen_t addrlen = sizeof(addr);
402
char buff[sizeof(CTL_MSG)];
405
struct talk_request {
406
struct talk_request *next;
407
struct socket *udp_so;
408
struct socket *tcp_so;
411
static struct talk_request *req_tbl = 0;
416
uint16_t d_family; /* destination family */
417
uint16_t d_port; /* destination port */
418
uint32_t d_addr; /* destination address */
419
uint16_t s_family; /* source family */
420
uint16_t s_port; /* source port */
421
uint32_t so_addr; /* source address */
422
uint32_t seqn; /* sequence number */
423
uint16_t message; /* message */
424
uint16_t data_type; /* data type */
425
uint16_t pkt_len; /* packet length */
434
* Talk emulation. We always change the ctl_addr to get
435
* some answers from the daemon. When an ANNOUNCE comes,
436
* we send LEAVE_INVITE to the local daemons. Also when a
437
* DELETE comes, we send copies to the local daemons.
439
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
442
#define IS_OLD (so->so_emu == EMU_TALK)
444
#define COPY_MSG(dest, src) { dest->type = src->type; \
445
dest->id_num = src->id_num; \
446
dest->pid = src->pid; \
447
dest->addr = src->addr; \
448
dest->ctl_addr = src->ctl_addr; \
449
memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
450
memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
451
memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
453
#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
454
/* old_sockaddr to sockaddr_in */
457
if (IS_OLD) { /* old talk */
458
omsg = mtod(m, CTL_MSG_OLD*);
459
nmsg = (CTL_MSG *) buff;
461
OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
462
OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
463
strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD);
464
} else { /* new talk */
465
omsg = (CTL_MSG_OLD *) buff;
466
nmsg = mtod(m, CTL_MSG *);
468
OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
469
OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
470
strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD);
474
return; /* for LOOK_UP this is enough */
476
if (IS_OLD) { /* make a copy of the message */
477
COPY_MSG(nmsg, omsg);
481
COPY_MSG(omsg, nmsg);
484
* If if is an ANNOUNCE message, we go through the
485
* request table to see if a tcp port has already
486
* been redirected for this socket. If not, we solisten()
487
* a new socket and add this entry to the table.
488
* The port number of the tcp socket and our IP
489
* are put to the addr field of the message structures.
490
* Then a LEAVE_INVITE is sent to both local daemon
491
* ports, 517 and 518. This is why we have two copies
492
* of the message, one in old talk and one in new talk
496
if (type == ANNOUNCE) {
500
for(req = req_tbl; req; req = req->next)
501
if (so == req->udp_so)
502
break; /* found it */
504
if (!req) { /* no entry for so, create new */
505
req = (struct talk_request *)
506
malloc(sizeof(struct talk_request));
508
req->tcp_so = solisten(0,
509
OTOSIN(omsg, addr)->sin_addr.s_addr,
510
OTOSIN(omsg, addr)->sin_port,
516
/* replace port number in addr field */
517
addrlen = sizeof(addr);
518
getsockname(req->tcp_so->s,
519
(struct sockaddr *) &addr,
521
OTOSIN(omsg, addr)->sin_port = addr.sin_port;
522
OTOSIN(omsg, addr)->sin_addr = our_addr;
523
OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
524
OTOSIN(nmsg, addr)->sin_addr = our_addr;
526
/* send LEAVE_INVITEs */
527
temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
528
OTOSIN(omsg, ctl_addr)->sin_port = 0;
529
OTOSIN(nmsg, ctl_addr)->sin_port = 0;
530
omsg->type = nmsg->type = LEAVE_INVITE;
532
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
533
addr.sin_addr = our_addr;
534
addr.sin_family = AF_INET;
535
addr.sin_port = htons(517);
536
sendto(s, (char *)omsg, sizeof(*omsg), 0,
537
(struct sockaddr *)&addr, sizeof(addr));
538
addr.sin_port = htons(518);
539
sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
540
(struct sockaddr *) &addr, sizeof(addr));
543
omsg->type = nmsg->type = ANNOUNCE;
544
OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
545
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
549
* If it is a DELETE message, we send a copy to the
550
* local daemons. Then we delete the entry corresponding
551
* to our socket from the request table.
554
if (type == DELETE) {
555
struct talk_request *temp_req, *req_next;
559
temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
560
OTOSIN(omsg, ctl_addr)->sin_port = 0;
561
OTOSIN(nmsg, ctl_addr)->sin_port = 0;
563
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
564
addr.sin_addr = our_addr;
565
addr.sin_family = AF_INET;
566
addr.sin_port = htons(517);
567
sendto(s, (char *)omsg, sizeof(*omsg), 0,
568
(struct sockaddr *)&addr, sizeof(addr));
569
addr.sin_port = htons(518);
570
sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
571
(struct sockaddr *)&addr, sizeof(addr));
574
OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
575
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
577
/* delete table entry */
578
if (so == req_tbl->udp_so) {
580
req_tbl = req_tbl->next;
584
for(req = req_tbl->next; req; req = req_next) {
585
req_next = req->next;
586
if (so == req->udp_so) {
587
temp_req->next = req_next;
603
* Cu-SeeMe emulation.
604
* Hopefully the packet is more that 16 bytes long. We don't
605
* do any other tests, just replace the address and port
608
if (m->m_len >= sizeof (*cu_head)) {
609
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
611
cu_head = mtod(m, struct cu_header *);
612
cu_head->s_port = addr.sin_port;
613
cu_head->so_addr = our_addr.s_addr;
621
udp_listen(PNATState pData, u_int port, u_int32_t laddr, u_int lport, int flags)
623
struct sockaddr_in addr;
625
socklen_t addrlen = sizeof(struct sockaddr_in);
628
if ((so = socreate()) == NULL) {
632
so->s = socket(AF_INET,SOCK_DGRAM,0);
633
so->so_expire = curtime + SO_EXPIRE;
634
insque(pData, so,&udb);
636
addr.sin_family = AF_INET;
637
addr.sin_addr.s_addr = INADDR_ANY;
638
addr.sin_port = port;
640
if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
641
udp_detach(pData, so);
644
setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
645
/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
647
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
648
so->so_fport = addr.sin_port;
649
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
650
so->so_faddr = alias_addr;
652
so->so_faddr = addr.sin_addr;
654
so->so_lport = lport;
655
so->so_laddr.s_addr = laddr;
656
if (flags != SS_FACCEPTONCE)
659
so->so_state = SS_ISFCONNECTED;