Hi,
To get active ftp (in both directions) working with ipvs patch for
2.2.19,
I patched ip_masq_ftp.c with the following and loaded with in_ports=21.
Anyone like to cast an eye over it?
This masquerades the port and ip correct. With just in_ports=21 only
the ip gets masqueraded.
--- orig_ip_masq_ftp Thu Sep 12 12:15:42 2002
+++ ip_masq_ftp.c Tue Sep 10 16:40:21 2002
@@ -142,6 +142,10 @@
/* Dummy variable */
static int masq_ftp_pasv;
+#ifdef CONFIG_IP_MASQUERADE_VS
+ static int ipvs_ftp_pasv; /* dummy variable for IPVS ftp
passive */
+#endif /* CONFIG_IP_MASQUERADE_VS */
+
/*
* This function parses the IP address and Port number found in PORT
commands
* and PASV responses. This used to be done in-line, but with four
cases it
@@ -255,6 +259,9 @@
struct iphdr *iph;
struct tcphdr *th;
char *p, *data, *data0, *data_limit;
+#ifdef CONFIG_IP_MASQUERADE_VS
+ unsigned char p1,p2,p3,p4,p5,p6;
+#endif
__u32 from=0;
__u32 from_n;
__u16 port;
@@ -268,6 +275,106 @@
if (ms->state != IP_MASQ_S_ESTABLISHED)
return 0;
+
+#ifdef CONFIG_IP_MASQUERADE_VS
+ if (ms->app_data == &ipvs_ftp_pasv) {
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+ data_limit = skb->h.raw + skb->len;
+
+ while (data < data_limit && *data != ' ')
+ ++data;
+ while (data < data_limit && *data == ' ')
+ ++data;
+ data += 22;
+ p = data+1;
+ if (data >= data_limit || *data != '(')
+ return 0;
+ p1 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p2 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p3 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p4 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p5 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p6 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ')')
+ return 0;
+
+ from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+ port = (p5<<8) | p6;
+
+ port = (p5<<8) | p6;
+
+ /*
+ * Now update or create an masquerade entry for it
+ */
+ IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X
detected\n",
+ntohl(ms->saddr), 0, from, port);
+
+ n_ms = ip_masq_out_get(iph->protocol,
+ htonl(from), htons(port),
+ ms->daddr, 0);
+ if (!n_ms) {
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, htons(port),
+ htonl(from), htons(port),
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+
+ if (n_ms==NULL)
+ return 0;
+ ip_masq_control_add(n_ms, ms);
+ }
+
+ /*
+ * Replace the old passive address with the new one
+ */
+ from = ntohl(n_ms->maddr);
+ port = ntohs(n_ms->mport);
+ sprintf(buf,"%d,%d,%d,%d,%d,%d",
+ from>>24&255,from>>16&255,from>>8&255,from&255,
+ port>>8&255,port&255);
+ buf_len = strlen(buf);
+
+ IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port);
+
+ /*
+ * Calculate required delta-offset to keep TCP happy
+ */
+
+ diff = buf_len - (data-p);
+
+ /*
+ * No shift.
+ */
+
+ if (diff==0) {
+ /*
+ * simple case, just replace the old PORT cmd
+ */
+ memcpy(p,buf,buf_len);
+ } else {
+
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p,
buf, buf_len);
+ }
+
+ ms->app_data = NULL;
+ ip_masq_put(n_ms);
+
+ return diff;
+ }
+
+#endif
+
skb = *skb_p;
iph = skb->nh.iph;
th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
@@ -440,6 +547,12 @@
struct iphdr *iph;
struct tcphdr *th;
char *data, *data_limit;
+
+#ifdef CONFIG_IP_MASQUERADE_VS
+ unsigned char p1,p2,p3,p4,p5,p6;
+ char *p;
+#endif
+
__u32 to;
__u32 from_n;
__u16 port;
@@ -448,6 +561,101 @@
/* Only useful for established sessions */
if (ms->state != IP_MASQ_S_ESTABLISHED)
return 0;
+
+#ifdef CONFIG_IP_MASQUERADE_VS
+
+ /*
+ * Detecting whether it is passive
+ */
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+ data_limit = skb->h.raw + skb->len;
+
+ while (data < data_limit) {
+ if (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data,
"pasv\r\n", 6) == 0) {
+ IP_MASQ_DEBUG(1-debug, "got PASV at %d of %d\n",
+ data-(char *)&th[1],
data_limit-(char *)&th[1]);
+ ms->app_data = &ipvs_ftp_pasv;
+
+ return 0;
+ }
+ data++;
+ }
+
+ /*
+ * To support virtual FTP server, the scenerio is as follows:
+ * FTP client ----> Load Balancer ----> FTP server
+ * First detect the port number in the application data,
+ * then create a new masquerading entry for the coming data
+ * connection.
+ */
+ data = (char *)&th[1];
+ data_limit = skb->h.raw + skb->len - 18;
+
+ while (data < data_limit)
+ {
+ if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5))
+ {
+ data ++;
+ continue;
+ }
+ p = data+5;
+ p1 = simple_strtoul(data+5,&data,10);
+ if (*data!=',')
+ continue;
+ p2 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p3 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p4 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p5 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p6 = simple_strtoul(data+1,&data,10);
+ if (*data!='\r' && *data!='\n')
+ continue;
+
+ to = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+ port = (p5<<8) | p6;
+
+ IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",to,port);
+ /*
+ * Now update or create an masquerade entry for it
+ */
+
+ IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n",
iph->protocol, htonl(to), htons(port), iph->daddr, 0);
+
+ n_ms = ip_masq_in_get(iph->protocol,
+ htonl(to), htons(port),
+ iph->daddr, 0);
+ if (!n_ms) {
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, htons(ntohs(ms->mport)-1),
+ ms->saddr, htons(ntohs(ms->sport)-1),
+ htonl(to), htons(port),
+ 0);
+
+ if (n_ms==NULL)
+ return 0;
+ ip_masq_control_add(n_ms, ms);
+ }
+
+ /*
+ * Move tunnel to listen state
+ */
+ ip_masq_listen(n_ms);
+ ip_masq_put(n_ms);
+
+ return 0;
+ }
+
+#endif
skb = *skb_p;
iph = skb->nh.iph;
|