libipt_CLUSTERIP.c revision 7ac405297ec38449b30e3b05fd6bf2082fd3d803
1/* Shared library add-on to iptables to add CLUSTERIP target support. 2 * (C) 2003 by Harald Welte <laforge@gnumonks.org> 3 * 4 * Development of this code was funded by SuSE AG, http://www.suse.com/ 5 */ 6#include <stdbool.h> 7#include <stdio.h> 8#include <string.h> 9#include <stdlib.h> 10#include <getopt.h> 11#include <stddef.h> 12 13#if defined(__GLIBC__) && __GLIBC__ == 2 14#include <net/ethernet.h> 15#else 16#include <linux/if_ether.h> 17#endif 18 19#include <xtables.h> 20#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> 21 22static void CLUSTERIP_help(void) 23{ 24 printf( 25"CLUSTERIP target options:\n" 26" --new Create a new ClusterIP\n" 27" --hashmode <mode> Specify hashing mode\n" 28" sourceip\n" 29" sourceip-sourceport\n" 30" sourceip-sourceport-destport\n" 31" --clustermac <mac> Set clusterIP MAC address\n" 32" --total-nodes <num> Set number of total nodes in cluster\n" 33" --local-node <num> Set the local node number\n" 34" --hash-init <num> Set init value of the Jenkins hash\n"); 35} 36 37#define PARAM_NEW 0x0001 38#define PARAM_HMODE 0x0002 39#define PARAM_MAC 0x0004 40#define PARAM_TOTALNODE 0x0008 41#define PARAM_LOCALNODE 0x0010 42#define PARAM_HASHINIT 0x0020 43 44static const struct option CLUSTERIP_opts[] = { 45 {.name = "new", .has_arg = false, .val = '1'}, 46 {.name = "hashmode", .has_arg = true, .val = '2'}, 47 {.name = "clustermac", .has_arg = true, .val = '3'}, 48 {.name = "total-nodes", .has_arg = true, .val = '4'}, 49 {.name = "local-node", .has_arg = true, .val = '5'}, 50 {.name = "hash-init", .has_arg = true, .val = '6'}, 51 XT_GETOPT_TABLEEND, 52}; 53 54static void 55parse_mac(const char *mac, char *macbuf) 56{ 57 unsigned int i = 0; 58 59 if (strlen(mac) != ETH_ALEN*3-1) 60 xtables_error(PARAMETER_PROBLEM, "Bad mac address \"%s\"", mac); 61 62 for (i = 0; i < ETH_ALEN; i++) { 63 long number; 64 char *end; 65 66 number = strtol(mac + i*3, &end, 16); 67 68 if (end == mac + i*3 + 2 69 && number >= 0 70 && number <= 255) 71 macbuf[i] = number; 72 else 73 xtables_error(PARAMETER_PROBLEM, 74 "Bad mac address `%s'", mac); 75 } 76} 77 78static int CLUSTERIP_parse(int c, char **argv, int invert, unsigned int *flags, 79 const void *entry, struct xt_entry_target **target) 80{ 81 struct ipt_clusterip_tgt_info *cipinfo 82 = (struct ipt_clusterip_tgt_info *)(*target)->data; 83 84 switch (c) { 85 unsigned int num; 86 case '1': 87 cipinfo->flags |= CLUSTERIP_FLAG_NEW; 88 if (*flags & PARAM_NEW) 89 xtables_error(PARAMETER_PROBLEM, "Can only specify \"--new\" once\n"); 90 *flags |= PARAM_NEW; 91 break; 92 case '2': 93 if (!(*flags & PARAM_NEW)) 94 xtables_error(PARAMETER_PROBLEM, "Can only specify hashmode combined with \"--new\"\n"); 95 if (*flags & PARAM_HMODE) 96 xtables_error(PARAMETER_PROBLEM, "Can only specify hashmode once\n"); 97 if (!strcmp(optarg, "sourceip")) 98 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP; 99 else if (!strcmp(optarg, "sourceip-sourceport")) 100 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT; 101 else if (!strcmp(optarg, "sourceip-sourceport-destport")) 102 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT; 103 else 104 xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n", 105 optarg); 106 *flags |= PARAM_HMODE; 107 break; 108 case '3': 109 if (!(*flags & PARAM_NEW)) 110 xtables_error(PARAMETER_PROBLEM, "Can only specify MAC combined with \"--new\"\n"); 111 if (*flags & PARAM_MAC) 112 xtables_error(PARAMETER_PROBLEM, "Can only specify MAC once\n"); 113 parse_mac(optarg, (char *)cipinfo->clustermac); 114 if (!(cipinfo->clustermac[0] & 0x01)) 115 xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n"); 116 *flags |= PARAM_MAC; 117 break; 118 case '4': 119 if (!(*flags & PARAM_NEW)) 120 xtables_error(PARAMETER_PROBLEM, "Can only specify node number combined with \"--new\"\n"); 121 if (*flags & PARAM_TOTALNODE) 122 xtables_error(PARAMETER_PROBLEM, "Can only specify total node number once\n"); 123 if (!xtables_strtoui(optarg, NULL, &num, 1, CLUSTERIP_MAX_NODES)) 124 xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg); 125 cipinfo->num_total_nodes = num; 126 *flags |= PARAM_TOTALNODE; 127 break; 128 case '5': 129 if (!(*flags & PARAM_NEW)) 130 xtables_error(PARAMETER_PROBLEM, "Can only specify node number combined with \"--new\"\n"); 131 if (*flags & PARAM_LOCALNODE) 132 xtables_error(PARAMETER_PROBLEM, "Can only specify local node number once\n"); 133 if (!xtables_strtoui(optarg, NULL, &num, 1, CLUSTERIP_MAX_NODES)) 134 xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg); 135 cipinfo->num_local_nodes = 1; 136 cipinfo->local_nodes[0] = num; 137 *flags |= PARAM_LOCALNODE; 138 break; 139 case '6': 140 if (!(*flags & PARAM_NEW)) 141 xtables_error(PARAMETER_PROBLEM, "Can only specify hash init value combined with \"--new\"\n"); 142 if (*flags & PARAM_HASHINIT) 143 xtables_error(PARAMETER_PROBLEM, "Can specify hash init value only once\n"); 144 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT_MAX)) 145 xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg); 146 cipinfo->hash_initval = num; 147 *flags |= PARAM_HASHINIT; 148 break; 149 default: 150 return 0; 151 } 152 153 return 1; 154} 155 156static void CLUSTERIP_check(unsigned int flags) 157{ 158 if (flags == 0) 159 return; 160 161 if ((flags & (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE)) 162 == (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE)) 163 return; 164 165 xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n"); 166} 167 168static char *hashmode2str(enum clusterip_hashmode mode) 169{ 170 char *retstr; 171 switch (mode) { 172 case CLUSTERIP_HASHMODE_SIP: 173 retstr = "sourceip"; 174 break; 175 case CLUSTERIP_HASHMODE_SIP_SPT: 176 retstr = "sourceip-sourceport"; 177 break; 178 case CLUSTERIP_HASHMODE_SIP_SPT_DPT: 179 retstr = "sourceip-sourceport-destport"; 180 break; 181 default: 182 retstr = "unknown-error"; 183 break; 184 } 185 return retstr; 186} 187 188static char *mac2str(const uint8_t mac[ETH_ALEN]) 189{ 190 static char buf[ETH_ALEN*3]; 191 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", 192 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 193 return buf; 194} 195 196static void CLUSTERIP_print(const void *ip, 197 const struct xt_entry_target *target, int numeric) 198{ 199 const struct ipt_clusterip_tgt_info *cipinfo = 200 (const struct ipt_clusterip_tgt_info *)target->data; 201 202 if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) { 203 printf("CLUSTERIP"); 204 return; 205 } 206 207 printf("CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u", 208 hashmode2str(cipinfo->hash_mode), 209 mac2str(cipinfo->clustermac), 210 cipinfo->num_total_nodes, 211 cipinfo->local_nodes[0], 212 cipinfo->hash_initval); 213} 214 215static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target) 216{ 217 const struct ipt_clusterip_tgt_info *cipinfo = 218 (const struct ipt_clusterip_tgt_info *)target->data; 219 220 /* if this is not a new entry, we don't need to save target 221 * parameters */ 222 if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) 223 return; 224 225 printf("--new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u", 226 hashmode2str(cipinfo->hash_mode), 227 mac2str(cipinfo->clustermac), 228 cipinfo->num_total_nodes, 229 cipinfo->local_nodes[0], 230 cipinfo->hash_initval); 231} 232 233static struct xtables_target clusterip_tg_reg = { 234 .name = "CLUSTERIP", 235 .version = XTABLES_VERSION, 236 .family = NFPROTO_IPV4, 237 .size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)), 238 .userspacesize = offsetof(struct ipt_clusterip_tgt_info, config), 239 .help = CLUSTERIP_help, 240 .parse = CLUSTERIP_parse, 241 .final_check = CLUSTERIP_check, 242 .print = CLUSTERIP_print, 243 .save = CLUSTERIP_save, 244 .extra_opts = CLUSTERIP_opts, 245}; 246 247void _init(void) 248{ 249 xtables_register_target(&clusterip_tg_reg); 250} 251