1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ip_vs_proto_ah_esp.c: AH/ESP IPSec load balancing support for IPVS 4 * 5 * Authors: Julian Anastasov <ja@ssi.bg>, February 2002 6 * Wensong Zhang <wensong@linuxvirtualserver.org> 7 */ 8 9 #define pr_fmt(fmt) "IPVS: " fmt 10 11 #include <linux/in.h> 12 #include <linux/ip.h> 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/netfilter.h> 16 #include <linux/netfilter_ipv4.h> 17 18 #include <net/ip_vs.h> 19 20 21 /* TODO: 22 23 struct isakmp_hdr { 24 __u8 icookie[8]; 25 __u8 rcookie[8]; 26 __u8 np; 27 __u8 version; 28 __u8 xchgtype; 29 __u8 flags; 30 __u32 msgid; 31 __u32 length; 32 }; 33 34 */ 35 36 #define PORT_ISAKMP 500 37 38 static void 39 ah_esp_conn_fill_param_proto(struct netns_ipvs *ipvs, int af, 40 const struct ip_vs_iphdr *iph, 41 struct ip_vs_conn_param *p) 42 { 43 if (likely(!ip_vs_iph_inverse(iph))) 44 ip_vs_conn_fill_param(ipvs, af, IPPROTO_UDP, 45 &iph->saddr, htons(PORT_ISAKMP), 46 &iph->daddr, htons(PORT_ISAKMP), p); 47 else 48 ip_vs_conn_fill_param(ipvs, af, IPPROTO_UDP, 49 &iph->daddr, htons(PORT_ISAKMP), 50 &iph->saddr, htons(PORT_ISAKMP), p); 51 } 52 53 static struct ip_vs_conn * 54 ah_esp_conn_in_get(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb, 55 const struct ip_vs_iphdr *iph) 56 { 57 struct ip_vs_conn *cp; 58 struct ip_vs_conn_param p; 59 60 ah_esp_conn_fill_param_proto(ipvs, af, iph, &p); 61 cp = ip_vs_conn_in_get(&p); 62 if (!cp) { 63 /* 64 * We are not sure if the packet is from our 65 * service, so our conn_schedule hook should return NF_ACCEPT 66 */ 67 IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet " 68 "%s%s %s->%s\n", 69 ip_vs_iph_icmp(iph) ? "ICMP+" : "", 70 ip_vs_proto_get(iph->protocol)->name, 71 IP_VS_DBG_ADDR(af, &iph->saddr), 72 IP_VS_DBG_ADDR(af, &iph->daddr)); 73 } 74 75 return cp; 76 } 77 78 79 static struct ip_vs_conn * 80 ah_esp_conn_out_get(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb, 81 const struct ip_vs_iphdr *iph) 82 { 83 struct ip_vs_conn *cp; 84 struct ip_vs_conn_param p; 85 86 ah_esp_conn_fill_param_proto(ipvs, af, iph, &p); 87 cp = ip_vs_conn_out_get(&p); 88 if (!cp) { 89 IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet " 90 "%s%s %s->%s\n", 91 ip_vs_iph_icmp(iph) ? "ICMP+" : "", 92 ip_vs_proto_get(iph->protocol)->name, 93 IP_VS_DBG_ADDR(af, &iph->saddr), 94 IP_VS_DBG_ADDR(af, &iph->daddr)); 95 } 96 97 return cp; 98 } 99 100 101 static int 102 ah_esp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb, 103 struct ip_vs_proto_data *pd, 104 int *verdict, struct ip_vs_conn **cpp, 105 struct ip_vs_iphdr *iph) 106 { 107 /* 108 * AH/ESP is only related traffic. Pass the packet to IP stack. 109 */ 110 *verdict = NF_ACCEPT; 111 return 0; 112 } 113 114 #ifdef CONFIG_IP_VS_PROTO_AH 115 struct ip_vs_protocol ip_vs_protocol_ah = { 116 .name = "AH", 117 .protocol = IPPROTO_AH, 118 .num_states = 1, 119 .dont_defrag = 1, 120 .init = NULL, 121 .exit = NULL, 122 .conn_schedule = ah_esp_conn_schedule, 123 .conn_in_get = ah_esp_conn_in_get, 124 .conn_out_get = ah_esp_conn_out_get, 125 .snat_handler = NULL, 126 .dnat_handler = NULL, 127 .state_transition = NULL, 128 .register_app = NULL, 129 .unregister_app = NULL, 130 .app_conn_bind = NULL, 131 .debug_packet = ip_vs_tcpudp_debug_packet, 132 .timeout_change = NULL, /* ISAKMP */ 133 }; 134 #endif 135 136 #ifdef CONFIG_IP_VS_PROTO_ESP 137 struct ip_vs_protocol ip_vs_protocol_esp = { 138 .name = "ESP", 139 .protocol = IPPROTO_ESP, 140 .num_states = 1, 141 .dont_defrag = 1, 142 .init = NULL, 143 .exit = NULL, 144 .conn_schedule = ah_esp_conn_schedule, 145 .conn_in_get = ah_esp_conn_in_get, 146 .conn_out_get = ah_esp_conn_out_get, 147 .snat_handler = NULL, 148 .dnat_handler = NULL, 149 .state_transition = NULL, 150 .register_app = NULL, 151 .unregister_app = NULL, 152 .app_conn_bind = NULL, 153 .debug_packet = ip_vs_tcpudp_debug_packet, 154 .timeout_change = NULL, /* ISAKMP */ 155 }; 156 #endif 157