Unix Technical Forum

SEO

vBulletin Search Engine Optimization


Go Back   Unix Technical Forum > Unix Operating Systems > OpenBSD > lucky.openbsd.tech

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 02-22-2008, 11:20 AM
Ronnel P. Maglasang
 
Posts: n/a
Default Re: upgraded ftp-proxy to support ipv6

thanks, got that. just learned the convention here is
diff -urN <orig> <new>.

here's using diff -urN.


Dries Schellekens wrote:

> Ronnel P. Maglasang wrote:
>
>> apologies, the patch is incorrect, i diff'ed in the wrong direction.
>> please disregard the previous one.
>>
>> this is the correct patch file.

>
>
> OpenBSD developers prefer if you use diff -u
>
>
> Cheers,
>
> Dries




diff -urN ftp-proxy/Makefile ftp-proxy-new/Makefile
--- ftp-proxy/Makefile Fri Nov 21 07:23:09 2003
+++ ftp-proxy-new/Makefile Fri Mar 18 16:34:47 2005
@@ -14,4 +14,7 @@
DPADD+= ${LIBWRAP}
.endif

+# For ipv6 support
+CFLAGS+= -DIPV6_SUP
+
.include <bsd.prog.mk>
diff -urN ftp-proxy/ftp-proxy.c ftp-proxy-new/ftp-proxy.c
--- ftp-proxy/ftp-proxy.c Sun Jul 11 09:54:36 2004
+++ ftp-proxy-new/ftp-proxy.c Fri Mar 18 18:04:33 2005
@@ -55,6 +55,13 @@
* the real destination address - the tcp wrapper stuff is done after
* the real destination address is retrieved from pf
*
+ * Added support for IPv6.
+ * Changed all address structures to accomodate IPv4 and IPv6 addresses.
+ * Modified processing of EPRT. Added support for processing the response
+ * of LPRT to support IPv6 ftp session.
+ *
+ * - Ronnel Maglasang(rmaglasang@infoweapons.com)
+ * www.infoweapons.com
*/

/*
@@ -125,11 +132,24 @@

double xfer_start_time;

+#ifdef IPV6_SUP
+struct sockaddr_storage real_server_sa;
+struct sockaddr_storage client_listen_sa;
+struct sockaddr_storage server_listen_sa;
+struct sockaddr_storage proxy_sa;
+int address_family;
+#else
struct sockaddr_in real_server_sa;
struct sockaddr_in client_listen_sa;
struct sockaddr_in server_listen_sa;
struct sockaddr_in proxy_sa;
+#endif
+
+#ifdef IPV6_SUP
+struct sockaddr_storage src_addr;
+#else
struct in_addr src_addr;
+#endif

int client_listen_socket = -1; /* Only used in PASV mode */
int client_data_socket = -1; /* Connected socket to real client */
@@ -146,18 +166,33 @@
char RealServerName[NI_MAXHOST];
char OurName[NI_MAXHOST];

+#ifdef IPV6_SUP
+char ClientPortName[NI_MAXHOST];
+char RealServerPortName[NI_MAXHOST];
+char OurPortName[NI_MAXHOST];
+#endif
+
char *User = "proxy";
char *Group;

extern int Debug_Level;
extern int Use_Rdns;
+#ifdef IPV6_SUP
+extern int Bind_Addr_Flag;
+extern struct sockaddr_storage Bind_Addr;
+#else
extern in_addr_t Bind_Addr;
+#endif
extern char *__progname;

typedef enum {
UNKNOWN_MODE,
PORT_MODE,
PASV_MODE,
+#ifdef IPV6_SUP
+ LPRT_MODE,
+ LPSV_MODE,
+#endif
EPRT_MODE,
EPSV_MODE
} connection_mode_t;
@@ -246,16 +281,50 @@
* if we are set to do reverse DNS, otherwise no.
*/
static int
+#ifdef IPV6_SUP
+check_host(struct sockaddr_storage *client_sin, struct sockaddr_storage *server_sin)
+#else
check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin)
+#endif
{
char cname[NI_MAXHOST];
char sname[NI_MAXHOST];
+#ifdef IPV6_SUP
+ char caddr[NI_MAXHOST];
+ char saddr[NI_MAXHOST];
+#endif
struct request_info request;
int i;

+#ifdef IPV6_SUP
+ /* retrieve client address */
+ i = getnameinfo((struct sockaddr *)client_sin,
+ client_sin->ss_len, caddr, sizeof(caddr),
+ NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
+ syslog(LOG_NOTICE, "1 getnameinfo() failed!\n");
+ return(0);
+ }
+
+ /* retrieve server address */
+ i = getnameinfo((struct sockaddr *)server_sin,
+ server_sin->ss_len, saddr, sizeof(saddr),
+ NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
+ syslog(LOG_NOTICE, "2 getnameinfo() failed!\n");
+ return(0);
+ }
+
+ request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN,
+ client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR,
+ caddr, 0);
+#else
request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN,
client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR,
inet_ntoa(client_sin->sin_addr), 0);
+#endif

if (Use_Rdns) {
/*
@@ -264,6 +333,21 @@
* the tcp wrapper cares about these things, and we don't
* want to pass in a printed address as a name.
*/
+#ifdef IPV6_SUP
+ i = getnameinfo((struct sockaddr *)client_sin,
+ client_sin->ss_len, cname, sizeof(cname),
+ NULL, 0, NI_NAMEREQD);
+
+ if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
+ strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
+
+ i = getnameinfo((struct sockaddr *)server_sin,
+ server_sin->ss_len, sname, sizeof(sname),
+ NULL, 0, NI_NAMEREQD);
+
+ if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
+ strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
+#else
i = getnameinfo((struct sockaddr *) &client_sin->sin_addr,
sizeof(&client_sin->sin_addr), cname, sizeof(cname),
NULL, 0, NI_NAMEREQD);
@@ -277,6 +361,7 @@

if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
+#endif
} else {
/*
* ensure the TCP wrapper doesn't start doing
@@ -286,8 +371,12 @@
strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
}

+#ifdef IPV6_SUP
+ request_set(&request, RQ_SERVER_ADDR, saddr, 0);
+#else
request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr),
0);
+#endif
request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0);

if (!hosts_access(&request)) {
@@ -422,6 +511,12 @@
* Close existing data conn.
*/

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "new_dataconn() server: [%d]\n", server);
+#endif
+#endif
+
if (client_listen_socket != -1) {
close(client_listen_socket);
client_listen_socket = -1;
@@ -436,8 +531,13 @@

if (server) {
bzero(&server_listen_sa, sizeof(server_listen_sa));
+#ifdef IPV6_SUP
+ server_listen_socket = get_backchannel_socket(address_family,
+ SOCK_STREAM, min_port, max_port, -1, 1, &server_listen_sa);
+#else
server_listen_socket = get_backchannel_socket(SOCK_STREAM,
min_port, max_port, -1, 1, &server_listen_sa);
+#endif

if (server_listen_socket == -1) {
syslog(LOG_INFO, "server socket bind() failed (%m)");
@@ -449,8 +549,13 @@
}
} else {
bzero(&client_listen_sa, sizeof(client_listen_sa));
+#ifdef IPV6_SUP
+ client_listen_socket = get_backchannel_socket(address_family,
+ SOCK_STREAM, min_port, max_port, -1, 1, &client_listen_sa);
+#else
client_listen_socket = get_backchannel_socket(SOCK_STREAM,
min_port, max_port, -1, 1, &client_listen_sa);
+#endif

if (client_listen_socket == -1) {
syslog(LOG_NOTICE,
@@ -469,14 +574,32 @@
static void
connect_pasv_backchannel(void)
{
+#ifdef IPV6_SUP
+ struct sockaddr_storage listen_sa;
+#else
struct sockaddr_in listen_sa;
+#endif
socklen_t salen;
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ char host[NI_MAXHOST];
+ char port[NI_MAXHOST];
+#endif
+#endif

/*
* We are about to accept a connection from the client.
* This is a PASV data connection.
*/
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "client listen socket ready");
+#endif
+
debuglog(2, "client listen socket ready");
+#else
+ debuglog(2, "client listen socket ready");
+#endif

close_server_data();
close_client_data();
@@ -493,14 +616,41 @@
client_listen_socket = -1;
memset(&listen_sa, 0, sizeof(listen_sa));

+#ifdef IPV6_SUP
+ server_data_socket = get_backchannel_socket(address_family, SOCK_STREAM, min_port,
+ max_port, -1, 1, (struct sockaddr_storage *)&listen_sa);
+#else
server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port,
- max_port, -1, 1, &listen_sa);
+ max_port, -1, 1, &listen_sa);
+#endif
if (server_data_socket < 0) {
syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
exit(EX_OSERR);
}
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&server_listen_sa,
+ server_listen_sa.ss_len,
+ host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "1 server_data_socket: [%d], host: [%s], port: [%s]\n",
+ server_data_socket, host, port);
+
+ getnameinfo((struct sockaddr *)&listen_sa,
+ listen_sa.ss_len,
+ host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "2 host: [%s], port: [%s]\n", host, port);
+#endif
+
+ if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa,
+ server_listen_sa.ss_len) != 0) {
+#else
if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa,
sizeof(server_listen_sa)) != 0) {
+#endif
syslog(LOG_NOTICE, "connect() failed (%m)");
exit(EX_NOHOST);
}
@@ -512,14 +662,34 @@
static void
connect_port_backchannel(void)
{
+#ifdef IPV6_SUP
+ struct sockaddr_storage listen_sa;
+ struct sockaddr_in *sockaddr4;
+ struct sockaddr_in6 *sockaddr6;
+#else
struct sockaddr_in listen_sa;
+#endif
socklen_t salen;
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ char host[NI_MAXHOST];
+ char port[NI_MAXHOST];
+#endif
+#endif

/*
* We are about to accept a connection from the server.
* This is a PORT or EPRT data connection.
*/
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "server listen socket ready");
+#endif
+
debuglog(2, "server listen socket ready");
+#else
+ debuglog(2, "server listen socket ready");
+#endif

