wmsun: Update contact information.
[dockapps.git] / wmbiff / wmbiff / socket.c
blob7f7a9ecaeff0c153a356ef27eb793d8632f58422
1 /* $Id: socket.c,v 1.14 2004/10/01 21:05:36 bluehal Exp $ */
2 /* Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
3 * (C) 1999 Trent Piepho <xyzzy@speakeasy.org>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include <time.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <netdb.h>
32 #include <stdio.h>
33 #include "regulo.h"
35 #ifdef USE_DMALLOC
36 #include <dmalloc.h>
37 #endif
39 /* be paranoid about leaking passwords as hostnames, enough
40 that we'll avoid attempting lookups on things that aren't
41 host names */
42 extern int Relax;
43 static int sanity_check_hostname(const char *hostname)
45 struct in_addr dummy;
46 return (Relax
47 || regulo_match("^[A-Za-z][-_A-Za-z0-9.]+$", hostname, NULL)
48 || inet_aton(hostname, &dummy));
51 static int ipv4_sock_connect(struct in_addr *address, short port)
53 struct sockaddr_in addr;
54 int fd, i;
55 fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
56 if (fd == -1) {
57 perror("Error opening socket");
58 printf("socket() failed.\n");
59 return (-1);
61 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
62 perror("fcntl(FD_CLOEXEC)");
64 addr.sin_family = AF_INET;
65 addr.sin_addr.s_addr = *(u_long *) address;
66 addr.sin_port = htons(port);
67 i = connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
68 if (i == -1) {
69 int saved_errno = errno;
70 perror("Error connecting");
71 printf("connect(%s:%d) failed: %s\n", inet_ntoa(addr.sin_addr),
72 port, strerror(saved_errno));
73 close(fd);
74 return (-1);
76 return (fd);
79 /* nspring/blueHal, 10 Apr 2002; added some extra error
80 printing, in line with the debug-messages-to-stdout
81 philosophy of the rest of the wmbiff code */
82 /* 1 June 2002; incorporated IPv6 support by
83 Jun-ichiro itojun Hagino <itojun@iijlab.net>, thanks! */
85 int sock_connect(const char *hostname, int port)
87 #ifdef HAVE_GETADDRINFO
88 struct addrinfo hints, *res, *res0;
89 struct sockaddr_in addr;
90 int fd;
91 char pbuf[NI_MAXSERV];
92 int error;
94 if (!sanity_check_hostname(hostname)) {
95 printf
96 ("socket/connect to '%s' aborted: it does not appear to be a valid hostname\n",
97 hostname);
98 printf("if you really want this, use wmbiff's -relax option.\n");
99 return -1;
102 /* we were given an IP address, no need to try getaddrinfo on it */
103 if (inet_aton(hostname, &addr.sin_addr)) {
104 return ipv4_sock_connect(&addr.sin_addr, port);
107 memset(&hints, 0, sizeof(hints));
108 hints.ai_socktype = SOCK_STREAM;
109 snprintf(pbuf, sizeof(pbuf), "%d", port);
110 error = getaddrinfo(hostname, pbuf, &hints, &res0);
111 if (error) {
112 static int last_error;
113 if (last_error != error) {
114 /* only report a problem if it's new. this is an
115 approximation that minimizes kept state. */
116 printf("%s: %s\n", hostname, gai_strerror(error));
117 last_error = error;
119 return -1;
122 fd = -1;
123 for (res = res0; res; res = res->ai_next) {
124 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
125 if (fd < 0)
126 continue;
127 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
128 perror("fcntl(FD_CLOEXEC)");
129 if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
130 close(fd);
131 fd = -1;
132 continue;
134 break;
136 freeaddrinfo(res0);
137 if (fd < 0) {
138 static int last_connecterr;
139 if (errno != last_connecterr) {
140 /* only report a problem if it's new.
141 EHOSTUNREACH is common when the net is down,
142 for example; again, this is an approximation
143 to minimize kept state. */
144 last_connecterr = errno;
145 fprintf(stderr, "Error connecting to %s:%d: %s\n",
146 hostname, port, strerror(errno));
147 printf("socket/connect to %s failed: %s (%d)\n", hostname,
148 strerror(errno), errno);
150 return -1;
152 return fd;
153 #else
154 #warning "This build will not support IPv6"
155 struct hostent *host;
157 if (!sanity_check_hostname(hostname)) {
158 printf
159 ("socket/connect to '%s' aborted: it does not appear to be a valid hostname\n",
160 hostname);
161 printf("if you really want this, use wmbiff's -relax option.\n");
162 return -1;
165 host = gethostbyname(hostname);
166 if (host == NULL) {
167 herror("gethostbyname");
168 printf("gethostbyname(%s) failed.\n", hostname);
169 return (-1);
172 return ipv4_sock_connect(host->h_addr_list[0], port);
174 #endif
177 /* vim:set ts=4: */
179 * Local Variables:
180 * tab-width: 4
181 * c-indent-level: 4
182 * c-basic-offset: 4
183 * End: