summaryrefslogtreecommitdiffstats
path: root/sys/netinet/libalias/alias_ftp.c
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2011-06-22 20:00:27 +0000
committerae <ae@FreeBSD.org>2011-06-22 20:00:27 +0000
commit5c101cd76879e8bb9585cf791002fb61ca6bb0e7 (patch)
tree7121d365ba3ae2aac0d32cc16415c586ea401b20 /sys/netinet/libalias/alias_ftp.c
parent0a8537fb6af36d227389d693dc514cbd503ba043 (diff)
downloadFreeBSD-src-5c101cd76879e8bb9585cf791002fb61ca6bb0e7.zip
FreeBSD-src-5c101cd76879e8bb9585cf791002fb61ca6bb0e7.tar.gz
Export AddLink() function from libalias. It can be used when custom
alias address needs to be specified. Add inbound handler to the alias_ftp module. It helps handle active FTP transfer mode for the case with external clients and FTP server behind NAT. Fix passive FTP transfer case for server behind NAT using redirect with external IP address different from NAT ip address. PR: kern/157957 Submitted by: Alexander V. Chernikov
Diffstat (limited to 'sys/netinet/libalias/alias_ftp.c')
-rw-r--r--sys/netinet/libalias/alias_ftp.c124
1 files changed, 103 insertions, 21 deletions
diff --git a/sys/netinet/libalias/alias_ftp.c b/sys/netinet/libalias/alias_ftp.c
index ef0e52c..8e7d05b 100644
--- a/sys/netinet/libalias/alias_ftp.c
+++ b/sys/netinet/libalias/alias_ftp.c
@@ -100,38 +100,68 @@ __FBSDID("$FreeBSD$");
#define FTP_CONTROL_PORT_NUMBER 21
static void
-AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *,
- int maxpacketsize);
+AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *,
+ int maxpacketsize);
+static void
+AliasHandleFtpIn(struct libalias *, struct ip *, struct alias_link *);
-static int
-fingerprint(struct libalias *la, struct alias_data *ah)
+static int
+fingerprint_out(struct libalias *la, struct alias_data *ah)
{
- if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
- ah->maxpktsize == 0)
+ if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
+ ah->maxpktsize == 0)
return (-1);
- if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER
- || ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
+ if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER ||
+ ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
return (0);
return (-1);
}
-static int
-protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
+static int
+fingerprint_in(struct libalias *la, struct alias_data *ah)
+{
+
+ if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
+ return (-1);
+ if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER ||
+ ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
+ return (0);
+ return (-1);
+}
+
+static int
+protohandler_out(struct libalias *la, struct ip *pip, struct alias_data *ah)
{
-
+
AliasHandleFtpOut(la, pip, ah->lnk, ah->maxpktsize);
return (0);
}
+
+static int
+protohandler_in(struct libalias *la, struct ip *pip, struct alias_data *ah)
+{
+
+ AliasHandleFtpIn(la, pip, ah->lnk);
+ return (0);
+}
+
struct proto_handler handlers[] = {
- {
- .pri = 80,
- .dir = OUT,
- .proto = TCP,
- .fingerprint = &fingerprint,
- .protohandler = &protohandler
- },
+ {
+ .pri = 80,
+ .dir = OUT,
+ .proto = TCP,
+ .fingerprint = &fingerprint_out,
+ .protohandler = &protohandler_out
+ },
+ {
+ .pri = 80,
+ .dir = IN,
+ .proto = TCP,
+ .fingerprint = &fingerprint_in,
+ .protohandler = &protohandler_in
+ },
{ EOH }
};
@@ -256,6 +286,57 @@ AliasHandleFtpOut(
}
}
+static void
+AliasHandleFtpIn(struct libalias *la,
+ struct ip *pip, /* IP packet to examine/patch */
+ struct alias_link *lnk) /* The link to go through (aliased port) */
+{
+ int hlen, tlen, dlen, pflags;
+ char *sptr;
+ struct tcphdr *tc;
+
+ /* Calculate data length of TCP packet */
+ tc = (struct tcphdr *)ip_next(pip);
+ hlen = (pip->ip_hl + tc->th_off) << 2;
+ tlen = ntohs(pip->ip_len);
+ dlen = tlen - hlen;
+
+ /* Place string pointer and beginning of data */
+ sptr = (char *)pip;
+ sptr += hlen;
+
+ /*
+ * Check that data length is not too long and previous message was
+ * properly terminated with CRLF.
+ */
+ pflags = GetProtocolFlags(lnk);
+ if (dlen <= MAX_MESSAGE_SIZE && (pflags & WAIT_CRLF) == 0 &&
+ ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER &&
+ (ParseFtpPortCommand(la, sptr, dlen) != 0 ||
+ ParseFtpEprtCommand(la, sptr, dlen) != 0)) {
+ /*
+ * Alias active mode client requesting data from server
+ * behind NAT. We need to alias server->client connection
+ * to external address client is connecting to.
+ */
+ AddLink(la, GetOriginalAddress(lnk), la->true_addr,
+ GetAliasAddress(lnk), htons(FTP_CONTROL_PORT_NUMBER - 1),
+ htons(la->true_port), GET_ALIAS_PORT, IPPROTO_TCP);
+ }
+ /* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
+ if (dlen) {
+ sptr = (char *)pip; /* start over at beginning */
+ tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may
+ * have grown.
+ */
+ if (sptr[tlen - 2] == '\r' && sptr[tlen - 1] == '\n')
+ pflags &= ~WAIT_CRLF;
+ else
+ pflags |= WAIT_CRLF;
+ SetProtocolFlags(lnk, pflags);
+ }
+}
+
static int
ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen)
{
@@ -576,9 +657,10 @@ NewFtpMessage(struct libalias *la, struct ip *pip,
if (la->true_port < IPPORT_RESERVED)
return;
-/* Establish link to address and port found in FTP control message. */
- ftp_lnk = FindUdpTcpOut(la, la->true_addr, GetDestAddress(lnk),
- htons(la->true_port), 0, IPPROTO_TCP, 1);
+ /* Establish link to address and port found in FTP control message. */
+ ftp_lnk = AddLink(la, la->true_addr, GetDestAddress(lnk),
+ GetAliasAddress(lnk), htons(la->true_port), 0, GET_ALIAS_PORT,
+ IPPROTO_TCP);
if (ftp_lnk != NULL) {
int slen, hlen, tlen, dlen;
OpenPOWER on IntegriCloud