Revision 97df1ee5

b/slirp/misc.h
36 36

  
37 37
#define EMU_NOCONNECT 0x10	/* Don't connect */
38 38

  
39
/* UDP emulations */
40
#define EMU_TALK	0x1
41
#define EMU_NTALK	0x2
42
#define EMU_CUSEEME	0x3
43

  
44 39
struct tos_t {
45 40
	u_int16_t lport;
46 41
	u_int16_t fport;
b/slirp/slirp_config.h
2 2
 * User definable configuration options
3 3
 */
4 4

  
5
/* Undefine if you don't want talk emulation */
6
#undef EMULATE_TALK
7

  
8 5
/* Define if you want the connection to be probed */
9 6
/* XXX Not working yet, so ignore this for now */
10 7
#undef PROBE_CONN
b/slirp/udp.c
42 42
#include "ip_icmp.h"
43 43

  
44 44
static u_int8_t udp_tos(struct socket *so);
45
static void udp_emu(struct socket *so, struct mbuf *m);
46 45

  
47 46
void
48 47
udp_init(Slirp *slirp)
......
202 201
	/*
203 202
	 * Now we sendto() the packet.
204 203
	 */
205
	if (so->so_emu)
206
	   udp_emu(so, m);
207

  
208 204
	if(sosendto(so,m) == -1) {
209 205
	  m->m_len += iphlen;
210 206
	  m->m_data -= iphlen;
......
306 302
int
307 303
udp_attach(struct socket *so)
308 304
{
309
  struct sockaddr_in addr;
310

  
311 305
  if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
312
    /*
313
     * Here, we bind() the socket.  Although not really needed
314
     * (sendto() on an unbound socket will bind it), it's done
315
     * here so that emulation of ytalk etc. don't have to do it
316
     */
317
    addr.sin_family = AF_INET;
318
    addr.sin_port = 0;
319
    addr.sin_addr.s_addr = INADDR_ANY;
320
    if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
321
      int lasterrno=errno;
322
      closesocket(so->s);
323
      so->s=-1;
324
#ifdef _WIN32
325
      WSASetLastError(lasterrno);
326
#else
327
      errno=lasterrno;
328
#endif
329
    } else {
330
      /* success, insert in queue */
331
      so->so_expire = curtime + SO_EXPIRE;
332
      insque(so, &so->slirp->udb);
333
    }
306
    so->so_expire = curtime + SO_EXPIRE;
307
    insque(so, &so->slirp->udb);
334 308
  }
335 309
  return(so->s);
336 310
}
......
344 318

  
345 319
static const struct tos_t udptos[] = {
346 320
	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
347
	{517, 517, IPTOS_LOWDELAY, EMU_TALK},	/* talk */
348
	{518, 518, IPTOS_LOWDELAY, EMU_NTALK},	/* ntalk */
349
	{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME},	/* Cu-Seeme */
350 321
	{0, 0, 0, 0}
351 322
};
352 323

  
......
367 338
	return 0;
368 339
}
369 340

  
370
#ifdef EMULATE_TALK
371
#include "talkd.h"
372
#endif
373

  
374
/*
375
 * Here, talk/ytalk/ntalk requests must be emulated
376
 */
