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