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