* Wed Jun 23 2004 David Parrish <david@dparrish.com> 2.0.0
[l2tpns.git] / garden.c
1 #include <string.h>
2 #include <malloc.h>
3 #include <stdlib.h>
4 #include <sys/wait.h>
5 #include <sys/types.h>
6 #include "l2tpns.h"
7 #include "plugin.h"
8 #include "control.h"
9
10 int __plugin_api_version = 1;
11 static struct pluginfuncs *p = 0;
12
13 static int iam_master = 0; // We're all slaves! Slaves I tell you!
14
15 char *up_commands[] = {
16 "iptables -t nat -N garden >/dev/null 2>&1", // Create a chain that all gardened users will go through
17 "iptables -t nat -F garden",
18 ". " PLUGINCONF "/build-garden", // Populate with site-specific DNAT rules
19 "iptables -t nat -N garden_users >/dev/null 2>&1",// Empty chain, users added/removed by garden_session
20 "iptables -t nat -F garden_users",
21 "iptables -t nat -A PREROUTING -j garden_users", // DNAT any users on the garden_users chain
22 NULL,
23 };
24
25 char *down_commands[] = {
26 "iptables -t nat -F PREROUTING",
27 "iptables -t nat -F garden_users",
28 "iptables -t nat -X garden_users",
29 "iptables -t nat -F garden",
30 "iptables -t nat -X garden",
31 "rmmod iptable_nat ip_conntrack",
32 NULL,
33 };
34
35 int garden_session(sessiont *s, int flag);
36
37 int plugin_post_auth(struct param_post_auth *data)
38 {
39 // Ignore if user authentication was successful
40 if (data->auth_allowed) return PLUGIN_RET_OK;
41
42 p->log(3, 0, 0, 0, "Walled Garden allowing login\n");
43 data->auth_allowed = 1;
44 data->s->walled_garden = 1;
45 return PLUGIN_RET_OK;
46 }
47
48 int plugin_new_session(struct param_new_session *data)
49 {
50 if (!iam_master)
51 return PLUGIN_RET_OK; // Slaves don't do walled garden processing.
52
53 if (data->s->walled_garden)
54 garden_session(data->s, 1);
55
56 return PLUGIN_RET_OK;
57 }
58
59 int plugin_kill_session(struct param_new_session *data)
60 {
61 if (!iam_master)
62 return PLUGIN_RET_OK; // Slaves don't do walled garden processing.
63
64 if (data->s->walled_garden)
65 garden_session(data->s, 0);
66
67 return PLUGIN_RET_OK;
68 }
69
70 int plugin_control(struct param_control *data)
71 {
72 sessiont *s;
73 sessionidt session;
74
75 if (!iam_master) // All garden processing happens on the master.
76 return PLUGIN_RET_OK;
77
78 if (data->type != PKT_GARDEN && data->type != PKT_UNGARDEN)
79 return PLUGIN_RET_OK;
80
81 if (!data->data && data->data_length)
82 return PLUGIN_RET_OK;
83
84 session = atoi((char*)(data->data));
85 if (!session)
86 return PLUGIN_RET_OK;
87
88 data->send_response = 1;
89 s = p->get_session_by_id(session);
90 if (!s || !s->ip)
91 {
92 char *errormsg = "Session not connected";
93 *(short *)(data->response + 2) = ntohs(PKT_RESP_ERROR);
94 sprintf((data->response + data->response_length), "%s", errormsg);
95 data->response_length += strlen(errormsg) + 1;
96
97 p->log(3, 0, 0, 0, "Unknown session %d\n", session);
98 return PLUGIN_RET_STOP;
99 }
100 *(short *)(data->response + 2) = ntohs(PKT_RESP_OK);
101
102 if (!(garden_session(s, (data->type == PKT_GARDEN))))
103 {
104 char *errormsg = "User not connected";
105 *(short *)(data->response + 2) = ntohs(PKT_RESP_ERROR);
106 sprintf((data->response + data->response_length), "%s", errormsg);
107 data->response_length += strlen(errormsg) + 1;
108 }
109
110 return PLUGIN_RET_STOP;
111 }
112
113 int plugin_become_master(void)
114 {
115 int i;
116 iam_master = 1; // We just became the master. Wow!
117
118 for (i = 0; up_commands[i] && *up_commands[i]; i++)
119 {
120 p->log(3, 0, 0, 0, "Running %s\n", up_commands[i]);
121 system(up_commands[i]);
122 }
123
124 return PLUGIN_RET_OK;
125 }
126
127 // Called for each active session after becoming master
128 int plugin_new_session_master(sessiont * s)
129 {
130 if (s->walled_garden)
131 garden_session(s, 1);
132
133 return PLUGIN_RET_OK;
134 }
135
136 int garden_session(sessiont *s, int flag)
137 {
138 char cmd[2048];
139
140 if (!s) return 0;
141 if (!s->opened) return 0;
142
143 if (flag == 1)
144 {
145 p->log(2, 0, 0, s->tunnel, "Garden user %s (%s)\n", s->user, p->inet_toa(htonl(s->ip)));
146 snprintf(cmd, 2048, "iptables -t nat -A garden_users -s %s -j garden", p->inet_toa(htonl(s->ip)));
147 p->log(3, 0, 0, s->tunnel, "%s\n", cmd);
148 system(cmd);
149 s->walled_garden = 1;
150 }
151 else
152 {
153 sessionidt other;
154 int count = 40;
155
156 // Normal User
157 p->log(2, 0, 0, s->tunnel, "Un-Garden user %s (%s)\n", s->user, p->inet_toa(htonl(s->ip)));
158 // Kick off any duplicate usernames
159 // but make sure not to kick off ourself
160 if (s->ip && !s->die && (other = p->get_session_by_username(s->user)) && s != p->get_session_by_id(other)) {
161 p->sessionkill(other, "Duplicate session when user released from walled garden");
162 }
163 /* Clean up counters */
164 s->cin = s->cout = 0;
165 s->pin = s->pout = 0;
166
167 snprintf(cmd, 2048, "iptables -t nat -D garden_users -s %s -j garden", p->inet_toa(htonl(s->ip)));
168 p->log(3, 0, 0, s->tunnel, "%s\n", cmd);
169 while (--count)
170 {
171 int status = system(cmd);
172 if (WEXITSTATUS(status) != 0) break;
173 }
174
175 s->walled_garden = 0;
176
177 if (!s->die) {
178 /* OK, we're up! */
179 u16 r = p->radiusnew(p->get_id_by_session(s));
180 p->radiussend(r, RADIUSSTART);
181 }
182 }
183 s->walled_garden = flag;
184 return 1;
185 }
186
187 int plugin_init(struct pluginfuncs *funcs)
188 {
189 FILE *tables;
190 int found_nat = 0;
191
192 if (!funcs)
193 return 0;
194
195 p = funcs;
196
197 if ((tables = fopen("/proc/net/ip_tables_names", "r")))
198 {
199 char buf[1024];
200 while (fgets(buf, sizeof(buf), tables) && !found_nat)
201 found_nat = !strcmp(buf, "nat\n");
202
203 fclose(tables);
204 }
205
206 /* master killed/crashed? */
207 if (found_nat)
208 {
209 int i;
210 for (i = 0; down_commands[i] && *down_commands[i]; i++)
211 {
212 p->log(3, 0, 0, 0, "Running %s\n", down_commands[i]);
213 system(down_commands[i]);
214 }
215 }
216
217 return 1;
218 }
219
220 void plugin_done()
221 {
222 int i;
223
224 if (!iam_master) // Never became master. nothing to do.
225 return;
226
227 for (i = 0; down_commands[i] && *down_commands[i]; i++)
228 {
229 p->log(3, 0, 0, 0, "Running %s\n", down_commands[i]);
230 system(down_commands[i]);
231 }
232 }
233