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