blob: 301e0e1d0b32177b3b026b0f0586aec82328baf1 [file] [log] [blame]
Harald Weltec340f6c2003-11-11 18:41:36 +00001/* 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 Engelhardt32b8e612010-07-23 21:16:14 +02006#include <stdbool.h>
Harald Weltec340f6c2003-11-11 18:41:36 +00007#include <stdio.h>
8#include <string.h>
9#include <stdlib.h>
10#include <getopt.h>
Pablo Neira800938f2005-03-07 14:02:02 +000011#include <stddef.h>
Harald Weltec340f6c2003-11-11 18:41:36 +000012
13#if defined(__GLIBC__) && __GLIBC__ == 2
14#include <net/ethernet.h>
15#else
16#include <linux/if_ether.h>
17#endif
18
Jan Engelhardt5d9678a2008-11-20 10:15:35 +010019#include <xtables.h>
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020020#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
Harald Weltec340f6c2003-11-11 18:41:36 +000021
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020022enum {
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 Engelhardt1d5b63d2007-10-04 16:29:00 +000038static void CLUSTERIP_help(void)
Harald Weltec340f6c2003-11-11 18:41:36 +000039{
40 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020041"CLUSTERIP target options:\n"
Harald Weltec340f6c2003-11-11 18:41:36 +000042" --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 Engelhardt8b7c64d2008-04-15 11:48:25 +020050" --hash-init <num> Set init value of the Jenkins hash\n");
Harald Weltec340f6c2003-11-11 18:41:36 +000051}
52
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020053#define s struct ipt_clusterip_tgt_info
54static 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 Weltec340f6c2003-11-11 18:41:36 +000070};
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020071#undef s
Harald Weltec340f6c2003-11-11 18:41:36 +000072
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020073static void CLUSTERIP_parse(struct xt_option_call *cb)
Harald Weltec340f6c2003-11-11 18:41:36 +000074{
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020075 struct ipt_clusterip_tgt_info *cipinfo = cb->data;
Harald Weltec340f6c2003-11-11 18:41:36 +000076
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020077 xtables_option_parse(cb);
78 switch (cb->entry->id) {
79 case O_NEW:
Harald Weltec340f6c2003-11-11 18:41:36 +000080 cipinfo->flags |= CLUSTERIP_FLAG_NEW;
Harald Weltec340f6c2003-11-11 18:41:36 +000081 break;
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020082 case O_HASHMODE:
83 if (strcmp(cb->arg, "sourceip") == 0)
Harald Weltec340f6c2003-11-11 18:41:36 +000084 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP;
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020085 else if (strcmp(cb->arg, "sourceip-sourceport") == 0)
Harald Weltec340f6c2003-11-11 18:41:36 +000086 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT;
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020087 else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0)
Harald Weltec340f6c2003-11-11 18:41:36 +000088 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT;
89 else
Jan Engelhardt1829ed42009-02-21 03:29:44 +010090 xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n",
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020091 cb->arg);
Harald Weltec340f6c2003-11-11 18:41:36 +000092 break;
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020093 case O_CLUSTERMAC:
Harald Weltedb986e82003-11-26 12:50:38 +000094 if (!(cipinfo->clustermac[0] & 0x01))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010095 xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
Harald Weltec340f6c2003-11-11 18:41:36 +000096 break;
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +020097 case O_LOCAL_NODE:
Harald Weltec340f6c2003-11-11 18:41:36 +000098 cipinfo->num_local_nodes = 1;
KOVACS Krisztian3643aca2005-09-19 14:50:06 +000099 break;
Harald Weltec340f6c2003-11-11 18:41:36 +0000100 }
Harald Weltec340f6c2003-11-11 18:41:36 +0000101}
102
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +0200103static void CLUSTERIP_check(struct xt_fcheck_call *cb)
Harald Weltec340f6c2003-11-11 18:41:36 +0000104{
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +0200105 if (cb->xflags == 0)
Harald Weltec340f6c2003-11-11 18:41:36 +0000106 return;
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +0200107 if ((cb->xflags & F_FULL) == F_FULL)
Harald Weltec340f6c2003-11-11 18:41:36 +0000108 return;
109
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100110 xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
Harald Weltec340f6c2003-11-11 18:41:36 +0000111}
112
Jan Engelhardte814c8b2011-01-08 03:16:51 +0100113static const char *hashmode2str(enum clusterip_hashmode mode)
Harald Weltec340f6c2003-11-11 18:41:36 +0000114{
Jan Engelhardte814c8b2011-01-08 03:16:51 +0100115 const char *retstr;
Harald Weltec340f6c2003-11-11 18:41:36 +0000116 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 Engelhardte814c8b2011-01-08 03:16:51 +0100133static const char *mac2str(const uint8_t mac[ETH_ALEN])
Harald Weltec340f6c2003-11-11 18:41:36 +0000134{
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 Weltec340f6c2003-11-11 18:41:36 +0000140
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000141static void CLUSTERIP_print(const void *ip,
142 const struct xt_entry_target *target, int numeric)
Harald Weltec340f6c2003-11-11 18:41:36 +0000143{
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 Engelhardt73866352010-12-18 02:04:59 +0100148 printf(" CLUSTERIP");
Harald Weltec340f6c2003-11-11 18:41:36 +0000149 return;
150 }
151
Jan Engelhardt73866352010-12-18 02:04:59 +0100152 printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u",
Harald Weltec340f6c2003-11-11 18:41:36 +0000153 hashmode2str(cipinfo->hash_mode),
154 mac2str(cipinfo->clustermac),
155 cipinfo->num_total_nodes,
KOVACS Krisztian3643aca2005-09-19 14:50:06 +0000156 cipinfo->local_nodes[0],
157 cipinfo->hash_initval);
Harald Weltec340f6c2003-11-11 18:41:36 +0000158}
159
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000160static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target)
Harald Weltec340f6c2003-11-11 18:41:36 +0000161{
KOVACS Krisztian3643aca2005-09-19 14:50:06 +0000162 const struct ipt_clusterip_tgt_info *cipinfo =
163 (const struct ipt_clusterip_tgt_info *)target->data;
Harald Weltec340f6c2003-11-11 18:41:36 +0000164
KOVACS Krisztian3643aca2005-09-19 14:50:06 +0000165 /* 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 Engelhardt73866352010-12-18 02:04:59 +0100170 printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u",
KOVACS Krisztian3643aca2005-09-19 14:50:06 +0000171 hashmode2str(cipinfo->hash_mode),
172 mac2str(cipinfo->clustermac),
173 cipinfo->num_total_nodes,
174 cipinfo->local_nodes[0],
175 cipinfo->hash_initval);
Harald Weltec340f6c2003-11-11 18:41:36 +0000176}
177
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200178static struct xtables_target clusterip_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000179 .name = "CLUSTERIP",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200180 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100181 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200182 .size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)),
Pablo Neira800938f2005-03-07 14:02:02 +0000183 .userspacesize = offsetof(struct ipt_clusterip_tgt_info, config),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000184 .help = CLUSTERIP_help,
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +0200185 .x6_parse = CLUSTERIP_parse,
186 .x6_fcheck = CLUSTERIP_check,
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000187 .print = CLUSTERIP_print,
188 .save = CLUSTERIP_save,
Jan Engelhardt4eb3d6d2011-05-08 14:43:55 +0200189 .x6_options = CLUSTERIP_opts,
Harald Weltec340f6c2003-11-11 18:41:36 +0000190};
191
192void _init(void)
193{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200194 xtables_register_target(&clusterip_tg_reg);
Harald Weltec340f6c2003-11-11 18:41:36 +0000195}