close_server_data();
close_client_data();
@@ -531,6 +701,17 @@
syslog(LOG_NOTICE, "accept() failed (%m)");
exit(EX_OSERR);
}
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&listen_sa,
+ listen_sa.ss_len,
+ host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "server_listen_socket: [%d], host: [%s], port: [%s]\n",
+ server_listen_socket, host, port);
+#endif
+#endif
close(server_listen_socket);
server_listen_socket = -1;

@@ -541,9 +722,34 @@
* getting one bound to port 20 - This is deliberately
* not RFC compliant.
*/
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "running as non-root\n");
+ syslog(LOG_INFO, "address_family: [%d]\n", address_family);
+#endif
+#endif
+
+#ifdef IPV6_SUP
+ /* clear address based on address family */
+ if (address_family == AF_INET) {
+ sockaddr4 = (struct sockaddr_in *)&listen_sa;
+ bzero(&sockaddr4->sin_addr, sizeof(struct in_addr));
+ }
+ else {
+ sockaddr6 = (struct sockaddr_in6 *)&listen_sa;
+ bzero(&sockaddr6->sin6_addr, sizeof(struct in6_addr));
+ }
+#else
bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
+#endif
+
+#ifdef IPV6_SUP
+ client_data_socket = get_backchannel_socket(address_family, SOCK_STREAM,
+ min_port, max_port, -1, 1, (struct sockaddr_storage *)&listen_sa);
+#else
client_data_socket = get_backchannel_socket(SOCK_STREAM,
- min_port, max_port, -1, 1, &listen_sa);
+ min_port, max_port, -1, 1, &listen_sa);
+#endif
if (client_data_socket < 0) {
syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
exit(EX_OSERR);
@@ -555,12 +761,33 @@
* We're root, get our backchannel socket bound to port
* 20 here, so we're fully RFC compliant.
*/
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "running as root\n");
+#endif
+#endif
+
+#ifdef IPV6_SUP
+ client_data_socket = socket(address_family, SOCK_STREAM, 0);
+
+ salen = 1;
+ if (address_family == AF_INET) {
+ sockaddr4 = (struct sockaddr_in *)&listen_sa;
+ sockaddr4->sin_family = AF_INET;
+ bcopy(&((struct sockaddr_in *)&src_addr)->sin_addr,
+ &sockaddr4->sin_addr, sizeof(struct in_addr));
+ sockaddr4->sin_port = htons(20);
+ }
+ else {
+ }
+#else
client_data_socket = socket(AF_INET, SOCK_STREAM, 0);

salen = 1;
listen_sa.sin_family = AF_INET;
bcopy(&src_addr, &listen_sa.sin_addr, sizeof(struct in_addr));
listen_sa.sin_port = htons(20);
+#endif

if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR,
&salen, sizeof(salen)) == -1) {
@@ -575,8 +802,23 @@
}
}

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&client_listen_sa,
+ client_listen_sa.ss_len,
+ host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "client_data_socket: [%d], host: [%s], port: [%s]\n",
+ client_data_socket, host, port);
+#endif
+
+ if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa,
+ client_listen_sa.ss_len) != 0) {
+#else
if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa,
sizeof(client_listen_sa)) != 0) {
+#endif
syslog(LOG_INFO, "cannot connect data channel (%m)");
exit(EX_NOHOST);
}
@@ -592,9 +834,32 @@
int i, j, rv;
char tbuf[100];
char *sendbuf = NULL;
+#ifdef IPV6_SUP
+ char c_addr_str[NI_MAXHOST];
+ char c_port_str[NI_MAXHOST];
+ char s_addr_str[NI_MAXHOST];
+ char s_port_str[NI_MAXHOST];
+ int ret;
+#endif

log_control_command((char *)client->line_buffer, 1);

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "client->line_buffer: [%s]\n", (char *)client->line_buffer);
+#endif
+#endif
+
+#ifdef IPV6_SUP
+ ret = getnameinfo((struct sockaddr *)&server->sa, server->sa.ss_len, s_addr_str,
+ sizeof(s_addr_str), NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (ret != 0) {
+ strcpy(s_addr_str, "unknown server address");
+ }
+#endif
+
/* client->line_buffer is an ftp control command.
* There is no reason for these to be very long.
* In the interest of limiting buffer overrun attempts,
@@ -667,11 +932,20 @@
goto protounsupp;

memset(&hints, 0, sizeof(hints));
+#ifdef IPV6_SUP
+ /* Support for both IPV4 and IPV6 */
+ if ((proto != 1) && (proto != 2))
+ goto protounsupp;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
+#else
if (proto != 1) /* 1 == AF_INET - all we support for now */
goto protounsupp;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
+#endif
if (getaddrinfo(result[1], result[2], &hints, &res))
goto parsefail;
if (res->ai_next)
@@ -680,9 +954,28 @@
goto parsefail;
memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen);

+#ifdef IPV6_SUP
+ ret = getnameinfo(res->ai_addr, res->ai_addrlen, c_addr_str,
+ sizeof(c_addr_str), c_port_str, sizeof(c_port_str),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (ret != 0) {
+ strcpy(c_addr_str, "unknown client address");
+ strcpy(c_port_str, "unknown client port");
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "client wants us to use %s:%s",
+ c_addr_str, c_port_str);
+#endif
+
+ debuglog(1, "client wants us to use %s:%s",
+ c_addr_str, c_port_str);
+#else
debuglog(1, "client wants us to use %s:%u",
inet_ntoa(client_listen_sa.sin_addr),
htons(client_listen_sa.sin_port));
+#endif

/*
* Configure our own listen socket and tell the server about it
@@ -690,13 +983,42 @@
new_dataconn(1);
connection_mode = EPRT_MODE;

+#ifdef IPV6_SUP
+ i = getnameinfo((struct sockaddr *)&server_listen_sa, server_listen_sa.ss_len, NULL,
+ 0, s_port_str, sizeof(s_port_str),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (ret != 0) {
+ strcpy(s_port_str, "unknown server port");
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "we want server to use %s:%s",
+ s_addr_str, s_port_str);
+#endif
+
+ debuglog(1, "we want server to use %s:%s",
+ s_addr_str, s_port_str);
+#else
debuglog(1, "we want server to use %s:%u",
inet_ntoa(server->sa.sin_addr),
ntohs(server_listen_sa.sin_port));
+#endif

+#ifdef IPV6_SUP
+ snprintf(tbuf, sizeof(tbuf), "EPRT |%u|%s|%s|\r\n", (unsigned int)proto,
+ s_addr_str, s_port_str);
+#else
snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1,
inet_ntoa(server->sa.sin_addr),
ntohs(server_listen_sa.sin_port));
+#endif
+
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "to server (modified): %s", tbuf);
+#endif
+#endif
debuglog(1, "to server (modified): %s", tbuf);
sendbuf = tbuf;
goto out;
@@ -706,6 +1028,11 @@
sendbuf = NULL;
goto out;
protounsupp:
+#ifdef IPV6_SUP
+ /* we support AF_INET and AF_INET6 now */
+ snprintf(tbuf, sizeof(tbuf),
+ "501 Protocol not supported\r\n");
+#else
/* we only support AF_INET for now */
if (proto == 2)
snprintf(tbuf, sizeof(tbuf),
@@ -713,6 +1040,7 @@
else
snprintf(tbuf, sizeof(tbuf),
"501 Protocol not supported\r\n");
+#endif
sendbuf = NULL;
out:
if (line)
@@ -765,6 +1093,11 @@
strlen("port ")) == 0) {
unsigned int values[6];
char *tailptr;
+#ifdef IPV6_SUP
+ struct sockaddr_in *client_sockaddr_in;
+ struct sockaddr_in *server_sockaddr_in;
+ struct sockaddr_in *server_listen_sockaddr_in;
+#endif

debuglog(1, "Got a PORT command");

@@ -789,6 +1122,19 @@
}
}

