Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 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 | */ |
Jan Engelhardt | 32b8e61 | 2010-07-23 21:16:14 +0200 | [diff] [blame] | 6 | #include <stdbool.h> |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 7 | #include <stdio.h> |
| 8 | #include <string.h> |
| 9 | #include <stdlib.h> |
| 10 | #include <getopt.h> |
Pablo Neira | 800938f | 2005-03-07 14:02:02 +0000 | [diff] [blame] | 11 | #include <stddef.h> |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 12 | |
| 13 | #if defined(__GLIBC__) && __GLIBC__ == 2 |
| 14 | #include <net/ethernet.h> |
| 15 | #else |
| 16 | #include <linux/if_ether.h> |
| 17 | #endif |
| 18 | |
Jan Engelhardt | 5d9678a | 2008-11-20 10:15:35 +0100 | [diff] [blame] | 19 | #include <xtables.h> |
Jan Engelhardt | a2a7f2b | 2008-09-01 14:20:13 +0200 | [diff] [blame] | 20 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 21 | |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 22 | enum { |
| 23 | O_NEW = 0, |
| 24 | O_HASHMODE, |
| 25 | O_CLUSTERMAC, |
| 26 | O_TOTAL_NODES, |
| 27 | O_LOCAL_NODE, |
| 28 | O_HASH_INIT, |
| 29 | F_NEW = 1 << O_NEW, |
| 30 | F_HASHMODE = 1 << O_HASHMODE, |
| 31 | F_CLUSTERMAC = 1 << O_CLUSTERMAC, |
| 32 | F_TOTAL_NODES = 1 << O_TOTAL_NODES, |
| 33 | F_LOCAL_NODE = 1 << O_LOCAL_NODE, |
| 34 | F_FULL = F_NEW | F_HASHMODE | F_CLUSTERMAC | |
| 35 | F_TOTAL_NODES | F_LOCAL_NODE, |
| 36 | }; |
| 37 | |
Jan Engelhardt | 1d5b63d | 2007-10-04 16:29:00 +0000 | [diff] [blame] | 38 | static void CLUSTERIP_help(void) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 39 | { |
| 40 | printf( |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 41 | "CLUSTERIP target options:\n" |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 42 | " --new Create a new ClusterIP\n" |
| 43 | " --hashmode <mode> Specify hashing mode\n" |
| 44 | " sourceip\n" |
| 45 | " sourceip-sourceport\n" |
| 46 | " sourceip-sourceport-destport\n" |
| 47 | " --clustermac <mac> Set clusterIP MAC address\n" |
| 48 | " --total-nodes <num> Set number of total nodes in cluster\n" |
| 49 | " --local-node <num> Set the local node number\n" |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 50 | " --hash-init <num> Set init value of the Jenkins hash\n"); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 51 | } |
| 52 | |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 53 | #define s struct ipt_clusterip_tgt_info |
| 54 | static const struct xt_option_entry CLUSTERIP_opts[] = { |
| 55 | {.name = "new", .id = O_NEW, .type = XTTYPE_NONE}, |
| 56 | {.name = "hashmode", .id = O_HASHMODE, .type = XTTYPE_STRING, |
| 57 | .also = O_NEW}, |
| 58 | {.name = "clustermac", .id = O_CLUSTERMAC, .type = XTTYPE_ETHERMAC, |
| 59 | .also = O_NEW, .flags = XTOPT_PUT, XTOPT_POINTER(s, clustermac)}, |
| 60 | {.name = "total-nodes", .id = O_TOTAL_NODES, .type = XTTYPE_UINT16, |
| 61 | .flags = XTOPT_PUT, XTOPT_POINTER(s, num_total_nodes), |
| 62 | .also = O_NEW, .max = CLUSTERIP_MAX_NODES}, |
| 63 | {.name = "local-node", .id = O_LOCAL_NODE, .type = XTTYPE_UINT16, |
| 64 | .flags = XTOPT_PUT, XTOPT_POINTER(s, local_nodes[0]), |
| 65 | .also = O_NEW, .max = CLUSTERIP_MAX_NODES}, |
| 66 | {.name = "hash-init", .id = O_HASH_INIT, .type = XTTYPE_UINT32, |
| 67 | .flags = XTOPT_PUT, XTOPT_POINTER(s, hash_initval), |
| 68 | .also = O_NEW, .max = UINT_MAX}, |
| 69 | XTOPT_TABLEEND, |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 70 | }; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 71 | #undef s |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 72 | |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 73 | static void CLUSTERIP_parse(struct xt_option_call *cb) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 74 | { |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 75 | struct ipt_clusterip_tgt_info *cipinfo = cb->data; |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 76 | |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 77 | xtables_option_parse(cb); |
| 78 | switch (cb->entry->id) { |
| 79 | case O_NEW: |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 80 | cipinfo->flags |= CLUSTERIP_FLAG_NEW; |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 81 | break; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 82 | case O_HASHMODE: |
| 83 | if (strcmp(cb->arg, "sourceip") == 0) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 84 | cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 85 | else if (strcmp(cb->arg, "sourceip-sourceport") == 0) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 86 | cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 87 | else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 88 | cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT; |
| 89 | else |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 90 | xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n", |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 91 | cb->arg); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 92 | break; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 93 | case O_CLUSTERMAC: |
Harald Welte | db986e8 | 2003-11-26 12:50:38 +0000 | [diff] [blame] | 94 | if (!(cipinfo->clustermac[0] & 0x01)) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 95 | xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n"); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 96 | break; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 97 | case O_LOCAL_NODE: |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 98 | cipinfo->num_local_nodes = 1; |
KOVACS Krisztian | 3643aca | 2005-09-19 14:50:06 +0000 | [diff] [blame] | 99 | break; |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 100 | } |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 101 | } |
| 102 | |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 103 | static void CLUSTERIP_check(struct xt_fcheck_call *cb) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 104 | { |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 105 | if (cb->xflags == 0) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 106 | return; |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 107 | if ((cb->xflags & F_FULL) == F_FULL) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 108 | return; |
| 109 | |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 110 | xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n"); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 111 | } |
| 112 | |
Jan Engelhardt | e814c8b | 2011-01-08 03:16:51 +0100 | [diff] [blame] | 113 | static const char *hashmode2str(enum clusterip_hashmode mode) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 114 | { |
Jan Engelhardt | e814c8b | 2011-01-08 03:16:51 +0100 | [diff] [blame] | 115 | const char *retstr; |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 116 | switch (mode) { |
| 117 | case CLUSTERIP_HASHMODE_SIP: |
| 118 | retstr = "sourceip"; |
| 119 | break; |
| 120 | case CLUSTERIP_HASHMODE_SIP_SPT: |
| 121 | retstr = "sourceip-sourceport"; |
| 122 | break; |
| 123 | case CLUSTERIP_HASHMODE_SIP_SPT_DPT: |
| 124 | retstr = "sourceip-sourceport-destport"; |
| 125 | break; |
| 126 | default: |
| 127 | retstr = "unknown-error"; |
| 128 | break; |
| 129 | } |
| 130 | return retstr; |
| 131 | } |
| 132 | |
Jan Engelhardt | e814c8b | 2011-01-08 03:16:51 +0100 | [diff] [blame] | 133 | static const char *mac2str(const uint8_t mac[ETH_ALEN]) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 134 | { |
| 135 | static char buf[ETH_ALEN*3]; |
| 136 | sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", |
| 137 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); |
| 138 | return buf; |
| 139 | } |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 140 | |
Jan Engelhardt | 1d5b63d | 2007-10-04 16:29:00 +0000 | [diff] [blame] | 141 | static void CLUSTERIP_print(const void *ip, |
| 142 | const struct xt_entry_target *target, int numeric) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 143 | { |
| 144 | const struct ipt_clusterip_tgt_info *cipinfo = |
| 145 | (const struct ipt_clusterip_tgt_info *)target->data; |
| 146 | |
| 147 | if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) { |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 148 | printf(" CLUSTERIP"); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 149 | return; |
| 150 | } |
| 151 | |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 152 | printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u", |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 153 | hashmode2str(cipinfo->hash_mode), |
| 154 | mac2str(cipinfo->clustermac), |
| 155 | cipinfo->num_total_nodes, |
KOVACS Krisztian | 3643aca | 2005-09-19 14:50:06 +0000 | [diff] [blame] | 156 | cipinfo->local_nodes[0], |
| 157 | cipinfo->hash_initval); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 158 | } |
| 159 | |
Jan Engelhardt | 1d5b63d | 2007-10-04 16:29:00 +0000 | [diff] [blame] | 160 | static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target) |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 161 | { |
KOVACS Krisztian | 3643aca | 2005-09-19 14:50:06 +0000 | [diff] [blame] | 162 | const struct ipt_clusterip_tgt_info *cipinfo = |
| 163 | (const struct ipt_clusterip_tgt_info *)target->data; |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 164 | |
KOVACS Krisztian | 3643aca | 2005-09-19 14:50:06 +0000 | [diff] [blame] | 165 | /* if this is not a new entry, we don't need to save target |
| 166 | * parameters */ |
| 167 | if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) |
| 168 | return; |
| 169 | |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 170 | printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u", |
KOVACS Krisztian | 3643aca | 2005-09-19 14:50:06 +0000 | [diff] [blame] | 171 | hashmode2str(cipinfo->hash_mode), |
| 172 | mac2str(cipinfo->clustermac), |
| 173 | cipinfo->num_total_nodes, |
| 174 | cipinfo->local_nodes[0], |
| 175 | cipinfo->hash_initval); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 176 | } |
| 177 | |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 178 | static struct xtables_target clusterip_tg_reg = { |
Pablo Neira | 8caee8b | 2004-12-28 13:11:59 +0000 | [diff] [blame] | 179 | .name = "CLUSTERIP", |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 180 | .version = XTABLES_VERSION, |
Jan Engelhardt | 03d9948 | 2008-11-18 12:27:54 +0100 | [diff] [blame] | 181 | .family = NFPROTO_IPV4, |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 182 | .size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)), |
Pablo Neira | 800938f | 2005-03-07 14:02:02 +0000 | [diff] [blame] | 183 | .userspacesize = offsetof(struct ipt_clusterip_tgt_info, config), |
Jan Engelhardt | 1d5b63d | 2007-10-04 16:29:00 +0000 | [diff] [blame] | 184 | .help = CLUSTERIP_help, |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 185 | .x6_parse = CLUSTERIP_parse, |
| 186 | .x6_fcheck = CLUSTERIP_check, |
Jan Engelhardt | 1d5b63d | 2007-10-04 16:29:00 +0000 | [diff] [blame] | 187 | .print = CLUSTERIP_print, |
| 188 | .save = CLUSTERIP_save, |
Jan Engelhardt | 4eb3d6d | 2011-05-08 14:43:55 +0200 | [diff] [blame] | 189 | .x6_options = CLUSTERIP_opts, |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 190 | }; |
| 191 | |
| 192 | void _init(void) |
| 193 | { |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 194 | xtables_register_target(&clusterip_tg_reg); |
Harald Welte | c340f6c | 2003-11-11 18:41:36 +0000 | [diff] [blame] | 195 | } |