version 1.1.1.7, 2018/04/24 17:25:49
|
version 1.1.1.8, 2018/04/24 17:41:09
|
Line 42
|
Line 42
|
#include "ip_icmp.h" |
#include "ip_icmp.h" |
|
|
static u_int8_t udp_tos(struct socket *so); |
static u_int8_t udp_tos(struct socket *so); |
static void udp_emu(struct socket *so, struct mbuf *m); |
|
|
|
void |
void |
udp_init(Slirp *slirp) |
udp_init(Slirp *slirp) |
Line 202 udp_input(register struct mbuf *m, int i
|
Line 201 udp_input(register struct mbuf *m, int i
|
/* |
/* |
* Now we sendto() the packet. |
* Now we sendto() the packet. |
*/ |
*/ |
if (so->so_emu) |
|
udp_emu(so, m); |
|
|
|
if(sosendto(so,m) == -1) { |
if(sosendto(so,m) == -1) { |
m->m_len += iphlen; |
m->m_len += iphlen; |
m->m_data -= iphlen; |
m->m_data -= iphlen; |
Line 306 int udp_output(struct socket *so, struct
|
Line 302 int udp_output(struct socket *so, struct
|
int |
int |
udp_attach(struct socket *so) |
udp_attach(struct socket *so) |
{ |
{ |
struct sockaddr_in addr; |
if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) { |
|
so->so_expire = curtime + SO_EXPIRE; |
if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { |
insque(so, &so->slirp->udb); |
/* |
|
* Here, we bind() the socket. Although not really needed |
|
* (sendto() on an unbound socket will bind it), it's done |
|
* here so that emulation of ytalk etc. don't have to do it |
|
*/ |
|
addr.sin_family = AF_INET; |
|
addr.sin_port = 0; |
|
addr.sin_addr.s_addr = INADDR_ANY; |
|
if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { |
|
int lasterrno=errno; |
|
closesocket(so->s); |
|
so->s=-1; |
|
#ifdef _WIN32 |
|
WSASetLastError(lasterrno); |
|
#else |
|
errno=lasterrno; |
|
#endif |
|
} else { |
|
/* success, insert in queue */ |
|
so->so_expire = curtime + SO_EXPIRE; |
|
insque(so, &so->slirp->udb); |
|
} |
|
} |
} |
return(so->s); |
return(so->s); |
} |
} |
Line 344 udp_detach(struct socket *so)
|
Line 318 udp_detach(struct socket *so)
|
|
|
static const struct tos_t udptos[] = { |
static const struct tos_t udptos[] = { |
{0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ |
{0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ |
{517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ |
|
{518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ |
|
{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ |
|
{0, 0, 0, 0} |
{0, 0, 0, 0} |
}; |
}; |
|
|
Line 367 udp_tos(struct socket *so)
|
Line 338 udp_tos(struct socket *so)
|
return 0; |
return 0; |
} |
} |
|
|
#ifdef EMULATE_TALK |
|
#include "talkd.h" |
|
#endif |
|
|
|
/* |
|
* Here, talk/ytalk/ntalk requests must be emulated |
|
*/ |
|
static void |
|
udp_emu(struct socket *so, struct mbuf *m) |
|
{ |
|
struct sockaddr_in addr; |
|
socklen_t addrlen = sizeof(addr); |
|
#ifdef EMULATE_TALK |
|
CTL_MSG_OLD *omsg; |
|
CTL_MSG *nmsg; |
|
char buff[sizeof(CTL_MSG)]; |
|
u_char type; |
|
|
|
struct talk_request { |
|
struct talk_request *next; |
|
struct socket *udp_so; |
|
struct socket *tcp_so; |
|
} *req; |
|
|
|
static struct talk_request *req_tbl = 0; |
|
|
|
#endif |
|
|
|
struct cu_header { |
|
uint16_t d_family; // destination family |
|
uint16_t d_port; // destination port |
|
uint32_t d_addr; // destination address |
|
uint16_t s_family; // source family |
|
uint16_t s_port; // source port |
|
uint32_t so_addr; // source address |
|
uint32_t seqn; // sequence number |
|
uint16_t message; // message |
|
uint16_t data_type; // data type |
|
uint16_t pkt_len; // packet length |
|
} *cu_head; |
|
|
|
switch(so->so_emu) { |
|
|
|
#ifdef EMULATE_TALK |
|
case EMU_TALK: |
|
case EMU_NTALK: |
|
/* |
|
* Talk emulation. We always change the ctl_addr to get |
|
* some answers from the daemon. When an ANNOUNCE comes, |
|
* we send LEAVE_INVITE to the local daemons. Also when a |
|
* DELETE comes, we send copies to the local daemons. |
|
*/ |
|
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) |
|
return; |
|
|
|
#define IS_OLD (so->so_emu == EMU_TALK) |
|
|
|
#define COPY_MSG(dest, src) { dest->type = src->type; \ |
|
dest->id_num = src->id_num; \ |
|
dest->pid = src->pid; \ |
|
dest->addr = src->addr; \ |
|
dest->ctl_addr = src->ctl_addr; \ |
|
memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ |
|
memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ |
|
memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } |
|
|
|
#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) |
|
/* old_sockaddr to sockaddr_in */ |
|
|
|
|
|
if (IS_OLD) { /* old talk */ |
|
omsg = mtod(m, CTL_MSG_OLD*); |
|
nmsg = (CTL_MSG *) buff; |
|
type = omsg->type; |
|
OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; |
|
OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; |
|
pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin()); |
|
} else { /* new talk */ |
|
omsg = (CTL_MSG_OLD *) buff; |
|
nmsg = mtod(m, CTL_MSG *); |
|
type = nmsg->type; |
|
OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; |
|
OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; |
|
pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin()); |
|
} |
|
|
|
if (type == LOOK_UP) |
|
return; /* for LOOK_UP this is enough */ |
|
|
|
if (IS_OLD) { /* make a copy of the message */ |
|
COPY_MSG(nmsg, omsg); |
|
nmsg->vers = 1; |
|
nmsg->answer = 0; |
|
} else |
|
COPY_MSG(omsg, nmsg); |
|
|
|
/* |
|
* If if is an ANNOUNCE message, we go through the |
|
* request table to see if a tcp port has already |
|
* been redirected for this socket. If not, we solisten() |
|
* a new socket and add this entry to the table. |
|
* The port number of the tcp socket and our IP |
|
* are put to the addr field of the message structures. |
|
* Then a LEAVE_INVITE is sent to both local daemon |
|
* ports, 517 and 518. This is why we have two copies |
|
* of the message, one in old talk and one in new talk |
|
* format. |
|
*/ |
|
|
|
if (type == ANNOUNCE) { |
|
int s; |
|
u_short temp_port; |
|
|
|
for(req = req_tbl; req; req = req->next) |
|
if (so == req->udp_so) |
|
break; /* found it */ |
|
|
|
if (!req) { /* no entry for so, create new */ |
|
req = (struct talk_request *) |
|
malloc(sizeof(struct talk_request)); |
|
req->udp_so = so; |
|
req->tcp_so = solisten(0, |
|
OTOSIN(omsg, addr)->sin_addr.s_addr, |
|
OTOSIN(omsg, addr)->sin_port, |
|
SS_FACCEPTONCE); |
|
req->next = req_tbl; |
|
req_tbl = req; |
|
} |
|
|
|
/* replace port number in addr field */ |
|
addrlen = sizeof(addr); |
|
getsockname(req->tcp_so->s, |
|
(struct sockaddr *) &addr, |
|
&addrlen); |
|
OTOSIN(omsg, addr)->sin_port = addr.sin_port; |
|
OTOSIN(omsg, addr)->sin_addr = our_addr; |
|
OTOSIN(nmsg, addr)->sin_port = addr.sin_port; |
|
OTOSIN(nmsg, addr)->sin_addr = our_addr; |
|
|
|
/* send LEAVE_INVITEs */ |
|
temp_port = OTOSIN(omsg, ctl_addr)->sin_port; |
|
OTOSIN(omsg, ctl_addr)->sin_port = 0; |
|
OTOSIN(nmsg, ctl_addr)->sin_port = 0; |
|
omsg->type = nmsg->type = LEAVE_INVITE; |
|
|
|
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
|
addr.sin_addr = our_addr; |
|
addr.sin_family = AF_INET; |
|
addr.sin_port = htons(517); |
|
sendto(s, (char *)omsg, sizeof(*omsg), 0, |
|
(struct sockaddr *)&addr, sizeof(addr)); |
|
addr.sin_port = htons(518); |
|
sendto(s, (char *)nmsg, sizeof(*nmsg), 0, |
|
(struct sockaddr *) &addr, sizeof(addr)); |
|
closesocket(s) ; |
|
|
|
omsg->type = nmsg->type = ANNOUNCE; |
|
OTOSIN(omsg, ctl_addr)->sin_port = temp_port; |
|
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; |
|
} |
|
|
|
/* |
|
* If it is a DELETE message, we send a copy to the |
|
* local daemons. Then we delete the entry corresponding |
|
* to our socket from the request table. |
|
*/ |
|
|
|
if (type == DELETE) { |
|
struct talk_request *temp_req, *req_next; |
|
int s; |
|
u_short temp_port; |
|
|
|
temp_port = OTOSIN(omsg, ctl_addr)->sin_port; |
|
OTOSIN(omsg, ctl_addr)->sin_port = 0; |
|
OTOSIN(nmsg, ctl_addr)->sin_port = 0; |
|
|
|
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
|
addr.sin_addr = our_addr; |
|
addr.sin_family = AF_INET; |
|
addr.sin_port = htons(517); |
|
sendto(s, (char *)omsg, sizeof(*omsg), 0, |
|
(struct sockaddr *)&addr, sizeof(addr)); |
|
addr.sin_port = htons(518); |
|
sendto(s, (char *)nmsg, sizeof(*nmsg), 0, |
|
(struct sockaddr *)&addr, sizeof(addr)); |
|
closesocket(s); |
|
|
|
OTOSIN(omsg, ctl_addr)->sin_port = temp_port; |
|
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; |
|
|
|
/* delete table entry */ |
|
if (so == req_tbl->udp_so) { |
|
temp_req = req_tbl; |
|
req_tbl = req_tbl->next; |
|
free(temp_req); |
|
} else { |
|
temp_req = req_tbl; |
|
for(req = req_tbl->next; req; req = req_next) { |
|
req_next = req->next; |
|
if (so == req->udp_so) { |
|
temp_req->next = req_next; |
|
free(req); |
|
break; |
|
} else { |
|
temp_req = req; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return; |
|
#endif |
|
|
|
case EMU_CUSEEME: |
|
|
|
/* |
|
* Cu-SeeMe emulation. |
|
* Hopefully the packet is more that 16 bytes long. We don't |
|
* do any other tests, just replace the address and port |
|
* fields. |
|
*/ |
|
if (m->m_len >= sizeof (*cu_head)) { |
|
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) |
|
return; |
|
cu_head = mtod(m, struct cu_header *); |
|
cu_head->s_port = addr.sin_port; |
|
cu_head->so_addr = our_addr.s_addr; |
|
} |
|
|
|
return; |
|
} |
|
} |
|
|
|
struct socket * |
struct socket * |
udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr, |
udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr, |
u_int lport, int flags) |
u_int lport, int flags) |
Line 612 udp_listen(Slirp *slirp, u_int32_t haddr
|
Line 350 udp_listen(Slirp *slirp, u_int32_t haddr
|
if (!so) { |
if (!so) { |
return NULL; |
return NULL; |
} |
} |
so->s = socket(AF_INET,SOCK_DGRAM,0); |
so->s = qemu_socket(AF_INET,SOCK_DGRAM,0); |
so->so_expire = curtime + SO_EXPIRE; |
so->so_expire = curtime + SO_EXPIRE; |
insque(so, &slirp->udb); |
insque(so, &slirp->udb); |
|
|