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