1From f09a6460a62aacb87bb8683d16aa3ce55848bf7e Mon Sep 17 00:00:00 2001
2From: Li xin <lixin.fnst@cn.fujitsu.com>
3Date: Fri, 28 Nov 2014 07:06:24 +0900
4Subject: [PATCH 1/2] To aviod buffer overflow in telnet
5
6This patch is from Fedora.
7
8Upstream-Status: pending
9
10Signed-off-by: Li Xin <lixin.fnst@cn.fujitsu.com>
11---
12 telnet/Makefile     |   4 +-
13 telnet/commands.cc  | 270 +++++++++++++++++++++++++++++++++++-----------------
14 telnet/defines.h    |   2 +
15 telnet/externs.h    |   7 +-
16 telnet/main.cc      |  65 ++++++++++---
17 telnet/netlink.cc   |  78 +++++++++------
18 telnet/netlink.h    |   7 +-
19 telnet/network.cc   |   1 +
20 telnet/proto.h      |   2 +-
21 telnet/ring.cc      |   2 +-
22 telnet/ring.h       |   2 +-
23 telnet/sys_bsd.cc   |  11 +++
24 telnet/telnet.1     |  37 +++++--
25 telnet/telnet.cc    |  45 +++++----
26 telnet/terminal.cc  |  17 +++-
27 telnet/utilities.cc |   2 +
28 16 files changed, 380 insertions(+), 172 deletions(-)
29
30diff --git a/telnet/Makefile b/telnet/Makefile
31index cef866f..39249e1 100644
32--- a/telnet/Makefile
33+++ b/telnet/Makefile
34@@ -7,7 +7,7 @@ include ../MRULES
35
36 # -DAUTHENTICATE
37 CXXFLAGS += -DUSE_TERMIO -DKLUDGELINEMODE
38-LIBS += $(LIBTERMCAP)
39+LIBS = $(LIBTERMCAP)
40
41 SRCS = commands.cc main.cc network.cc ring.cc sys_bsd.cc telnet.cc \
42 	terminal.cc tn3270.cc utilities.cc genget.cc environ.cc netlink.cc
43@@ -22,7 +22,7 @@ depend:
44 	$(CXX) $(CXXFLAGS) -MM $(SRCS) >depend.mk
45
46 install: telnet
47-	install -s -m$(BINMODE) telnet $(INSTALLROOT)$(BINDIR)
48+	install -m$(BINMODE) telnet $(INSTALLROOT)$(BINDIR)
49 	install -m$(MANMODE) telnet.1 $(INSTALLROOT)$(MANDIR)/man1
50
51 clean:
52diff --git a/telnet/commands.cc b/telnet/commands.cc
53index d92bccd..02c593e 100644
54--- a/telnet/commands.cc
55+++ b/telnet/commands.cc
56@@ -86,10 +86,6 @@ char cmd_rcsid[] =
57
58 #define HELPINDENT ((int) sizeof ("connect"))
59
60-#ifndef       MAXHOSTNAMELEN
61-#define       MAXHOSTNAMELEN 64
62-#endif        MAXHOSTNAMELEN
63-
64 #if	defined(HAS_IPPROTO_IP) && defined(IP_TOS)
65 int tos = -1;
66 #endif	/* defined(HAS_IPPROTO_IP) && defined(IP_TOS) */
67@@ -98,7 +94,7 @@ static unsigned long sourceroute(char *arg, char **cpp, int *lenp);
68
69
70 char	*hostname;
71-static char _hostname[MAXHOSTNAMELEN];
72+static char *_hostname;
73
74 //typedef int (*intrtn_t)(int argc, const char *argv[]);
75
76@@ -161,7 +157,7 @@ class command_entry {
77 	assert(argc>=1);
78 	if (nargs>=0 && argc!=nargs+1) {
79 	    fprintf(stderr, "Wrong number of arguments for command.\n");
80-	    fprintf(stderr, "Try %s ? for help\n", argv[0]);
81+	    fprintf(stderr, "Try ? %s for help\n", argv[0]);
82 	    return 0;    /* is this right? */
83 	}
84 	if (nargs==-2) {
85@@ -480,6 +476,7 @@ static int send_wontcmd(const char *name, const char *) {
86 int send_tncmd(int (*func)(int, int), const char *cmd, const char *name) {
87     char **cpp;
88     extern char *telopts[];
89+    long opt;
90
91     if (isprefix(name, "help") || isprefix(name, "?")) {
92 	register int col, len;
93@@ -506,16 +503,23 @@ int send_tncmd(int (*func)(int, int), const char *cmd, const char *name) {
94 					name, cmd);
95 	return 0;
96     }
97+
98+    opt = cpp - telopts;
99     if (cpp == 0) {
100-	fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
101+	char *end;
102+
103+	opt = strtol(name, &end, 10);
104+	if (*end || opt < 0 || opt > 255) {
105+	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
106 					name, cmd);
107-	return 0;
108+	    return 0;
109+	}
110     }
111     if (!connected) {
112 	printf("?Need to be connected first.\n");
113 	return 0;
114     }
115-    (*func)(cpp - telopts, 1);
116+    (*func)(opt, 1);
117     return 1;
118 }
119
120@@ -689,9 +693,9 @@ static struct togglelist Togglelist[] = {
121       "print encryption debugging information" },
122 #endif
123
124-    { "skiprc", "don't read ~/.telnetrc file",
125+    { "skiprc", "don't read the telnetrc files",
126       NULL, &skiprc,
127-      "read ~/.telnetrc file" },
128+      "read the telnetrc files" },
129     { "binary",
130       "sending and receiving of binary data",
131       togbinary, NULL,
132@@ -1615,15 +1619,20 @@ void ayt_status(int) {
133 #endif
134
135 int tn(int argc, const char *argv[]) {
136-    register struct hostent *host = 0;
137     struct sockaddr_in sn;
138-    struct servent *sp = 0;
139     char *srp = NULL;
140     int srlen;
141-
142-    const char *cmd, *volatile user = 0;
143+    int family = 0;
144+    const char *cmd, *volatile user = 0, *srchostp = 0;
145     const char *portp = NULL;
146     char *hostp = NULL;
147+    char *resolv_hostp;
148+    struct addrinfo hints;
149+    struct addrinfo *hostaddr = 0;
150+    int res;
151+    char name[NI_MAXHOST];
152+    char service[NI_MAXSERV];
153+    struct addrinfo *tmpaddr;
154
155     /* clear the socket address prior to use */
156     memset(&sn, 0, sizeof(sn));
157@@ -1632,6 +1641,10 @@ int tn(int argc, const char *argv[]) {
158 	printf("?Already connected to %s\n", hostname);
159 	return 0;
160     }
161+    if (_hostname) {
162+	delete[] _hostname;
163+	_hostname = 0;
164+    }
165     if (argc < 2) {
166 	(void) strcpy(line, "open ");
167 	printf("(to) ");
168@@ -1657,11 +1670,33 @@ int tn(int argc, const char *argv[]) {
169 	    --argc;
170 	    continue;
171 	}
172+	if (strcmp(*argv, "-b") == 0) {
173+	    --argc; ++argv;
174+	    if (argc == 0)
175+		goto usage;
176+	    srchostp = *argv++;
177+	    --argc;
178+	    continue;
179+	}
180 	if (strcmp(*argv, "-a") == 0) {
181 	    --argc; ++argv;
182 	    autologin = 1;
183 	    continue;
184 	}
185+	if (strcmp(*argv, "-6") == 0) {
186+	    --argc; ++argv;
187+#ifdef AF_INET6
188+	    family = AF_INET6;
189+#else
190+	    puts("IPv6 unsupported");
191+#endif
192+	    continue;
193+	}
194+	if (strcmp(*argv, "-4") == 0) {
195+	    --argc; ++argv;
196+	    family = AF_INET;
197+	    continue;
198+	}
199 	if (hostp == 0) {
200 	    /* this leaks memory - FIXME */
201 	    hostp = strdup(*argv++);
202@@ -1680,6 +1715,8 @@ int tn(int argc, const char *argv[]) {
203     if (hostp == 0)
204 	goto usage;
205
206+    resolv_hostp = hostp;
207+
208 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
209     if (hostp[0] == '@' || hostp[0] == '!') {
210 	if ((hostname = strrchr(hostp, ':')) == NULL)
211@@ -1696,78 +1733,122 @@ int tn(int argc, const char *argv[]) {
212 	} else {
213 	    sn.sin_addr.s_addr = temp;
214 	    sn.sin_family = AF_INET;
215+	    /*
216+	     * For source route we just make sure to get the IP given
217+	     * on the command line when looking up the port.
218+	     */
219+	    resolv_hostp = inet_ntoa(sn.sin_addr);
220 	}
221     }
222-    else {
223-#endif
224-	if (inet_aton(hostp, &sn.sin_addr)) {
225-	    sn.sin_family = AF_INET;
226-	    strcpy(_hostname, hostp);
227-	    hostname = _hostname;
228-	}
229-	else {
230-	    host = gethostbyname(hostp);
231-	    if (host) {
232-		sn.sin_family = host->h_addrtype;
233-		if (host->h_length > (int)sizeof(sn.sin_addr)) {
234-		    host->h_length = sizeof(sn.sin_addr);
235-		}
236-#if	defined(h_addr)		/* In 4.3, this is a #define */
237-		memcpy((caddr_t)&sn.sin_addr,
238-				host->h_addr_list[0], host->h_length);
239-#else	/* defined(h_addr) */
240-		memcpy((caddr_t)&sn.sin_addr, host->h_addr, host->h_length);
241-#endif	/* defined(h_addr) */
242-		strncpy(_hostname, host->h_name, sizeof(_hostname));
243-		_hostname[sizeof(_hostname)-1] = '\0';
244-		hostname = _hostname;
245-	    } else {
246-		herror(hostp);
247-		return 0;
248-	    }
249-	}
250-#if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
251-    }
252 #endif
253+
254+    /* User port or the default name of telnet. */
255     if (portp) {
256 	if (*portp == '-') {
257 	    portp++;
258 	    telnetport = 1;
259-	} else
260+	} else {
261 	    telnetport = 0;
262-	sn.sin_port = atoi(portp);
263-	if (sn.sin_port == 0) {
264-	    sp = getservbyname(portp, "tcp");
265-	    if (sp)
266-		sn.sin_port = sp->s_port;
267-	    else {
268-		printf("%s: bad port number\n", portp);
269-		return 0;
270+	    if (*portp >='0' && *portp<='9') {
271+	       char *end;
272+	       long int p;
273+
274+	       p=strtol(portp, &end, 10);
275+	       if (ERANGE==errno && (LONG_MIN==p || LONG_MAX==p)) {
276+	          fprintf(stderr, "telnet: port %s overflows\n", portp);
277+		  return 0;
278+	       } else if (p<=0 || p>=65536) {
279+	          fprintf(stderr, "telnet: port %s out of range\n", portp);
280+		  return 0;
281+	       }
282 	    }
283-	}
284-	else {
285-	    sn.sin_port = htons(sn.sin_port);
286 	}
287-    }
288+    }
289     else {
290-	if (sp == 0) {
291-	    sp = getservbyname("telnet", "tcp");
292-	    if (sp == 0) {
293-		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
294-		return 0;
295-	    }
296-	    sn.sin_port = sp->s_port;
297-	}
298+	portp = "telnet";
299 	telnetport = 1;
300     }
301-    printf("Trying %s...\n", inet_ntoa(sn.sin_addr));
302+
303+    /* We only understand SOCK_STREAM sockets. */
304+    memset(&hints, 0, sizeof(hints));
305+    hints.ai_socktype = SOCK_STREAM;
306+    hints.ai_flags = AI_NUMERICHOST;
307+    hints.ai_family = family;
308+
309+    if (srchostp) {
310+	res = getaddrinfo(srchostp, "0", &hints, &hostaddr);
311+	if (res) {
312+	    fprintf(stderr, "telnet: could not resolve %s: %s\n", srchostp,
313+		    gai_strerror(res));
314+	    return 0;
315+	}
316+	hints.ai_family = hostaddr->ai_family;
317+	res = nlink.bind(hostaddr);
318+	freeaddrinfo(hostaddr);
319+	if (res < 0)
320+	    return 0;
321+    }
322+
323+    /* Resolve both the host and service simultaneously. */
324+    res = getaddrinfo(resolv_hostp, portp, &hints, &hostaddr);
325+    if (res == EAI_NONAME) {
326+	hints.ai_flags = AI_CANONNAME;
327+	res = getaddrinfo(resolv_hostp, portp, &hints, &hostaddr);
328+    } else if (hostaddr) {
329+	hostaddr->ai_canonname = 0;
330+    }
331+    if (res || !hostaddr) {
332+	fprintf(stderr, "telnet: could not resolve %s/%s: %s\n", resolv_hostp, portp, gai_strerror(res));
333+	return 0;
334+    }
335+
336+    /* Try to connect to every listed round robin IP. */
337+    tmpaddr = hostaddr;
338+    errno = 0;
339     do {
340-	int x = nlink.connect(debug, host, &sn, srp, srlen, tos);
341-	if (!x) return 0;
342-	else if (x==1) continue;
343+	int x;
344+
345+	if (!tmpaddr) {
346+	    if (errno)
347+		perror("telnet: Unable to connect to remote host");
348+	    else
349+		fputs("telnet: Unable to connect to remote host: "
350+		      "Bad port number\n", stderr);
351+err:
352+	    freeaddrinfo(hostaddr);
353+	    return 0;
354+	}
355+
356+	if (tmpaddr->ai_family == AF_UNIX) {
357+nextaddr:
358+	    tmpaddr = tmpaddr->ai_next;
359+	    continue;
360+	}
361+
362+	getnameinfo(tmpaddr->ai_addr, tmpaddr->ai_addrlen,
363+		    name, sizeof(name), service, sizeof(service),
364+		    NI_NUMERICHOST | NI_NUMERICSERV);
365+
366+	printf("Trying %s...\n", name);
367+	x = nlink.connect(debug, tmpaddr, srp, srlen, tos);
368+	if (!x)
369+	    goto err;
370+	else if (x==1)
371+	    goto nextaddr;
372+
373 	connected++;
374     } while (connected == 0);
375-    cmdrc(hostp, hostname);
376+    if (tmpaddr->ai_canonname == 0) {
377+	hostname = new char[strlen(hostp)+1];
378+	strcpy(hostname, hostp);
379+    }
380+    else {
381+	hostname = new char[strlen(tmpaddr->ai_canonname)+1];
382+	strcpy(hostname, tmpaddr->ai_canonname);
383+    }
384+
385+    cmdrc(hostp, hostname, portp);
386+    freeaddrinfo(hostaddr);
387     if (autologin && user == NULL) {
388 	struct passwd *pw;
389
390@@ -2013,30 +2094,21 @@ static int help(command_table *tab, int argc, const char *argv[]) {
391     return 0;
392 }
393
394-static char *rcname = 0;
395-static char rcbuf[128];
396-
397-void cmdrc(const char *m1, const char *m2) {
398+static void readrc(const char *m1, const char *m2, const char *port,
399+		   const char *rcname)
400+{
401     FILE *rcfile;
402     int gotmachine = 0;
403     int l1 = strlen(m1);
404     int l2 = strlen(m2);
405-    char m1save[64];
406-
407-    if (skiprc) return;
408+    int lport = strlen(port);
409+    char m1save[l1 + 1];
410+    char portsave[lport + 1];
411
412     strcpy(m1save, m1);
413     m1 = m1save;
414-
415-    if (rcname == 0) {
416-	rcname = getenv("HOME");
417-	if (rcname)
418-	    strcpy(rcbuf, rcname);
419-	else
420-	    rcbuf[0] = '\0';
421-	strcat(rcbuf, "/.telnetrc");
422-	rcname = rcbuf;
423-    }
424+    strcpy(portsave, port);
425+    port = portsave;
426
427     rcfile = fopen(rcname, "r");
428     if (!rcfile) return;
429@@ -2061,6 +2133,13 @@ void cmdrc(const char *m1, const char *m2) {
430 		strncpy(line, &line[7], sizeof(line) - 7);
431 	    else
432 		continue;
433+
434+	    if (line[0] == ':') {
435+		if (!strncasecmp(&line[1], port, lport))
436+		    continue;
437+		strncpy(line, &line[lport + 1], sizeof(line) - lport - 1);
438+	    }
439+
440 	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
441 		continue;
442 	    gotmachine = 1;
443@@ -2073,6 +2152,21 @@ void cmdrc(const char *m1, const char *m2) {
444     fclose(rcfile);
445 }
446
447+void cmdrc(const char *m1, const char *m2, const char *port) {
448+    char *rcname = NULL;
449+
450+    if (skiprc) return;
451+
452+    readrc(m1, m2, port, "/etc/telnetrc");
453+    if (asprintf (&rcname, "%s/.telnetrc", getenv ("HOME")) == -1)
454+      {
455+        perror ("asprintf");
456+        return;
457+      }
458+    readrc(m1, m2, port, rcname);
459+    free (rcname);
460+}
461+
462 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
463
464 /*
465diff --git a/telnet/defines.h b/telnet/defines.h
466index 2784400..d5edc46 100644
467--- a/telnet/defines.h
468+++ b/telnet/defines.h
469@@ -50,3 +50,5 @@
470 #define	MODE_COMMAND_LINE(m)	((m)==-1)
471
472 #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
473+
474+#define MODE_OUT8	0x8000			/* binary mode sans -opost */
475diff --git a/telnet/externs.h b/telnet/externs.h
476index 955df79..0730e8a 100644
477--- a/telnet/externs.h
478+++ b/telnet/externs.h
479@@ -48,9 +48,7 @@
480 typedef unsigned char cc_t;
481 #endif
482
483-#ifdef __linux__
484 #include <unistd.h>   /* get _POSIX_VDISABLE */
485-#endif
486
487 #ifndef	_POSIX_VDISABLE
488 #error "Please fix externs.h to define _POSIX_VDISABLE"
489@@ -60,7 +58,8 @@ typedef unsigned char cc_t;
490
491 extern int autologin;		/* Autologin enabled */
492 extern int skiprc;		/* Don't process the ~/.telnetrc file */
493-extern int eight;		/* use eight bit mode (binary in and/or out */
494+extern int eight;		/* use eight bit mode (binary in and/or out) */
495+extern int binary;		/* use binary option (in and/or out) */
496 extern int flushout;		/* flush output */
497 extern int connected;		/* Are we connected to the other side? */
498 extern int globalmode;		/* Mode tty should be in */
499@@ -225,6 +224,8 @@ cc_t *tcval(int);
500
501 //#if 0
502 extern struct termios new_tc;
503+extern struct termios old_tc;
504+
505
506 #define termEofChar		new_tc.c_cc[VEOF]
507 #define termEraseChar		new_tc.c_cc[VERASE]
508diff --git a/telnet/main.cc b/telnet/main.cc
509index b67f2ce..b626e54 100644
510--- a/telnet/main.cc
511+++ b/telnet/main.cc
512@@ -45,7 +45,10 @@ char main_rcsid[] =
513
514 #include <sys/types.h>
515 #include <getopt.h>
516+#include <stdlib.h>
517 #include <string.h>
518+#include <netdb.h>
519+#include <errno.h>
520
521 #include "ring.h"
522 #include "externs.h"
523@@ -80,12 +83,13 @@ tninit(void)
524 void usage(void) {
525     fprintf(stderr, "Usage: %s %s%s%s%s\n",
526 	    prompt,
527-	    " [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile]",
528-	    "\n\t",
529+	    "[-4] [-6] [-8] [-E] [-L] [-a] [-d] [-e char] [-l user]",
530+	    "\n\t[-n tracefile] [ -b addr ]",
531 #ifdef TN3270
532+	    "\n\t"
533 	    "[-noasynch] [-noasynctty] [-noasyncnet] [-r] [-t transcom]\n\t",
534 #else
535-	    "[-r] ",
536+	    " [-r] ",
537 #endif
538 	    "[host-name [port]]"
539 	);
540@@ -102,7 +106,8 @@ main(int argc, char *argv[])
541 	extern char *optarg;
542 	extern int optind;
543 	int ch;
544-	char *user;
545+	char *user, *srcaddr;
546+	int family;
547
548 	tninit();		/* Clear out things */
549 #if	defined(CRAY) && !defined(__STDC__)
550@@ -110,21 +115,38 @@ main(int argc, char *argv[])
551 #endif
552
553 	TerminalSaveState();
554+	if ((old_tc.c_cflag & (CSIZE|PARENB)) != CS8)
555+		eight = 0;
556
557 	if ((prompt = strrchr(argv[0], '/'))!=NULL)
558 		++prompt;
559 	else
560 		prompt = argv[0];
561
562-	user = NULL;
563+	user = srcaddr = NULL;
564+	family = 0;
565
566 	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
567 	autologin = -1;
568
569-	while ((ch = getopt(argc, argv, "8EKLS:X:ade:k:l:n:rt:x")) != EOF) {
570+	while ((ch = getopt(argc, argv,
571+			    "4678EKLS:X:ab:de:k:l:n:rt:x")) != EOF) {
572 		switch(ch) {
573+		case '4':
574+			family = AF_INET;
575+			break;
576+		case '6':
577+#ifdef AF_INET6
578+			family = AF_INET6;
579+#else
580+			fputs("IPv6 unsupported\n", stderr);
581+#endif
582+			break;
583+		case '7':
584+			eight = 0;	/* 7-bit ouput and input */
585+			break;
586 		case '8':
587-			eight = 3;	/* binary output and input */
588+			binary = 3;	/* binary output and input */
589 			break;
590 		case 'E':
591 			rlogin = escapechar = _POSIX_VDISABLE;
592@@ -133,23 +155,26 @@ main(int argc, char *argv[])
593 		        //autologin = 0;
594 			break;
595 		case 'L':
596-			eight |= 2;	/* binary output only */
597+			binary |= 2;	/* binary output only */
598 			break;
599 		case 'S':
600 		    {
601-#ifdef	HAS_GETTOS
602 			extern int tos;
603+			int num;
604
605-			if ((tos = parsetos(optarg, "tcp")) < 0)
606+#ifdef	HAS_GETTOS
607+			if ((num = parsetos(optarg, "tcp")) < 0) {
608+#else
609+			errno = 0;
610+			num = strtol(optarg, 0, 0);
611+			if (errno) {
612+#endif
613 				fprintf(stderr, "%s%s%s%s\n",
614 					prompt, ": Bad TOS argument '",
615 					optarg,
616 					"; will try to use default TOS");
617-#else
618-			fprintf(stderr,
619-			   "%s: Warning: -S ignored, no parsetos() support.\n",
620-								prompt);
621-#endif
622+			} else
623+				tos = num;
624 		    }
625 			break;
626 		case 'X':
627@@ -210,6 +235,9 @@ main(int argc, char *argv[])
628 				"%s: -x ignored, no encryption support.\n",
629 				prompt);
630 			break;
631+		case 'b':
632+			srcaddr = optarg;
633+			break;
634 		case '?':
635 		default:
636 			usage();
637@@ -233,6 +261,13 @@ main(int argc, char *argv[])
638 			*argp++ = "-l";
639 			*argp++ = user;
640 		}
641+		if (srcaddr) {
642+			*argp++ = "-b";
643+			*argp++ = srcaddr;
644+		}
645+		if (family) {
646+			*argp++ = family == AF_INET ? "-4" : "-6";
647+		}
648 		*argp++ = argv[0];		/* host */
649 		if (argc > 1)
650 			*argp++ = argv[1];	/* port */
651diff --git a/telnet/netlink.cc b/telnet/netlink.cc
652index f439cff..f839747 100644
653--- a/telnet/netlink.cc
654+++ b/telnet/netlink.cc
655@@ -79,22 +79,61 @@ void netlink::close(int doshutdown) {
656 	shutdown(net, 2);
657     }
658     ::close(net);
659+    net = -1;
660 }
661
662-int netlink::connect(int debug, struct hostent *host,
663-		     struct sockaddr_in *sn,
664-		     char *srcroute, int srlen, int tos)
665+int netlink::bind(struct addrinfo *addr)
666 {
667-    int on=1;
668+    int res;
669+
670+    res = socket(addr->ai_family);
671+    if (res < 2) {
672+	if (res == 1)
673+	    perror("telnet: socket");
674+	return -1;
675+    }
676+
677+    if (::bind(net, addr->ai_addr, addr->ai_addrlen) < 0) {
678+	perror("telnet: bind");
679+	return -1;
680+    }
681+
682+    return 0;
683+}
684+
685+int netlink::socket(int family)
686+{
687+    if (this->family != family)
688+	close(0);
689
690-    net = socket(AF_INET, SOCK_STREAM, 0);
691     if (net < 0) {
692-	perror("telnet: socket");
693-	return 0;
694+	this->family = family;
695+	net = ::socket(family, SOCK_STREAM, 0);
696+	if (net < 0) {
697+	    if (errno == EAFNOSUPPORT)
698+		return 1;
699+	    perror("telnet: socket");
700+	    return 0;
701+	}
702     }
703
704+    return 2;
705+}
706+
707+int netlink::connect(int debug, struct addrinfo *addr,
708+		     char *srcroute, int srlen, int tos)
709+{
710+    int on=1;
711+    int res;
712+
713+    res = socket(addr->ai_family);
714+    if (res < 2)
715+	return res;
716+
717 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
718     if (srcroute) {
719+	if (addr->ai_family != AF_INET)
720+	    fputs("Source route is only supported for IPv4\n", stderr);
721 	if (setsockopt(net, IPPROTO_IP, IP_OPTIONS, srcroute, srlen) < 0)
722 	    perror("setsockopt (IP_OPTIONS)");
723     }
724@@ -108,7 +147,7 @@ int netlink::connect(int debug, struct hostent *host,
725 #endif
726     if (tos < 0) tos = 020;	/* Low Delay bit */
727     if (tos && (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
728-	&& (errno != ENOPROTOOPT))
729+	&& (errno != ENOPROTOOPT) && (errno != EOPNOTSUPP))
730 	perror("telnet: setsockopt (IP_TOS) (ignored)");
731 #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
732
733@@ -116,27 +155,8 @@ int netlink::connect(int debug, struct hostent *host,
734 	perror("setsockopt (SO_DEBUG)");
735     }
736
737-    if (::connect(net, (struct sockaddr *)sn, sizeof(*sn)) < 0) {
738-#if defined(h_addr)		/* In 4.3, this is a #define */
739-	if (host && host->h_addr_list[1]) {
740-	    int oerrno = errno;
741-
742-	    fprintf(stderr, "telnet: connect to address %s: ",
743-		    inet_ntoa(sn->sin_addr));
744-	    errno = oerrno;
745-	    perror(NULL);
746-	    host->h_addr_list++;
747-	    if (host->h_length > (int)sizeof(sn->sin_addr)) {
748-		host->h_length = sizeof(sn->sin_addr);
749-	    }
750-	    memcpy(&sn->sin_addr, host->h_addr_list[0], host->h_length);
751-	    close(net);
752-	    return 1;
753-	}
754-#endif	/* defined(h_addr) */
755-
756-	perror("telnet: Unable to connect to remote host");
757-	return 0;
758+    if (::connect(net, addr->ai_addr, addr->ai_addrlen) < 0) {
759+	return 1;
760     }
761     return 2;
762 }
763diff --git a/telnet/netlink.h b/telnet/netlink.h
764index 9852b30..0ac8a08 100644
765--- a/telnet/netlink.h
766+++ b/telnet/netlink.h
767@@ -1,13 +1,16 @@
768
769 class netlink {
770+ private:
771+    int family;
772  protected:
773     int net;
774  public:
775     netlink();
776     ~netlink();
777
778-    int connect(int debug, struct hostent *host,
779-		struct sockaddr_in *sin,
780+    int bind(struct addrinfo *hostaddr);
781+    int socket(int family);
782+    int connect(int debug, struct addrinfo *hostaddr,
783 		char *srcroute, int srlen,
784 		int tos);
785     void close(int doshutdown);
786diff --git a/telnet/network.cc b/telnet/network.cc
787index 6a2c374..0dcf3e2 100644
788--- a/telnet/network.cc
789+++ b/telnet/network.cc
790@@ -40,6 +40,7 @@ char net_rcsid[] =
791 #include <sys/types.h>
792 #include <sys/socket.h>
793 #include <sys/time.h>
794+#include <stdlib.h>
795 #include <errno.h>
796 #include <arpa/telnet.h>
797
798diff --git a/telnet/proto.h b/telnet/proto.h
799index 8be4a39..92f2419 100644
800--- a/telnet/proto.h
801+++ b/telnet/proto.h
802@@ -13,7 +13,7 @@ int TerminalWindowSize(long *rows, long *cols);
803 void auth_encrypt_user(char *);
804 void auth_name(unsigned char *, int);
805 void auth_printsub(unsigned char *, int, unsigned char *, int);
806-void cmdrc(const char *m1, const char *m2);
807+void cmdrc(const char *, const char *, const char *);
808 void env_init(void);
809 int getconnmode(void);
810 void init_network(void);
811diff --git a/telnet/ring.cc b/telnet/ring.cc
812index be57396..772c6c5 100644
813--- a/telnet/ring.cc
814+++ b/telnet/ring.cc
815@@ -165,7 +165,7 @@ int ringbuf::flush() {
816
817 /////////////////////////////////////////////////// supply //////////////
818
819-void ringbuf::printf(const char *format, ...) {
820+void ringbuf::xprintf(const char *format, ...) {
821     char xbuf[256];
822     va_list ap;
823     va_start(ap, format);
824diff --git a/telnet/ring.h b/telnet/ring.h
825index 15d3f3f..049377e 100644
826--- a/telnet/ring.h
827+++ b/telnet/ring.h
828@@ -83,7 +83,7 @@ class ringbuf {
829     // manual supply
830     void putch(char c) { write(&c, 1); }
831     void write(const char *buffer, int ct);
832-    void printf(const char *format, ...);
833+    void xprintf(const char *format, ...);
834     int empty_count() { return size - count; }
835
836     // automatic supply
837diff --git a/telnet/sys_bsd.cc b/telnet/sys_bsd.cc
838index 93fba7e..a8c9aab 100644
839--- a/telnet/sys_bsd.cc
840+++ b/telnet/sys_bsd.cc
841@@ -189,18 +189,25 @@ void NetSetPgrp(int fd) {
842  * Various signal handling routines.
843  */
844
845+#if 0
846 static void deadpeer(int /*sig*/) {
847     setcommandmode();
848     siglongjmp(peerdied, -1);
849 }
850+#endif
851
852 static void intr(int /*sig*/) {
853     if (localchars) {
854 	intp();
855     }
856     else {
857+#if 0
858         setcommandmode();
859 	siglongjmp(toplevel, -1);
860+#else
861+	signal(SIGINT, SIG_DFL);
862+	raise(SIGINT);
863+#endif
864     }
865 }
866
867@@ -214,6 +221,8 @@ static void intr2(int /*sig*/) {
868 	    sendabort();
869 	return;
870     }
871+    signal(SIGQUIT, SIG_DFL);
872+    raise(SIGQUIT);
873 }
874
875 #ifdef	SIGWINCH
876@@ -238,7 +247,9 @@ void ayt(int sig) {
877 void sys_telnet_init(void) {
878     signal(SIGINT, intr);
879     signal(SIGQUIT, intr2);
880+#if 0
881     signal(SIGPIPE, deadpeer);
882+#endif
883 #ifdef	SIGWINCH
884     signal(SIGWINCH, sendwin);
885 #endif
886diff --git a/telnet/telnet.1 b/telnet/telnet.1
887index 54a47fb..8365e42 100644
888--- a/telnet/telnet.1
889+++ b/telnet/telnet.1
890@@ -42,8 +42,9 @@
891 protocol
892 .Sh SYNOPSIS
893 .Nm telnet
894-.Op Fl 8ELadr
895+.Op Fl 468ELadr
896 .Op Fl S Ar tos
897+.Op Fl b Ar address
898 .Op Fl e Ar escapechar
899 .Op Fl l Ar user
900 .Op Fl n Ar tracefile
901@@ -68,6 +69,10 @@ command implicitly; see the description below.
902 .Pp
903 Options:
904 .Bl -tag -width indent
905+.It Fl 4
906+Force IPv4 address resolution.
907+.It Fl 6
908+Force IPv6 address resolution.
909 .It Fl 8
910 Request 8-bit operation. This causes an attempt to negotiate the
911 .Dv TELNET BINARY
912@@ -89,6 +94,8 @@ of the
913 option if supported by the remote system. The username is retrieved
914 via
915 .Xr getlogin 3 .
916+.It Fl b Ar address
917+Use bind(2) on the local socket to bind it to a specific local address.
918 .It Fl d
919 Sets the initial value of the
920 .Ic debug
921@@ -474,17 +481,29 @@ protocol without making a mess. Protocol negotiation can be forced by
922 placing a dash before the port number.
923 .Pp
924 After establishing a connection, any commands associated with the
925-remote host in the user's
926+remote host in
927+.Pa /etc/telnetrc
928+and the user's
929 .Pa .telnetrc
930-file are executed.
931+file are executed, in that order.
932 .Pp
933-The format of the .telnetrc file is as follows: Lines beginning with a
934+The format of the telnetrc files is as follows: Lines beginning with a
935 #, and blank lines, are ignored.  The rest of the file should consist
936 of hostnames and sequences of
937 .Nm telnet
938 commands to use with that host. Commands should be one per line,
939 indented by whitespace; lines beginning without whitespace are
940-interpreted as hostnames. Upon connecting to a particular host, the
941+interpreted as hostnames.  Lines beginning with the special hostname
942+.Ql DEFAULT
943+will apply to all hosts.  Hostnames including
944+.Ql DEFAULT
945+may be followed immediately by a colon and a port number or string.
946+If a port is specified it must match exactly with what is specified
947+on the command line.  If no port was specified on the command line,
948+then the value
949+.Ql telnet
950+is used.
951+Upon connecting to a particular host, the
952 commands associated with that host are executed.
953 .It Ic quit
954 Close any open session and exit
955@@ -1184,9 +1203,7 @@ escape sequences are preceded by a '*' to aid in locating them.
956 When the skiprc toggle is
957 .Dv TRUE ,
958 .Tn telnet
959-does not read the
960-.Pa \&.telnetrc
961-file.  The initial value for this toggle is
962+does not read the telnetrc files.  The initial value for this toggle is
963 .Dv FALSE.
964 .It Ic termdata
965 Toggles the display of all terminal data (in hexadecimal format).
966@@ -1239,7 +1256,9 @@ to the other side via the
967 .Dv TELNET ENVIRON
968 option.
969 .Sh FILES
970-.Bl -tag -width ~/.telnetrc -compact
971+.Bl -tag -width /etc/telnetrc -compact
972+.It Pa /etc/telnetrc
973+global telnet startup values
974 .It Pa ~/.telnetrc
975 user customized telnet startup values
976 .El
977diff --git a/telnet/telnet.cc b/telnet/telnet.cc
978index 4fc3b1f..7eca811 100644
979--- a/telnet/telnet.cc
980+++ b/telnet/telnet.cc
981@@ -88,7 +88,8 @@ char	do_dont_resp[256];
982 char	will_wont_resp[256];
983
984 int
985-eight = 0,
986+  eight = 3,
987+  binary = 0,
988   autologin = 0,	/* Autologin anyone? */
989   skiprc = 0,
990   connected,
991@@ -639,14 +640,14 @@ static const char *gettermname(void) {
992   if (resettermname) {
993     resettermname = 0;
994     tname = env_getvalue("TERM", 0);
995-    if (!tname || my_setupterm(tname, 1, &err)) {
996+    if (!tname /* || my_setupterm(tname, 1, &err) */) {
997       termbuf[0] = 0;
998       tname = "UNKNOWN";
999     }
1000     mklist(termbuf, tname, termtypes);
1001     next = 0;
1002   }
1003-  if (next==termtypes.num()) next = 0;
1004+  if (next==termtypes.num()-1) next = 0;
1005   return termtypes[next++];
1006 }
1007 /*
1008@@ -681,7 +682,7 @@ static void suboption(void) {
1009       }
1010 #endif /* TN3270 */
1011       name = gettermname();
1012-      netoring.printf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1013+      netoring.xprintf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1014 		      TELQUAL_IS, name, IAC, SE);
1015     }
1016     break;
1017@@ -693,7 +694,7 @@ static void suboption(void) {
1018     if (SB_GET() == TELQUAL_SEND) {
1019       long oospeed, iispeed;
1020       TerminalSpeeds(&iispeed, &oospeed);
1021-      netoring.printf("%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
1022+      netoring.xprintf("%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
1023 		      TELQUAL_IS, oospeed, iispeed, IAC, SE);
1024     }
1025     break;
1026@@ -780,7 +781,7 @@ static void suboption(void) {
1027 	send_wont(TELOPT_XDISPLOC, 1);
1028 	break;
1029       }
1030-      netoring.printf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
1031+      netoring.xprintf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
1032 		      TELQUAL_IS, dp, IAC, SE);
1033     }
1034     break;
1035@@ -798,7 +799,7 @@ void lm_will(unsigned char *cmd, int len) {
1036     return;
1037   }
1038
1039-  netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1040+  netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1041 		  DONT, cmd[0], IAC, SE);
1042 }
1043
1044@@ -815,7 +816,7 @@ void lm_do(unsigned char *cmd, int len) {
1045     /*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
1046     return;
1047   }
1048-  netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1049+  netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1050 		  WONT, cmd[0], IAC, SE);
1051 }
1052
1053@@ -838,7 +839,7 @@ void lm_mode(unsigned char *cmd, int len, int init) {
1054     k |= MODE_ACK;
1055   }
1056
1057-  netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE,
1058+  netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE,
1059 		  k, IAC, SE);
1060
1061   setconnmode(0);	/* set changed mode */
1062@@ -933,11 +934,11 @@ void slc_mode_import(int def) {
1063
1064 void slc_import(int def) {
1065   if (def) {
1066-    netoring.printf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1067+    netoring.xprintf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1068 		    LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE);
1069   }
1070   else {
1071-    netoring.printf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1072+    netoring.xprintf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
1073 		    LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE);
1074   }
1075 }
1076@@ -1050,6 +1051,7 @@ void slc_check(void) {
1077
1078
1079 unsigned char slc_reply[128];
1080+unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
1081 unsigned char *slc_replyp;
1082
1083 void slc_start_reply(void) {
1084@@ -1061,6 +1063,14 @@ void slc_start_reply(void) {
1085 }
1086
1087 void slc_add_reply(int func, int flags, int value) {
1088+  /* A sequence of up to 6 bytes my be written for this member of the SLC
1089+   * suboption list by this function.  The end of negotiation command,
1090+   * which is written by slc_end_reply(), will require 2 additional
1091+   * bytes.  Do not proceed unless there is sufficient space for these
1092+   * items.
1093+   */
1094+  if (&slc_replyp[6+2] > slc_reply_eom)
1095+    return;
1096   if ((*slc_replyp++ = func) == IAC)
1097     *slc_replyp++ = IAC;
1098   if ((*slc_replyp++ = flags) == IAC)
1099@@ -1142,6 +1152,7 @@ void env_opt(unsigned char *buf, int len) {
1100   }
1101 }
1102
1103+/* OPT_REPLY_SIZE must be a multiple of 2. */
1104 #define	OPT_REPLY_SIZE	256
1105 unsigned char *opt_reply;
1106 unsigned char *opt_replyp;
1107@@ -1173,6 +1184,7 @@ void env_opt_start_info(void) {
1108
1109 void env_opt_add(const char *ep) {
1110   const char *vp;
1111+  const unsigned char *tp;
1112   unsigned char c;
1113
1114   if (opt_reply == NULL)		/*XXX*/
1115@@ -1185,11 +1197,12 @@ void env_opt_add(const char *ep) {
1116     return;
1117   }
1118   vp = env_getvalue(ep, 1);
1119-  if (opt_replyp + (vp ? strlen(vp) : 0) + strlen(ep) + 6 > opt_replyend)
1120+  tp = opt_replyp + (vp ? strlen(vp) * 2 : 0) + strlen(ep) * 2 + 6;
1121+  if (tp > opt_replyend)
1122     {
1123       register int len;
1124-      opt_replyend += OPT_REPLY_SIZE;
1125-      len = opt_replyend - opt_reply;
1126+      len = ((tp - opt_reply) + OPT_REPLY_SIZE - 1) & ~(OPT_REPLY_SIZE - 1);
1127+      opt_replyend = opt_reply + len;
1128       opt_reply = (unsigned char *)realloc(opt_reply, len);
1129       if (opt_reply == NULL) {
1130 	/*@*/			printf("env_opt_add: realloc() failed!!!\n");
1131@@ -1740,8 +1753,8 @@ void telnet(const char * /*user*/) {
1132     send_do(TELOPT_STATUS, 1);
1133     if (env_getvalue("DISPLAY", 0))
1134       send_will(TELOPT_XDISPLOC, 1);
1135-    if (eight)
1136-      tel_enter_binary(eight);
1137+    if (binary)
1138+      tel_enter_binary(binary);
1139   }
1140 #endif /* !defined(TN3270) */
1141
1142diff --git a/telnet/terminal.cc b/telnet/terminal.cc
1143index 9eb47ae..764f18f 100644
1144--- a/telnet/terminal.cc
1145+++ b/telnet/terminal.cc
1146@@ -45,6 +45,8 @@ char terminal_rcsid[] =
1147 #include <signal.h>
1148 #include <errno.h>
1149 #include <stdio.h>
1150+#include <string.h>
1151+#include <stdlib.h>
1152
1153 #include "ring.h"
1154 #include "defines.h"
1155@@ -155,9 +157,11 @@ int getconnmode(void) {
1156     if (localflow)
1157 	mode |= MODE_FLOW;
1158
1159-    if (my_want_state_is_will(TELOPT_BINARY))
1160+    if ((eight & 1) || my_want_state_is_will(TELOPT_BINARY))
1161 	mode |= MODE_INBIN;
1162
1163+    if (eight & 2)
1164+	mode |= MODE_OUT8;
1165     if (his_want_state_is_will(TELOPT_BINARY))
1166 	mode |= MODE_OUTBIN;
1167
1168@@ -449,10 +453,13 @@ void TerminalNewMode(int f)
1169 		// breaks SunOS.
1170 	 	tmp_tc.c_iflag |= ISTRIP;
1171 	}
1172-	if (f & MODE_OUTBIN) {
1173+	if (f & (MODE_OUTBIN|MODE_OUT8)) {
1174 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
1175 		tmp_tc.c_cflag |= CS8;
1176-		tmp_tc.c_oflag &= ~OPOST;
1177+		if (f & MODE_OUTBIN)
1178+			tmp_tc.c_oflag &= ~OPOST;
1179+		else
1180+			tmp_tc.c_oflag |= OPOST;
1181 	} else {
1182 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
1183 		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
1184@@ -468,7 +475,7 @@ void TerminalNewMode(int f)
1185
1186 #ifdef	SIGINFO
1187 	signal(SIGINFO, ayt);
1188-#endif	SIGINFO
1189+#endif	/* SIGINFO */
1190
1191 #if defined(NOKERNINFO)
1192 	tmp_tc.c_lflag |= NOKERNINFO;
1193@@ -504,7 +511,7 @@ void TerminalNewMode(int f)
1194
1195 #ifdef	SIGINFO
1196 	signal(SIGINFO, ayt_status);
1197-#endif	SIGINFO
1198+#endif	/* SIGINFO */
1199
1200 #ifdef	SIGTSTP
1201 	signal(SIGTSTP, SIG_DFL);
1202diff --git a/telnet/utilities.cc b/telnet/utilities.cc
1203index 0448f0a..66839ab 100644
1204--- a/telnet/utilities.cc
1205+++ b/telnet/utilities.cc
1206@@ -47,6 +47,8 @@ char util_rcsid[] =
1207 #include <sys/socket.h>
1208 #include <unistd.h>
1209 #include <ctype.h>
1210+#include <string.h>
1211+#include <stdlib.h>
1212
1213 #include "ring.h"
1214 #include "defines.h"
1215--
12161.8.4.2
1217
1218