diff -uNr vsftpd-1.2.1.orig/main.c vsftpd-1.2.1.llc/main.c --- vsftpd-1.2.1.orig/main.c 2003-11-05 23:13:28.000000000 -0200 +++ vsftpd-1.2.1.llc/main.c 2003-11-30 18:48:31.000000000 -0200 @@ -101,7 +101,7 @@ /* Warning -- warning -- may nuke argv, environ */ vsf_sysutil_setproctitle_init(argc, argv); } - if (tunable_listen || tunable_listen_ipv6) + if (tunable_listen || tunable_listen_ipv6 || tunable_listen_llc) { /* Standalone mode */ struct vsf_client_launch ret = vsf_standalone_main(); diff -uNr vsftpd-1.2.1.orig/parseconf.c vsftpd-1.2.1.llc/parseconf.c --- vsftpd-1.2.1.orig/parseconf.c 2003-11-05 23:09:19.000000000 -0200 +++ vsftpd-1.2.1.llc/parseconf.c 2003-11-30 18:48:10.000000000 -0200 @@ -75,6 +75,7 @@ { "use_sendfile", &tunable_use_sendfile }, { "force_dot_files", &tunable_force_dot_files }, { "listen_ipv6", &tunable_listen_ipv6 }, + { "listen_llc", &tunable_listen_llc }, { "dual_log_enable", &tunable_dual_log_enable }, { "syslog_enable", &tunable_syslog_enable }, { "background", &tunable_background }, @@ -140,6 +141,7 @@ { "listen_address", &tunable_listen_address }, { "user_config_dir", &tunable_user_config_dir }, { "listen_address6", &tunable_listen_address6 }, + { "listen_address_llc", &tunable_listen_address_llc }, { "cmds_allowed", &tunable_cmds_allowed }, { "hide_file", &tunable_hide_file }, { "deny_file", &tunable_deny_file }, diff -uNr vsftpd-1.2.1.orig/postlogin.c vsftpd-1.2.1.llc/postlogin.c --- vsftpd-1.2.1.orig/postlogin.c 2003-11-05 01:39:51.000000000 -0200 +++ vsftpd-1.2.1.llc/postlogin.c 2003-12-01 21:09:28.000000000 -0200 @@ -489,6 +489,7 @@ int bind_retries = 10; unsigned short the_port = 0; int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr); + int is_llc = vsf_sysutil_sockaddr_is_llc(p_sess->p_local_addr); if (is_epsv && !str_isempty(&p_sess->ftp_arg_str)) { int argval; @@ -512,6 +513,10 @@ { p_sess->pasv_listen_fd = vsf_sysutil_get_ipv6_sock(); } + else if (is_llc) + { + p_sess->pasv_listen_fd = vsf_sysutil_get_llc_sock(); + } else { p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock(); @@ -522,23 +527,30 @@ int retval; double scaled_port; /* IPPORT_RESERVED */ - unsigned short min_port = 1024; - unsigned short max_port = 65535; - if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port) + unsigned short min_port = is_llc ? 1 : 1024; + unsigned short max_port = is_llc ? 254 : 65535; + if (!is_llc && + tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port) { min_port = tunable_pasv_min_port; } - if (tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port) + if (!is_llc && + tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port) { max_port = tunable_pasv_max_port; } the_port = vsf_sysutil_get_random_byte(); - the_port <<= 8; - the_port |= vsf_sysutil_get_random_byte(); - scaled_port = (double) min_port; - scaled_port += ((double) the_port / (double) 65536) * - ((double) max_port - min_port + 1); - the_port = (unsigned short) scaled_port; + if (is_llc) + the_port &= 0xfe; + else + { + the_port <<= 8; + the_port |= vsf_sysutil_get_random_byte(); + scaled_port = (double) min_port; + scaled_port += ((double) the_port / (double) 65536) * + ((double) max_port - min_port + 1); + the_port = (unsigned short) scaled_port; + } vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr); vsf_sysutil_sockaddr_set_port(s_p_sockaddr, the_port); retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr); @@ -588,8 +600,10 @@ } str_replace_char(&s_pasv_res_str, '.', ','); str_append_text(&s_pasv_res_str, ","); - str_append_ulong(&s_pasv_res_str, the_port >> 8); - str_append_text(&s_pasv_res_str, ","); + if (!is_llc) { + str_append_ulong(&s_pasv_res_str, the_port >> 8); + str_append_text(&s_pasv_res_str, ","); + } str_append_ulong(&s_pasv_res_str, the_port & 255); str_append_text(&s_pasv_res_str, ")"); vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str); @@ -918,7 +932,7 @@ { if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_sess->p_port_sockaddr) || - vsf_sysutil_is_port_reserved(the_port)) + vsf_sysutil_is_port_reserved(p_sess->p_port_sockaddr, the_port)) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command."); port_cleanup(p_sess); @@ -1463,6 +1477,7 @@ int port; const unsigned char* p_raw_addr; int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr); + int is_llc = vsf_sysutil_sockaddr_is_llc(p_sess->p_local_addr); port_cleanup(p_sess); pasv_cleanup(p_sess); str_copy(&s_part1_str, &p_sess->ftp_arg_str); @@ -1474,31 +1489,42 @@ /* Split out the protocol and check it */ str_split_char(&s_part2_str, &s_part1_str, '|'); proto = str_atoi(&s_part2_str); - if (!is_ipv6 || proto != 2) + if (!(is_ipv6 && proto == 2) && !(is_llc && proto == 9)) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT protocol."); return; } /* Split out address and parse it */ str_split_char(&s_part1_str, &s_part2_str, '|'); - p_raw_addr = vsf_sysutil_parse_ipv6(&s_part1_str); + if (is_ipv6) + p_raw_addr = vsf_sysutil_parse_ipv6(&s_part1_str); + else + p_raw_addr = vsf_sysutil_parse_llc(&s_part1_str); if (!p_raw_addr) { - goto bad_eprt; + goto bad_eprt_addr; } /* Split out port and parse it */ str_split_char(&s_part2_str, &s_part1_str, '|'); if (!str_isempty(&s_part1_str) || str_isempty(&s_part2_str)) { - goto bad_eprt; + goto bad_eprt_port; } port = str_atoi(&s_part2_str); - if (port < 0 || port > 65535) + if (port < 0 || port > (is_llc ? 254 : 65535)) { - goto bad_eprt; + goto bad_eprt_port_range; + } + if (is_ipv6) + { + vsf_sysutil_sockaddr_alloc_ipv6(&p_sess->p_port_sockaddr); + vsf_sysutil_sockaddr_set_ipv6addr(p_sess->p_port_sockaddr, p_raw_addr); + } + else + { + vsf_sysutil_sockaddr_alloc_llc(&p_sess->p_port_sockaddr); + vsf_sysutil_sockaddr_set_llcaddr(p_sess->p_port_sockaddr, p_raw_addr); } - vsf_sysutil_sockaddr_alloc_ipv6(&p_sess->p_port_sockaddr); - vsf_sysutil_sockaddr_set_ipv6addr(p_sess->p_port_sockaddr, p_raw_addr); vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, (unsigned short)port); /* SECURITY: * 1) Reject requests not connecting to the control socket IP @@ -1508,7 +1534,7 @@ { if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_sess->p_port_sockaddr) || - vsf_sysutil_is_port_reserved(port)) + vsf_sysutil_is_port_reserved(p_sess->p_port_sockaddr, port)) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal EPRT command."); port_cleanup(p_sess); @@ -1520,6 +1546,16 @@ return; bad_eprt: vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command."); + return; +bad_eprt_addr: + vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command(address)."); + return; +bad_eprt_port: + vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command(port)."); + return; +bad_eprt_port_range: + vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command(port range)."); + return; } static void diff -uNr vsftpd-1.2.1.orig/standalone.c vsftpd-1.2.1.llc/standalone.c --- vsftpd-1.2.1.orig/standalone.c 2003-04-07 20:56:57.000000000 -0300 +++ vsftpd-1.2.1.llc/standalone.c 2003-11-30 19:46:43.000000000 -0200 @@ -39,9 +39,9 @@ int listen_sock = -1; int retval; s_ipaddr_size = vsf_sysutil_get_ipaddr_size(); - if (tunable_listen && tunable_listen_ipv6) + if (tunable_listen && (tunable_listen_ipv6 || tunable_listen_llc)) { - die("run two copies of vsftpd for IPv4 and IPv6"); + die("run several copies of vsftpd for IPv4 and/or IPv6 or LLC"); } if (tunable_background) { @@ -57,10 +57,14 @@ { listen_sock = vsf_sysutil_get_ipv4_sock(); } - else + else if (tunable_listen_ipv6) { listen_sock = vsf_sysutil_get_ipv6_sock(); } + else + { + listen_sock = vsf_sysutil_get_llc_sock(); + } vsf_sysutil_activate_reuseaddr(listen_sock); s_p_ip_count_hash = hash_alloc(256, s_ipaddr_size, @@ -96,7 +100,7 @@ die("could not bind listening IPv4 socket"); } } - else + else if (tunable_listen_ipv6) { struct vsf_sysutil_sockaddr* p_sockaddr = 0; vsf_sysutil_sockaddr_alloc_ipv6(&p_sockaddr); @@ -125,6 +129,29 @@ die("could not bind listening IPv6 socket"); } } + else + { + struct vsf_sysutil_sockaddr* p_sockaddr = 0; + vsf_sysutil_sockaddr_alloc_llc(&p_sockaddr); + vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_listen_port); + if (!tunable_listen_address_llc) + { + vsf_sysutil_sockaddr_set_any(p_sockaddr); + } + else + { + if (!vsf_sysutil_llc_aton(tunable_listen_address_llc, p_sockaddr)) + { + die2("bad listen_address_llc: ", tunable_listen_address_llc); + } + } + retval = vsf_sysutil_bind(listen_sock, p_sockaddr); + vsf_sysutil_free(p_sockaddr); + if (vsf_sysutil_retval_is_error(retval)) + { + die("could not bind listening LLC socket"); + } + } vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG); while (1) { diff -uNr vsftpd-1.2.1.orig/sysutil.c vsftpd-1.2.1.llc/sysutil.c --- vsftpd-1.2.1.orig/sysutil.c 2003-11-10 23:37:16.000000000 -0200 +++ vsftpd-1.2.1.llc/sysutil.c 2003-12-01 21:24:16.000000000 -0200 @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include @@ -81,6 +83,7 @@ struct sockaddr u_sockaddr; struct sockaddr_in u_sockaddr_in; struct sockaddr_in6 u_sockaddr_in6; + struct sockaddr_llc u_sockaddr_llc; } u; }; @@ -1530,6 +1533,17 @@ } int +vsf_sysutil_get_llc_sock(void) +{ + int retval = socket(PF_LLC, SOCK_STREAM, 0); + if (retval < 0) + { + die("socket"); + } + return retval; +} + +int vsf_sysutil_get_ipv6_sock(void) { int retval = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); @@ -1568,9 +1582,13 @@ { len = sizeof(struct sockaddr_in6); } + else if (p_sockaddr->sa_family == AF_LLC) + { + len = sizeof(struct sockaddr_llc); + } else { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); } return bind(fd, p_sockaddr, len); } @@ -1627,9 +1645,10 @@ return -1; } if (remote_addr.u.u_sockaddr.sa_family != AF_INET && - remote_addr.u.u_sockaddr.sa_family != AF_INET6) + remote_addr.u.u_sockaddr.sa_family != AF_INET6 && + remote_addr.u.u_sockaddr.sa_family != AF_LLC) { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); } if (p_sockptr) { @@ -1641,11 +1660,16 @@ vsf_sysutil_memcpy(*p_sockptr, &remote_addr.u.u_sockaddr_in, sizeof(remote_addr.u.u_sockaddr_in)); } - else + else if (remote_addr.u.u_sockaddr.sa_family == AF_INET6) { vsf_sysutil_memcpy(*p_sockptr, &remote_addr.u.u_sockaddr_in6, sizeof(remote_addr.u.u_sockaddr_in6)); } + else + { + vsf_sysutil_memcpy(*p_sockptr, &remote_addr.u.u_sockaddr_llc, + sizeof(remote_addr.u.u_sockaddr_llc)); + } } return retval; } @@ -1665,9 +1689,13 @@ { addrlen = sizeof(p_addr->u.u_sockaddr_in6); } + else if (p_sockaddr->sa_family == AF_LLC) + { + addrlen = sizeof(p_addr->u.u_sockaddr_llc); + } else { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); } if (wait_seconds > 0) { @@ -1723,9 +1751,10 @@ die("getsockname"); } if (the_addr.u.u_sockaddr.sa_family != AF_INET && - the_addr.u.u_sockaddr.sa_family != AF_INET6) + the_addr.u.u_sockaddr.sa_family != AF_INET6 && + the_addr.u.u_sockaddr.sa_family != AF_LLC) { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); } vsf_sysutil_sockaddr_alloc(p_sockptr); if (socklen > sizeof(the_addr)) @@ -1748,9 +1777,10 @@ die("getpeername"); } if (the_addr.u.u_sockaddr.sa_family != AF_INET && - the_addr.u.u_sockaddr.sa_family != AF_INET6) + the_addr.u.u_sockaddr.sa_family != AF_INET6 && + the_addr.u.u_sockaddr.sa_family != AF_LLC) { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); } vsf_sysutil_sockaddr_alloc(p_sockptr); if (socklen > sizeof(the_addr)) @@ -1803,6 +1833,13 @@ } void +vsf_sysutil_sockaddr_alloc_llc(struct vsf_sysutil_sockaddr** p_sockptr) +{ + vsf_sysutil_sockaddr_alloc(p_sockptr); + (*p_sockptr)->u.u_sockaddr.sa_family = AF_LLC; +} + +void vsf_sysutil_sockaddr_clone(struct vsf_sysutil_sockaddr** p_sockptr, const struct vsf_sysutil_sockaddr* p_src) { @@ -1823,9 +1860,16 @@ &p_src->u.u_sockaddr_in6.sin6_addr, sizeof(p_sockaddr->u.u_sockaddr_in6.sin6_addr)); } + else if (p_src->u.u_sockaddr.sa_family == AF_LLC) + { + p_sockaddr->u.u_sockaddr.sa_family = AF_LLC; + vsf_sysutil_memcpy(&p_sockaddr->u.u_sockaddr_llc.sllc_mac, + &p_src->u.u_sockaddr_llc.sllc_mac, + sizeof(p_sockaddr->u.u_sockaddr_llc.sllc_mac)); + } else { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); } } @@ -1877,6 +1921,15 @@ return 1; } } + else if (family1 == AF_LLC) + { + if (vsf_sysutil_memcmp(&p1->u.u_sockaddr_llc.sllc_mac, + &p2->u.u_sockaddr_llc.sllc_mac, + sizeof(p1->u.u_sockaddr_llc.sllc_mac)) == 0) + { + return 1; + } + } return 0; } @@ -1891,6 +1944,17 @@ } int +vsf_sysutil_sockaddr_is_llc(const struct vsf_sysutil_sockaddr* p_sockaddr) +{ + if (p_sockaddr->u.u_sockaddr.sa_family == AF_LLC) + { + return 1; + } + return 0; +} + + +int vsf_sysutil_sockaddr_same_family(const struct vsf_sysutil_sockaddr* p1, const struct vsf_sysutil_sockaddr* p2) { @@ -1931,6 +1995,21 @@ } } +void +vsf_sysutil_sockaddr_set_llcaddr(struct vsf_sysutil_sockaddr* p_sockptr, + const unsigned char* p_raw) +{ + if (p_sockptr->u.u_sockaddr.sa_family == AF_LLC) + { + vsf_sysutil_memcpy(&p_sockptr->u.u_sockaddr_llc.sllc_mac, p_raw, + sizeof(p_sockptr->u.u_sockaddr_llc.sllc_mac)); + } + else + { + bug("bad family"); + } +} + const void* vsf_sysutil_sockaddr_ipv6_v4(const struct vsf_sysutil_sockaddr* p_addr) { @@ -1959,6 +2038,10 @@ { return &p_sockptr->u.u_sockaddr_in6.sin6_addr; } + else if (p_sockptr->u.u_sockaddr.sa_family == AF_LLC) + { + return &p_sockptr->u.u_sockaddr_llc.sllc_mac; + } else { bug("bad family"); @@ -1990,6 +2073,10 @@ { return vsf_sysutil_get_ipv6_sock(); } + else if (p_addr->u.u_sockaddr.sa_family == AF_LLC) + { + return vsf_sysutil_get_llc_sock(); + } else { bug("bad family"); @@ -2010,6 +2097,11 @@ vsf_sysutil_memclr(&p_sockaddr->u.u_sockaddr_in6.sin6_addr, sizeof(p_sockaddr->u.u_sockaddr_in6.sin6_addr)); } + else if (p_sockaddr->u.u_sockaddr.sa_family == AF_LLC) + { + vsf_sysutil_memclr(&p_sockaddr->u.u_sockaddr_llc.sllc_mac, + sizeof(p_sockaddr->u.u_sockaddr_llc.sllc_mac)); + } else { bug("bad family"); @@ -2028,6 +2120,10 @@ { p_sockptr->u.u_sockaddr_in6.sin6_port = htons(the_port); } + else if (p_sockptr->u.u_sockaddr.sa_family == AF_LLC) + { + p_sockptr->u.u_sockaddr_llc.sllc_sap = the_port; + } else { bug("bad family"); @@ -2035,15 +2131,24 @@ } int -vsf_sysutil_is_port_reserved(unsigned short the_port) +vsf_sysutil_is_port_reserved(struct vsf_sysutil_sockaddr* p_sockptr, + unsigned short the_port) { - if (the_port < IPPORT_RESERVED) - { - return 1; - } + if (p_sockptr->u.u_sockaddr.sa_family != AF_LLC) + if (the_port < IPPORT_RESERVED) + { + return 1; + } return 0; } +const unsigned char* +vsf_sysutil_parse_llc(const struct mystr* p_str) +{ + char *eaddr = str_getbuf(p_str); + return (const unsigned char *)ether_aton(eaddr); +} + const char* vsf_sysutil_inet_ntop(const struct vsf_sysutil_sockaddr* p_sockptr) { @@ -2065,9 +2170,13 @@ } return inaddr_buf; } + else if (p_sockaddr->sa_family == AF_LLC) + { + return ether_ntoa((struct ether_addr *)p_sockptr->u.u_sockaddr_llc.sllc_mac); + } else { - die("can only support ipv4 and ipv6 currently"); + die("can only support ipv4, ipv6 and llc currently"); return 0; } } @@ -2098,6 +2207,26 @@ } } +int +vsf_sysutil_llc_aton(const char* p_text, struct vsf_sysutil_sockaddr* p_addr) +{ + struct ether_addr eaddr; + if (p_addr->u.u_sockaddr.sa_family != AF_LLC) + { + bug("bad family"); + } + if (ether_aton_r(p_text, &eaddr)) + { + vsf_sysutil_memcpy(&p_addr->u.u_sockaddr_llc.sllc_mac, + &eaddr, sizeof(p_addr->u.u_sockaddr_llc.sllc_mac)); + return 1; + } + else + { + return 0; + } +} + struct vsf_sysutil_user* vsf_sysutil_getpwuid(const int uid) { diff -uNr vsftpd-1.2.1.orig/sysutil.h vsftpd-1.2.1.llc/sysutil.h --- vsftpd-1.2.1.orig/sysutil.h 2003-11-05 01:33:52.000000000 -0200 +++ vsftpd-1.2.1.llc/sysutil.h 2003-12-01 20:23:59.000000000 -0200 @@ -68,6 +68,9 @@ void vsf_sysutil_closedir(struct vsf_sysutil_dir* p_dir); const char* vsf_sysutil_next_dirent(struct vsf_sysutil_dir* p_dir); +struct mystr; +const unsigned char* vsf_sysutil_parse_llc(const struct mystr* p_str); + /* File create/open/close etc. */ enum EVSFSysUtilOpenMode { @@ -206,6 +209,7 @@ void vsf_sysutil_sockaddr_clear(struct vsf_sysutil_sockaddr** p_sockptr); void vsf_sysutil_sockaddr_alloc_ipv4(struct vsf_sysutil_sockaddr** p_sockptr); void vsf_sysutil_sockaddr_alloc_ipv6(struct vsf_sysutil_sockaddr** p_sockptr); +void vsf_sysutil_sockaddr_alloc_llc(struct vsf_sysutil_sockaddr** p_sockptr); void vsf_sysutil_sockaddr_clone( struct vsf_sysutil_sockaddr** p_sockptr, const struct vsf_sysutil_sockaddr* p_src); @@ -213,6 +217,8 @@ const struct vsf_sysutil_sockaddr* p2); int vsf_sysutil_sockaddr_is_ipv6( const struct vsf_sysutil_sockaddr* p_sockaddr); +int vsf_sysutil_sockaddr_is_llc( + const struct vsf_sysutil_sockaddr* p_sockaddr); int vsf_sysutil_sockaddr_same_family( const struct vsf_sysutil_sockaddr* p1, const struct vsf_sysutil_sockaddr* p2); @@ -220,10 +226,13 @@ const unsigned char* p_raw); void vsf_sysutil_sockaddr_set_ipv6addr(struct vsf_sysutil_sockaddr* p_sockptr, const unsigned char* p_raw); +void vsf_sysutil_sockaddr_set_llcaddr(struct vsf_sysutil_sockaddr* p_sockptr, + const unsigned char* p_raw); void vsf_sysutil_sockaddr_set_any(struct vsf_sysutil_sockaddr* p_sockaddr); void vsf_sysutil_sockaddr_set_port(struct vsf_sysutil_sockaddr* p_sockptr, unsigned short the_port); -int vsf_sysutil_is_port_reserved(unsigned short port); +int vsf_sysutil_is_port_reserved(struct vsf_sysutil_sockaddr* p_sockptr, + unsigned short port); int vsf_sysutil_get_ipsock(const struct vsf_sysutil_sockaddr* p_sockaddr); unsigned int vsf_sysutil_get_ipaddr_size(void); void* vsf_sysutil_sockaddr_get_raw_addr( @@ -232,6 +241,7 @@ const struct vsf_sysutil_sockaddr* p_sockaddr); int vsf_sysutil_get_ipv4_sock(void); int vsf_sysutil_get_ipv6_sock(void); +int vsf_sysutil_get_llc_sock(void); struct vsf_sysutil_socketpair_retval vsf_sysutil_unix_dgram_socketpair(void); int vsf_sysutil_bind(int fd, const struct vsf_sysutil_sockaddr* p_sockptr); @@ -263,6 +273,8 @@ const char* vsf_sysutil_inet_ntoa(const void* p_raw_addr); int vsf_sysutil_inet_aton( const char* p_text, struct vsf_sysutil_sockaddr* p_addr); +int vsf_sysutil_llc_aton(const char* p_text, + struct vsf_sysutil_sockaddr* p_addr); /* User database queries etc. */ struct vsf_sysutil_user; diff -uNr vsftpd-1.2.1.orig/tunables.c vsftpd-1.2.1.llc/tunables.c --- vsftpd-1.2.1.orig/tunables.c 2003-11-05 23:08:29.000000000 -0200 +++ vsftpd-1.2.1.llc/tunables.c 2003-11-30 19:46:58.000000000 -0200 @@ -47,6 +47,7 @@ int tunable_use_sendfile = 1; int tunable_force_dot_files = 0; int tunable_listen_ipv6 = 0; +int tunable_listen_llc = 0; int tunable_dual_log_enable = 0; int tunable_syslog_enable = 0; int tunable_background = 0; @@ -97,6 +98,7 @@ const char* tunable_listen_address = 0; const char* tunable_user_config_dir = 0; const char* tunable_listen_address6 = 0; +const char* tunable_listen_address_llc = 0; const char* tunable_cmds_allowed = 0; const char* tunable_hide_file = 0; const char* tunable_deny_file = 0; diff -uNr vsftpd-1.2.1.orig/tunables.h vsftpd-1.2.1.llc/tunables.h --- vsftpd-1.2.1.orig/tunables.h 2003-11-05 23:07:53.000000000 -0200 +++ vsftpd-1.2.1.llc/tunables.h 2003-11-30 18:49:26.000000000 -0200 @@ -43,6 +43,7 @@ extern int tunable_use_sendfile; /* Use sendfile() if we can */ extern int tunable_force_dot_files; /* Show dotfiles without -a */ extern int tunable_listen_ipv6; /* Standalone with IPv6 listen */ +extern int tunable_listen_llc; /* Standalone with LLC listen */ extern int tunable_dual_log_enable; /* Log vsftpd.log AND xferlog */ extern int tunable_syslog_enable; /* Use syslog not vsftpd.log */ extern int tunable_background; /* Background listener process */ @@ -92,6 +93,7 @@ extern const char* tunable_listen_address; extern const char* tunable_user_config_dir; extern const char* tunable_listen_address6; +extern const char* tunable_listen_address_llc; extern const char* tunable_cmds_allowed; extern const char* tunable_hide_file; extern const char* tunable_deny_file; diff -uNr vsftpd-1.2.1.orig/vsftpd.conf.5 vsftpd-1.2.1.llc/vsftpd.conf.5 --- vsftpd-1.2.1.orig/vsftpd.conf.5 2003-11-11 23:06:25.000000000 -0200 +++ vsftpd-1.2.1.llc/vsftpd.conf.5 2003-11-30 18:45:12.000000000 -0200 @@ -221,8 +221,15 @@ .TP .B listen_ipv6 Like the listen parameter, except vsftpd will listen on an IPv6 socket instead -of an IPv4 one. This parameter and the listen parameter are mutually -exclusive. +of an IPv4 one. This parameter and the listen and listen_llc parameters are +mutually exclusive. + +Default: NO +.TP +.B listen_llc +Like the listen parameter, except vsftpd will listen on an LLC socket instead +of an IPv4 or IPv6 one. This parameter and the listen and listen_ipv6 +parameters are mutually exclusive. Default: NO .TP @@ -653,6 +660,13 @@ Default: (none) .TP +.B listen_address_llc +Like listen_address and listen_address6, but specifies a default listen +address for the LLC listener (which is used if listen_llc is set). Format is +standard MAC address format. + +Default: (none) +.TP .B local_root This option represents a directory which vsftpd will try to change into after a local (i.e. non-anonymous) login. Failure is silently ignored.