diff options
Diffstat (limited to 'lib/libalias/alias_ftp.c')
-rw-r--r-- | lib/libalias/alias_ftp.c | 902 |
1 files changed, 498 insertions, 404 deletions
diff --git a/lib/libalias/alias_ftp.c b/lib/libalias/alias_ftp.c index 08693a7..91d4952 100644 --- a/lib/libalias/alias_ftp.c +++ b/lib/libalias/alias_ftp.c @@ -87,495 +87,589 @@ __FBSDID("$FreeBSD$"); #define WAIT_CRLF 0x01 enum ftp_message_type { - FTP_PORT_COMMAND, - FTP_EPRT_COMMAND, - FTP_227_REPLY, - FTP_229_REPLY, - FTP_UNKNOWN_MESSAGE + FTP_PORT_COMMAND, + FTP_EPRT_COMMAND, + FTP_227_REPLY, + FTP_229_REPLY, + FTP_UNKNOWN_MESSAGE }; -static int ParseFtpPortCommand(struct libalias *la, char *, int); -static int ParseFtpEprtCommand(struct libalias *la, char *, int); -static int ParseFtp227Reply(struct libalias *la, char *, int); -static int ParseFtp229Reply(struct libalias *la, char *, int); -static void NewFtpMessage(struct libalias *la, struct ip *, struct alias_link *, int, int); +static int ParseFtpPortCommand(struct libalias *la, char *, int); +static int ParseFtpEprtCommand(struct libalias *la, char *, int); +static int ParseFtp227Reply(struct libalias *la, char *, int); +static int ParseFtp229Reply(struct libalias *la, char *, int); +static void NewFtpMessage(struct libalias *la, struct ip *, struct alias_link *, int, int); void AliasHandleFtpOut( -struct libalias *la, -struct ip *pip, /* IP packet to examine/patch */ -struct alias_link *link, /* The link to go through (aliased port) */ -int maxpacketsize /* The maximum size this packet can grow to (including headers) */) + struct libalias *la, + struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *link, /* The link to go through (aliased port) */ + int maxpacketsize /* The maximum size this packet can grow to + (including headers) */ ) { - int hlen, tlen, dlen, pflags; - char *sptr; - struct tcphdr *tc; - int ftp_message_type; + int hlen, tlen, dlen, pflags; + char *sptr; + struct tcphdr *tc; + int ftp_message_type; /* Calculate data length of TCP packet */ - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; + tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); + 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; + sptr = (char *)pip; + sptr += hlen; /* * Check that data length is not too long and previous message was * properly terminated with CRLF. */ - pflags = GetProtocolFlags(link); - if (dlen <= MAX_MESSAGE_SIZE && !(pflags & WAIT_CRLF)) { - ftp_message_type = FTP_UNKNOWN_MESSAGE; + pflags = GetProtocolFlags(link); + if (dlen <= MAX_MESSAGE_SIZE && !(pflags & WAIT_CRLF)) { + ftp_message_type = FTP_UNKNOWN_MESSAGE; - if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) { + if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) { /* * When aliasing a client, check for the PORT/EPRT command. */ - if (ParseFtpPortCommand(la, sptr, dlen)) - ftp_message_type = FTP_PORT_COMMAND; - else if (ParseFtpEprtCommand(la, sptr, dlen)) - ftp_message_type = FTP_EPRT_COMMAND; - } else { + if (ParseFtpPortCommand(la, sptr, dlen)) + ftp_message_type = FTP_PORT_COMMAND; + else if (ParseFtpEprtCommand(la, sptr, dlen)) + ftp_message_type = FTP_EPRT_COMMAND; + } else { /* * When aliasing a server, check for the 227/229 reply. */ - if (ParseFtp227Reply(la, sptr, dlen)) - ftp_message_type = FTP_227_REPLY; - else if (ParseFtp229Reply(la, sptr, dlen)) { - ftp_message_type = FTP_229_REPLY; - la->true_addr.s_addr = pip->ip_src.s_addr; - } - } - - if (ftp_message_type != FTP_UNKNOWN_MESSAGE) - NewFtpMessage(la, pip, link, maxpacketsize, ftp_message_type); - } + if (ParseFtp227Reply(la, sptr, dlen)) + ftp_message_type = FTP_227_REPLY; + else if (ParseFtp229Reply(la, sptr, dlen)) { + ftp_message_type = FTP_229_REPLY; + la->true_addr.s_addr = pip->ip_src.s_addr; + } + } + if (ftp_message_type != FTP_UNKNOWN_MESSAGE) + NewFtpMessage(la, pip, link, maxpacketsize, ftp_message_type); + } /* Track the msgs which are CRLF term'd for PORT/PASV FW breach */ - if (dlen) { /* only if there's data */ - 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(link, pflags); - } + if (dlen) { /* only if there's data */ + 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(link, pflags); + } } static int ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen) { - char ch; - int i, state; - u_int32_t addr; - u_short port; - u_int8_t octet; - - /* Format: "PORT A,D,D,R,PO,RT". */ - - /* Return if data length is too short. */ - if (dlen < 18) - return 0; - - addr = port = octet = 0; - state = -4; - for (i = 0; i < dlen; i++) { - ch = sptr[i]; - switch (state) { - case -4: if (ch == 'P') state++; else return 0; break; - case -3: if (ch == 'O') state++; else return 0; break; - case -2: if (ch == 'R') state++; else return 0; break; - case -1: if (ch == 'T') state++; else return 0; break; - - case 0: - if (isspace(ch)) - break; - else - state++; - case 1: case 3: case 5: case 7: case 9: case 11: - if (isdigit(ch)) { - octet = ch - '0'; - state++; - } else - return 0; - break; - case 2: case 4: case 6: case 8: - if (isdigit(ch)) - octet = 10 * octet + ch - '0'; - else if (ch == ',') { - addr = (addr << 8) + octet; - state++; - } else - return 0; - break; - case 10: case 12: - if (isdigit(ch)) - octet = 10 * octet + ch - '0'; - else if (ch == ',' || state == 12) { - port = (port << 8) + octet; - state++; - } else + char ch; + int i, state; + u_int32_t addr; + u_short port; + u_int8_t octet; + + /* Format: "PORT A,D,D,R,PO,RT". */ + + /* Return if data length is too short. */ + if (dlen < 18) return 0; - break; + + addr = port = octet = 0; + state = -4; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) { + case -4: + if (ch == 'P') + state++; + else + return 0; + break; + case -3: + if (ch == 'O') + state++; + else + return 0; + break; + case -2: + if (ch == 'R') + state++; + else + return 0; + break; + case -1: + if (ch == 'T') + state++; + else + return 0; + break; + + case 0: + if (isspace(ch)) + break; + else + state++; + case 1: + case 3: + case 5: + case 7: + case 9: + case 11: + if (isdigit(ch)) { + octet = ch - '0'; + state++; + } else + return 0; + break; + case 2: + case 4: + case 6: + case 8: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',') { + addr = (addr << 8) + octet; + state++; + } else + return 0; + break; + case 10: + case 12: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',' || state == 12) { + port = (port << 8) + octet; + state++; + } else + return 0; + break; + } } - } - - if (state == 13) { - la->true_addr.s_addr = htonl(addr); - la->true_port = port; - return 1; - } else - return 0; + + if (state == 13) { + la->true_addr.s_addr = htonl(addr); + la->true_port = port; + return 1; + } else + return 0; } static int ParseFtpEprtCommand(struct libalias *la, char *sptr, int dlen) { - char ch, delim; - int i, state; - u_int32_t addr; - u_short port; - u_int8_t octet; - - /* Format: "EPRT |1|A.D.D.R|PORT|". */ - - /* Return if data length is too short. */ - if (dlen < 18) - return 0; - - addr = port = octet = 0; - delim = '|'; /* XXX gcc -Wuninitialized */ - state = -4; - for (i = 0; i < dlen; i++) { - ch = sptr[i]; - switch (state) - { - case -4: if (ch == 'E') state++; else return 0; break; - case -3: if (ch == 'P') state++; else return 0; break; - case -2: if (ch == 'R') state++; else return 0; break; - case -1: if (ch == 'T') state++; else return 0; break; - - case 0: - if (!isspace(ch)) { - delim = ch; - state++; - } - break; - case 1: - if (ch == '1') /* IPv4 address */ - state++; - else - return 0; - break; - case 2: - if (ch == delim) - state++; - else - return 0; - break; - case 3: case 5: case 7: case 9: - if (isdigit(ch)) { - octet = ch - '0'; - state++; - } else - return 0; - break; - case 4: case 6: case 8: case 10: - if (isdigit(ch)) - octet = 10 * octet + ch - '0'; - else if (ch == '.' || state == 10) { - addr = (addr << 8) + octet; - state++; - } else - return 0; - break; - case 11: - if (isdigit(ch)) { - port = ch - '0'; - state++; - } else - return 0; - break; - case 12: - if (isdigit(ch)) - port = 10 * port + ch - '0'; - else if (ch == delim) - state++; - else + char ch, delim; + int i, state; + u_int32_t addr; + u_short port; + u_int8_t octet; + + /* Format: "EPRT |1|A.D.D.R|PORT|". */ + + /* Return if data length is too short. */ + if (dlen < 18) return 0; - break; + + addr = port = octet = 0; + delim = '|'; /* XXX gcc -Wuninitialized */ + state = -4; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) { + case -4: + if (ch == 'E') + state++; + else + return 0; + break; + case -3: + if (ch == 'P') + state++; + else + return 0; + break; + case -2: + if (ch == 'R') + state++; + else + return 0; + break; + case -1: + if (ch == 'T') + state++; + else + return 0; + break; + + case 0: + if (!isspace(ch)) { + delim = ch; + state++; + } + break; + case 1: + if (ch == '1') /* IPv4 address */ + state++; + else + return 0; + break; + case 2: + if (ch == delim) + state++; + else + return 0; + break; + case 3: + case 5: + case 7: + case 9: + if (isdigit(ch)) { + octet = ch - '0'; + state++; + } else + return 0; + break; + case 4: + case 6: + case 8: + case 10: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == '.' || state == 10) { + addr = (addr << 8) + octet; + state++; + } else + return 0; + break; + case 11: + if (isdigit(ch)) { + port = ch - '0'; + state++; + } else + return 0; + break; + case 12: + if (isdigit(ch)) + port = 10 * port + ch - '0'; + else if (ch == delim) + state++; + else + return 0; + break; + } } - } - - if (state == 13) { - la->true_addr.s_addr = htonl(addr); - la->true_port = port; - return 1; - } else - return 0; + + if (state == 13) { + la->true_addr.s_addr = htonl(addr); + la->true_port = port; + return 1; + } else + return 0; } static int ParseFtp227Reply(struct libalias *la, char *sptr, int dlen) { - char ch; - int i, state; - u_int32_t addr; - u_short port; - u_int8_t octet; - - /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */ - - /* Return if data length is too short. */ - if (dlen < 17) - return 0; - - addr = port = octet = 0; - - state = -3; - for (i = 0; i < dlen; i++) { - ch = sptr[i]; - switch (state) - { - case -3: if (ch == '2') state++; else return 0; break; - case -2: if (ch == '2') state++; else return 0; break; - case -1: if (ch == '7') state++; else return 0; break; - - case 0: - if (ch == '(') - state++; - break; - case 1: case 3: case 5: case 7: case 9: case 11: - if (isdigit(ch)) { - octet = ch - '0'; - state++; - } else - return 0; - break; - case 2: case 4: case 6: case 8: - if (isdigit(ch)) - octet = 10 * octet + ch - '0'; - else if (ch == ',') { - addr = (addr << 8) + octet; - state++; - } else - return 0; - break; - case 10: case 12: - if (isdigit(ch)) - octet = 10 * octet + ch - '0'; - else if (ch == ',' || (state == 12 && ch == ')')) { - port = (port << 8) + octet; - state++; - } else + char ch; + int i, state; + u_int32_t addr; + u_short port; + u_int8_t octet; + + /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */ + + /* Return if data length is too short. */ + if (dlen < 17) return 0; - break; + + addr = port = octet = 0; + + state = -3; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) { + case -3: + if (ch == '2') + state++; + else + return 0; + break; + case -2: + if (ch == '2') + state++; + else + return 0; + break; + case -1: + if (ch == '7') + state++; + else + return 0; + break; + + case 0: + if (ch == '(') + state++; + break; + case 1: + case 3: + case 5: + case 7: + case 9: + case 11: + if (isdigit(ch)) { + octet = ch - '0'; + state++; + } else + return 0; + break; + case 2: + case 4: + case 6: + case 8: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',') { + addr = (addr << 8) + octet; + state++; + } else + return 0; + break; + case 10: + case 12: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',' || (state == 12 && ch == ')')) { + port = (port << 8) + octet; + state++; + } else + return 0; + break; + } } - } - - if (state == 13) { - la->true_port = port; - la->true_addr.s_addr = htonl(addr); - return 1; - } else - return 0; + + if (state == 13) { + la->true_port = port; + la->true_addr.s_addr = htonl(addr); + return 1; + } else + return 0; } static int ParseFtp229Reply(struct libalias *la, char *sptr, int dlen) { - char ch, delim; - int i, state; - u_short port; - - /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */ - - /* Return if data length is too short. */ - if (dlen < 11) - return 0; - - port = 0; - delim = '|'; /* XXX gcc -Wuninitialized */ - - state = -3; - for (i = 0; i < dlen; i++) { - ch = sptr[i]; - switch (state) - { - case -3: if (ch == '2') state++; else return 0; break; - case -2: if (ch == '2') state++; else return 0; break; - case -1: if (ch == '9') state++; else return 0; break; - - case 0: - if (ch == '(') - state++; - break; - case 1: - delim = ch; - state++; - break; - case 2: case 3: - if (ch == delim) - state++; - else - return 0; - break; - case 4: - if (isdigit(ch)) { - port = ch - '0'; - state++; - } else - return 0; - break; - case 5: - if (isdigit(ch)) - port = 10 * port + ch - '0'; - else if (ch == delim) - state++; - else - return 0; - break; - case 6: - if (ch == ')') - state++; - else + char ch, delim; + int i, state; + u_short port; + + /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */ + + /* Return if data length is too short. */ + if (dlen < 11) return 0; - break; + + port = 0; + delim = '|'; /* XXX gcc -Wuninitialized */ + + state = -3; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) { + case -3: + if (ch == '2') + state++; + else + return 0; + break; + case -2: + if (ch == '2') + state++; + else + return 0; + break; + case -1: + if (ch == '9') + state++; + else + return 0; + break; + + case 0: + if (ch == '(') + state++; + break; + case 1: + delim = ch; + state++; + break; + case 2: + case 3: + if (ch == delim) + state++; + else + return 0; + break; + case 4: + if (isdigit(ch)) { + port = ch - '0'; + state++; + } else + return 0; + break; + case 5: + if (isdigit(ch)) + port = 10 * port + ch - '0'; + else if (ch == delim) + state++; + else + return 0; + break; + case 6: + if (ch == ')') + state++; + else + return 0; + break; + } } - } - if (state == 7) { - la->true_port = port; - return 1; - } else - return 0; + if (state == 7) { + la->true_port = port; + return 1; + } else + return 0; } static void NewFtpMessage(struct libalias *la, struct ip *pip, - struct alias_link *link, - int maxpacketsize, - int ftp_message_type) + struct alias_link *link, + int maxpacketsize, + int ftp_message_type) { - struct alias_link *ftp_link; + struct alias_link *ftp_link; /* Security checks. */ - if (pip->ip_src.s_addr != la->true_addr.s_addr) - return; + if (pip->ip_src.s_addr != la->true_addr.s_addr) + return; - if (la->true_port < IPPORT_RESERVED) - return; + if (la->true_port < IPPORT_RESERVED) + return; /* Establish link to address and port found in FTP control message. */ - ftp_link = FindUdpTcpOut(la, la->true_addr, GetDestAddress(link), - htons(la->true_port), 0, IPPROTO_TCP, 1); + ftp_link = FindUdpTcpOut(la, la->true_addr, GetDestAddress(link), + htons(la->true_port), 0, IPPROTO_TCP, 1); - if (ftp_link != NULL) - { - int slen, hlen, tlen, dlen; - struct tcphdr *tc; + if (ftp_link != NULL) { + int slen, hlen, tlen, dlen; + struct tcphdr *tc; #ifndef NO_FW_PUNCH - /* Punch hole in firewall */ - PunchFWHole(ftp_link); + /* Punch hole in firewall */ + PunchFWHole(ftp_link); #endif /* Calculate data length of TCP packet */ - tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); - hlen = (pip->ip_hl + tc->th_off) << 2; - tlen = ntohs(pip->ip_len); - dlen = tlen - hlen; + tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; /* Create new FTP message. */ - { - char stemp[MAX_MESSAGE_SIZE + 1]; - char *sptr; - u_short alias_port; - u_char *ptr; - int a1, a2, a3, a4, p1, p2; - struct in_addr alias_address; + { + char stemp[MAX_MESSAGE_SIZE + 1]; + char *sptr; + u_short alias_port; + u_char *ptr; + int a1, a2, a3, a4, p1, p2; + struct in_addr alias_address; /* Decompose alias address into quad format */ - alias_address = GetAliasAddress(link); - ptr = (u_char *) &alias_address.s_addr; - a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr; - - alias_port = GetAliasPort(ftp_link); - - switch (ftp_message_type) - { - case FTP_PORT_COMMAND: - case FTP_227_REPLY: - /* Decompose alias port into pair format. */ - ptr = (char *) &alias_port; - p1 = *ptr++; p2=*ptr; - - if (ftp_message_type == FTP_PORT_COMMAND) { - /* Generate PORT command string. */ - sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", - a1,a2,a3,a4,p1,p2); - } else { - /* Generate 227 reply string. */ - sprintf(stemp, - "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", - a1,a2,a3,a4,p1,p2); - } - break; - case FTP_EPRT_COMMAND: - /* Generate EPRT command string. */ - sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n", - a1,a2,a3,a4,ntohs(alias_port)); - break; - case FTP_229_REPLY: - /* Generate 229 reply string. */ - sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n", - ntohs(alias_port)); - break; - } + alias_address = GetAliasAddress(link); + ptr = (u_char *) & alias_address.s_addr; + a1 = *ptr++; + a2 = *ptr++; + a3 = *ptr++; + a4 = *ptr; + + alias_port = GetAliasPort(ftp_link); + + switch (ftp_message_type) { + case FTP_PORT_COMMAND: + case FTP_227_REPLY: + /* Decompose alias port into pair format. */ + ptr = (char *)&alias_port; + p1 = *ptr++; + p2 = *ptr; + + if (ftp_message_type == FTP_PORT_COMMAND) { + /* Generate PORT command string. */ + sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", + a1, a2, a3, a4, p1, p2); + } else { + /* Generate 227 reply string. */ + sprintf(stemp, + "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", + a1, a2, a3, a4, p1, p2); + } + break; + case FTP_EPRT_COMMAND: + /* Generate EPRT command string. */ + sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n", + a1, a2, a3, a4, ntohs(alias_port)); + break; + case FTP_229_REPLY: + /* Generate 229 reply string. */ + sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n", + ntohs(alias_port)); + break; + } /* Save string length for IP header modification */ - slen = strlen(stemp); + slen = strlen(stemp); /* Copy modified buffer into IP packet. */ - sptr = (char *) pip; sptr += hlen; - strncpy(sptr, stemp, maxpacketsize-hlen); - } + sptr = (char *)pip; + sptr += hlen; + strncpy(sptr, stemp, maxpacketsize - hlen); + } /* Save information regarding modified seq and ack numbers */ - { - int delta; + { + int delta; - SetAckModified(link); - delta = GetDeltaSeqOut(pip, link); - AddSeq(pip, link, delta+slen-dlen); - } + SetAckModified(link); + delta = GetDeltaSeqOut(pip, link); + AddSeq(pip, link, delta + slen - dlen); + } /* Revise IP header */ - { - u_short new_len; - - new_len = htons(hlen + slen); - DifferentialChecksum(&pip->ip_sum, - &new_len, - &pip->ip_len, - 1); - pip->ip_len = new_len; - } + { + u_short new_len; + + new_len = htons(hlen + slen); + DifferentialChecksum(&pip->ip_sum, + &new_len, + &pip->ip_len, + 1); + pip->ip_len = new_len; + } /* Compute TCP checksum for revised packet */ - tc->th_sum = 0; - tc->th_sum = TcpChecksum(pip); - } - else - { + tc->th_sum = 0; + tc->th_sum = TcpChecksum(pip); + } else { #ifdef DEBUG - fprintf(stderr, - "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n"); + fprintf(stderr, + "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n"); #endif - } + } } |