+#ifdef IPV6_SUP
+ client_sockaddr_in = (struct sockaddr_in *)&client_listen_sa;
+ client_sockaddr_in->sin_family = AF_INET;
+ client_sockaddr_in->sin_addr.s_addr = htonl((values[0] << 24) |
+ (values[1] << 16) | (values[2] << 8) |
+ (values[3] << 0));
+
+ client_sockaddr_in->sin_port = htons((values[4] << 8) |
+ values[5]);
+ debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
+ values[0], values[1], values[2], values[3],
+ (values[4] << 8) | values[5]);
+#else
client_listen_sa.sin_family = AF_INET;
client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
(values[1] << 16) | (values[2] << 8) |
@@ -799,6 +1145,7 @@
debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
values[0], values[1], values[2], values[3],
(values[4] << 8) | values[5]);
+#endif

/*
* Configure our own listen socket and tell the server about it
@@ -806,10 +1153,39 @@
new_dataconn(1);
connection_mode = PORT_MODE;

+#ifdef IPV6_SUP
+ i = getnameinfo((struct sockaddr *)&server_listen_sa, server_listen_sa.ss_len, NULL,
+ 0, s_port_str, sizeof(s_port_str),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (ret != 0) {
+ strcpy(s_port_str, "unknown server port");
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "we want server to use %s:%s",
+ s_addr_str, s_port_str);
+#endif
+
+ debuglog(1, "we want server to use %s:%s",
+ s_addr_str, s_port_str);
+#else
debuglog(1, "we want server to use %s:%u",
inet_ntoa(server->sa.sin_addr),
ntohs(server_listen_sa.sin_port));
+#endif

+#ifdef IPV6_SUP
+ server_sockaddr_in = (struct sockaddr_in *)&server->sa;
+ server_listen_sockaddr_in = (struct sockaddr_in *)&server_listen_sa;
+ snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n",
+ ((u_char *)&server_sockaddr_in->sin_addr.s_addr)[0],
+ ((u_char *)&server_sockaddr_in->sin_addr.s_addr)[1],
+ ((u_char *)&server_sockaddr_in->sin_addr.s_addr)[2],
+ ((u_char *)&server_sockaddr_in->sin_addr.s_addr)[3],
+ ((u_char *)&server_listen_sockaddr_in->sin_port)[0],
+ ((u_char *)&server_listen_sockaddr_in->sin_port)[1]);
+#else
snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n",
((u_char *)&server->sa.sin_addr.s_addr)[0],
((u_char *)&server->sa.sin_addr.s_addr)[1],
@@ -817,7 +1193,13 @@
((u_char *)&server->sa.sin_addr.s_addr)[3],
((u_char *)&server_listen_sa.sin_port)[0],
((u_char *)&server_listen_sa.sin_port)[1]);
+#endif

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "to server (modified): %s", tbuf);
+#endif
+#endif
debuglog(1, "to server (modified): %s", tbuf);

sendbuf = tbuf;
@@ -848,9 +1230,25 @@
struct in_addr *iap;
static int continuing = 0;
char tbuf[100], *sendbuf, *p;
+#ifdef IPV6_SUP
+ struct sockaddr_in *client_sockaddr_in;
+ struct sockaddr_in *server_sockaddr_in;
+ struct sockaddr_in *proxy_sockaddr_in;
+ struct sockaddr_in6 *client_sockaddr_in6;
+ struct sockaddr_in6 *server_sockaddr_in6;
+ struct sockaddr_in6 *use_sockaddr_in6;
+ char host[NI_MAXHOST];
+ char port[NI_MAXHOST];
+#endif

log_control_command((char *)server->line_buffer, 0);

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "server->line_buffer: [%s]\n", (char *)server->line_buffer);
+#endif
+#endif
+
if (strlen((char *)server->line_buffer) > 512) {
/*
* someone's playing games. Have a cow in the syslogs and
@@ -887,6 +1285,13 @@
unsigned int values[6];
char *tailptr;

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "PASV reply\n");
+ syslog(LOG_INFO, "address_family: [%d]\n", address_family);
+#endif
+#endif
+
debuglog(1, "Got a PASV reply");
debuglog(1, "{%s}", (char *)server->line_buffer);

@@ -917,6 +1322,32 @@
exit(EX_DATAERR);
}

+#ifdef IPV6_SUP
+ if (address_family == AF_INET) {
+ server_sockaddr_in = (struct sockaddr_in *)&server_listen_sa;
+ server_sockaddr_in->sin_family = AF_INET;
+ server_sockaddr_in->sin_len = sizeof(struct sockaddr_in);
+ server_sockaddr_in->sin_addr.s_addr = htonl((values[0] << 24) |
+ (values[1] << 16) | (values[2] << 8) | (values[3] << 0));
+ server_sockaddr_in->sin_port = htons((values[4] << 8) |
+ values[5]);
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "server wants us to use %s:%u",
+ inet_ntoa(server_sockaddr_in->sin_addr), (values[4] << 8) |
+ values[5]);
+#endif
+
+ debuglog(1, "server wants us to use %s:%u",
+ inet_ntoa(server_sockaddr_in->sin_addr), (values[4] << 8) |
+ values[5]);
+ }
+ else {
+ syslog(LOG_NOTICE, "failed in do_server_reply(), unknown af: [%d]\n",
+ address_family);
+ exit(EX_DATAERR);
+ }
+#else
server_listen_sa.sin_family = AF_INET;
server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
(values[1] << 16) | (values[2] << 8) | (values[3] << 0));
@@ -926,9 +1357,42 @@
debuglog(1, "server wants us to use %s:%u",
inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) |
values[5]);
+#endif

new_dataconn(0);
connection_mode = PASV_MODE;
+
+#ifdef IPV6_SUP
+ if (ReverseMode) {
+ if (address_family == AF_INET) {
+ proxy_sockaddr_in = (struct sockaddr_in *)&proxy_sa;
+ iap = &(proxy_sockaddr_in->sin_addr);
+ }
+ }
+ else {
+ if (address_family == AF_INET) {
+ server_sockaddr_in = (struct sockaddr_in *)&server->sa;
+ iap = &(server_sockaddr_in->sin_addr);
+ }
+ }
+
+ if (address_family == AF_INET) {
+ client_sockaddr_in = (struct sockaddr_in *)&client_listen_sa;
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "we want client to use %s:%u", inet_ntoa(*iap),
+ htons(client_sockaddr_in->sin_port));
+#endif
+ debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap),
+ htons(client_sockaddr_in->sin_port));
+
+ snprintf(tbuf, sizeof(tbuf),
+ "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n",
+ ((u_char *)iap)[0], ((u_char *)iap)[1],
+ ((u_char *)iap)[2], ((u_char *)iap)[3],
+ ((u_char *)&client_sockaddr_in->sin_port)[0],
+ ((u_char *)&client_sockaddr_in->sin_port)[1]);
+ }
+#else
if (ReverseMode)
iap = &(proxy_sa.sin_addr);
else
@@ -943,9 +1407,264 @@
((u_char *)iap)[2], ((u_char *)iap)[3],
((u_char *)&client_listen_sa.sin_port)[0],
((u_char *)&client_listen_sa.sin_port)[1]);
+#endif
+
debuglog(1, "to client (modified): %s", tbuf);
sendbuf = tbuf;
- } else {
+ }
+#ifdef IPV6_SUP
+ /*
+ * Hack to support IPV6.
+ * Process LPSV response which includes IPV6 packets.
+ * Basically same processing with PASV.
+ */
+ else if (code == 228 && !NatMode) {
+
+ unsigned int af = 0;
+ unsigned int hal = 0;
+ unsigned int pal = 0;
+ unsigned int h_values[16];
+ unsigned int p_values[2];
+ char *tailptr;
+ int x;
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "LPSV reply\n");
+ syslog(LOG_INFO, "address_family: [%d]\n", address_family);
+#endif
+
+ /* support only IPV6 */
+ if (address_family != AF_INET6) {
+ syslog(LOG_NOTICE, "for LPSV only IPv6 is supported");
+ exit(EX_DATAERR);
+ }
+
+ debuglog(1, "Got a LPSV reply");
+ debuglog(1, "{%s}", (char *)server->line_buffer);
+
+ tailptr = (char *)strchr((char *)server->line_buffer, '(');
+ if (tailptr == NULL) {
+ tailptr = strrchr((char *)server->line_buffer, ' ');
+ if (tailptr == NULL) {
+ syslog(LOG_NOTICE, "malformed 228 reply");
+ exit(EX_DATAERR);
+ }
+ }
+
+ tailptr++; /* skip past space or ( */
+
+ /* read af */
+ i = sscanf(tailptr, "%u", &af);
+ if (i != 1) {
+ syslog(LOG_INFO, "1 malformed LPSV reply (%s)",
+ client->line_buffer);
+ exit(EX_DATAERR);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "af: [%d]\n", af);
+#endif
+
+ /* move past af */
+ tailptr = (char *)strchr(tailptr, ',');
+ if (tailptr == NULL) {
+ syslog(LOG_NOTICE, "malformed 228 reply, af not found");
+ exit(EX_DATAERR);
+ }
+
+ tailptr++;
+
+ /* read address length */
+ i = sscanf(tailptr, "%u", &hal);
+ if (i != 1) {
+ syslog(LOG_INFO, "2 malformed LPSV reply (%s)",
+ client->line_buffer);
+ exit(EX_DATAERR);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "hal: [%d]\n", hal);
+#endif
+ /* we only support a hack for IPV6 for now */
+ if (hal != 16) {
+ syslog(LOG_NOTICE, "malformed 228 reply, address length not supported");
+ exit(EX_DATAERR);
+ }
+
+ /* move past hal */
+ tailptr = (char *)strchr(tailptr, ',');
+ if (tailptr == NULL) {
+ syslog(LOG_NOTICE, "malformed 228 reply, hal not found");
+ exit(EX_DATAERR);
+ }
+
+ tailptr++;
+
+ /* read address */
+ bzero(&h_values, sizeof(h_values));
+ i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u, %u",
+ &h_values[0], &h_values[1], &h_values[2], &h_values[3],
+ &h_values[4], &h_values[5], &h_values[6], &h_values[7],
+ &h_values[8], &h_values[9], &h_values[10], &h_values[11],
+ &h_values[12], &h_values[13], &h_values[14], &h_values[15]);
+ if (i != 16) {
+ syslog(LOG_INFO, "3 malformed LPSV reply (%s)",
+ client->line_buffer);
+ exit(EX_DATAERR);
+ }
+
+ /* move past address */
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "h_values: ");
+#endif
+ for (x = 0; x < i; x++) {
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "h_values[%d]: %d\n", x, h_values[x]);
+#endif
+ if (tailptr != NULL) {
+ tailptr = (char *)strchr(tailptr, ',');
+ if (tailptr != NULL)
+ tailptr++;
+ }
+ }
+
+ if (tailptr == NULL) {
+ syslog(LOG_NOTICE, "malformed 228 reply, adderess not found");
+ exit(EX_DATAERR);
+ }
+
+ /* read port length */
+ i = sscanf(tailptr, "%u", &pal);
+ if (i != 1) {
+ syslog(LOG_INFO, "4 malformed LPSV reply (%s)",
+ client->line_buffer);
+ exit(EX_DATAERR);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "pal: [%d]\n", pal);
+#endif
+ /* we only support a hack for IPV6 for now */
+ if (pal != 2) {
+ syslog(LOG_NOTICE, "malformed 228 reply, port length not supported");
+ exit(EX_DATAERR);
+ }
+
+ /* move past pal */
+ tailptr = (char *)strchr(tailptr, ',');
+ if (tailptr == NULL) {
+ syslog(LOG_NOTICE, "malformed 228 reply, pal not found");
+ exit(EX_DATAERR);
+ }
+ tailptr++;
+
+ /* read port */
+ bzero(&p_values, sizeof(p_values));
+ i = sscanf(tailptr, "%u,%u", &p_values[0], &p_values[1]);
+ if (i != 2) {
+ syslog(LOG_INFO, "5 malformed LPSV reply (%s)",
+ client->line_buffer);
+ exit(EX_DATAERR);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "p_values: ");
+#endif
+ for (x = 0; x < i; x++) {
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "p_values[%d]: %d\n", x, p_values[x]);
+#endif
+
+ if (tailptr != NULL)
+ tailptr = (char *)strchr(tailptr, ',');
+ }
+
+ if (address_family == AF_INET6) {
+ bzero(&server_listen_sa, sizeof(server_listen_sa));
+ server_sockaddr_in6 = (struct sockaddr_in6 *)&server_listen_sa;
+ server_sockaddr_in6->sin6_family = AF_INET6;
+ server_sockaddr_in6->sin6_len = sizeof(struct sockaddr_in6);
+ server_sockaddr_in6->sin6_port = htons((p_values[0] << 8) | p_values[1]);
+ server_sockaddr_in6->sin6_addr.s6_addr[0] = h_values[0];
+ server_sockaddr_in6->sin6_addr.s6_addr[1] = h_values[1];
+ server_sockaddr_in6->sin6_addr.s6_addr[2] = h_values[2];
+ server_sockaddr_in6->sin6_addr.s6_addr[3] = h_values[3];
+ server_sockaddr_in6->sin6_addr.s6_addr[4] = h_values[4];
+ server_sockaddr_in6->sin6_addr.s6_addr[5] = h_values[5];
+ server_sockaddr_in6->sin6_addr.s6_addr[6] = h_values[6];
+ server_sockaddr_in6->sin6_addr.s6_addr[7] = h_values[7];
+ server_sockaddr_in6->sin6_addr.s6_addr[8] = h_values[8];
+ server_sockaddr_in6->sin6_addr.s6_addr[9] = h_values[9];
+ server_sockaddr_in6->sin6_addr.s6_addr[10] = h_values[10];
+ server_sockaddr_in6->sin6_addr.s6_addr[11] = h_values[11];
+ server_sockaddr_in6->sin6_addr.s6_addr[12] = h_values[12];
+ server_sockaddr_in6->sin6_addr.s6_addr[13] = h_values[13];
+ server_sockaddr_in6->sin6_addr.s6_addr[14] = h_values[14];
+ server_sockaddr_in6->sin6_addr.s6_addr[15] = h_values[15];
+
+ getnameinfo((struct sockaddr *)&server_listen_sa, server_listen_sa.ss_len,
+ host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "server wants us to use %s:%s\n", host, port);
+#endif
+ }
+
+ new_dataconn(0);
+
+ connection_mode = LPSV_MODE;
+
+ if (ReverseMode) {
+ if (address_family == AF_INET6) {
+ use_sockaddr_in6 = (struct sockaddr_in6 *)&proxy_sa;
+ }
+ }
+ else {
+ if (address_family == AF_INET6) {
+ use_sockaddr_in6 = (struct sockaddr_in6 *)&server->sa;
+ }
+ }
+
+ if (address_family == AF_INET6) {
+ client_sockaddr_in6 = (struct sockaddr_in6 *)&client_listen_sa;
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&use_sockaddr_in6, use_sockaddr_in6->sin6_len,
+ host, sizeof(host), NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ syslog(LOG_INFO, "we want client to use %s:%u", host,
+ htons(client_sockaddr_in6->sin6_port));
+#endif
+ snprintf(tbuf, sizeof(tbuf),
+ "228 Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,% u,%u,%u,%u,%u)\r\n",
+ 6, 16, use_sockaddr_in6->sin6_addr.s6_addr[0],
+ use_sockaddr_in6->sin6_addr.s6_addr[1],
+ use_sockaddr_in6->sin6_addr.s6_addr[2],
+ use_sockaddr_in6->sin6_addr.s6_addr[3],
+ use_sockaddr_in6->sin6_addr.s6_addr[4],
+ use_sockaddr_in6->sin6_addr.s6_addr[5],
+ use_sockaddr_in6->sin6_addr.s6_addr[6],
+ use_sockaddr_in6->sin6_addr.s6_addr[7],
+ use_sockaddr_in6->sin6_addr.s6_addr[8],
+ use_sockaddr_in6->sin6_addr.s6_addr[9],
+ use_sockaddr_in6->sin6_addr.s6_addr[10],
+ use_sockaddr_in6->sin6_addr.s6_addr[11],
+ use_sockaddr_in6->sin6_addr.s6_addr[12],
+ use_sockaddr_in6->sin6_addr.s6_addr[13],
+ use_sockaddr_in6->sin6_addr.s6_addr[14],
+ use_sockaddr_in6->sin6_addr.s6_addr[15],
+ 2, ((u_char *)&client_sockaddr_in6->sin6_port)[0],
+ ((u_char *)&client_sockaddr_in6->sin6_port)[1]);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "to client (modified): %s", tbuf);
+#endif
+ debuglog(1, "to client (modified): %s", tbuf);
+ sendbuf = tbuf;
+ }
+#endif
+ else {
sendit:
sendbuf = (char *)server->line_buffer;
}
@@ -963,7 +1682,6 @@
else if (rv != -1)
j += rv;
} while (j >= 0 && j < i);
-
}

