1: /* 2: ** Routines to open a TCP connection 3: ** 4: ** New version that supports the old (pre 4.2 BSD) socket calls, 5: ** and systems with the old (pre 4.2 BSD) hostname lookup stuff. 6: ** Compile-time options are: 7: ** 8: ** USG - you're on System III/V (you have my sympathies) 9: ** NONETDB - old hostname lookup with rhost() 10: ** OLDSOCKET - different args for socket() and connect() 11: ** 12: ** Erik E. Fair <fair@ucbarpa.berkeley.edu> 13: ** 14: */ 15: 16: #include <sys/types.h> 17: #include <sys/socket.h> 18: #include <netinet/in.h> 19: #include <ctype.h> 20: #include <stdio.h> 21: #include "get_tcp_conn.h" 22: #ifndef NONETDB 23: #include <netdb.h> 24: #endif NONETDB 25: 26: extern int errno; 27: extern char *Pname; 28: extern char *errmsg(); 29: #ifndef htons 30: extern u_short htons(); 31: #endif htons 32: #ifndef NONETDB 33: extern char *inet_ntoa(); 34: extern u_long inet_addr(); 35: #else 36: /* 37: * inet_addr for EXCELAN (which does not have it!) 38: * 39: */ 40: u_long 41: inet_addr(cp) 42: register char *cp; 43: { 44: u_long val, base, n; 45: register char c; 46: u_long octet[4], *octetptr = octet; 47: #ifndef htonl 48: extern u_long htonl(); 49: #endif htonl 50: again: 51: /* 52: * Collect number up to ``.''. 53: * Values are specified as for C: 54: * 0x=hex, 0=octal, other=decimal. 55: */ 56: val = 0; base = 10; 57: if (*cp == '0') 58: base = 8, cp++; 59: if (*cp == 'x' || *cp == 'X') 60: base = 16, cp++; 61: while (c = *cp) { 62: if (isdigit(c)) { 63: val = (val * base) + (c - '0'); 64: cp++; 65: continue; 66: } 67: if (base == 16 && isxdigit(c)) { 68: val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); 69: cp++; 70: continue; 71: } 72: break; 73: } 74: if (*cp == '.') { 75: /* 76: * Internet format: 77: * a.b.c.d 78: * a.b.c (with c treated as 16-bits) 79: * a.b (with b treated as 24 bits) 80: */ 81: if (octetptr >= octet + 4) 82: return (-1); 83: *octetptr++ = val, cp++; 84: goto again; 85: } 86: /* 87: * Check for trailing characters. 88: */ 89: if (*cp && !isspace(*cp)) 90: return (-1); 91: *octetptr++ = val; 92: /* 93: * Concoct the address according to 94: * the number of octet specified. 95: */ 96: n = octetptr - octet; 97: switch (n) { 98: 99: case 1: /* a -- 32 bits */ 100: val = octet[0]; 101: break; 102: 103: case 2: /* a.b -- 8.24 bits */ 104: val = (octet[0] << 24) | (octet[1] & 0xffffff); 105: break; 106: 107: case 3: /* a.b.c -- 8.8.16 bits */ 108: val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) | 109: (octet[2] & 0xffff); 110: break; 111: 112: case 4: /* a.b.c.d -- 8.8.8.8 bits */ 113: val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) | 114: ((octet[2] & 0xff) << 8) | (octet[3] & 0xff); 115: break; 116: 117: default: 118: return (-1); 119: } 120: val = htonl(val); 121: return (val); 122: } 123: 124: char * 125: inet_ntoa(in) 126: struct in_addr in; 127: { 128: static char address[20]; 129: 130: sprintf(address, "%u.%u.%u.%u", 131: (in.s_addr>>24)&0xff, 132: (in.s_addr>>16)&0xff, 133: (in.s_addr>>8 )&0xff, 134: (in.s_addr )&0xff); 135: return(address); 136: } 137: #endif NONETDB 138: 139: #ifdef USG 140: void 141: bcopy(s, d, l) 142: register caddr_t s, d; 143: register int l; 144: { 145: while (l-- > 0) *d++ = *s++; 146: } 147: #endif USG 148: 149: /* 150: ** Take the name of an internet host in ASCII (this may either be its 151: ** official host name or internet number (with or without enclosing 152: ** backets [])), and return a list of internet addresses. 153: ** 154: ** returns NULL for failure to find the host name in the local database, 155: ** or for a bad internet address spec. 156: */ 157: u_long ** 158: name_to_address(host) 159: char *host; 160: { 161: static u_long *host_addresses[2]; 162: static u_long haddr; 163: 164: if (host == (char *)NULL) { 165: return((u_long **)NULL); 166: } 167: 168: host_addresses[0] = &haddr; 169: host_addresses[1] = (u_long *)NULL; 170: 171: /* 172: ** Is this an ASCII internet address? (either of [10.0.0.78] or 173: ** 10.0.0.78). We get away with the second test because hostnames 174: ** and domain labels are not allowed to begin in numbers. 175: ** (cf. RFC952, RFC882). 176: */ 177: if (*host == '[' || isdigit(*host)) { 178: char namebuf[128]; 179: register char *cp = namebuf; 180: 181: /* 182: ** strip brackets [] or anything else we don't want. 183: */ 184: while(*host != '\0' && cp < &namebuf[sizeof(namebuf)]) { 185: if (isdigit(*host) || *host == '.') 186: *cp++ = *host++; /* copy */ 187: else 188: host++; /* skip */ 189: } 190: *cp = '\0'; 191: haddr = inet_addr(namebuf); 192: return(&host_addresses[0]); 193: } else { 194: #ifdef NONETDB 195: extern u_long rhost(); 196: 197: /* lint is gonna bitch about this (comparing an unsigned?!) */ 198: if ((haddr = rhost(&host)) == FAIL) 199: return((u_long **)NULL); /* no such host */ 200: return(&host_addresses[0]); 201: #else 202: struct hostent *hstp = gethostbyname(host); 203: 204: if (hstp == NULL) { 205: return((u_long **)NULL); /* no such host */ 206: } 207: 208: if (hstp->h_length != sizeof(u_long)) 209: abort(); /* this is fundamental */ 210: #ifndef h_addr 211: /* alignment problems (isn't dbm wonderful?) */ 212: bcopy((caddr_t)hstp->h_addr, (caddr_t)&haddr, sizeof(haddr)); 213: return(&host_addresses[0]); 214: #else 215: return((u_long **)hstp->h_addr_list); 216: #endif h_addr 217: #endif NONETDB 218: } 219: } 220: 221: /* 222: ** Get a service port number from a service name (or ASCII number) 223: ** 224: ** Return zero if something is wrong (that's a reserved port) 225: */ 226: #ifdef NONETDB 227: static struct Services { 228: char *name; 229: u_short port; 230: } Services[] = { 231: {"nntp", IPPORT_NNTP}, /* RFC977 */ 232: {"smtp", IPPORT_SMTP}, /* RFC821 */ 233: {"name", IPPORT_NAMESERVER}, /* RFC881, RFC882, RFC883 */ 234: {"time", IPPORT_TIMESERVER}, /* RFC868 */ 235: {"echo", IPPORT_ECHO}, /* RFC862 */ 236: {"discard", IPPORT_DISCARD}, /* RFC863 */ 237: {"daytime", IPPORT_DAYTIME}, /* RFC867 */ 238: {"login", IPPORT_LOGINSERVER}, /* N/A - 4BSD specific */ 239: }; 240: #endif NONETDB 241: 242: u_short 243: gservice(serv, proto) 244: char *serv, *proto; 245: { 246: if (serv == (char *)NULL || proto == (char *)NULL) 247: return((u_short)0); 248: 249: if (isdigit(*serv)) { 250: return(htons((u_short)(atoi(serv)))); 251: } else { 252: #ifdef NONETDB 253: register int i; 254: 255: for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) { 256: if (strcmp(serv, Services[i].name) == 0) 257: return(htons(Services[i].port)); 258: } 259: return((u_short)0); 260: #else 261: struct servent *srvp = getservbyname(serv, proto); 262: 263: if (srvp == (struct servent *)NULL) 264: return((u_short)0); 265: return((u_short)srvp->s_port); 266: #endif NONETDB 267: } 268: } 269: 270: /* 271: ** given a host name (either name or internet address) and service name 272: ** (or port number) (both in ASCII), give us a TCP connection to the 273: ** requested service at the requested host (or give us FAIL). 274: */ 275: get_tcp_conn(host, serv) 276: char *host, *serv; 277: { 278: register int sock; 279: u_long **addrlist; 280: struct sockaddr_in sadr; 281: #ifdef OLDSOCKET 282: struct sockproto sp; 283: 284: sp.sp_family = (u_short)AF_INET; 285: sp.sp_protocol = (u_short)IPPROTO_TCP; 286: #endif OLDSOCKET 287: 288: if ((addrlist = name_to_address(host)) == (u_long **)NULL) { 289: return(NOHOST); 290: } 291: 292: sadr.sin_family = (u_short)AF_INET; /* Only internet for now */ 293: if ((sadr.sin_port = gservice(serv, "tcp")) == 0) 294: return(NOSERVICE); 295: 296: for(; *addrlist != (u_long *)NULL; addrlist++) { 297: bcopy((caddr_t)*addrlist, (caddr_t)&sadr.sin_addr, 298: sizeof(sadr.sin_addr)); 299: 300: #ifdef OLDSOCKET 301: if ((sock = socket(SOCK_STREAM, &sp, (struct sockaddr *)NULL, 0)) < 0) 302: return(FAIL); 303: 304: if (connect(sock, (struct sockaddr *)&sadr) < 0) { 305: #else 306: if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 307: return(FAIL); 308: 309: if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) { 310: #endif OLDSOCKET 311: int e_save = errno; 312: 313: fprintf(stderr, "%s: %s [%s]: %s\n", Pname, host, 314: inet_ntoa(sadr.sin_addr), errmsg(errno)); 315: (void) close(sock); /* dump descriptor */ 316: errno = e_save; 317: } else 318: return(sock); 319: } 320: return(FAIL); 321: }