377
static void
378
udp_emu(struct socket *so, struct mbuf *m)
379
{
380
	struct sockaddr_in addr;
381
	socklen_t addrlen = sizeof(addr);
382
#ifdef EMULATE_TALK
383
	CTL_MSG_OLD *omsg;
384
	CTL_MSG *nmsg;
385
	char buff[sizeof(CTL_MSG)];
386
	u_char type;
387

  
388
struct talk_request {
389
	struct talk_request *next;
390
	struct socket *udp_so;
391
	struct socket *tcp_so;
392
} *req;
393

  
394
	static struct talk_request *req_tbl = 0;
395

  
396
#endif
397

  
398
struct cu_header {
399
	uint16_t	d_family;		// destination family
400
	uint16_t	d_port;			// destination port
401
	uint32_t	d_addr;			// destination address
402
	uint16_t	s_family;		// source family
403
	uint16_t	s_port;			// source port
404
	uint32_t	so_addr;		// source address
405
	uint32_t	seqn;			// sequence number
406
	uint16_t	message;		// message
407
	uint16_t	data_type;		// data type
408
	uint16_t	pkt_len;		// packet length
409
} *cu_head;
410

  
411
	switch(so->so_emu) {
412

  
413
#ifdef EMULATE_TALK
414
	 case EMU_TALK:
415
	 case EMU_NTALK:
416
		/*
417
		 * Talk emulation. We always change the ctl_addr to get
418
		 * some answers from the daemon. When an ANNOUNCE comes,
419
		 * we send LEAVE_INVITE to the local daemons. Also when a
420
		 * DELETE comes, we send copies to the local daemons.
421
		 */
422
		if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
423
			return;
424

  
425
#define	IS_OLD	(so->so_emu == EMU_TALK)
426

  
427
#define COPY_MSG(dest, src) { dest->type = src->type; \
428
			      dest->id_num = src->id_num; \
429
			      dest->pid = src->pid; \
430
			      dest->addr = src->addr; \
431
			      dest->ctl_addr = src->ctl_addr; \
432
			      memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
433
			      memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
434
	         	      memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
435

  
436
#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
437
/* old_sockaddr to sockaddr_in */
438

  
439

  
440
		if (IS_OLD) {  		/* old talk */
441
			omsg = mtod(m, CTL_MSG_OLD*);
442
			nmsg = (CTL_MSG *) buff;
443
			type = omsg->type;
444
			OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
445
			OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
446
                        pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
447
		} else {		/* new talk */
448
			omsg = (CTL_MSG_OLD *) buff;
449
			nmsg = mtod(m, CTL_MSG *);
450
			type = nmsg->type;
451
			OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
452
			OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
453
                        pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
454
		}
455

  
456
		if (type == LOOK_UP)
457
			return;		/* for LOOK_UP this is enough */
458

  
459
		if (IS_OLD) {		/* make a copy of the message */
460
			COPY_MSG(nmsg, omsg);
461
			nmsg->vers = 1;
462
			nmsg->answer = 0;
463
		} else
464
			COPY_MSG(omsg, nmsg);
465

  
466
		/*
467
		 * If if is an ANNOUNCE message, we go through the
468
		 * request table to see if a tcp port has already
469
		 * been redirected for this socket. If not, we solisten()
470
		 * a new socket and add this entry to the table.
471
		 * The port number of the tcp socket and our IP
472
		 * are put to the addr field of the message structures.
473
		 * Then a LEAVE_INVITE is sent to both local daemon
474
		 * ports, 517 and 518. This is why we have two copies
475
		 * of the message, one in old talk and one in new talk
476
		 * format.
477
		 */
478

  
479
		if (type == ANNOUNCE) {
480
			int s;
481
			u_short temp_port;
482

  
483
			for(req = req_tbl; req; req = req->next)
484
				if (so == req->udp_so)
485
					break;  	/* found it */
486

  
487
			if (!req) {	/* no entry for so, create new */
488
				req = (struct talk_request *)
489
					malloc(sizeof(struct talk_request));
490
				req->udp_so = so;
491
				req->tcp_so = solisten(0,
492
					OTOSIN(omsg, addr)->sin_addr.s_addr,
493
					OTOSIN(omsg, addr)->sin_port,
494
					SS_FACCEPTONCE);
495
				req->next = req_tbl;
496
				req_tbl = req;
497
			}
498

  
499
			/* replace port number in addr field */
500
			addrlen = sizeof(addr);
501
			getsockname(req->tcp_so->s,
502
					(struct sockaddr *) &addr,
503
					&addrlen);
504
			OTOSIN(omsg, addr)->sin_port = addr.sin_port;
505
			OTOSIN(omsg, addr)->sin_addr = our_addr;
506
			OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
507
			OTOSIN(nmsg, addr)->sin_addr = our_addr;
508

  
509
			/* send LEAVE_INVITEs */
510
			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
511
			OTOSIN(omsg, ctl_addr)->sin_port = 0;
512
			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
513
			omsg->type = nmsg->type = LEAVE_INVITE;
514

  
515
			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
516
			addr.sin_addr = our_addr;
517
			addr.sin_family = AF_INET;
518
			addr.sin_port = htons(517);
519
			sendto(s, (char *)omsg, sizeof(*omsg), 0,
520
				(struct sockaddr *)&addr, sizeof(addr));
521
			addr.sin_port = htons(518);
522
			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
523
				(struct sockaddr *) &addr, sizeof(addr));
524
			closesocket(s) ;
525

  
526
			omsg->type = nmsg->type = ANNOUNCE;
527
			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
528
			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
529
		}
530

  
531
		/*
532
		 * If it is a DELETE message, we send a copy to the
533
		 * local daemons. Then we delete the entry corresponding
534
		 * to our socket from the request table.
535
		 */
536

  
537
		if (type == DELETE) {
538
			struct talk_request *temp_req, *req_next;
539
			int s;
540
			u_short temp_port;
541

  
542
			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
543
			OTOSIN(omsg, ctl_addr)->sin_port = 0;
544
			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
545

  
546
			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
547
			addr.sin_addr = our_addr;
548
			addr.sin_family = AF_INET;
549
			addr.sin_port = htons(517);
550
			sendto(s, (char *)omsg, sizeof(*omsg), 0,
551
				(struct sockaddr *)&addr, sizeof(addr));
552
			addr.sin_port = htons(518);
553
			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
554
				(struct sockaddr *)&addr, sizeof(addr));
555
			closesocket(s);
556

  
557
			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
558
			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
559

  
560
			/* delete table entry */
561
			if (so == req_tbl->udp_so) {
562
				temp_req = req_tbl;
563
				req_tbl = req_tbl->next;
564
				free(temp_req);
565
			} else {
566
				temp_req = req_tbl;
567
				for(req = req_tbl->next; req; req = req_next) {
568
					req_next = req->next;
569
					if (so == req->udp_so) {
570
						temp_req->next = req_next;
571
						free(req);
572
						break;
573
					} else {
574
						temp_req = req;
575
					}
576
				}
577
			}
578
		}
579

  
580
		return;
581
#endif
582

  
583
	case EMU_CUSEEME:
584

  
585
		/*
586
		 * Cu-SeeMe emulation.
587
		 * Hopefully the packet is more that 16 bytes long. We don't
588
		 * do any other tests, just replace the address and port
589
		 * fields.
590
		 */
591
		if (m->m_len >= sizeof (*cu_head)) {
592
			if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
593
				return;
594
			cu_head = mtod(m, struct cu_header *);
595
			cu_head->s_port = addr.sin_port;
596
			cu_head->so_addr = our_addr.s_addr;
597
		}
598

  
599
		return;
600
	}
601
}
602

  
603 341
struct socket *
604 342
udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr,
605 343
           u_int lport, int flags)

Also available in: Unified diff