1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * mconnect.c - A program to test out SMTP connections.
28  * Usage: mconnect [host]
29  *  ... SMTP dialog
30  *  ^C or ^D or QUIT
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <signal.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <sgtty.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <unistd.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46 #include <arpa/nameser.h>
47 #include <arpa/inet.h>
48 #include <errno.h>
49 
50 union bigsockaddr
51 {
52 	struct sockaddr		sa;	/* general version */
53 	struct sockaddr_in	sin;	/* INET family */
54 	struct sockaddr_in6	sin6;	/* INET/IPv6 */
55 };
56 
57 static struct sgttyb TtyBuf;
58 static int raw = 0;
59 
60 /* ARGSUSED */
61 static void
finis(sig)62 finis(sig)
63 	int sig;
64 {
65 	if (raw)
66 		(void) ioctl(0, TIOCSETP, &TtyBuf);
67 	exit(0);
68 }
69 
70 int
main(argc,argv)71 main(argc, argv)
72 	int argc;
73 	char **argv;
74 {
75 	union bigsockaddr SendmailAddress;
76 	register int s;
77 	char *host = NULL;
78 	int pid;
79 	int on = 1;
80 	struct servent *sp;
81 	char buf[1000];
82 	register FILE *f;
83 	register struct hostent *hp;
84 	in_port_t port = 0;
85 	int err;
86 	char buf6[INET6_ADDRSTRLEN];
87 	int addr_num = 0;
88 	int addrlen;
89 
90 	(void) ioctl(0, TIOCGETP, &TtyBuf);
91 	(void) signal(SIGINT, finis);
92 
93 	while (--argc > 0)
94 	{
95 		register char *p;
96 
97 		p = *++argv;
98 		if (*p == '-')
99 		{
100 			switch (*++p)
101 			{
102 			    case 'h':		/* host */
103 				break;
104 
105 			    case 'p':		/* port */
106 				port = htons(atoi(*++argv));
107 				argc--;
108 				break;
109 
110 			    case 'r':		/* raw connection */
111 				raw = 1;
112 				break;
113 			}
114 		} else if (host == NULL)
115 			host = p;
116 	}
117 	if (host == NULL)
118 		host = "localhost";
119 
120 	bzero(&SendmailAddress, sizeof (SendmailAddress));
121 	hp = getipnodebyname(host, AF_INET6, AI_DEFAULT|AI_ALL, &err);
122 	if (hp == NULL)
123 	{
124 		(void) fprintf(stderr, "mconnect: unknown host %s\r\n", host);
125 		exit(0);
126 	}
127 
128 	if (port == 0) {
129 		sp = getservbyname("smtp", "tcp");
130 		if (sp != NULL)
131 			port = sp->s_port;
132 	}
133 
134 	for (;;) {
135 		bcopy(hp->h_addr_list[addr_num],
136 		    &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ);
137 		if (IN6_IS_ADDR_V4MAPPED(&SendmailAddress.sin6.sin6_addr)) {
138 			SendmailAddress.sa.sa_family = AF_INET;
139 			SendmailAddress.sin.sin_port = port;
140 			bcopy(&hp->h_addr_list[addr_num][IN6ADDRSZ - INADDRSZ],
141 				&SendmailAddress.sin.sin_addr, INADDRSZ);
142 			addrlen = sizeof (struct sockaddr_in);
143 		} else {
144 			SendmailAddress.sa.sa_family = AF_INET6;
145 			SendmailAddress.sin6.sin6_port = port;
146 			addrlen = sizeof (struct sockaddr_in6);
147 		}
148 
149 		s = socket(SendmailAddress.sa.sa_family, SOCK_STREAM, 0);
150 		if (s < 0)
151 		{
152 			perror("socket");
153 			exit(-1);
154 		}
155 		(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
156 		    sizeof (on));
157 		if (SendmailAddress.sa.sa_family == AF_INET)
158 			(void) printf("connecting to host %s (%s), port %d\r\n",
159 				host, inet_ntoa(SendmailAddress.sin.sin_addr),
160 				ntohs(SendmailAddress.sin.sin_port));
161 		else
162 			(void) printf("connecting to host %s (%s), port %d\r\n",
163 				host, inet_ntop(AF_INET6,
164 					SendmailAddress.sin6.sin6_addr.s6_addr,
165 					buf6, sizeof (buf6)),
166 				ntohs(SendmailAddress.sin6.sin6_port));
167 		if (connect(s, (struct sockaddr *)&SendmailAddress,
168 				addrlen) >= 0)
169 			break;
170 		if (hp->h_addr_list[++addr_num] != NULL) {
171 			(void) printf("connect failed (%s), next address ...\n",
172 				strerror(errno));
173 			bcopy(hp->h_addr_list[addr_num],
174 				&SendmailAddress.sin6.sin6_addr, IN6ADDRSZ);
175 			if (IN6_IS_ADDR_V4MAPPED(
176 			    &SendmailAddress.sin6.sin6_addr)) {
177 				SendmailAddress.sa.sa_family = AF_INET;
178 				bcopy(&hp->h_addr_list[addr_num]
179 				    [IN6ADDRSZ - INADDRSZ],
180 					&SendmailAddress.sin.sin_addr,
181 					INADDRSZ);
182 				addrlen = sizeof (struct sockaddr_in);
183 			} else {
184 				SendmailAddress.sa.sa_family = AF_INET6;
185 				addrlen = sizeof (struct sockaddr_in6);
186 			}
187 			continue;
188 		}
189 		perror("connect");
190 		exit(-1);
191 	}
192 
193 	if (raw) {
194 		TtyBuf.sg_flags &= ~CRMOD;
195 		(void) ioctl(0, TIOCSETP, &TtyBuf);
196 		TtyBuf.sg_flags |= CRMOD;
197 	}
198 
199 	/* good connection, fork both sides */
200 	(void) printf("connection open\n");
201 	pid = fork();
202 	if (pid < 0)
203 	{
204 		perror("fork");
205 		exit(-1);
206 	}
207 	if (pid == 0)
208 	{
209 		/* child -- standard input to sendmail */
210 		int c;
211 
212 		f = fdopen(s, "w");
213 		while ((c = fgetc(stdin)) >= 0)
214 		{
215 			if (!raw && c == '\n')
216 				(void) fputc('\r', f);
217 			(void) fputc(c, f);
218 			if (c == '\n')
219 				(void) fflush(f);
220 		}
221 		(void) shutdown(s, 1);
222 		(void) sleep(10);
223 	}
224 	else
225 	{
226 		/* parent -- sendmail to standard output */
227 		f = fdopen(s, "r");
228 		while (fgets(buf, sizeof (buf), f) != NULL)
229 		{
230 			(void) fputs(buf, stdout);
231 			(void) fflush(stdout);
232 		}
233 		(void) kill(pid, SIGTERM);
234 	}
235 	if (raw)
236 		(void) ioctl(0, TIOCSETP, &TtyBuf);
237 	return (0);
238 }
239