version 1.99, 2016/08/20 20:18:42 |
version 1.100, 2016/08/22 16:27:00 |
|
|
|
|
#include "ftp_var.h" |
#include "ftp_var.h" |
|
|
union sockunion { |
union sockaddr_union { |
struct sockinet { |
struct sockaddr sa; |
u_char si_len; |
struct sockaddr_in sin; |
u_char si_family; |
struct sockaddr_in6 sin6; |
u_short si_port; |
|
} su_si; |
|
struct sockaddr_in su_sin; |
|
struct sockaddr_in6 su_sin6; |
|
}; |
}; |
#define su_len su_si.si_len |
|
#define su_family su_si.si_family |
|
#define su_port su_si.si_port |
|
|
|
union sockunion myctladdr, hisctladdr, data_addr; |
union sockaddr_union myctladdr, hisctladdr, data_addr; |
|
|
int data = -1; |
int data = -1; |
int abrtflag = 0; |
int abrtflag = 0; |
|
|
ares = NULL; |
ares = NULL; |
} |
} |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
if (getsockname(s, (struct sockaddr *)&myctladdr, &namelen) < 0) { |
if (getsockname(s, &myctladdr.sa, &namelen) < 0) { |
warn("getsockname"); |
warn("getsockname"); |
code = -1; |
code = -1; |
goto bad; |
goto bad; |
} |
} |
if (hisctladdr.su_family == AF_INET) { |
if (hisctladdr.sa.sa_family == AF_INET) { |
tos = IPTOS_LOWDELAY; |
tos = IPTOS_LOWDELAY; |
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) |
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) |
warn("setsockopt TOS (ignored)"); |
warn("setsockopt TOS (ignored)"); |
|
|
struct addrinfo *ares; |
struct addrinfo *ares; |
#endif |
#endif |
|
|
if (myctladdr.su_family == AF_INET6 |
if (myctladdr.sa.sa_family == AF_INET6 |
&& (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr) |
&& (IN6_IS_ADDR_LINKLOCAL(&myctladdr.sin6.sin6_addr) |
|| IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) { |
|| IN6_IS_ADDR_SITELOCAL(&myctladdr.sin6.sin6_addr))) { |
warnx("use of scoped address can be troublesome"); |
warnx("use of scoped address can be troublesome"); |
} |
} |
#ifndef SMALL |
#ifndef SMALL |
|
|
reinit: |
reinit: |
if (passivemode) { |
if (passivemode) { |
data_addr = myctladdr; |
data_addr = myctladdr; |
data = socket(data_addr.su_family, SOCK_STREAM, 0); |
data = socket(data_addr.sa.sa_family, SOCK_STREAM, 0); |
if (data < 0) { |
if (data < 0) { |
warn("socket"); |
warn("socket"); |
return (1); |
return (1); |
|
|
sizeof(on)) < 0) |
sizeof(on)) < 0) |
warn("setsockopt (ignored)"); |
warn("setsockopt (ignored)"); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
switch (data_addr.su_family) { |
switch (data_addr.sa.sa_family) { |
case AF_INET: |
case AF_INET: |
if (epsv4 && !epsv4bad) { |
if (epsv4 && !epsv4bad) { |
int ov; |
int ov; |
|
|
if (!pasvcmd) |
if (!pasvcmd) |
goto bad; |
goto bad; |
if (strcmp(pasvcmd, "PASV") == 0) { |
if (strcmp(pasvcmd, "PASV") == 0) { |
if (data_addr.su_family != AF_INET) { |
if (data_addr.sa.sa_family != AF_INET) { |
fputs( |
fputs( |
"Passive mode AF mismatch. Shouldn't happen!\n", ttyout); |
"Passive mode AF mismatch. Shouldn't happen!\n", ttyout); |
goto bad; |
goto bad; |
|
|
goto bad; |
goto bad; |
} |
} |
memset(&data_addr, 0, sizeof(data_addr)); |
memset(&data_addr, 0, sizeof(data_addr)); |
data_addr.su_family = AF_INET; |
data_addr.sin.sin_family = AF_INET; |
data_addr.su_len = sizeof(struct sockaddr_in); |
data_addr.sin.sin_len = sizeof(struct sockaddr_in); |
data_addr.su_sin.sin_addr.s_addr = |
data_addr.sin.sin_addr.s_addr = |
htonl(pack4(addr, 0)); |
htonl(pack4(addr, 0)); |
data_addr.su_port = htons(pack2(port, 0)); |
data_addr.sin.sin_port = htons(pack2(port, 0)); |
} else if (strcmp(pasvcmd, "LPSV") == 0) { |
} else if (strcmp(pasvcmd, "LPSV") == 0) { |
if (code / 10 == 22 && code != 228) { |
if (code / 10 == 22 && code != 228) { |
fputs("wrong server: return code must be 228\n", |
fputs("wrong server: return code must be 228\n", |
ttyout); |
ttyout); |
goto bad; |
goto bad; |
} |
} |
switch (data_addr.su_family) { |
switch (data_addr.sa.sa_family) { |
case AF_INET: |
case AF_INET: |
error = sscanf(pasv, |
error = sscanf(pasv, |
"%u,%u,%u,%u,%u,%u,%u,%u,%u", |
"%u,%u,%u,%u,%u,%u,%u,%u,%u", |
|
|
} |
} |
|
|
memset(&data_addr, 0, sizeof(data_addr)); |
memset(&data_addr, 0, sizeof(data_addr)); |
data_addr.su_family = AF_INET; |
data_addr.sin.sin_family = AF_INET; |
data_addr.su_len = sizeof(struct sockaddr_in); |
data_addr.sin.sin_len = sizeof(struct sockaddr_in); |
data_addr.su_sin.sin_addr.s_addr = |
data_addr.sin.sin_addr.s_addr = |
htonl(pack4(addr, 0)); |
htonl(pack4(addr, 0)); |
data_addr.su_port = htons(pack2(port, 0)); |
data_addr.sin.sin_port = htons(pack2(port, 0)); |
break; |
break; |
case AF_INET6: |
case AF_INET6: |
error = sscanf(pasv, |
error = sscanf(pasv, |
|
|
} |
} |
|
|
memset(&data_addr, 0, sizeof(data_addr)); |
memset(&data_addr, 0, sizeof(data_addr)); |
data_addr.su_family = AF_INET6; |
data_addr.sin6.sin6_family = AF_INET6; |
data_addr.su_len = sizeof(struct sockaddr_in6); |
data_addr.sin6.sin6_len = sizeof(struct sockaddr_in6); |
{ |
{ |
u_int32_t *p32; |
u_int32_t *p32; |
p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr; |
p32 = (u_int32_t *)&data_addr.sin6.sin6_addr; |
p32[0] = htonl(pack4(addr, 0)); |
p32[0] = htonl(pack4(addr, 0)); |
p32[1] = htonl(pack4(addr, 4)); |
p32[1] = htonl(pack4(addr, 4)); |
p32[2] = htonl(pack4(addr, 8)); |
p32[2] = htonl(pack4(addr, 8)); |
p32[3] = htonl(pack4(addr, 12)); |
p32[3] = htonl(pack4(addr, 12)); |
} |
} |
data_addr.su_port = htons(pack2(port, 0)); |
data_addr.sin6.sin6_port = htons(pack2(port, 0)); |
break; |
break; |
default: |
default: |
fputs("Bad family!\n", ttyout); |
fputs("Bad family!\n", ttyout); |
|
|
goto bad; |
goto bad; |
} |
} |
data_addr = hisctladdr; |
data_addr = hisctladdr; |
data_addr.su_port = htons(port[1]); |
data_addr.sin.sin_port = htons(port[1]); |
} else |
} else |
goto bad; |
goto bad; |
|
|
for (error = connect(data, (struct sockaddr *)&data_addr, |
for (error = connect(data, &data_addr.sa, data_addr.sa.sa_len); |
data_addr.su_len); error != 0 && errno == EINTR; |
error != 0 && errno == EINTR; |
error = connect_wait(data)) |
error = connect_wait(data)) |
continue; |
continue; |
if (error != 0) { |
if (error != 0) { |
|
|
warn("connect"); |
warn("connect"); |
goto bad; |
goto bad; |
} |
} |
if (data_addr.su_family == AF_INET) { |
if (data_addr.sa.sa_family == AF_INET) { |
on = IPTOS_THROUGHPUT; |
on = IPTOS_THROUGHPUT; |
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, |
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, |
sizeof(int)) < 0) |
sizeof(int)) < 0) |
|
|
noport: |
noport: |
data_addr = myctladdr; |
data_addr = myctladdr; |
if (sendport) |
if (sendport) |
data_addr.su_port = 0; /* let system pick one */ |
data_addr.sin.sin_port = 0; /* let system pick one */ |
if (data != -1) |
if (data != -1) |
(void)close(data); |
(void)close(data); |
data = socket(data_addr.su_family, SOCK_STREAM, 0); |
data = socket(data_addr.sa.sa_family, SOCK_STREAM, 0); |
if (data < 0) { |
if (data < 0) { |
warn("socket"); |
warn("socket"); |
if (tmpno) |
if (tmpno) |
|
|
warn("setsockopt (reuse address)"); |
warn("setsockopt (reuse address)"); |
goto bad; |
goto bad; |
} |
} |
switch (data_addr.su_family) { |
switch (data_addr.sa.sa_family) { |
case AF_INET: |
case AF_INET: |
on = IP_PORTRANGE_HIGH; |
on = IP_PORTRANGE_HIGH; |
if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, |
if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, |
|
|
warn("setsockopt IPV6_PORTRANGE (ignored)"); |
warn("setsockopt IPV6_PORTRANGE (ignored)"); |
break; |
break; |
} |
} |
if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) { |
if (bind(data, &data_addr.sa, data_addr.sa.sa_len) < 0) { |
warn("bind"); |
warn("bind"); |
goto bad; |
goto bad; |
} |
} |
|
|
warn("setsockopt (ignored)"); |
warn("setsockopt (ignored)"); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
namelen = sizeof(data_addr); |
namelen = sizeof(data_addr); |
if (getsockname(data, (struct sockaddr *)&data_addr, &namelen) < 0) { |
if (getsockname(data, &data_addr.sa, &namelen) < 0) { |
warn("getsockname"); |
warn("getsockname"); |
goto bad; |
goto bad; |
} |
} |
|
|
if (sendport) { |
if (sendport) { |
char hname[NI_MAXHOST], pbuf[NI_MAXSERV]; |
char hname[NI_MAXHOST], pbuf[NI_MAXSERV]; |
int af_tmp; |
int af_tmp; |
union sockunion tmp; |
union sockaddr_union tmp; |
|
|
tmp = data_addr; |
tmp = data_addr; |
switch (tmp.su_family) { |
switch (tmp.sa.sa_family) { |
case AF_INET: |
case AF_INET: |
if (!epsv4 || epsv4bad) { |
if (!epsv4 || epsv4bad) { |
result = COMPLETE +1; |
result = COMPLETE +1; |
|
|
} |
} |
/*FALLTHROUGH*/ |
/*FALLTHROUGH*/ |
case AF_INET6: |
case AF_INET6: |
if (tmp.su_family == AF_INET6) |
if (tmp.sa.sa_family == AF_INET6) |
tmp.su_sin6.sin6_scope_id = 0; |
tmp.sin6.sin6_scope_id = 0; |
af_tmp = (tmp.su_family == AF_INET) ? 1 : 2; |
af_tmp = (tmp.sa.sa_family == AF_INET) ? 1 : 2; |
if (getnameinfo((struct sockaddr *)&tmp, |
if (getnameinfo(&tmp.sa, tmp.sa.sa_len, hname, |
tmp.su_len, hname, sizeof(hname), |
sizeof(hname), pbuf, sizeof(pbuf), |
pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { |
NI_NUMERICHOST | NI_NUMERICSERV)) { |
result = ERROR; |
result = ERROR; |
} else { |
} else { |
result = command("EPRT |%d|%s|%s|", |
result = command("EPRT |%d|%s|%s|", |
|
|
if (result == COMPLETE) |
if (result == COMPLETE) |
goto skip_port; |
goto skip_port; |
|
|
switch (data_addr.su_family) { |
switch (data_addr.sa.sa_family) { |
case AF_INET: |
case AF_INET: |
a = (char *)&data_addr.su_sin.sin_addr; |
a = (char *)&data_addr.sin.sin_addr; |
p = (char *)&data_addr.su_port; |
p = (char *)&data_addr.sin.sin_port; |
result = command("PORT %d,%d,%d,%d,%d,%d", |
result = command("PORT %d,%d,%d,%d,%d,%d", |
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), |
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), |
UC(p[0]), UC(p[1])); |
UC(p[0]), UC(p[1])); |
break; |
break; |
case AF_INET6: |
case AF_INET6: |
a = (char *)&data_addr.su_sin6.sin6_addr; |
a = (char *)&data_addr.sin6.sin6_addr; |
p = (char *)&data_addr.su_port; |
p = (char *)&data_addr.sin6.sin6_port; |
result = command( |
result = command( |
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", |
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", |
6, 16, |
6, 16, |
|
|
} |
} |
if (tmpno) |
if (tmpno) |
sendport = 1; |
sendport = 1; |
if (data_addr.su_family == AF_INET) { |
if (data_addr.sa.sa_family == AF_INET) { |
on = IPTOS_THROUGHPUT; |
on = IPTOS_THROUGHPUT; |
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, |
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, |
sizeof(int)) < 0) |
sizeof(int)) < 0) |
|
|
FILE * |
FILE * |
dataconn(const char *lmode) |
dataconn(const char *lmode) |
{ |
{ |
union sockunion from; |
union sockaddr_union from; |
socklen_t fromlen = myctladdr.su_len; |
socklen_t fromlen = myctladdr.sa.sa_len; |
int s; |
int s; |
|
|
if (passivemode) |
if (passivemode) |
return (fdopen(data, lmode)); |
return (fdopen(data, lmode)); |
|
|
s = accept(data, (struct sockaddr *) &from, &fromlen); |
s = accept(data, &from.sa, &fromlen); |
if (s < 0) { |
if (s < 0) { |
warn("accept"); |
warn("accept"); |
(void)close(data), data = -1; |
(void)close(data), data = -1; |
|
|
} |
} |
(void)close(data); |
(void)close(data); |
data = s; |
data = s; |
if (from.su_family == AF_INET) { |
if (from.sa.sa_family == AF_INET) { |
int tos = IPTOS_THROUGHPUT; |
int tos = IPTOS_THROUGHPUT; |
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, |
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, |
sizeof(int)) < 0) { |
sizeof(int)) < 0) { |
|
|
static struct comvars { |
static struct comvars { |
int connect; |
int connect; |
char name[HOST_NAME_MAX+1]; |
char name[HOST_NAME_MAX+1]; |
union sockunion mctl; |
union sockaddr_union mctl; |
union sockunion hctl; |
union sockaddr_union hctl; |
FILE *in; |
FILE *in; |
FILE *out; |
FILE *out; |
int tpe; |
int tpe; |