1 /* Shared library add-on to iptables to add CLUSTERIP target support.
2 * (C) 2003 by Harald Welte <[email protected]>
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,
91 "Unknown hashmode \"%s\"", cb->arg);
92 break;
93 case O_CLUSTERMAC:
94 if (!(cipinfo->clustermac[0] & 0x01))
95 xtables_error(PARAMETER_PROBLEM,
96 "MAC has to be a multicast ethernet address");
97 break;
98 case O_LOCAL_NODE:
99 cipinfo->num_local_nodes = 1;
100 break;
101 }
102 }
103
CLUSTERIP_check(struct xt_fcheck_call * cb)104 static void CLUSTERIP_check(struct xt_fcheck_call *cb)
105 {
106 if (cb->xflags == 0)
107 return;
108 if ((cb->xflags & F_FULL) == F_FULL)
109 return;
110
111 xtables_error(PARAMETER_PROBLEM,
112 "CLUSTERIP target: Invalid parameter combination");
113 }
114
hashmode2str(enum clusterip_hashmode mode)115 static const char *hashmode2str(enum clusterip_hashmode mode)
116 {
117 const char *retstr;
118 switch (mode) {
119 case CLUSTERIP_HASHMODE_SIP:
120 retstr = "sourceip";
121 break;
122 case CLUSTERIP_HASHMODE_SIP_SPT:
123 retstr = "sourceip-sourceport";
124 break;
125 case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
126 retstr = "sourceip-sourceport-destport";
127 break;
128 default:
129 retstr = "unknown-error";
130 break;
131 }
132 return retstr;
133 }
134
mac2str(const uint8_t mac[ETH_ALEN])135 static const char *mac2str(const uint8_t mac[ETH_ALEN])
136 {
137 static char buf[ETH_ALEN*3];
138 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
139 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
140 return buf;
141 }
142
CLUSTERIP_print(const void * ip,const struct xt_entry_target * target,int numeric)143 static void CLUSTERIP_print(const void *ip,
144 const struct xt_entry_target *target, int numeric)
145 {
146 const struct ipt_clusterip_tgt_info *cipinfo =
147 (const struct ipt_clusterip_tgt_info *)target->data;
148
149 if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
150 printf(" CLUSTERIP");
151 return;
152 }
153
154 printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u",
155 hashmode2str(cipinfo->hash_mode),
156 mac2str(cipinfo->clustermac),
157 cipinfo->num_total_nodes,
158 cipinfo->local_nodes[0],
159 cipinfo->hash_initval);
160 }
161
CLUSTERIP_save(const void * ip,const struct xt_entry_target * target)162 static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target)
163 {
164 const struct ipt_clusterip_tgt_info *cipinfo =
165 (const struct ipt_clusterip_tgt_info *)target->data;
166
167 /* if this is not a new entry, we don't need to save target
168 * parameters */
169 if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW))
170 return;
171
172 printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u",
173 hashmode2str(cipinfo->hash_mode),
174 mac2str(cipinfo->clustermac),
175 cipinfo->num_total_nodes,
176 cipinfo->local_nodes[0],
177 cipinfo->hash_initval);
178 }
179
180 static struct xtables_target clusterip_tg_reg = {
181 .name = "CLUSTERIP",
182 .version = XTABLES_VERSION,
183 .family = NFPROTO_IPV4,
184 .size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)),
185 .userspacesize = offsetof(struct ipt_clusterip_tgt_info, config),
186 .help = CLUSTERIP_help,
187 .x6_parse = CLUSTERIP_parse,
188 .x6_fcheck = CLUSTERIP_check,
189 .print = CLUSTERIP_print,
190 .save = CLUSTERIP_save,
191 .x6_options = CLUSTERIP_opts,
192 };
193
_init(void)194 void _init(void)
195 {
196 xtables_register_target(&clusterip_tg_reg);
197 }
198