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