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
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
CLUSTERIP_help(void)38 static void CLUSTERIP_help(void)
39 {
40 printf(
41 "CLUSTERIP target options:\n"
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"
50 " --hash-init <num> Set init value of the Jenkins hash\n");
51 }
52
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,
70 };
71 #undef s
72
CLUSTERIP_parse(struct xt_option_call * cb)73 static void CLUSTERIP_parse(struct xt_option_call *cb)
74 {
75 struct ipt_clusterip_tgt_info *cipinfo = cb->data;
76
77 xtables_option_parse(cb);
78 switch (cb->entry->id) {
79 case O_NEW:
80 cipinfo->flags |= CLUSTERIP_FLAG_NEW;
81 break;
82 case O_HASHMODE:
83 if (strcmp(cb->arg, "sourceip") == 0)
84 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP;
85 else if (strcmp(cb->arg, "sourceip-sourceport") == 0)
86 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT;
87 else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0)
88 cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT;
89 else
90 xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n",
91 cb->arg);
92 break;
93 case O_CLUSTERMAC:
94 if (!(cipinfo->clustermac[0] & 0x01))
95 xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
96 break;
97 case O_LOCAL_NODE:
98 cipinfo->num_local_nodes = 1;
99 break;
100 }
101 }
102
CLUSTERIP_check(struct xt_fcheck_call * cb)103 static void CLUSTERIP_check(struct xt_fcheck_call *cb)
104 {
105 if (cb->xflags == 0)
106 return;
107 if ((cb->xflags & F_FULL) == F_FULL)
108 return;
109
110 xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
111 }
112
hashmode2str(enum clusterip_hashmode mode)113 static const char *hashmode2str(enum clusterip_hashmode mode)
114 {
115 const char *retstr;
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
mac2str(const uint8_t mac[ETH_ALEN])133 static const char *mac2str(const uint8_t mac[ETH_ALEN])
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 }
140
CLUSTERIP_print(const void * ip,const struct xt_entry_target * target,int numeric)141 static void CLUSTERIP_print(const void *ip,
142 const struct xt_entry_target *target, int numeric)
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)) {
148 printf(" CLUSTERIP");
149 return;
150 }
151
152 printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u",
153 hashmode2str(cipinfo->hash_mode),
154 mac2str(cipinfo->clustermac),
155 cipinfo->num_total_nodes,
156 cipinfo->local_nodes[0],
157 cipinfo->hash_initval);
158 }
159
CLUSTERIP_save(const void * ip,const struct xt_entry_target * target)160 static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target)
161 {
162 const struct ipt_clusterip_tgt_info *cipinfo =
163 (const struct ipt_clusterip_tgt_info *)target->data;
164
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
170 printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u",
171 hashmode2str(cipinfo->hash_mode),
172 mac2str(cipinfo->clustermac),
173 cipinfo->num_total_nodes,
174 cipinfo->local_nodes[0],
175 cipinfo->hash_initval);
176 }
177
178 static struct xtables_target clusterip_tg_reg = {
179 .name = "CLUSTERIP",
180 .version = XTABLES_VERSION,
181 .family = NFPROTO_IPV4,
182 .size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)),
183 .userspacesize = offsetof(struct ipt_clusterip_tgt_info, config),
184 .help = CLUSTERIP_help,
185 .x6_parse = CLUSTERIP_parse,
186 .x6_fcheck = CLUSTERIP_check,
187 .print = CLUSTERIP_print,
188 .save = CLUSTERIP_save,
189 .x6_options = CLUSTERIP_opts,
190 };
191
_init(void)192 void _init(void)
193 {
194 xtables_register_target(&clusterip_tg_reg);
195 }
196