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
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 */
22 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
39 /* be paranoid about leaking passwords as hostnames, enough
40 that we'll avoid attempting lookups on things that aren't
43 static int sanity_check_hostname(const char *hostname
)
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
;
55 fd
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
57 perror("Error opening socket");
58 printf("socket() failed.\n");
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
));
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
));
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
;
91 char pbuf
[NI_MAXSERV
];
94 if (!sanity_check_hostname(hostname
)) {
96 ("socket/connect to '%s' aborted: it does not appear to be a valid hostname\n",
98 printf("if you really want this, use wmbiff's -relax option.\n");
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
);
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
));
123 for (res
= res0
; res
; res
= res
->ai_next
) {
124 fd
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
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) {
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
);
154 #warning "This build will not support IPv6"
155 struct hostent
*host
;
157 if (!sanity_check_hostname(hostname
)) {
159 ("socket/connect to '%s' aborted: it does not appear to be a valid hostname\n",
161 printf("if you really want this, use wmbiff's -relax option.\n");
165 host
= gethostbyname(hostname
);
167 herror("gethostbyname");
168 printf("gethostbyname(%s) failed.\n", hostname
);
172 return ipv4_sock_connect(host
->h_addr_list
[0], port
);