int
@@ -979,6 +1697,26 @@
#ifdef LIBWRAP
int use_tcpwrapper = 0;
#endif /* LIBWRAP */
+#ifdef IPV6_SUP
+ struct addrinfo hints;
+ struct addrinfo *res;
+#ifdef DEBUG_LOG
+ char addr_str[NI_MAXHOST];
+ char port_str[NI_MAXHOST];
+#endif
+#endif
+
+#ifdef IPV6_SUP
+ openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "Starting ftp-proxy... argc: [%d]\n", argc);
+
+ for (i=0; i< argc; i++)
+ {
+ syslog(LOG_INFO, " argv[%d]: [%s]\n", i, argv[i]);
+ }
+#endif
+#endif

while ((ch = getopt(argc, argv, "a:g:m:M:R:S:t:u:AnVwr")) != -1) {
char *p;
@@ -986,11 +1724,36 @@
case 'a':
if (!*optarg)
usage();
+#ifdef IPV6_SUP
+ Bind_Addr_Flag = 1;
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(optarg, NULL, &hints, &res) != 0) {
+ syslog(LOG_NOTICE,
+ "%s: invalid address", optarg);
+ usage();
+ }
+
+ memcpy(&Bind_Addr, res->ai_addr, res->ai_addrlen);
+
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&Bind_Addr,
+ Bind_Addr.ss_len, addr_str, sizeof(addr_str),
+ NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "Bind Address: [%s]\n", addr_str);
+#endif
+ freeaddrinfo(res);
+#else
if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) {
syslog(LOG_NOTICE,
"%s: invalid address", optarg);
usage();
}
+#endif
break;
case 'A':
AnonFtpOnly = 1; /* restrict to anon usernames only */
@@ -1024,6 +1787,82 @@
Use_Rdns = 1; /* look up hostnames */
break;
case 'R': {
+#ifdef IPV6_SUP
+ char *s, *t, *b, *a, *p;
+
+ if (!*optarg)
+ usage();
+
+ if ((s = strdup(optarg)) == NULL) {
+ syslog (LOG_NOTICE,
+ "Insufficient memory (malloc failed)");
+ exit(EX_UNAVAILABLE);
+ }
+
+ a = strchr(s, '[');
+ if (a != NULL) {
+ /* IPV6 address */
+ a++;
+
+ if (a == NULL) {
+ syslog(LOG_NOTICE,
+ "%s: invalid address or port", optarg);
+ usage();
+ }
+
+ p = strchr(a, ']');
+ if (p == NULL) {
+ syslog(LOG_NOTICE,
+ "%s: invalid address or port", optarg);
+ usage();
+ }
+
+ b = p;
+
+ p = strchr(p, ':');
+ if (p == NULL) {
+ p = "21";
+ }
+ else {
+ p++;
+ }
+
+ *b = 0;
+ }
+ else {
+ /* IPV6 address */
+ a = s;
+ t = strchr(s, ':');
+ if (t == NULL)
+ p = "21";
+ else {
+ p = t+1;
+ *t = 0;
+ }
+ }
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(a, p, &hints, &res) != 0) {
+ syslog(LOG_NOTICE,
+ "%s: invalid address or port", optarg);
+ usage();
+ }
+
+ memcpy(&real_server_sa, res->ai_addr, res->ai_addrlen);
+
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&real_server_sa,
+ real_server_sa.ss_len, addr_str, sizeof(addr_str),
+ port_str, sizeof(port_str), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "Reverse Address: [%s]/[%s]\n", addr_str, port_str);
+#endif
+ freeaddrinfo(res);
+ free(s);
+#else
char *s, *t;

