__be16 ports[2])
{
struct ip_vs_conn *cp = NULL;
- struct iphdr *iph = ip_hdr(skb);
+ struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
struct ip_vs_conn *ct;
- __be16 dport; /* destination port to forward */
- __be32 snet; /* source network of the client, after masking */
+ __be16 dport; /* destination port to forward */
+ union nf_inet_addr snet; /* source network of the client,
+ after masking */
+
+ ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
/* Mask saddr with the netmask to adjust template granularity */
- snet = iph->saddr & svc->netmask;
+#ifdef CONFIG_IP_VS_IPV6
+ if (svc->af == AF_INET6)
+ ipv6_addr_prefix(&snet.in6, &iph.saddr.in6, svc->netmask);
+ else
+#endif
+ snet.ip = iph.saddr.ip & svc->netmask;
- IP_VS_DBG(6, "p-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u "
- "mnet %u.%u.%u.%u\n",
- NIPQUAD(iph->saddr), ntohs(ports[0]),
- NIPQUAD(iph->daddr), ntohs(ports[1]),
- NIPQUAD(snet));
+ IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u "
+ "mnet %s\n",
+ IP_VS_DBG_ADDR(svc->af, &iph.saddr), ntohs(ports[0]),
+ IP_VS_DBG_ADDR(svc->af, &iph.daddr), ntohs(ports[1]),
+ IP_VS_DBG_ADDR(svc->af, &snet));
/*
* As far as we know, FTP is a very complicated network protocol, and
if (ports[1] == svc->port) {
/* Check if a template already exists */
if (svc->port != FTPPORT)
- ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
- iph->daddr, ports[1]);
+ ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+ &iph.daddr, ports[1]);
else
- ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
- iph->daddr, 0);
+ ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+ &iph.daddr, 0);
if (!ct || !ip_vs_check_template(ct)) {
/*
* for ftp service.
*/
if (svc->port != FTPPORT)
- ct = ip_vs_conn_new(iph->protocol,
- snet, 0,
- iph->daddr,
+ ct = ip_vs_conn_new(svc->af, iph.protocol,
+ &snet, 0,
+ &iph.daddr,
ports[1],
- dest->addr, dest->port,
+ &dest->addr, dest->port,
IP_VS_CONN_F_TEMPLATE,
dest);
else
- ct = ip_vs_conn_new(iph->protocol,
- snet, 0,
- iph->daddr, 0,
- dest->addr, 0,
+ ct = ip_vs_conn_new(svc->af, iph.protocol,
+ &snet, 0,
+ &iph.daddr, 0,
+ &dest->addr, 0,
IP_VS_CONN_F_TEMPLATE,
dest);
if (ct == NULL)
* fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
* port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
*/
- if (svc->fwmark)
- ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0,
- htonl(svc->fwmark), 0);
- else
- ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
- iph->daddr, 0);
+ if (svc->fwmark) {
+ union nf_inet_addr fwmark = {
+ .all = { 0, 0, 0, htonl(svc->fwmark) }
+ };
+
+ ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
+ &fwmark, 0);
+ } else
+ ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+ &iph.daddr, 0);
if (!ct || !ip_vs_check_template(ct)) {
/*
/*
* Create a template according to the service
*/
- if (svc->fwmark)
- ct = ip_vs_conn_new(IPPROTO_IP,
- snet, 0,
- htonl(svc->fwmark), 0,
- dest->addr, 0,
+ if (svc->fwmark) {
+ union nf_inet_addr fwmark = {
+ .all = { 0, 0, 0, htonl(svc->fwmark) }
+ };
+
+ ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
+ &snet, 0,
+ &fwmark, 0,
+ &dest->addr, 0,
IP_VS_CONN_F_TEMPLATE,
dest);
- else
- ct = ip_vs_conn_new(iph->protocol,
- snet, 0,
- iph->daddr, 0,
- dest->addr, 0,
+ } else
+ ct = ip_vs_conn_new(svc->af, iph.protocol,
+ &snet, 0,
+ &iph.daddr, 0,
+ &dest->addr, 0,
IP_VS_CONN_F_TEMPLATE,
dest);
if (ct == NULL)
/*
* Create a new connection according to the template
*/
- cp = ip_vs_conn_new(iph->protocol,
- iph->saddr, ports[0],
- iph->daddr, ports[1],
- dest->addr, dport,
+ cp = ip_vs_conn_new(svc->af, iph.protocol,
+ &iph.saddr, ports[0],
+ &iph.daddr, ports[1],
+ &dest->addr, dport,
0,
dest);
if (cp == NULL) {
ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
{
struct ip_vs_conn *cp = NULL;
- struct iphdr *iph = ip_hdr(skb);
+ struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
__be16 _ports[2], *pptr;
- pptr = skb_header_pointer(skb, iph->ihl*4,
- sizeof(_ports), _ports);
+ ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
+ pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
/*
* Create a connection entry.
*/
- cp = ip_vs_conn_new(iph->protocol,
- iph->saddr, pptr[0],
- iph->daddr, pptr[1],
- dest->addr, dest->port?dest->port:pptr[1],
+ cp = ip_vs_conn_new(svc->af, iph.protocol,
+ &iph.saddr, pptr[0],
+ &iph.daddr, pptr[1],
+ &dest->addr, dest->port ? dest->port : pptr[1],
0,
dest);
if (cp == NULL)
return NULL;
- IP_VS_DBG(6, "Schedule fwd:%c c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
- "d:%u.%u.%u.%u:%u conn->flags:%X conn->refcnt:%d\n",
- ip_vs_fwd_tag(cp),
- NIPQUAD(cp->caddr), ntohs(cp->cport),
- NIPQUAD(cp->vaddr), ntohs(cp->vport),
- NIPQUAD(cp->daddr), ntohs(cp->dport),
- cp->flags, atomic_read(&cp->refcnt));
+ IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
+ "d:%s:%u conn->flags:%X conn->refcnt:%d\n",
+ ip_vs_fwd_tag(cp),
+ IP_VS_DBG_ADDR(svc->af, &cp->caddr), ntohs(cp->cport),
+ IP_VS_DBG_ADDR(svc->af, &cp->vaddr), ntohs(cp->vport),
+ IP_VS_DBG_ADDR(svc->af, &cp->daddr), ntohs(cp->dport),
+ cp->flags, atomic_read(&cp->refcnt));
ip_vs_conn_stats(cp, svc);
return cp;
struct ip_vs_protocol *pp)
{
__be16 _ports[2], *pptr;
- struct iphdr *iph = ip_hdr(skb);
+ struct ip_vs_iphdr iph;
+ ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
- pptr = skb_header_pointer(skb, iph->ihl*4,
- sizeof(_ports), _ports);
+ pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
if (pptr == NULL) {
ip_vs_service_put(svc);
return NF_DROP;
and the destination is RTN_UNICAST (and not local), then create
a cache_bypass connection entry */
if (sysctl_ip_vs_cache_bypass && svc->fwmark
- && (inet_addr_type(&init_net, iph->daddr) == RTN_UNICAST)) {
+ && (inet_addr_type(&init_net, iph.daddr.ip) == RTN_UNICAST)) {
int ret, cs;
struct ip_vs_conn *cp;
/* create a new connection entry */
IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
- cp = ip_vs_conn_new(iph->protocol,
- iph->saddr, pptr[0],
- iph->daddr, pptr[1],
+ cp = ip_vs_conn_new(AF_INET, iph.protocol,
+ &iph.saddr, pptr[0],
+ &iph.daddr, pptr[1],
0, 0,
IP_VS_CONN_F_BYPASS,
NULL);
struct iphdr *ciph = (struct iphdr *)(icmph + 1);
if (inout) {
- iph->saddr = cp->vaddr;
+ iph->saddr = cp->vaddr.ip;
ip_send_check(iph);
- ciph->daddr = cp->vaddr;
+ ciph->daddr = cp->vaddr.ip;
ip_send_check(ciph);
} else {
- iph->daddr = cp->daddr;
+ iph->daddr = cp->daddr.ip;
ip_send_check(iph);
- ciph->saddr = cp->daddr;
+ ciph->saddr = cp->daddr.ip;
ip_send_check(ciph);
}
"Forwarding altered incoming ICMP");
}
+#ifdef CONFIG_IP_VS_IPV6
+void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int inout)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ unsigned int icmp_offset = sizeof(struct ipv6hdr);
+ struct icmp6hdr *icmph = (struct icmp6hdr *)(skb_network_header(skb) +
+ icmp_offset);
+ struct ipv6hdr *ciph = (struct ipv6hdr *)(icmph + 1);
+
+ if (inout) {
+ iph->saddr = cp->vaddr.in6;
+ ciph->daddr = cp->vaddr.in6;
+ } else {
+ iph->daddr = cp->daddr.in6;
+ ciph->saddr = cp->daddr.in6;
+ }
+
+ /* the TCP/UDP port */
+ if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr) {
+ __be16 *ports = (void *)ciph + sizeof(struct ipv6hdr);
+
+ if (inout)
+ ports[1] = cp->vport;
+ else
+ ports[0] = cp->dport;
+ }
+
+ /* And finally the ICMP checksum */
+ icmph->icmp6_cksum = 0;
+ /* TODO IPv6: is this correct for ICMPv6? */
+ ip_vs_checksum_complete(skb, icmp_offset);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (inout)
+ IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+ "Forwarding altered outgoing ICMPv6");
+ else
+ IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
+ "Forwarding altered incoming ICMPv6");
+}
+#endif
+
/*
* Handle ICMP messages in the inside-to-outside direction (outgoing).
* Find any that might be relevant, check against existing connections,
struct iphdr *iph;
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
+ struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict;
offset += cih->ihl * 4;
+ ip_vs_fill_iphdr(AF_INET, cih, &ciph);
/* The embedded headers contain source and dest in reverse order */
- cp = pp->conn_out_get(skb, pp, cih, offset, 1);
+ cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
if (!cp)
return NF_ACCEPT;
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct iphdr *iph;
+ struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
- int ihl;
EnterFunction(11);
if (skb->ipvs_property)
return NF_ACCEPT;
- iph = ip_hdr(skb);
- if (unlikely(iph->protocol == IPPROTO_ICMP)) {
+ ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+ if (unlikely(iph.protocol == IPPROTO_ICMP)) {
int related, verdict = ip_vs_out_icmp(skb, &related);
if (related)
return verdict;
- iph = ip_hdr(skb);
+ ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
}
- pp = ip_vs_proto_get(iph->protocol);
+ pp = ip_vs_proto_get(iph.protocol);
if (unlikely(!pp))
return NF_ACCEPT;
/* reassemble IP fragments */
- if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) &&
+ if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
!pp->dont_defrag)) {
if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
return NF_STOLEN;
- iph = ip_hdr(skb);
- }
- ihl = iph->ihl << 2;
+ ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
+ }
/*
* Check if the packet belongs to an existing entry
*/
- cp = pp->conn_out_get(skb, pp, iph, ihl, 0);
+ cp = pp->conn_out_get(AF_INET, skb, pp, &iph, iph.len, 0);
if (unlikely(!cp)) {
if (sysctl_ip_vs_nat_icmp_send &&
pp->protocol == IPPROTO_UDP)) {
__be16 _ports[2], *pptr;
- pptr = skb_header_pointer(skb, ihl,
+ pptr = skb_header_pointer(skb, iph.len,
sizeof(_ports), _ports);
if (pptr == NULL)
return NF_ACCEPT; /* Not for me */
- if (ip_vs_lookup_real_service(iph->protocol,
- iph->saddr, pptr[0])) {
+ if (ip_vs_lookup_real_service(iph.protocol,
+ iph.saddr.ip, pptr[0])) {
/*
* Notify the real server: there is no
* existing entry if it is not RST
* packet or not TCP packet.
*/
- if (iph->protocol != IPPROTO_TCP
+ if (iph.protocol != IPPROTO_TCP
|| !is_tcp_reset(skb)) {
icmp_send(skb,ICMP_DEST_UNREACH,
ICMP_PORT_UNREACH, 0);
IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
- if (!skb_make_writable(skb, ihl))
+ if (!skb_make_writable(skb, iph.len))
goto drop;
/* mangle the packet */
if (pp->snat_handler && !pp->snat_handler(skb, pp, cp))
goto drop;
- ip_hdr(skb)->saddr = cp->vaddr;
+ ip_hdr(skb)->saddr = cp->vaddr.ip;
ip_send_check(ip_hdr(skb));
/* For policy routing, packets originating from this
struct iphdr *iph;
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
+ struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict;
offset += cih->ihl * 4;
+ ip_vs_fill_iphdr(AF_INET, cih, &ciph);
/* The embedded headers contain source and dest in reverse order */
- cp = pp->conn_in_get(skb, pp, cih, offset, 1);
+ cp = pp->conn_in_get(AF_INET, skb, pp, &ciph, offset, 1);
if (!cp)
return NF_ACCEPT;
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- struct iphdr *iph;
+ struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
int ret, restart;
- int ihl;
+
+ ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
/*
* Big tappo: only PACKET_HOST (neither loopback nor mcasts)
*/
if (unlikely(skb->pkt_type != PACKET_HOST
|| skb->dev->flags & IFF_LOOPBACK || skb->sk)) {
- IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
- skb->pkt_type,
- ip_hdr(skb)->protocol,
- NIPQUAD(ip_hdr(skb)->daddr));
+ IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
+ skb->pkt_type,
+ iph.protocol,
+ IP_VS_DBG_ADDR(AF_INET, &iph.daddr));
return NF_ACCEPT;
}
- iph = ip_hdr(skb);
- if (unlikely(iph->protocol == IPPROTO_ICMP)) {
+ if (unlikely(iph.protocol == IPPROTO_ICMP)) {
int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
if (related)
return verdict;
- iph = ip_hdr(skb);
+ ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
}
/* Protocol supported? */
- pp = ip_vs_proto_get(iph->protocol);
+ pp = ip_vs_proto_get(iph.protocol);
if (unlikely(!pp))
return NF_ACCEPT;
- ihl = iph->ihl << 2;
-
/*
* Check if the packet belongs to an existing connection entry
*/
- cp = pp->conn_in_get(skb, pp, iph, ihl, 0);
+ cp = pp->conn_in_get(AF_INET, skb, pp, &iph, iph.len, 0);
if (unlikely(!cp)) {
int v;
- if (!pp->conn_schedule(skb, pp, &v, &cp))
+ if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp))
return v;
}