import fmirror-0.8.4

fmirror is a program for mirroring files and directories from a remote
FTP server.

from Vladimir Kotal

ok naddy@
This commit is contained in:
bernd 2005-09-17 12:19:40 +00:00
parent c60f742777
commit 5f279beea7
5 changed files with 1024 additions and 0 deletions

34
net/fmirror/Makefile Normal file
View File

@ -0,0 +1,34 @@
# $OpenBSD: Makefile,v 1.1.1.1 2005/09/17 12:19:40 bernd Exp $
COMMENT= "mirror files and directories from a remote FTP server"
DISTNAME= fmirror-0.8.4
CATEGORIES= net
MASTER_SITES= ftp://ftp.oav.net/pkg_freebsd/distfiles/
# GPL
PERMIT_PACKAGE_CDROM= Yes
PERMIT_PACKAGE_FTP= Yes
PERMIT_DISTFILES_CDROM= Yes
PERMIT_DISTFILES_FTP= Yes
NO_REGRESS= Yes
WANTLIB= c
MAINTAINER= Vladimir Kotal <vlada@devnull.cz>
CONFIGURE_STYLE= gnu
MAN1= fmirror.1
EXAMPLEDIR= ${PREFIX}/share/examples/fmirror
do-install:
${INSTALL_PROGRAM} ${WRKSRC}/fmirror ${PREFIX}/bin
${INSTALL_MAN} ${WRKSRC}/${MAN1} ${PREFIX}/man/man1
${INSTALL_DATA_DIR} ${EXAMPLEDIR}
cd ${WRKSRC}/configs && ${INSTALL_DATA} generic.conf redhat.conf \
sample.conf ${EXAMPLEDIR}
.include <bsd.port.mk>

4
net/fmirror/distinfo Normal file
View File

@ -0,0 +1,4 @@
MD5 (fmirror-0.8.4.tar.gz) = 78652ce5bb50e6c120c9ca0988cb9dca
RMD160 (fmirror-0.8.4.tar.gz) = f053b0d7f88d516890263e7b65e63a781dd2f044
SHA1 (fmirror-0.8.4.tar.gz) = 8c124c7655da71c7fc28e5f052fe2091e0bff3fb
SIZE (fmirror-0.8.4.tar.gz) = 59831

View File