if (!*optarg)
@@ -1051,12 +1890,34 @@
if (real_server_sa.sin_addr.s_addr == INADDR_NONE)
usage();
free(s);
+#endif
ReverseMode = 1;
break;
}
case 'S':
+#ifdef IPV6_SUP
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(optarg, NULL, &hints, &res) != 0) {
+ usage();
+ }
+
+ memcpy(&src_addr, res->ai_addr, res->ai_addrlen);
+
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&src_addr,
+ src_addr.ss_len, addr_str, sizeof(addr_str),
+ NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "Source Address: [%s]\n", addr_str);
+#endif
+ freeaddrinfo(res);
+#else
if (!inet_aton(optarg, &src_addr))
usage();
+#endif
break;
case 't':
timeout_seconds = strtol(optarg, &p, 10);
@@ -1085,7 +1946,9 @@
if (max_port < min_port)
usage();

+#ifndef IPV6_SUP
openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
+#endif

setlinebuf(stdout);
setlinebuf(stderr);
@@ -1118,21 +1981,36 @@
else
flags = NI_NUMERICHOST | NI_NUMERICSERV;

+#ifdef IPV6_SUP
+ i = getnameinfo((struct sockaddr *)&client_iob.sa,
+ client_iob.sa.ss_len, ClientName, sizeof(ClientName),
+ ClientPortName, sizeof(ClientPortName),
+ flags);
+#else
i = getnameinfo((struct sockaddr *)&client_iob.sa,
sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0,
flags);
+#endif

if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
debuglog(2, "name resolution failure (client)");
+ syslog(LOG_INFO, "1 name resolution failure: [%d]\n", i);
exit(EX_OSERR);
}

+#ifdef IPV6_SUP
+ i = getnameinfo((struct sockaddr *)&real_server_sa,
+ real_server_sa.ss_len, RealServerName, sizeof(RealServerName),
+ RealServerPortName, sizeof(RealServerPortName), flags);
+#else
i = getnameinfo((struct sockaddr *)&real_server_sa,
sizeof(real_server_sa), RealServerName, sizeof(RealServerName),
NULL, 0, flags);
+#endif

if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
debuglog(2, "name resolution failure (server)");
+ syslog(LOG_INFO, "2 name resolution failure: [%d]\n", i);
exit(EX_OSERR);
}

@@ -1143,17 +2021,35 @@

client_iob.fd = 0;

+#ifdef IPV6_SUP
+ syslog(LOG_INFO, "accepted connection from %s:%s to %s:%s", ClientName,
+ ClientPortName, RealServerName, RealServerPortName);
+#else
syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName,
ntohs(client_iob.sa.sin_port), RealServerName,
ntohs(real_server_sa.sin_port));
+#endif

+#ifdef IPV6_SUP
+ server_iob.fd = get_backchannel_socket(real_server_sa.ss_family,
+ SOCK_STREAM, min_port, max_port,
+ -1, 1, &server_iob.sa);
+#else
server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port,
-1, 1, &server_iob.sa);
+#endif

+#ifdef IPV6_SUP
+ if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa,
+ real_server_sa.ss_len) != 0) {
+ syslog(LOG_INFO, "cannot connect to %s:%s (%m)", RealServerName,
+ RealServerPortName);
+#else
if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa,
sizeof(real_server_sa)) != 0) {
syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName,
ntohs(real_server_sa.sin_port));
+#endif
exit(EX_NOHOST);
}

@@ -1165,16 +2061,32 @@
salen = sizeof(server_iob.sa);
getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen);

+#ifdef IPV6_SUP
+ i = getnameinfo((struct sockaddr *)&server_iob.sa,
+ server_iob.sa.ss_len, OurName, sizeof(OurName),
+ OurPortName, sizeof(OurPortName), flags);
+#else
i = getnameinfo((struct sockaddr *)&server_iob.sa,
sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags);
+#endif

