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 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * mconnect.c - A program to test out SMTP connections.
30 * Usage: mconnect [host]
31 * ... SMTP dialog
32 * ^C or ^D or QUIT
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <signal.h>
38 #include <ctype.h>
39 #include <string.h>
40 #include <strings.h>
41 #include <sgtty.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <unistd.h>
46 #include <netinet/in.h>
47 #include <netdb.h>
48 #include <arpa/nameser.h>
49 #include <arpa/inet.h>
50 #include <errno.h>
51
52 union bigsockaddr
53 {
54 struct sockaddr sa; /* general version */
55 struct sockaddr_in sin; /* INET family */
56 struct sockaddr_in6 sin6; /* INET/IPv6 */
57 };
58
59 static struct sgttyb TtyBuf;
60 static int raw = 0;
61
62 /* ARGSUSED */
63 static void
finis(sig)64 finis(sig)
65 int sig;
66 {
67 if (raw)
68 (void) ioctl(0, TIOCSETP, &TtyBuf);
69 exit(0);
70 }
71
72 int
main(argc,argv)73 main(argc, argv)
74 int argc;
75 char **argv;
76 {
77 union bigsockaddr SendmailAddress;
78 register int s;
79 char *host = NULL;
80 int pid;
81 int on = 1;
82 struct servent *sp;
83 char buf[1000];
84 register FILE *f;
85 register struct hostent *hp;
86 in_port_t port = 0;
87 int err;
88 char buf6[INET6_ADDRSTRLEN];
89 int addr_num = 0;
90 int addrlen;
91
92 (void) ioctl(0, TIOCGETP, &TtyBuf);
93 (void) signal(SIGINT, finis);
94
95 while (--argc > 0)
96 {
97 register char *p;
98
99 p = *++argv;
100 if (*p == '-')
101 {
102 switch (*++p)
103 {
104 case 'h': /* host */
105 break;
106
107 case 'p': /* port */
108 port = htons(atoi(*++argv));
109 argc--;
110 break;
111
112 case 'r': /* raw connection */
113 raw = 1;
114 break;
115 }
116 } else if (host == NULL)
117 host = p;
118 }
119 if (host == NULL)
120 host = "localhost";
121
122 bzero(&SendmailAddress, sizeof (SendmailAddress));
123 hp = getipnodebyname(host, AF_INET6, AI_DEFAULT|AI_ALL, &err);
124 if (hp == NULL)
125 {
126 (void) fprintf(stderr, "mconnect: unknown host %s\r\n", host);
127 exit(0);
128 }
129
130 if (port == 0) {
131 sp = getservbyname("smtp", "tcp");
132 if (sp != NULL)
133 port = sp->s_port;
134 }
135
136 for (;;) {
137 bcopy(hp->h_addr_list[addr_num],
138 &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ);
139 if (IN6_IS_ADDR_V4MAPPED(&SendmailAddress.sin6.sin6_addr)) {
140 SendmailAddress.sa.sa_family = AF_INET;
141 SendmailAddress.sin.sin_port = port;
142 bcopy(&hp->h_addr_list[addr_num][IN6ADDRSZ - INADDRSZ],
143 &SendmailAddress.sin.sin_addr, INADDRSZ);
144 addrlen = sizeof (struct sockaddr_in);
145 } else {
146 SendmailAddress.sa.sa_family = AF_INET6;
147 SendmailAddress.sin6.sin6_port = port;
148 addrlen = sizeof (struct sockaddr_in6);
149 }
150
151 s = socket(SendmailAddress.sa.sa_family, SOCK_STREAM, 0);
152 if (s < 0)
153 {
154 perror("socket");
155 exit(-1);
156 }
157 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
158 sizeof (on));
159 if (SendmailAddress.sa.sa_family == AF_INET)
160 (void) printf("connecting to host %s (%s), port %d\r\n",
161 host, inet_ntoa(SendmailAddress.sin.sin_addr),
162 ntohs(SendmailAddress.sin.sin_port));
163 else
164 (void) printf("connecting to host %s (%s), port %d\r\n",
165 host, inet_ntop(AF_INET6,
166 SendmailAddress.sin6.sin6_addr.s6_addr,
167 buf6, sizeof (buf6)),
168 ntohs(SendmailAddress.sin6.sin6_port));
169 if (connect(s, (struct sockaddr *)&SendmailAddress,
170 addrlen) >= 0)
171 break;
172 if (hp->h_addr_list[++addr_num] != NULL) {
173 (void) printf("connect failed (%s), next address ...\n",
174 strerror(errno));
175 bcopy(hp->h_addr_list[addr_num],
176 &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ);
177 if (IN6_IS_ADDR_V4MAPPED(
178 &SendmailAddress.sin6.sin6_addr)) {
179 SendmailAddress.sa.sa_family = AF_INET;
180 bcopy(&hp->h_addr_list[addr_num]
181 [IN6ADDRSZ - INADDRSZ],
182 &SendmailAddress.sin.sin_addr,
183 INADDRSZ);
184 addrlen = sizeof (struct sockaddr_in);
185 } else {
186 SendmailAddress.sa.sa_family = AF_INET6;
187 addrlen = sizeof (struct sockaddr_in6);
188 }
189 continue;
190 }
191 perror("connect");
192 exit(-1);
193 }
194
195 if (raw) {
196 TtyBuf.sg_flags &= ~CRMOD;
197 (void) ioctl(0, TIOCSETP, &TtyBuf);
198 TtyBuf.sg_flags |= CRMOD;
199 }
200
201 /* good connection, fork both sides */
202 (void) printf("connection open\n");
203 pid = fork();
204 if (pid < 0)
205 {
206 perror("fork");
207 exit(-1);
208 }
209 if (pid == 0)
210 {
211 /* child -- standard input to sendmail */
212 int c;
213
214 f = fdopen(s, "w");
215 while ((c = fgetc(stdin)) >= 0)
216 {
217 if (!raw && c == '\n')
218 (void) fputc('\r', f);
219 (void) fputc(c, f);
220 if (c == '\n')
221 (void) fflush(f);
222 }
223 (void) shutdown(s, 1);
224 (void) sleep(10);
225 }
226 else
227 {
228 /* parent -- sendmail to standard output */
229 f = fdopen(s, "r");
230 while (fgets(buf, sizeof (buf), f) != NULL)
231 {
232 (void) fputs(buf, stdout);
233 (void) fflush(stdout);
234 }
235 (void) kill(pid, SIGTERM);
236 }
237 if (raw)
238 (void) ioctl(0, TIOCSETP, &TtyBuf);
239 return (0);
240 }
241