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 64 finis(sig) 65 int sig; 66 { 67 if (raw) 68 (void) ioctl(0, TIOCSETP, &TtyBuf); 69 exit(0); 70 } 71 72 int 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