if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
debuglog(2, "name resolution failure (local)");
exit(EX_OSERR);
}

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "local socket is %s:%s", OurName,
+ OurPortName);
+#endif
+
+ debuglog(1, "local socket is %s:%s", OurName,
+ OurPortName);
+#else
debuglog(1, "local socket is %s:%u", OurName,
ntohs(server_iob.sa.sin_port));
+#endif

/* ignore SIGPIPE */
bzero(&new_sa, sizeof(new_sa));
@@ -1224,6 +2136,12 @@
int maxfd = 0;
fd_set *fdsp;

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "main loop\n");
+#endif
+#endif
+
if (client_iob.fd > maxfd)
maxfd = client_iob.fd;
if (client_listen_socket > maxfd)
@@ -1237,6 +2155,13 @@
if (server_data_socket > maxfd)
maxfd = server_data_socket;

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "client is %s; server is %s",
+ client_iob.alive ? "alive" : "dead",
+ server_iob.alive ? "alive" : "dead");
+#endif
+#endif
debuglog(3, "client is %s; server is %s",
client_iob.alive ? "alive" : "dead",
server_iob.alive ? "alive" : "dead");
@@ -1303,12 +2228,25 @@
FD_ISSET(client_data_socket, fdsp)) {
int rval;

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "transfer: client to server");
+#endif
+#endif
debuglog(3, "transfer: client to server");
+#ifdef IPV6_SUP
+ rval = xfer_data("client to server",
+ client_data_socket,
+ server_data_socket,
+ &client_iob.sa,
+ &real_server_sa);
+#else
rval = xfer_data("client to server",
client_data_socket,
server_data_socket,
client_iob.sa.sin_addr,
real_server_sa.sin_addr);
+#endif
if (rval <= 0) {
close_client_data();
close_server_data();
@@ -1320,12 +2258,25 @@
FD_ISSET(server_data_socket, fdsp)) {
int rval;

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "transfer: server to client");
+#endif
+#endif
debuglog(3, "transfer: server to client");
+#ifdef IPV6_SUP
+ rval = xfer_data("server to client",
+ server_data_socket,
+ client_data_socket,
+ &real_server_sa,
+ &client_iob.sa);
+#else
rval = xfer_data("server to client",
server_data_socket,
client_data_socket,
real_server_sa.sin_addr,
client_iob.sa.sin_addr);
+#endif
if (rval <= 0) {
close_client_data();
close_server_data();
diff -urN ftp-proxy/ftp-proxy.cat8 ftp-proxy-new/ftp-proxy.cat8
--- ftp-proxy/ftp-proxy.cat8 Thu Jan 1 08:00:00 1970
+++ ftp-proxy-new/ftp-proxy.cat8 Fri Mar 18 16:37:40 2005
@@ -0,0 +1,170 @@
+FTP-PROXY(8) OpenBSD System Manager's Manual FTP-PROXY(8)
+
+NNAAMMEE
+ ffttpp--pprrooxxyy - Internet File Transfer Protocol proxy server
+
+SSYYNNOOPPSSIISS
+ ffttpp--pprrooxxyy [--AAnnrrVVww] [--aa _a_d_d_r_e_s_s] [--DD _d_e_b_u_g_l_e_v_e_l] [--gg _g_r_o_u_p] [--MM _m_a_x_p_o_r_t]
+ [--mm _m_i_n_p_o_r_t] [--RR _a_d_d_r_e_s_s_[_:_p_o_r_t_]] [--SS _a_d_d_r_e_s_s] [--tt _t_i_m_e_o_u_t] [--uu
+ _u_s_e_r]
+
+DDEESSCCRRIIPPTTIIOONN
+ ffttpp--pprrooxxyy is a proxy for the Internet File Transfer Protocol. The proxy
+ uses pf(4) and expects to have the FTP control connection as described in
+ services(5) redirected to it via a pf(4) _r_d_r command. An example of how
+ to do that is further down in this document.
+
+ The options are as follows:
+
+ --AA Permit only anonymous FTP connections. The proxy will allow con-
+ nections to log in to other sites as the user "ftp" or
+ "anonymous" only. Any attempt to log in as another user will be
+ blocked by the proxy.
+
+ --aa _a_d_d_r_e_s_s
+ Specify the local IP address to use in bind(2) as the source for
+ connections made by ffttpp--pprrooxxyy when connecting to destination FTP
+ servers. This may be necessary if the interface address of your
+ default route is not reachable from the destinations ffttpp--pprrooxxyy is
+ attempting connections to, or this address is different from the
+ one connections are being NATed to. In the usual case this means
+ that _a_d_d_r_e_s_s should be a publicly visible IP address assigned to
+ one of the interfaces on the machine running ffttpp--pprrooxxyy and should
+ be the same address to which you are translating traffic if you
+ are using the --nn option.
+
+ --DD _d_e_b_u_g_l_e_v_e_l
+ Specify a debug level, where the proxy emits verbose debug output
+ into syslogd(8) at level LOG_DEBUG. Meaningful values of debu-
+ glevel are 0-3, where 0 is no debug output and 3 is lots of debug
+ output, the default being 0.
+
+ --gg _g_r_o_u_p
+ Specify the named group to drop group privileges to, after doing
+ pf(4) lookups which require root. By default, ffttpp--pprrooxxyy uses the
+ default group of the user it drops privilege to.
+
+ --MM _m_a_x_p_o_r_t
+ Specify the upper end of the port range the proxy will use for
+ the data connections it establishes. The default is
+ IPPORT_HILASTAUTO defined in <_n_e_t_i_n_e_t_/_i_n_._h> as 65535.
+
+ --mm _m_i_n_p_o_r_t
+ Specify the lower end of the port range the proxy will use for
+ all data connections it establishes. The default is
+ IPPORT_HIFIRSTAUTO defined in <_n_e_t_i_n_e_t_/_i_n_._h> as 49152.
+
+ --nn Activate network address translation (NAT) mode. In this mode,
+ the proxy will not attempt to proxy passive mode (PASV or EPSV)
+ data connections. In order for this to work, the machine running
+ the proxy will need to be forwarding packets and doing network
+ address translation to allow the outbound passive connections
+ from the client to reach the server. See pf.conf(5) for more de-
+ tails on NAT. The proxy only ignores passive mode data connec-
+ tions when using this flag; it will still proxy PORT and EPRT
+ mode data connections. Without this flag, ffttpp--pprrooxxyy does not re-
+ quire any IP forwarding or NAT beyond the _r_d_r necessary to cap-
+ ture the FTP control connection.
+
+ --rr Use reverse host (reverse DNS) lookups for logging and libwrap
+ use. By default, the proxy does not look up hostnames for lib-
+ wrap or logging purposes.
+
+ --RR _a_d_d_r_e_s_s_:_[_p_o_r_t_]
+ Reverse proxy mode for FTP servers running behind a NAT gateway.
+ In this mode, no redirection is needed. The proxy is run from
+ inetd(8) on the port that external clients connect to (usually
+ 21). Control connections and passive data connections are for-
+ warded to the server.
+
+ --SS _a_d_d_r_e_s_s
+ Source address to use for data connections made by the proxy.
+ Useful when there are multiple addresses (aliases) available to
+ the proxy. Clients may expect data connections to have the same
+ source address as the control connections, and reject or drop
+ other connections.
+
+ --tt _t_i_m_e_o_u_t
+ Specifies a timeout, in seconds. The proxy will exit and close
+ open connections if it sees no data for the duration of the time-
+ out. The default is 0, which means the proxy will not time out.
+
+ --uu _u_s_e_r
+ Specify the named user to drop privilege to, after doing pf(4)
+ lookups which require root privilege. By default, ffttpp--pprrooxxyy
+ drops privilege to the user _p_r_o_x_y.
+
+ Running as root means that the source of data connections the
+ proxy makes for PORT and EPRT will be the RFC mandated port 20.
+ When running as a non-root user, the source of the data connec-
+ tions from ffttpp--pprrooxxyy will be chosen randomly from the range
+ _m_i_n_p_o_r_t to _m_a_x_p_o_r_t as described above.
+
+ --VV Be verbose. With this option the proxy logs the control commands
+ sent by clients and the replies sent by the servers to
+ syslogd(8).
+
+ --ww Use the tcp wrapper access control library hosts_access(3), al-
+ lowing connections to be allowed or denied based on the tcp wrap-
+ per's hosts.allow(5) and hosts.deny(5) files. The proxy does
+ libwrap operations after determining the destination of the cap-
+ tured control connection, so that tcp wrapper rules may be writ-
+ ten based on the destination as well as the source of FTP connec-
+ tions.
+
+ ffttpp--pprrooxxyy is run from inetd(8) and requires that FTP connections are
+ redirected to it using a _r_d_r rule. A typical way to do this would be to
+ use a pf.conf(5) rule such as
+
+ int_if = "xl0"
+ rdr pass on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
+
+ inetd(8) must then be configured to run ffttpp--pprrooxxyy on the port from above
+ using
+
+ 127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy
+
+ in inetd.conf(5).
+
+ ffttpp--pprrooxxyy accepts the redirected control connections and forwards them to
+ the server. The proxy replaces the address and port number that the
+ client sends through the control connection to the server with its own
+ address and proxy port, where it listens for the data connection. When
+ the server opens the data connection back to this port, the proxy for-
+ wards it to the client. The pf.conf(5) rules need to let pass connec-
+ tions to these proxy ports (see options --uu, --mm, and --MM above) in on the
+ external interface. The following example allows only ports 49152 to
+ 65535 to pass in statefully:
+
+ block in on $ext_if proto tcp all
+ pass in on $ext_if inet proto tcp from any to $ext_if \
+ port > 49151 keep state
+
+ Alternatively, rules can make use of the fact that by default, ffttpp--pprrooxxyy
+ runs as user "proxy" to allow the backchannel connections, as in the fol-
+ lowing example:
+
+ block in on $ext_if proto tcp all
+ pass in on $ext_if inet proto tcp from any to $ext_if \
+ user proxy keep state
+
+ These examples do not cover the connections from the proxy to the foreign
+ FTP server. If one does not pass outgoing connections by default addi-
+ tional rules are needed.
+
+SSEEEE AALLSSOO
+ ftp(1), pf(4), hosts.allow(5), hosts.deny(5), inetd.conf(5), pf.conf(5),
+ inetd(8), pfctl(8), syslogd(8)
+
+BBUUGGSS
+ Extended Passive mode (EPSV) is not supported by the proxy and will not
+ work unless the proxy is run in network address translation mode. When
+ not in network address translation mode, the proxy returns an error to
+ the client, hopefully forcing the client to revert to passive mode (PASV)
+ which is supported. EPSV will work in network address translation mode,
+ assuming a pf.conf(5) setup which allows the EPSV connections through to
+ their destinations.
+
+ IPv6 already supported.
+
+OpenBSD 3.6 August 17, 2001 3
diff -urN ftp-proxy/util.c ftp-proxy-new/util.c
--- ftp-proxy/util.c Wed Jul 7 03:49:11 2004
+++ ftp-proxy-new/util.c Thu Mar 17 22:37:28 2005
@@ -58,9 +58,19 @@

extern int ReverseMode;

+#ifdef IPV6_SUP
+/* address family type (AF_INET|AF_INET6) */
+extern int address_family;
+#endif
+
int Debug_Level;
int Use_Rdns;
+#ifdef IPV6_SUP
+int Bind_Addr_Flag = 0;
+struct sockaddr_storage Bind_Addr;
+#else
in_addr_t Bind_Addr = INADDR_NONE;
+#endif

void debuglog(int debug_level, const char *fmt, ...);

@@ -76,12 +86,27 @@
}

