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