/* $OpenBSD: socks.c,v 1.17 2006/09/25 04:51:20 ray Exp $ */
/*
* Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
* Copyright (c) 2004, 2005 Damien Miller. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <resolv.h>
#include <strings.h>
#include "atomicio.h"
#define SOCKS_NOAUTH 0
int remote_connect(const char *, const char *, struct addrinfo);
int socks_connect(const char *, const char *,
const char *, const char *, struct addrinfo, int,
const char *);
/*
* sockaddr structure and return 0 on success, -1 on failure.
* Indicate whether the host address is IPv4 (v4only) and numeric.
*/
static int
{
int r;
/* Don't fatal when attempting to convert a numeric address */
if (r != 0) {
if (!numeric) {
gai_strerror(r));
}
return (-1);
}
}
return (0);
}
/*
* Read single line from a descriptor into buffer up to bufsz bytes,
* byte by byte. Returns length of the line (including ending NULL),
* exits upon failure.
*/
static int
{
for (off = 0; ; ) {
/* Skip CR */
continue;
break;
}
/*
* we rewite \r\n to NULL since socks_connect() relies
* on *buf being zero in that case.
*/
off++;
}
return (off);
}
/*
* Read proxy password from user and return it. The arguments are used
* only for prompt construction.
*/
static const char *
{
const char *pw;
return (pw);
}
/* perform connection via proxy using SOCKSv[45] or HTTP proxy CONNECT */
int
const char *proxyuser)
{
/* Abuse API to lookup port */
if (authretry++ > 3)
if (proxyfd < 0)
return (-1);
if (socksv == 5) {
/* Version 5, one method: no authentication */
if (cnt != 3)
if (cnt != 2)
case 0:
/* Version 5, connect: domain name */
/* Max domain name length is 255 bytes */
if (hlen > 255)
buf[2] = 0;
sizeof (serverport));
break;
case AF_INET:
/* Version 5, connect: IPv4 address */
buf[2] = 0;
break;
case AF_INET6:
/* Version 5, connect: IPv6 address */
buf[2] = 0;
break;
default:
}
/*
* read proxy reply which is 4 byte "header", BND.ADDR
* and BND.PORT according to RFC 1928, section 6. BND.ADDR
* is 4 bytes in case of IPv4 which gives us 10 bytes in sum.
*/
if (cnt != 10)
if (buf[1] != 0)
} else if (socksv == 4) {
/* This will exit on lookup failure */
sizeof (addr), 1, 0);
/* Version 4 */
wlen = 9;
/*
* SOCKSv4 proxy replies consists of 2 byte "header",
* port number and numeric IPv4 address which gives 8 bytes.
*/
if (cnt != 8)
} else if (socksv == -1) {
/* HTTP proxy CONNECT according to RFC 2817, section 5 */
/* Disallow bad chars in hostname */
/* Try to be sane about numeric IPv6 addresses */
"CONNECT [%s]:%d HTTP/1.0\r\n",
} else {
"CONNECT %s:%d HTTP/1.0\r\n",
}
if (cnt != r)
if (authretry > 1) {
sizeof (resp)) == -1)
"Basic %s\r\n", resp);
}
/* Terminate headers */
/* Read status reply */
if (authretry > 1) {
"failed\n");
}
goto again;
strlen(HTTP_11_200)) != 0)
/* Headers continue until we hit an empty line */
for (r = 0; r < HTTP_MAXHDRS; r++) {
if (*buf == '\0')
break;
}
if (*buf != '\0')
} else
return (proxyfd);
}