int
+#ifdef IPV6_SUP
+get_proxy_env(int connected_fd, struct sockaddr_storage *real_server_sa_ptr,
+ struct sockaddr_storage *client_sa_ptr, struct sockaddr_storage *proxy_sa_ptr)
+#else
get_proxy_env(int connected_fd, struct sockaddr_in *real_server_sa_ptr,
struct sockaddr_in *client_sa_ptr, struct sockaddr_in *proxy_sa_ptr)
+#endif
{
struct pfioc_natlook natlook;
socklen_t slen;
int fd;
+#ifdef IPV6_SUP
+ struct sockaddr_in *ipv4;
+ struct sockaddr_in6 *ipv6;
+ char client_host[NI_MAXHOST];
+ char client_port[NI_MAXHOST];
+ char proxy_host[NI_MAXHOST];
+ char proxy_port[NI_MAXHOST];
+ int ret;
+ char af;
+#endif

slen = sizeof(*proxy_sa_ptr);
if (getsockname(connected_fd, (struct sockaddr *)proxy_sa_ptr,
@@ -96,9 +121,96 @@
return(-1);
}

+#ifdef IPV6_SUP
+ ret = getnameinfo((struct sockaddr *)proxy_sa_ptr,
+ ((struct sockaddr *)proxy_sa_ptr)->sa_len,
+ proxy_host, sizeof(proxy_host),
+ proxy_port, sizeof(proxy_port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (ret != 0)
+ {
+ syslog(LOG_INFO, "getnameinfo() failed: [%d]\n", ret);
+ return(-1);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "proxy_host: [%s], proxy_port: [%s]\n",
+ proxy_host, proxy_port);
+#endif
+
+ /* updated global address family variable */
+ af = ((struct sockaddr *)proxy_sa_ptr)->sa_family;
+ switch (af)
+ {
+ case AF_INET:
+ /* set adderss family to AF_INET */
+ address_family = AF_INET;
+ break;
+
+ case AF_INET6:
+ /* set adderss family to AF_INET */
+ address_family = AF_INET6;
+ break;
+
+ default:
+ syslog(LOG_ERR, "unsupported address family: [%d]\n", af);
+ return(-1);
+ break;
+ }
+
+ ret = getnameinfo((struct sockaddr *)client_sa_ptr,
+ ((struct sockaddr *)client_sa_ptr)->sa_len,
+ client_host, sizeof(client_host),
+ client_port, sizeof(client_port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if (ret != 0)
+ {
+ syslog(LOG_INFO, "getnameinfo() failed: [%d]\n", ret);
+ return(-1);
+ }
+
+#ifdef DEBUG_LOG
+ syslog(LOG_INFO, "client_host: [%s], client_port: [%s]\n",
+ client_host, client_port);
+#endif
+#endif
+
if (ReverseMode)
return(0);

+#ifdef IPV6_SUP
+ /*
+ * Build up the pf natlook structure.
+ * Support only IPV4 and IPV6.
+ */
+ memset((void *)&natlook, 0, sizeof(natlook));
+ switch (af)
+ {
+ case AF_INET:
+ natlook.af = AF_INET;
+ ipv4 = (struct sockaddr_in *)client_sa_ptr;
+ natlook.saddr.addr32[0] = ipv4->sin_addr.s_addr;
+ natlook.sport = ipv4->sin_port;
+ ipv4 = (struct sockaddr_in *)proxy_sa_ptr;
+ natlook.daddr.addr32[0] = ipv4->sin_addr.s_addr;
+ natlook.dport = ipv4->sin_port;
+ natlook.proto = IPPROTO_TCP;
+ natlook.direction = PF_OUT;
+ break;
+
+ case AF_INET6:
+ natlook.af = AF_INET6;
+ ipv6 = (struct sockaddr_in6 *)client_sa_ptr;
+ natlook.saddr.v6 = ipv6->sin6_addr;
+ natlook.sport = ipv6->sin6_port;
+ ipv6 = (struct sockaddr_in6 *)proxy_sa_ptr;
+ natlook.daddr.v6 = ipv6->sin6_addr;
+ natlook.dport = ipv6->sin6_port;
+ natlook.proto = IPPROTO_TCP;
+ natlook.direction = PF_OUT;
+ break;
+ }
+#else
/*
* Build up the pf natlook structure.
* Just for IPv4 right now
@@ -111,6 +223,7 @@
natlook.sport = client_sa_ptr->sin_port;
natlook.dport = proxy_sa_ptr->sin_port;
natlook.direction = PF_OUT;
+#endif

/*
* Open the pf device and lookup the mapping pair to find
@@ -123,10 +236,16 @@
}

if (ioctl(fd, DIOCNATLOOK, &natlook) == -1) {
+#ifdef IPV6_SUP
+ syslog(LOG_INFO,
+ "pf nat lookup failed %s:%s (%m)",
+ client_host, client_port);
+#else
syslog(LOG_INFO,
"pf nat lookup failed %s:%hu (%m)",
inet_ntoa(client_sa_ptr->sin_addr),
ntohs(client_sa_ptr->sin_port));
+#endif
close(fd);
return(-1);
}
@@ -136,11 +255,38 @@
* Now jam the original address and port back into the into
* destination sockaddr_in for the proxy to deal with.
*/
+#ifdef IPV6_SUP
+ memset((void *)real_server_sa_ptr, 0, sizeof(struct sockaddr_storage));
+ switch (af)
+ {
+ case AF_INET:
+ ipv4 = (struct sockaddr_in *)real_server_sa_ptr;
+ ipv4->sin_port = natlook.rdport;
+ ipv4->sin_addr.s_addr = natlook.rdaddr.addr32[0];
+ ipv4->sin_len = sizeof(struct sockaddr_in);
+ ipv4->sin_family = AF_INET;
+ break;
+
+ case AF_INET6:
+ ipv6 = (struct sockaddr_in6 *)real_server_sa_ptr;
+ ipv6->sin6_port = natlook.rdport;
+ ipv6->sin6_addr = natlook.rdaddr.v6;
+ ipv6->sin6_len = sizeof(struct sockaddr_in6);
+ ipv6->sin6_family = AF_INET6;
+ break;
+
+ default:
+ syslog(LOG_ERR, "unsupported address family returned by pf: [%d]\n", af);
+ return(-1);
+ }
+#else
memset((void *)real_server_sa_ptr, 0, sizeof(struct sockaddr_in));
real_server_sa_ptr->sin_port = natlook.rdport;
real_server_sa_ptr->sin_addr.s_addr = natlook.rdaddr.addr32[0];
real_server_sa_ptr->sin_len = sizeof(struct sockaddr_in);
real_server_sa_ptr->sin_family = AF_INET;
+#endif
+
return(0);
}

@@ -151,8 +297,13 @@
* A unit of data is as much as we get with a single read(2) call.
*/
int
+#ifdef IPV6_SUP
+xfer_data(const char *what_read,int from_fd, int to_fd, struct sockaddr_storage *from,
+ struct sockaddr_storage *to)
+#else
xfer_data(const char *what_read,int from_fd, int to_fd, struct in_addr from,
struct in_addr to)
+#endif
{
int rlen, offset, xerrno, mark, flags = 0;
char tbuf[4096];
@@ -216,15 +367,84 @@
}
}

+
+#ifdef IPV6_SUP
+/*
+ * create sockaddr_storage structure for the INADDR_ANY for both
+ * IPV4 and IPV6 address family.
+ */
+int
+create_sockaddr_any(int af, int type, int port, struct sockaddr_storage *sa)
+{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ char port_str[NI_MAXHOST];
+ int ret;
+
+#ifdef DEBUG_LOG
+ char addr_buf[NI_MAXHOST];
+ char port_buf[NI_MAXHOST];
+#endif
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = type;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ /* convert port into string */
+ snprintf(port_str, NI_MAXHOST, "%d", port);
+
+ /* create based on address family type */
+ if (af == AF_INET)
+ ret = getaddrinfo("0.0.0.0", port_str, &hints, &res);
+ else if (af == AF_INET6)
+ ret = getaddrinfo("::", port_str, &hints, &res);
+ else {
+ syslog(LOG_INFO, "unknown af: [%d]\n", af);
+ return(-1);
+ }
+
+ if (ret != 0) {
+ syslog(LOG_INFO, "getaddrinfo() failed: [%d]\n", ret);
+ }
+
+ /* copy resulting address to our ouput argument */
+ memcpy(sa, res->ai_addr, res->ai_addrlen);
+
+#ifdef DEBUG_LOG
+ getnameinfo(res->ai_addr, res->ai_addrlen, addr_buf,
+ sizeof(addr_buf), port_buf, sizeof(port_buf),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "addr_buf: [%s], port_buf: [%s]\n", addr_buf, port_buf);
+#endif
+ freeaddrinfo(res);
+
+ return(0);
+}
+#endif
+
+
/*
* get_backchannel_socket gets us a socket bound somewhere in a
* particular range of ports
*/
int
+#ifdef IPV6_SUP
+get_backchannel_socket(int af, int type, int min_port, int max_port, int start_port,
+ int direction, struct sockaddr_storage *sap)
+#else
get_backchannel_socket(int type, int min_port, int max_port, int start_port,
int direction, struct sockaddr_in *sap)
+#endif
{
int count;
+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ char host[NI_MAXHOST];
+ char port[NI_MAXHOST];
+#endif
+#endif

/*
* Make sure that direction is 'defined' and that min_port is not
@@ -257,9 +477,39 @@
}

while (count-- > 0) {
+#ifdef IPV6_SUP
+ struct sockaddr_storage sa;
+ struct sockaddr_in *sockaddr4;
+ struct sockaddr_in6 *sockaddr6;
+#else
struct sockaddr_in sa;
+#endif
int one, fd;

+#ifdef IPV6_SUP
+ fd = socket(af, type, 0);
+
+ bzero(&sa, sizeof(sa));
+ if (Bind_Addr_Flag == 0) {
+ if (sap == NULL) {
+ if (create_sockaddr_any(af, type, start_port, &sa) != 0)
+ return(-1);
+ }
+ else {
+ if ((sap->ss_family == AF_INET) ||
+ (sap->ss_family == AF_INET6)) {
+ memcpy(&sa, sap, sap->ss_len);
+ }
+ else {
+ if (create_sockaddr_any(af, type, start_port, &sa) != 0)
+ return(-1);
+ }
+ }
+ }
+ else {
+ memcpy(&sa, &Bind_Addr, sizeof(sa));
+ }
+#else
fd = socket(AF_INET, type, 0);

bzero(&sa, sizeof sa);
@@ -271,6 +521,7 @@
sa.sin_addr.s_addr = sap->sin_addr.s_addr;
else
sa.sin_addr.s_addr = Bind_Addr;
+#endif

/*
* Indicate that we want to reuse a port if it happens that the
@@ -281,13 +532,42 @@
sizeof(one)) == -1)
return(-1);

+#ifdef IPV6_SUP
+ /* update port */
+ if (af == AF_INET) {
+ sockaddr4 = (struct sockaddr_in *)&sa;
+ sockaddr4->sin_port = htons(start_port);
+ }
+ else {
+ sockaddr6 = (struct sockaddr_in6 *)&sa;
+ sockaddr6->sin6_port = htons(start_port);
+ }
+#else
sa.sin_port = htons(start_port);
+#endif

+#ifdef IPV6_SUP
+#ifdef DEBUG_LOG
+ getnameinfo((struct sockaddr *)&sa,
+ sa.ss_len,
+ host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ syslog(LOG_INFO, "binding to host: [%s], port: [%s]\n",
+ host, port);
+#endif
+ if (bind(fd, (struct sockaddr *)&sa, sa.ss_len) == 0) {
+#else
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == 0) {
+#endif
if (sap != NULL)
*sap = sa;
return(fd);
}
+
+#ifdef IPV6_SUP
+ syslog(LOG_INFO, "bind() failed\n");
+#endif

if (errno != EADDRINUSE)
return(-1);
diff -urN ftp-proxy/util.h ftp-proxy-new/util.h
--- ftp-proxy/util.h Wed Jul 7 03:49:11 2004
+++ ftp-proxy-new/util.h Fri Mar 11 23:30:48 2005
@@ -45,7 +45,11 @@
int fd;
int line_buffer_size, io_buffer_size, io_buffer_len, next_byte;
unsigned char *io_buffer, *line_buffer;
+#ifdef IPV6_SUP
+ struct sockaddr_storage sa, real_sa;
+#else
struct sockaddr_in sa, real_sa;
+#endif
char *who;
char alive, got_eof, data_available;
int send_oob_flags;
@@ -54,14 +58,29 @@
extern int telnet_getline(struct csiob *iobp,
struct csiob *telnet_passthrough);

+#ifdef IPV6_SUP
+extern int get_proxy_env(int fd, struct sockaddr_storage *server_sa_ptr,
+ struct sockaddr_storage *client_sa_ptr, struct sockaddr_storage *proxy_sa_ptr);
+#else
extern int get_proxy_env(int fd, struct sockaddr_in *server_sa_ptr,
struct sockaddr_in *client_sa_ptr, struct sockaddr_in *proxy_sa_ptr);
+#endif

+#ifdef IPV6_SUP
+extern int get_backchannel_socket(int af, int type, int min_port, int max_port,
+ int start_port, int direction, struct sockaddr_storage *sap);
+#else
extern int get_backchannel_socket(int type, int min_port, int max_port,
int start_port, int direction, struct sockaddr_in *sap);
+#endif

+#ifdef IPV6_SUP
+extern int xfer_data(const char *what_read, int from_fd, int to_fd,
+ struct sockaddr_storage *from, struct sockaddr_storage *to);
+#else
extern int xfer_data(const char *what_read, int from_fd, int to_fd,
struct in_addr from, struct in_addr to);
+#endif

extern char *ProgName;


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 05:38 PM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
UnixAdminTalk.com

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168