1 #include "netheaders.h"
7 #include <event2/event.h>
8 #include <event2/bufferevent.h>
9 #include <event2/buffer.h>
10 #include <event2/util.h>
11 #include <event2/dns.h>
20 struct bufferevent
*bev
;
23 conn_connectcb on_connect
;
27 struct sockaddr_storage addr
;
31 static enum socks_ver use_socks
= SOCKS_NONE
;
32 static struct sockaddr_storage socks_addr
;
33 static int socks_addr_len
= sizeof(socks_addr
);
34 static char *conn_error_string
= NULL
;
37 finish_connection(struct conninfo
*info
, int ok
, const char *reason
)
39 mem_free(conn_error_string
);
40 conn_error_string
= NULL
;
42 conn_error_string
= mem_strdup(reason
);
43 bufferevent_disable(info
->bev
, EV_READ
);
44 bufferevent_setcb(info
->bev
, NULL
, NULL
, NULL
, NULL
);
45 info
->on_connect(info
->bev
, ok
, info
->cbarg
);
51 write_socks_request(struct conninfo
*info
)
53 if (info
->socks
== SOCKS_4
) {
54 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&info
->addr
;
56 if (info
->addr
.ss_family
!= AF_INET
) {
57 finish_connection(info
, 0,
58 "SOCKS 4 can't handle ipv6!");
61 /* connection request */
62 bufferevent_write(info
->bev
, "\x04\x01", 2);
63 bufferevent_write(info
->bev
, &sin
->sin_port
,
64 sizeof(sin
->sin_port
));
65 bufferevent_write(info
->bev
, &sin
->sin_addr
.s_addr
,
66 sizeof(sin
->sin_addr
.s_addr
));
67 bufferevent_write(info
->bev
, "xx", 3);
69 ev_uint16_t port
= htons(info
->port
);
71 assert(info
->host
!= NULL
);
72 bufferevent_write(info
->bev
, "\x04\x01", 2);
73 bufferevent_write(info
->bev
, &port
, sizeof(port
));
74 bufferevent_write(info
->bev
, "\x00\x00\x00\xff", 4);
75 bufferevent_write(info
->bev
, "xx", 3);
76 bufferevent_write(info
->bev
, info
->host
, strlen(info
->host
)+1);
79 bufferevent_enable(info
->bev
, EV_READ
);
83 conn_errorcb(struct bufferevent
*bev
, short what
, void *arg
)
85 struct conninfo
*info
= arg
;
87 if (info
->connecting
) {
89 if (what
& BEV_EVENT_CONNECTED
) {
90 if (info
->socks
!= SOCKS_NONE
)
91 write_socks_request(info
);
93 finish_connection(info
, 1, NULL
);
95 // XXX need better err msg
96 const char *msg
= "Connection failed";
97 if (info
->socks
!= SOCKS_NONE
)
98 msg
= "Connection to proxy server failed";
99 finish_connection(info
, 0, msg
);
102 finish_connection(info
, 0, "SOCKS I/O error");
107 socks4_error_to_string(unsigned char err
)
111 return "SOCKS 4: request failed";
113 return "SOCKS 4: client is not running identd";
115 return "SOCKS 4: invalid user ID";
118 return "SOCKS 4: unknown error";
122 conn_readcb(struct bufferevent
*bev
, void *arg
)
124 struct conninfo
*info
= arg
;
125 struct evbuffer
*inbuf
= bufferevent_get_input(bev
);
129 /* socks4 and socks4a both have an 8 byte response */
130 if (evbuffer_get_length(inbuf
) < 8) {
131 log_debug("conn: waiting for full socks response");
135 data
= evbuffer_pullup(inbuf
, 8);
137 evbuffer_drain(inbuf
, 8);
140 finish_connection(info
, 0, socks4_error_to_string(code
));
142 finish_connection(info
, 1, NULL
);
146 void socks_resolvecb(int result
, struct evutil_addrinfo
*ai
, void *arg
)
148 struct conninfo
*info
= arg
;
152 evutil_snprintf(buf
, sizeof(buf
), "DNS Failure: %s",
153 evutil_gai_strerror(result
));
154 finish_connection(info
, 0, buf
);
156 log_debug("conn: socks resolve %s",
157 format_addr(ai
->ai_addr
));
158 assert(ai
->ai_addrlen
<= sizeof(info
->addr
));
159 memcpy(&info
->addr
, ai
->ai_addr
, ai
->ai_addrlen
);
160 info
->addr_len
= ai
->ai_addrlen
;
161 bufferevent_socket_connect(info
->bev
,
162 (struct sockaddr
*)&socks_addr
,
167 evutil_freeaddrinfo(ai
);
171 conn_connect_bufferevent(struct bufferevent
*bev
, struct evdns_base
*dns
,
172 int family
, const char *name
, int port
,
173 conn_connectcb conncb
, void *arg
)
175 struct conninfo
*info
;
179 info
= mem_calloc(1, sizeof(*info
));
181 info
->on_connect
= conncb
;
183 info
->connecting
= 1;
184 info
->socks
= use_socks
;
186 bufferevent_setcb(bev
, conn_readcb
, NULL
, conn_errorcb
, info
);
187 if (use_socks
!= SOCKS_NONE
) {
188 info
->host
= mem_strdup(name
);
190 if (use_socks
== SOCKS_4a
) {
191 rv
= bufferevent_socket_connect(bev
,
192 (struct sockaddr
*)&socks_addr
,
196 #ifndef DISABLE_DIRECT_CONNECTIONS
198 struct evutil_addrinfo hint
;
199 char portstr
[NI_MAXSERV
];
201 evutil_snprintf(portstr
, sizeof(portstr
), "%d", port
);
202 memset(&hint
, 0, sizeof(hint
));
203 hint
.ai_family
= AF_INET
;
204 hint
.ai_protocol
= IPPROTO_TCP
;
205 hint
.ai_socktype
= SOCK_STREAM
;
207 evdns_getaddrinfo(dns
, name
, portstr
, &hint
,
208 socks_resolvecb
, info
);
213 #ifdef DISABLE_DIRECT_CONNECTIONS
216 msg
= "Direct connections disabled, but I have no SOCKS 4a "
217 "proxy to connect to!";
218 log_error("conn: %s", msg
);
219 finish_connection(info
, 0, msg
);
222 rv
= bufferevent_socket_connect_hostname(bev
, dns
, family
, name
, port
);
229 conn_set_socks_server(const char *name
, int port
, enum socks_ver ver
)
233 struct evutil_addrinfo
*ai
= NULL
;
234 struct evutil_addrinfo hint
;
235 char portstr
[NI_MAXSERV
];
237 assert(ver
!= SOCKS_NONE
);
239 evutil_snprintf(portstr
, sizeof(portstr
), "%d", port
);
240 memset(&hint
, 0, sizeof(hint
));
241 hint
.ai_family
= AF_UNSPEC
;
242 hint
.ai_protocol
= IPPROTO_TCP
;
243 hint
.ai_socktype
= SOCK_STREAM
;
244 hint
.ai_flags
= EVUTIL_AI_ADDRCONFIG
;
246 ret
= evutil_getaddrinfo(name
, portstr
, &hint
, &ai
);
249 memset(&socks_addr
, 0, sizeof(socks_addr
));
250 memcpy(&socks_addr
, ai
->ai_addr
, ai
->ai_addrlen
);
251 socks_addr_len
= ai
->ai_addrlen
;
253 log_notice("conn: socks server set to %s",
254 format_addr((struct sockaddr
*)&socks_addr
));
256 log_error("conn: can't resolve socks server %s: %s",
257 name
, evutil_gai_strerror(ret
));
261 evutil_freeaddrinfo(ai
);
267 conn_get_connect_error(void)
269 return conn_error_string
;
273 void do_connect(struct bufferevent
*bev
, int ok
, void *arg
)
276 log_notice("conn: failed: %s", conn_get_connect_error());
278 log_notice("conn: conn OK!");
280 bufferevent_free(bev
);
283 int main(int argc
, char **argv
)
285 struct evdns_base
*dns
;
286 struct event_base
*base
;
287 struct bufferevent
*bev
;
288 struct url
*socks
, *host
;
291 base
= event_base_new();
292 dns
= evdns_base_new(base
, 1);
295 log_set_min_level(LOG_DEBUG
);
297 socks
= url_tokenize(argv
[2]);
298 s4
= !evutil_ascii_strcasecmp("socks4", socks
->scheme
);
299 if (conn_set_socks_server(socks
->host
, socks
->port
, s4
?
300 SOCKS_4
: SOCKS_4a
) < 0)
304 host
= url_connect_tokenize(argv
[1]);
306 bev
= bufferevent_socket_new(base
, -1, BEV_OPT_CLOSE_ON_FREE
);
308 conn_connect_bufferevent(bev
, dns
, AF_INET
, host
->host
, host
->port
,
311 event_base_dispatch(base
);