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");
62 addr
.sin_family
= AF_INET
;
63 addr
.sin_addr
.s_addr
= *(u_long
*) address
;
64 addr
.sin_port
= htons(port
);
65 i
= connect(fd
, (struct sockaddr
*) &addr
, sizeof(struct sockaddr
));
67 int saved_errno
= errno
;
68 perror("Error connecting");
69 printf("connect(%s:%d) failed: %s\n", inet_ntoa(addr
.sin_addr
),
70 port
, strerror(saved_errno
));
77 /* nspring/blueHal, 10 Apr 2002; added some extra error
78 printing, in line with the debug-messages-to-stdout
79 philosophy of the rest of the wmbiff code */
80 /* 1 June 2002; incorporated IPv6 support by
81 Jun-ichiro itojun Hagino <itojun@iijlab.net>, thanks! */
83 int sock_connect(const char *hostname
, int port
)
85 #ifdef HAVE_GETADDRINFO
86 struct addrinfo hints
, *res
, *res0
;
87 struct sockaddr_in addr
;
89 char pbuf
[NI_MAXSERV
];
92 if (!sanity_check_hostname(hostname
)) {
94 ("socket/connect to '%s' aborted: it does not appear to be a valid hostname\n",
96 printf("if you really want this, use wmbiff's -relax option.\n");
100 /* we were given an IP address, no need to try getaddrinfo on it */
101 if (inet_aton(hostname
, &addr
.sin_addr
)) {
102 return ipv4_sock_connect(&addr
.sin_addr
, port
);
105 memset(&hints
, 0, sizeof(hints
));
106 hints
.ai_socktype
= SOCK_STREAM
;
107 snprintf(pbuf
, sizeof(pbuf
), "%d", port
);
108 error
= getaddrinfo(hostname
, pbuf
, &hints
, &res0
);
110 static int last_error
;
111 if (last_error
!= error
) {
112 /* only report a problem if it's new. this is an
113 approximation that minimizes kept state. */
114 printf("%s: %s\n", hostname
, gai_strerror(error
));
121 for (res
= res0
; res
; res
= res
->ai_next
) {
122 fd
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
125 if (connect(fd
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
134 static int last_connecterr
;
135 if (errno
!= last_connecterr
) {
136 /* only report a problem if it's new.
137 EHOSTUNREACH is common when the net is down,
138 for example; again, this is an approximation
139 to minimize kept state. */
140 last_connecterr
= errno
;
141 fprintf(stderr
, "Error connecting to %s:%d: %s\n",
142 hostname
, port
, strerror(errno
));
143 printf("socket/connect to %s failed: %s (%d)\n", hostname
,
144 strerror(errno
), errno
);
150 #warning "This build will not support IPv6"
151 struct hostent
*host
;
153 if (!sanity_check_hostname(hostname
)) {
155 ("socket/connect to '%s' aborted: it does not appear to be a valid hostname\n",
157 printf("if you really want this, use wmbiff's -relax option.\n");
161 host
= gethostbyname(hostname
);
163 herror("gethostbyname");
164 printf("gethostbyname(%s) failed.\n", hostname
);
168 return ipv4_sock_connect(host
->h_addr_list
[0], port
);