@ -0,0 +1,973 @@
$OpenBSD: patch-fmirror_c,v 1.1.1.1 2005/09/17 12:19:41 bernd Exp $
ipv6 patch by Vladimir Kotal <vlada@devnull.cz>
--- fmirror.c.orig Thu Sep 15 16:30:34 2005
+++ fmirror.c Thu Sep 15 16:30:37 2005
@@ -135,11 +135,12 @@ static FILE *in_file, *out_file;
static int loglevel = 3; /* Default logging level is 3 */
-#define FTP_CONTROL_PORT 21
+#define FTP_CONTROL_PORT "21"
static double totalsum = 0.0;
static double totalbytes = 0.0;
+static int af = PF_UNSPEC;
static char *localdir = NULL;
static char *remotedir = NULL;
static char *host = NULL;
@@ -170,6 +171,12 @@ static int keep_newer = 0; /* don't down
static int reset_times = 0; /* reset access and mod times to remote */
static int use_mdtm = 1; /* default is use MDTM if we can find remote TZ */
+struct in6_addr dst6_addr; /* IPv6 destination address.
+ for EPSV handling */
+size_t dst_addrlen;
+struct sockaddr_storage localaddr; /* local IP address, used for PORT/EPRT
+ command construction */
+
static volatile sig_atomic_t alarmed = 0;
static int input_timeout = 240;
@@ -183,6 +190,8 @@ static char whitespace[] = " \f\t\v";
static char rcsid[] = "$Id: patch-fmirror_c,v 1.1.1.1 2005/09/17 12:19:41 bernd Exp $";
static char usage[] =
+" -4 - use only IPv4 connections\n"
+" -6 - use only IPv6 connections\n"
" -A <mask> - binary and remote file permissions with <mask> [0111]\n"
" -O <mask> - binary or remote file permissions with <mask> [0444]\n"
" -C <whatever> - parse <whatever> as if it was a line in a config-file\n"
@@ -218,13 +227,16 @@ static char usage[] =
struct mirror_info {
char *hostname;
char *path;
- int port;
+ int af; /* force to use this address family */
+ char *port;
};
struct connection {
int fd;
- struct sockaddr_in sad;
- struct sockaddr_in dest;
+ struct sockaddr_storage sad;
+ struct sockaddr_storage dest; /* in network order */
+ unsigned short dport; /* dest port - for printing only, in HOST order */
+ int af;
FILE *file;
};
@@ -274,15 +286,17 @@ static struct reg_list *last_regex = NUL
static int parse_args(int argc, char *const *argv);
static void do_mirror(struct mirror_info *);
-static int do_connect(const char *, int);
+static int do_connect(const char *, const char *);
static void clog(const char *);
static int logit(const char *, ...) __attribute__((format(printf, 1, 2)));
static int handle_input(const char **msg);
static int cmd(const char *, ...);
static void get_filelist(void);
+static const char *make_active_args(struct sockaddr *);
+static const char *make_eprt_args(struct sockaddr *);
static const char *make_port_args(struct sockaddr_in *);
+static const char *make_port_verb(int portaf);
static struct connection *new_connection(void);
-static uint lookup_hostname(const char *);
static void handle_dir_listing(struct connection *c);
static int parse_filename(char *, char *, struct parse_info *);
static struct timeinfo *Date2Min(const char *);
@@ -301,7 +315,6 @@ static int skip_file(const char *filenam
static int time_dif(time_t, time_t);
static int size_dif(unsigned, unsigned);
static int mode_dif(int, int);
-static uint get_local_ip(int);
static int recursive_unlink(const char *filename, struct stat *st);
static void maybe_delete_dir(const char *pathname);
static void delete_delayed_dirs(void);
@@ -314,12 +327,15 @@ static int is_newer(time_t, time_t);
static void set_time(const char *name, time_t);
static time_t utc_mktime(struct tm *tm);
static int sig_permanent(int sig, RETSIGTYPE (*handler)(int));
-static int make_connected_socket(struct sockaddr_in *sad);
+static int make_connected_socket(struct sockaddr *sad, size_t addrlen);
static void init_active(struct connection *c);
static int init_passive(struct connection *c);
+static int init_passive_ipv6(struct connection *c);
+static int init_passive_ipv4(struct connection *c);
static int make_passive_connection(struct connection *c);
-static int accept_connection(int fd, struct sockaddr_in *sad);
+static int accept_connection(int fd, struct sockaddr *sad);
static int find_timezone(char *);
+void log_conn_from(struct sockaddr *sa);
static FILE *tempfile;
static FILE *delayed_delfile;
@@ -571,7 +587,8 @@ main(int argc, char *const *argv)
mi.hostname = host;
mi.path = remotedir;
- mi.port = port ? strtol(port, NULL, 0) : FTP_CONTROL_PORT;
+ mi.port = port ? port : FTP_CONTROL_PORT;
+ mi.af = af;
LOG(1, finished, ("%s @ %s -> %s", remotedir,
mi.hostname, localdir));
@@ -642,7 +659,7 @@ cmd(const char *format, ...)
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
- l = fprintf(out_file, "%s\n", buffer);
+ l = fprintf(out_file, "%s\r\n", buffer);
fflush(out_file);
buffer[l - 1] = 0;
LOG(6, cmd, ("---> %s", buffer));
@@ -694,55 +711,98 @@ handle_input(const char **msg)
}
-static uint
-lookup_hostname(const char *addr)
-{
- /* Converts a hostname to an IP address */
- uint r;
- struct hostent *host_info;
- r = inet_addr(addr);
- if (r == (uint)-1) {
- host_info = gethostbyname(addr);
- if(host_info == 0) {
- LOG(0, failure,
- ("-- ERROR -- gethostbyname(\"%s\") : unknown host", addr));
- exit(EXIT_FAILURE);
- }
- memcpy((char *)&r, host_info->h_addr, host_info->h_length);
- }
- return r;
-}
-
-
static int
-do_connect(const char *addr, int dport)
+do_connect(const char *addr, const char *dport)
{
/* Connects to a specified host and port, and returns a
* filedescriptor for the connection. */
- struct sockaddr_in address;
- int sockfd;
+ struct addrinfo hints, *res, *res0;
+ int error;
+ int sockfd = 0;
+ char msg[32];
+ char numaddr[64];
+ int protocol = 0;
- memset(&address, 0, sizeof(address));
- address.sin_addr.s_addr = lookup_hostname(addr);
- address.sin_family = AF_INET;
- address.sin_port = htons(dport);
-
- sockfd = make_connected_socket(&address);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af; /* use global variable af */
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(addr, dport, &hints, &res0);
+ if (error) {
+ LOG(0, failure,
+ ("-- ERROR -- getaddrinfo : %s", gai_strerror(errno)));
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ switch(res->ai_family) {
+ case AF_INET:
+ inet_ntop(res->ai_family,
+ &((struct sockaddr_in *)res->ai_addr)->sin_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ case AF_INET6:
+ inet_ntop(res->ai_family,
+ &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ }
+ LOG(4, ctrl_connect, ("Attempting to connect to %s", numaddr));
+ sockfd = make_connected_socket(res->ai_addr, res->ai_addrlen);
+ if (sockfd == -1) {
+ LOG(0, failure,
+ ("Too many connect attempts. Giving up connecting to %s", numaddr));
+ continue;
+ }
+
+ protocol = res->ai_protocol;
+
+ /* use global variable to export addrlen
+ this variable will be used by make_passive_connection() */
+ dst_addrlen = res->ai_addrlen;
+
+ /* set global variable af to acquired address family.
+ this variable will be used by new_connection() */
+ af = res->ai_family;
+ switch (af) {
+ case AF_INET:
+ snprintf(msg, sizeof(msg), "Connected [IPv4]");
+ break;
+ case AF_INET6:
+ /* set global variable dst_addr to res0 if af is IPv6
+ we will need it in EPSV handling */
+ dst6_addr = ((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr;
+ snprintf(msg, sizeof(msg), "Connected [IPv6]");
+ break;
+ default:
+ LOG(0, failure,
+ ("do_connect: wrong AF specification"));
+ break;
+ }
+ LOG(3, ctrl_connect, (msg));
+
+ /* sucessfully connected, break the loop */
+ break;
+ } /* for */
+
if (sockfd == -1) {
- LOG(0, failure, ("Too many connect attempts. Giving up."));
+ LOG(0, failure, ("Was not able to connect to any address. Giving up."));
return -1;
}
#if (defined(IPTOS_LOWDELAY) && defined(IP_TOS))
{
int opt = IPTOS_LOWDELAY;
- if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt)))
+ if (af == AF_INET) /* use IP_TOS only for IPv4 */
+ if (setsockopt(sockfd, protocol, IP_TOS, (char *)&opt, sizeof(opt)))
LOG(0, failure,
("-- ERROR -- setsockopt LOWDELAY : %s", strerror(errno)));
}
#endif
+ freeaddrinfo(res0);
+
return sockfd;
}
@@ -770,13 +830,14 @@ do_mirror(struct mirror_info *mi)
goto first;
do {
+ LOG(4, ctrl_connect, ("Reconnect timeout - sleeping %d secs",
+ reconnect_timeout));
sleep(reconnect_timeout);
first:
LOG(3, ctrl_connect, ("Connecting to %s...", mi->hostname));
control_fd = do_connect(mi->hostname, mi->port);
if (control_fd >= 0) {
- get_local_ip(control_fd);
- LOG(3, ctrl_connect, ("Connected."));
+ LOG(3, ctrl_connect, ("Acquired local IP address."));
if (!(in_file = fdopen(control_fd, "r"))) {
LOG(0, failure, ("-- ERROR -- fdopen on in_file failed : %s",
strerror(errno)));
@@ -918,7 +979,7 @@ find_timezone(char *gotodir)
struct connection *c;
int x;
const char *msg;
- struct sockaddr_in sad;
+ struct sockaddr_storage sad;
FILE *stream;
char line[PATH_MAX + 80];
int fd;
@@ -928,13 +989,14 @@ find_timezone(char *gotodir)
} sample_dirs, *nextsdl;
struct parse_info p, sample_fil, *pp;
int foundtz = 0;
+ char numaddr[64];
sample_fil.filename=0;
memset(&sample_dirs, 0, sizeof(sample_dirs));
if (gotodir) {
cmd("CWD %s", gotodir);
- if (!success()) {
+ if (!success() && strcmp(gotodir, "/") != 0) {
LOG(4, findtz, ("Cannot CWD %s for timezone", gotodir));
gotodir = 0;
goto dirdone;
@@ -953,7 +1015,8 @@ find_timezone(char *gotodir)
}
} else {
init_active(c);
- cmd("PORT %s", make_port_args(&c->sad));
+ cmd("%s %s", make_port_verb(c->af),
+ make_active_args((struct sockaddr *)&c->sad));
if(!success()) {
close(c->fd);
free(c);
@@ -967,8 +1030,19 @@ find_timezone(char *gotodir)
LOG(0, failure, ("Passive conection failed, aborting."));
exit(EXIT_FAILURE);
}
+ switch (c->af) {
+ case AF_INET:
+ inet_ntop(c->af, &((struct sockaddr_in *)&c->dest)->sin_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ case AF_INET6:
+ inet_ntop(c->af, &((struct sockaddr_in6 *)&c->dest)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ }
LOG(5, connect, ("hdl: Connected passively to %s port %d",
- inet_ntoa(c->dest.sin_addr), ntohs(c->dest.sin_port)));
+ numaddr,
+ c->dport));
}
x = handle_input(&msg);
if (x >= 400) {
@@ -981,14 +1055,13 @@ find_timezone(char *gotodir)
fd = c->fd;
} else {
LOG(5, other, ("Dir list: Waiting for connection..."));
- fd = accept_connection(c->fd, &sad);
+ fd = accept_connection(c->fd, (struct sockaddr *)&sad);
if (fd == -1) {
LOG(0, failure, ("accept() : %s", errno == EINTR
? "Operation timed out" : strerror(errno)));
exit(EXIT_FAILURE);
}
- LOG(5, connect, ("hdl: Connection from %s port %d",
- inet_ntoa(sad.sin_addr), htons(sad.sin_port)));
+ log_conn_from((struct sockaddr *)&sad);
}
if (!(stream = fdopen(fd, "r"))) {
LOG(0, failure, ("fdopen(%d, \"r\"): %s", fd, strerror(errno)));
@@ -1142,11 +1215,52 @@ rdig(unsigned char **s)
static int
+parse_epsv_reply(char *buffer, struct connection *c)
+{
+
+ /* parses EPSV command response (for IPv6) stored in buffer
+ and fills connection structure with address/port it has acquired */
+ unsigned char *s = (unsigned char *)buffer + 4;
+ unsigned short cport;
+ struct sockaddr_in6 *si6;
+ char numaddr[64];
+
+ while (*s && !isdigit(*s))
+ s++;
+ if (!*s)
+ return -1;
+
+ memset(&c->dest, 0, sizeof(c->dest));
+
+ si6 = (struct sockaddr_in6 *)&c->dest;
+ /* set destination address to the same address to which control
+ connection is established (according to RFC 2428,
+ "The response to this command includes only the TCP port number
+ of the listening connection."
+ */
+ si6->sin6_addr = dst6_addr;
+ si6->sin6_family = AF_INET6;
+ cport = rdig(&s);
+ c->dport = cport;
+ si6->sin6_port = htons(cport);
+
+ inet_ntop(si6->sin6_family, &(si6->sin6_addr), numaddr, sizeof(numaddr));
+ LOG(5, addrinfo ,("passive reply is %d (using addr %s)",
+ c->dport, numaddr));
+ return 0;
+}
+
+
+static int
parse_pasv_reply(char *buffer, struct connection *c)
{
+
+ /* parses PASV command (for IPv4) */
unsigned char *s = (unsigned char *)buffer + 4;
unsigned long addr;
unsigned short cport;
+ struct sockaddr_in *si;
+
while (*s && !isdigit(*s))
s++;
if (!*s)
@@ -1160,24 +1274,67 @@ parse_pasv_reply(char *buffer, struct co
addr += rdig(&s) << 8;
addr += rdig(&s);
- c->dest.sin_addr.s_addr = htonl(addr);
+ si = (struct sockaddr_in *)&c->dest;
+ si->sin_addr.s_addr = htonl(addr);
cport = rdig(&s) << 8;
cport += rdig(&s);
+ c->dport = cport;
- c->dest.sin_port = htons(cport);
- c->dest.sin_family = AF_INET;
- LOG(5, addrinfo ,("passive reply is %s.%d", inet_ntoa(c->dest.sin_addr),
- ntohs(c->dest.sin_port)));
+ si->sin_port = htons(cport);
+ si->sin_family = AF_INET;
+ c->af = AF_INET;
+ LOG(5, addrinfo ,("passive reply is %s.%d", inet_ntoa(si->sin_addr),
+ ntohs(si->sin_port)));
+
return 0;
}
+
static int
-init_passive(struct connection *c)
+init_passive(struct connection *c) {
+
+ /* wrapper for _ipv4/_ipv6 functions */
+ switch (c->af) {
+ case AF_INET:
+ return(init_passive_ipv4(c));
+ break;
+ case AF_INET6:
+ return(init_passive_ipv6(c));
+ break;
+ default:
+ return(0);
+ }
+}
+
+static int
+init_passive_ipv6(struct connection *c)
{
char buffer[PATH_MAX + 80];
int err;
+ cmd("EPSV");
+ err = get_input(buffer, sizeof(buffer));
+ if (err != 229) { /* RFC 2428, section 3 */
+ LOG(0, cmdfail, ("EPSV command failed, skipping: %s", buffer));
+ return -1;
+ }
+
+ if (parse_epsv_reply(buffer, c)) {
+ LOG(0, protoerr, ("EPSV reply not understood: %s", buffer));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+init_passive_ipv4(struct connection *c)
+{
+ char buffer[PATH_MAX + 80];
+ int err;
+
cmd("PASV");
err = get_input(buffer, sizeof(buffer));
if (err != 227) {
@@ -1193,6 +1350,7 @@ init_passive(struct connection *c)
return 0;
}
+
static int
do_get_file(char *arg_cmd, time_t mtime, uint perm, uint msize)
{
@@ -1200,6 +1358,9 @@ do_get_file(char *arg_cmd, time_t mtime,
int x;
int retries = 4;
int err;
+ unsigned short dport = 0;
+ char numaddr[64];
+
LOG(7, other, ("do_get_file called with arg `%s'", arg_cmd));
do {
const char *msg;
@@ -1212,7 +1373,8 @@ do_get_file(char *arg_cmd, time_t mtime,
}
} else {
init_active(c);
- cmd("PORT %s", make_port_args(&c->sad));
+ cmd("%s %s", make_port_verb(c->af),
+ make_active_args((struct sockaddr *)&c->sad));
if(!success()) {
LOG(1, cmdfail, ("Port command failed, skipping file"));
close(c->fd);
@@ -1227,8 +1389,20 @@ do_get_file(char *arg_cmd, time_t mtime,
free(c);
return 1;
}
+ switch (c->af) {
+ case AF_INET:
+ inet_ntop(c->af, &((struct sockaddr_in *)&c->dest)->sin_addr,
+ numaddr, sizeof(numaddr));
+ dport = ((struct sockaddr_in *)&c->dest)->sin_port;
+ break;
+ case AF_INET6:
+ inet_ntop(c->af, &((struct sockaddr_in6 *)&c->dest)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ dport = ((struct sockaddr_in *)&c->dest)->sin_port;
+ break;
+ }
LOG(5, connect, ("hdl: Connected passively to %s port %d",
- inet_ntoa(c->dest.sin_addr), ntohs(c->dest.sin_port)));
+ numaddr, ntohs(dport)));
}
x = handle_input(&msg);
/* ### Should handle transient errors better here */
@@ -1366,6 +1540,29 @@ supermkdir(char *d)
}
+void
+log_conn_from(struct sockaddr *sa)
+{
+ char numaddr[64];
+ unsigned short cport = 0;
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr,
+ numaddr, sizeof(numaddr));
+ cport = ((struct sockaddr_in *)sa)->sin_port;
+ break;
+ case AF_INET6:
+ inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ cport = ((struct sockaddr_in6 *)sa)->sin6_port;
+ break;
+ }
+
+ LOG(5, connect, ("hdl: Connection from %s port %d", numaddr, cport));
+}
+
+
static int
handle_ftp_transfer(struct connection *c, char *filename, time_t mtime,
uint perm, uint msize)
@@ -1373,7 +1570,7 @@ handle_ftp_transfer(struct connection *c
int ffd;
char buffer[10240];
int len;
- struct sockaddr_in sad;
+ struct sockaddr_storage sad;
int fd = -1;
int totlen = 0;
int hashedlen = 0;
@@ -1395,7 +1592,7 @@ handle_ftp_transfer(struct connection *c
} else {
LOG(5, connect, ("ftp trans: Waiting for connection..."));
alarm(connect_timeout);
- fd = accept_connection(c->fd, &sad);
+ fd = accept_connection(c->fd, (struct sockaddr *)&sad);
alarm(0);
if (fd == -1) {
if (errno == EINTR) {
@@ -1406,8 +1603,7 @@ handle_ftp_transfer(struct connection *c
LOG(0, connect, ("-- ERROR -- accept() : %s", strerror(errno)));
exit(EXIT_FAILURE);
}
- LOG(5, connect, ("hdl: Connection from %s port %d",
- inet_ntoa(sad.sin_addr), htons(sad.sin_port)));
+ log_conn_from((struct sockaddr *)&sad);
}
if ((ffd = creat(tmp_name, 0200)) == -1) { /* create unreadble tempfile */
@@ -1536,6 +1732,7 @@ static void
get_filelist()
{
struct connection *c;
+ char numaddr[64];
int x;
const char *msg;
@@ -1557,7 +1754,8 @@ get_filelist()
}
} else {
init_active(c);
- cmd("PORT %s", make_port_args(&c->sad));
+ cmd("%s %s", make_port_verb(c->af),
+ make_active_args((struct sockaddr *)(&c->sad)));
if(!success()) {
close(c->fd);
free(c);
@@ -1578,8 +1776,18 @@ get_filelist()
LOG(0, failure, ("Passive conection failed, aborting."));
exit(EXIT_FAILURE);
}
+ switch (c->af) {
+ case AF_INET:
+ inet_ntop(c->af, &((struct sockaddr_in *)&c->dest)->sin_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ case AF_INET6:
+ inet_ntop(c->af, &((struct sockaddr_in6 *)&c->dest)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ }
LOG(5, connect, ("hdl: Connected passively to %s port %d",
- inet_ntoa(c->dest.sin_addr), ntohs(c->dest.sin_port)));
+ numaddr, c->dport));
}
x = handle_input(&msg);
if (x >= 400) {
@@ -2331,7 +2539,7 @@ no_such_dir:
static void
handle_dir_listing(struct connection *c)
{
- struct sockaddr_in sad;
+ struct sockaddr_storage sad;
FILE *stream;
char line[PATH_MAX + 80];
char prefix[PATH_MAX] = ".";
@@ -2341,14 +2549,13 @@ handle_dir_listing(struct connection *c)
fd = c->fd;
} else {
LOG(5, other, ("Dir list: Waiting for connection..."));
- fd = accept_connection(c->fd, &sad);
+ fd = accept_connection(c->fd, (struct sockaddr *)&sad);
if (fd == -1) {
LOG(0, failure, ("accept() : %s", errno == EINTR
? "Operation timed out" : strerror(errno)));
exit(EXIT_FAILURE);
}
- LOG(5, connect, ("hdl: Connection from %s port %d",
- inet_ntoa(sad.sin_addr), htons(sad.sin_port)));
+ log_conn_from((struct sockaddr *)&sad);
}
if (compressed) {
@@ -2415,32 +2622,83 @@ handle_dir_listing(struct connection *c)
}
-static uint
-get_local_ip(int fd)
+static const char *
+make_port_verb(int portaf)
{
- /* Returns the ip address of this machine in HOST byte order.
- * Caches the result for later use.
- *
- * if fd == -1 return the cached ip-number, otherwise assume
- * fd is the file-descriptor used for the control-connection
- * to the ftp-server and get the socket-address from that. */
-
- static uint ip = 0;
+ /* use PORT for IPv4, EPORT for IPv6 */
+ switch(portaf) {
+ case AF_INET:
+ return("PORT");
+ break;
+ case AF_INET6:
+ return("EPRT");
+ break;
+ default:
+ LOG(0, failure,
+ ("make_port_verb: wrong AF specification"));
+ return(NULL);
+ break;
+ }
+}
- if (fd != -1) {
- struct sockaddr_in sad;
- int len = sizeof(sad);
- if (getsockname(fd, (struct sockaddr *)&sad, &len)) {
- LOG(0, failure, ("ERROR: getsockname(): %s", strerror(errno)));
- exit(EXIT_FAILURE);
- }
- ip = ntohl(sad.sin_addr.s_addr);
+
+static const char *
+make_active_args(struct sockaddr *sad)
+{
+ switch (sad->sa_family) {
+ case AF_INET:
+ return(make_port_args((struct sockaddr_in *)sad));
+ break;
+ case AF_INET6:
+ return(make_eprt_args((struct sockaddr *)sad));
+ break;
+ default:
+ LOG(0, failure,
+ ("make_active_args: wrong AF specification"));
+ return(NULL);
+ break;
}
- return ip;
}
static const char *
+make_eprt_args(struct sockaddr *sad)
+{
+ /* construct arguments of EPRT verb according to RFC 2428, section 2.
+ this function is currently used only for IPv6 connections,
+ it can be however used for both IPv4 and IPv6 */
+ static char buf[128];
+ char numaddr[64];
+ struct sockaddr_in *si;
+ struct sockaddr_in6 *si6;
+ uint p;
+
+ switch(sad->sa_family) {
+ case AF_INET:
+ si = (struct sockaddr_in *)sad;
+ inet_ntop(sad->sa_family,
+ &(((struct sockaddr_in *)&localaddr)->sin_addr),
+ numaddr, sizeof(numaddr));
+ p = ntohs(si->sin_port);
+ break;
+ case AF_INET6:
+ si6 = (struct sockaddr_in6 *)sad;
+ inet_ntop(sad->sa_family,
+ &(((struct sockaddr_in6 *)&localaddr)->sin6_addr),
+ numaddr, sizeof(numaddr));
+ p = ntohs(si6->sin6_port);
+ break;
+ }
+
+ snprintf(buf, sizeof(buf), "|%s|%s|%d|",
+ sad->sa_family == AF_INET ? "1" : "2",
+ numaddr, p);
+
+ return buf;
+}
+
+
+static const char *
make_port_args(struct sockaddr_in *sad)
{
/* Translates an ip address and a port number from a sockaddr_in
@@ -2450,10 +2708,13 @@ make_port_args(struct sockaddr_in *sad)
static char buf[64]; /* more than enough to hold x,x,x,x,x,x */
uint ip;
uint p;
- ip = get_local_ip(-1); /* get the cached ip-address */
+ /* get the cached ip-address */
+ ip = ntohl(((struct sockaddr_in *)&localaddr)->sin_addr.s_addr);
p = ntohs(sad->sin_port);
- sprintf(buf, "%d,%d,%d,%d,%d,%d", ip >> 24, (ip >> 16) & 0xff,
- (ip >> 8) & 0xff, ip & 0xff, p >> 8, p & 0xff);
+ snprintf(buf, sizeof(buf), "%d,%d,%d,%d,%d,%d",
+ ip >> 24, (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff, ip & 0xff, p >> 8, p & 0xff);
+ LOG(3, ctrl_connect, ("PORT args: %s", buf));
return buf;
}
@@ -2465,6 +2726,7 @@ new_connection(void)
memset(c, 0, sizeof(*c));
c->fd = -1;
c->file = NULL;
+ c->af = af;
return c;
}
@@ -2472,8 +2734,14 @@ static void
init_active(struct connection *c)
{
int opt, len;
- int sock = socket(AF_INET, SOCK_STREAM, 0);
- struct sockaddr_in sad;
+ int sock = socket(c->af, SOCK_STREAM, 0);
+ unsigned int addrlen = 0;
+ struct sockaddr_storage sad;
+ struct sockaddr_in *si;
+ struct sockaddr_in6 *si6;
+ char numaddr[64];
+ const struct in6_addr my_in6addr_any = IN6ADDR_ANY_INIT;
+
if (sock < 0) {
LOG(0, failure, ("ERROR: socket() : %s", strerror(errno)));
exit(EXIT_FAILURE);
@@ -2481,16 +2749,36 @@ init_active(struct connection *c)
#if (defined(IP_TOS) && defined(IPTOS_THROUGHPUT))
opt = IPTOS_THROUGHPUT;
- setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
+ if (c->af == AF_INET) /* set IP_TOS for AF_INET only */
+ setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&opt, sizeof(opt));
#endif
- sad.sin_family = AF_INET;
- sad.sin_addr.s_addr = INADDR_ANY;
- sad.sin_port = 0;
+ switch (c->af) {
+ case AF_INET:
+ si = (struct sockaddr_in *)&sad;
+ si->sin_family = c->af;
+ si->sin_addr.s_addr = INADDR_ANY;
+ si->sin_port = 0;
+ addrlen = sizeof(*si);
+ inet_ntop(c->af, &(si->sin_addr), numaddr, sizeof(numaddr));
+ break;
+ case AF_INET6:
+ si6 = (struct sockaddr_in6 *)&sad;
+ si6->sin6_family = c->af;
+ si6->sin6_addr = my_in6addr_any;
+ si6->sin6_port = 0;
+ addrlen = sizeof(*si6);
+ inet_ntop(c->af, &(si6->sin6_addr), numaddr, sizeof(numaddr));
+ break;
+ }
- if (bind(sock, (struct sockaddr *)&sad, sizeof(sad))) {
- LOG(0, failure, ("ERROR: bind(%s,%d): %s", inet_ntoa(sad.sin_addr),
- ntohs(sad.sin_port), strerror(errno)));
+ if (bind(sock, (struct sockaddr *)&sad, addrlen)) {
+ LOG(0, failure, ("ERROR: bind(%s,%d): %s",
+ numaddr,
+ c->af == AF_INET ?
+ ntohs(((struct sockaddr_in *)&sad)->sin_port)
+ : ntohs(((struct sockaddr_in6 *)&sad)->sin6_port),
+ strerror(errno)));
close(sock);
exit(EXIT_FAILURE);
}
@@ -2502,10 +2790,14 @@ init_active(struct connection *c)
}
len = sizeof(sad);
if (getsockname(sock, (struct sockaddr *)&sad, &len)) {
- LOG(0, failure, ("getsockname fails, expect PORT to fail..: %s",
- strerror(errno)));
+ LOG(0, failure, ("ERROR: getsockname(): %s", strerror(errno)));
+ exit(EXIT_FAILURE);
}
-
+ LOG(3, ctrl_connect, ("listening on ANY:%d",
+ c->af == AF_INET ?
+ ntohs(((struct sockaddr_in *)&sad)->sin_port)
+ : ntohs(((struct sockaddr_in6 *)&sad)->sin6_port)));
+
c->fd = sock;
c->sad = sad;
c->file = NULL;
@@ -2719,10 +3011,16 @@ parse_args(int argc, char *const *argv)
{
while (1) {
int c = getopt(argc, argv,
- "A:C:c:D:d:e:f:F:hi:kl:M:m:NO:o:P:p:Rr:s:ST:t:u:vV:x:z:");
+ "46A:C:c:D:d:e:f:F:hi:kl:M:m:NO:o:P:p:Rr:s:ST:t:u:vV:x:z:");
if (c == -1)
break;
switch (c) {
+ case '4':
+ af = AF_INET;
+ break;
+ case '6':
+ af = AF_INET6;
+ break;
case 'A':
file_and_mask = strtoul(optarg, NULL, 0);
break;
@@ -3318,12 +3616,15 @@ sig_permanent(int sig, RETSIGTYPE (*hand
static int
-make_connected_socket(struct sockaddr_in *sad)
+make_connected_socket(struct sockaddr *sad, size_t addrlen)
{
int n = connect_retries;
+ char numaddr[64];
+ unsigned short cport = 0;
+
while (n--) {
int err;
- int sockfd = socket(sad->sin_family, SOCK_STREAM, 0);
+ int sockfd = socket(sad->sa_family, SOCK_STREAM, 0);
if(sockfd < 0) {
LOG(0, failure, ("-- ERROR -- creating socket: %s",
strerror(errno)));
@@ -3331,16 +3632,54 @@ make_connected_socket(struct sockaddr_in
}
alarm(connect_timeout);
- err = connect(sockfd, (struct sockaddr *)sad, sizeof(*sad));
+ err = connect(sockfd, (struct sockaddr *)sad, addrlen);
alarm(0);
if (err == -1) {
+ switch(sad->sa_family) {
+ case AF_INET:
+ inet_ntop(sad->sa_family,
+ &((struct sockaddr_in *)sad)->sin_addr,
+ numaddr, sizeof(numaddr));
+ cport = ((struct sockaddr_in *)sad)->sin_port;
+ break;
+ case AF_INET6:
+ inet_ntop(sad->sa_family,
+ &((struct sockaddr_in6 *)sad)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ cport = ((struct sockaddr_in6 *)sad)->sin6_port;
+ break;
+ default:
+ LOG(0, failure,
+ ("make_connected_socket: wrong AF specification"));
+ break;
+ }
LOG(0, failure,
("Connection to %s port %d failed: %s [%s]",
- inet_ntoa(sad->sin_addr), ntohs(sad->sin_port),
+ numaddr,
+ cport,
errno == EINTR ? "Connection timed out" : strerror(errno),
n ? "retrying" : "giving up"));
close(sockfd);
} else {
+ if (getsockname(sockfd, (struct sockaddr *)&localaddr, &addrlen)) {
+ LOG(0, failure, ("getsockname fails, expect PORT to fail..: %s",
+ strerror(errno)));
+ }
+ switch(sad->sa_family) {
+ case AF_INET:
+ inet_ntop(sad->sa_family,
+ &((struct sockaddr_in *)&localaddr)->sin_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ case AF_INET6:
+ inet_ntop(sad->sa_family,
+ &((struct sockaddr_in6 *)&localaddr)->sin6_addr,
+ numaddr, sizeof(numaddr));
+ break;
+ }
+ LOG(0, failure, ("make_connected_socket: local address: %s",
+ numaddr));
+
return sockfd;
}
}
@@ -3349,7 +3688,7 @@ make_connected_socket(struct sockaddr_in
static int
-accept_connection(int fd, struct sockaddr_in *sad)
+accept_connection(int fd, struct sockaddr *sad)
{
int l = sizeof(*sad);
alarm(connect_timeout); /* die if no connection in 70 seconds */
@@ -3361,11 +3700,15 @@ accept_connection(int fd, struct sockadd
static int
make_passive_connection(struct connection *c)
{
- c->fd = make_connected_socket(&c->dest);
+ size_t addrlen = dst_addrlen;
+ char numaddr[64];
+
+ c->fd = make_connected_socket((struct sockaddr *)(&c->dest), addrlen);
if (c->fd == -1) {
+ inet_ntop(c->af, &(c->dest), numaddr, sizeof(numaddr));
LOG(0, failure, ("Could not open passive connection to %s port %d",
- inet_ntoa(c->dest.sin_addr),
- ntohs(c->dest.sin_port)));
+ numaddr,
+ c->dport));
return -1;
}
#if (defined(IP_TOS) && defined(IPTOS_THROUGHPUT))

6
net/fmirror/pkg/DESCR Normal file
View File

@ -0,0 +1,6 @@
fmirror is a program for mirroring files and directories from a remote
FTP server. It allows regex-matching for files that are to be included
and excluded. It uses a combination of timestamp, file size, and file
permissions to decide what files to transfer from the FTP server.
The primary goal of fmirror is to use as little memory as possible,
but still be able to do its job efficiently.

7
net/fmirror/pkg/PLIST Normal file
View File

@ -0,0 +1,7 @@
@comment $OpenBSD: PLIST,v 1.1.1.1 2005/09/17 12:19:41 bernd Exp $
bin/fmirror
@man man/man1/fmirror.1
share/examples/fmirror/
share/examples/fmirror/generic.conf
share/examples/fmirror/redhat.conf
share/examples/fmirror/sample.conf