b3bb6c4ac60968da4219eb66bdeef0f0764eab47
[mtetherd] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/sysctl.h>
10 #include <sys/wait.h>
11 #include <dbus/dbus.h>
12 //#include <hal/libhal.h>
13
14 static const char *INETDEV = "gprs0";
15 static const char *DEVICES[] = {
16         "bnep0",
17         "usb0",
18         NULL
19 };
20 static const char *ADDRESSES[] = {
21         "192.168.253.254",
22         "192.168.254.254",
23         NULL
24 };
25 static const char *STARTADDRESSES[] = {
26         "192.168.253.1",
27         "192.168.254.1",
28         NULL
29 };
30 static const char *ENDADDRESSES[] = {
31         "192.168.253.254",
32         "192.168.254.254",
33         NULL
34 };
35
36 static int running;
37 static unsigned int active;
38
39 static void sigIntHandler(int sig) {
40         fprintf(stderr, "SIGINIT received, exiting\n");
41         running = 0;
42 }
43
44 /*static void deviceAdded(LibHalContext *ctx, const char *udi) {
45         DBusError err;
46         dbus_error_init(&err);
47         char *device = libhal_device_get_property_string(ctx, udi, "net.interface", &err);
48         if (!device) {
49                 if (dbus_error_is_set(&err)) {
50                         fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
51                         dbus_error_free(&err);
52                 }
53         }
54         printf("Device %s added.\n", device);
55 }
56
57 static void deviceRemoved(LibHalContext *ctx, const char *udi) {
58         DBusError err;
59         dbus_error_init(&err);
60         char *device = libhal_device_get_property_string(ctx, udi, "net.interface", &err);
61         if (!device) {
62                 if (dbus_error_is_set(&err)) {
63                         fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
64                         dbus_error_free(&err);
65                 }
66         }
67         printf("Device %s removed.\n", device);
68 }*/
69
70 static int launch(const char *args[]) {
71         pid_t pid = fork();
72         if (pid == 0) {
73                 if (execv(args[0], (char **const) args) == -1) {
74                         fprintf(stderr, "Error launching external process %s: %s\n", args[0], strerror(errno));
75                         exit(1);
76                 }
77         } else if (pid == -1) {
78                 fprintf(stderr, "Can't fork external process %s: %s\n", args[0], strerror(errno));
79                 return -1;
80         } else {
81                 int status = 0;
82                 if (waitpid(pid, &status, 0) == -1) {
83                         perror("Error waiting for child process completion");
84                         return -1;
85                 }
86                 if (WIFEXITED(status)) {
87                         if (WEXITSTATUS(status) != 0) {
88                                 fprintf(stderr, "Child process returned error: %d\n", WEXITSTATUS(status));
89                                 return -1;
90                         }
91                 } else if (WIFSIGNALED(status)) {
92                         fprintf(stderr, "Child process killed by signal: %d\n", WTERMSIG(status));
93                         return -1;
94                 }
95         }
96         return 0;
97 }
98
99 static void added(const char *device, const char *inetdev, const char *address, const char *startaddress, const char *endaddress) {
100         printf("Got org.kernel.kevent.add on %s\n", device);
101         const char *ifconfig[] = { "/sbin/ifconfig", device, address, "up", NULL };
102         launch(ifconfig);
103         const char *modprobe[] = { "/sbin/modprobe", "ipt_MASQUERADE", NULL };
104         launch(modprobe);
105         const char *iptables[] = { "/usr/sbin/iptables", "-t", "nat", "-A", "POSTROUTING", "-o", inetdev, "-j", "MASQUERADE", NULL };
106         launch(iptables);
107         char *runfile = NULL;
108         asprintf(&runfile, "/var/run/tethering.%s.pid", device);
109         char *range = NULL;
110         asprintf(&range, "%s-%s,3600", startaddress, endaddress);
111         const char *dnsmasq[] = { "/sbin/start-stop-daemon", "-S", "-p", runfile, "-m", "-b", "-x", "/usr/sbin/dnsmasq", "--", "-k", "-I", "lo", "-i", device, "-a", address, "-z", "-F", range, NULL };
112         launch(dnsmasq);
113         free(range);
114         free(runfile);
115         char *forwsysctl = NULL;
116         asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", device);
117         int fd = open(forwsysctl, O_WRONLY, 0666);
118         if (fd < 0) {
119                 perror("Can't enable forwarding on PAN device");
120         } else {
121                 if (write(fd, "0", 1) == -1) {
122                         perror("Can't enable forwarding on PAN device");
123                 }
124                 close(fd);
125         }
126         free(forwsysctl);
127         asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", inetdev);
128         fd = open(forwsysctl, O_WRONLY, 0666);
129         if (fd < 0) {
130                 perror("Can't enable forwarding on WAN device");
131         } else {
132                 if (write(fd, "0", 1) == -1) {
133                         perror("Can't enable forwarding on WAN device");
134                 }
135                 close(fd);
136         }
137         free(forwsysctl);
138         active++;
139 }
140
141 static void removed(const char *device, const char *inetdev) {
142         printf("Got org.kernel.kevent.remove on %s\n", device);
143         char *runfile = NULL;
144         asprintf(&runfile, "/var/run/tethering.%s.pid", device);
145         const char *dnsmasq[] = { "/sbin/start-stop-daemon", "-K", "-p", runfile, "-x", "/usr/sbin/dnsmasq", NULL };
146         launch(dnsmasq);
147         free(runfile);
148         const char *iptables[] = { "/usr/sbin/iptables", "-t", "nat", "-D", "POSTROUTING", "-o", inetdev, "-j", "MASQUERADE", NULL };
149         launch(iptables);
150         if (active > 0) active--;
151         if (active == 0) {
152                 char *forwsysctl = NULL;
153                 asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", inetdev);
154                 int fd = open(forwsysctl, O_WRONLY, 0666);
155                 if (fd < 0) {
156                         perror("Can't disable forwarding on WAN device");
157                 } else {
158                         if (write(fd, "0", 1) == -1) {
159                                 perror("Can't disable forwarding on WAN device");
160                         }
161                         close(fd);
162                 }
163                 free(forwsysctl);
164         }
165 }
166
167 static int finddev(const char* device, const char *devices[]) {
168         int i;
169         for (i = 0; devices[i]; i++) {
170                 if (strcmp(device, devices[i]) == 0) {
171                         return i;
172                 }
173         }
174         return -1;
175 }
176
177 int main(int argc, const char *argv[]) {
178         running = 1;
179         active = 0;
180         signal(SIGINT, sigIntHandler);
181
182         DBusError err;
183         dbus_error_init(&err);
184         DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
185         if (dbus_error_is_set(&err)) {
186                 fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
187                 dbus_error_free(&err);
188         }
189         if (!conn) {
190                 return 1;
191         }
192         /*LibHalContext *ctx = libhal_ctx_new();
193         if (!ctx) {
194                 fprintf(stderr, "Error occured: Can't create HAL context.\n");
195                 return 2;
196         }
197         if (!libhal_ctx_set_dbus_connection(ctx, conn)) {
198                 fprintf(stderr, "Error occured: Can't assign DBUS connection to HAL context.\n");
199                 return 3;
200         }
201         if (!libhal_ctx_set_device_added(ctx, deviceAdded)) {
202                 fprintf(stderr, "Error occured: Can't set device added message handler.\n");
203                 return 4;
204         }
205         if (!libhal_ctx_set_device_removed(ctx, deviceRemoved)) {
206                 fprintf(stderr, "Error occured: Can't set device removed message handler.\n");
207                 return 4;
208         }
209         if (!libhal_ctx_init(ctx, &err)) {
210                 if (dbus_error_is_set(&err)) {
211                         fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
212                         dbus_error_free(&err);
213                 }
214                 return 5;
215         }
216         dbus_bool_t nodisc = TRUE;
217         while (running && nodisc) {
218                 nodisc = dbus_connection_read_write_dispatch(conn, 500);
219         }*/
220         //dbus_bus_add_match(conn, "type='signal',interface='org.freedesktop.Hal.Manager',member='DeviceAdded'", NULL);
221         //dbus_bus_add_match(conn, "type='signal',interface='org.freedesktop.Hal.Manager',member='DeviceRemoved'", NULL);
222         //dbus_bus_add_match(conn, "type='signal',interface='org.kernel.kevent',path='/org/kernel/class/net/bnep0'", NULL);
223         //dbus_bus_add_match(conn, "type='signal',interface='org.kernel.kevent',path='/org/kernel/class/net/usb0'", NULL);
224         int i;
225         for (i = 0; DEVICES[i]; i++) {
226                 char *filter = NULL;
227                 if (!asprintf(&filter, "type='signal',interface='org.kernel.kevent',path='/org/kernel/class/net/%s'", DEVICES[i])) {
228                         perror("Can't construct filter rule");
229                 } else {
230                         dbus_bus_add_match(conn, filter, NULL);
231                 }
232         }
233         dbus_connection_flush(conn);
234         while (running) {
235                 dbus_connection_read_write(conn, 500);
236                 DBusMessage* msg = dbus_connection_pop_message(conn);
237                 if (msg) {
238                         /*if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Manager", "DeviceAdded")) {
239                                 DBusMessageIter args;
240                                 if (!dbus_message_iter_init(msg, &args)) {
241                                         fprintf(stderr, "Message has no arguments!\n");
242                                 } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
243                                         fprintf(stderr, "Argument is not a string!\n");
244                                 } else {
245                                         char *sigvalue = NULL;
246                                         dbus_message_iter_get_basic(&args, &sigvalue);
247                                         fprintf(stderr, "Got DeviceAdded with value %s\n", sigvalue);
248                                 }
249                         } else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Manager", "DeviceRemoved")) {
250                                 DBusMessageIter args;
251                                 if (!dbus_message_iter_init(msg, &args)) {
252                                         fprintf(stderr, "Message has no arguments!\n");
253                                 } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
254                                         fprintf(stderr, "Argument is not a string!\n");
255                                 } else {
256                                         char *sigvalue = NULL;
257                                         dbus_message_iter_get_basic(&args, &sigvalue);
258                                         fprintf(stderr, "Got DeviceRemoved with value %s\n", sigvalue);
259                                 }
260                         } else */
261                         if (dbus_message_is_signal(msg, "org.kernel.kevent", "add")) {
262                                 char **path = NULL;
263                                 if (!dbus_message_get_path_decomposed(msg, &path)) {
264                                         fprintf(stderr, "Can't get add message path!\n");
265                                 } else {
266                                         unsigned int last;
267                                         for (last = 0; path[last] && last <= 6; last++);
268                                         if (last == 0 || last > 6) {
269                                                 fprintf(stderr, "Add message has no path or path too long!\n");
270                                         } else {
271                                                 int index = finddev(path[last - 1], DEVICES);
272                                                 if (index >= 0) {
273                                                         
274                                                         added(DEVICES[index], INETDEV, ADDRESSES[index], STARTADDRESSES[index], ENDADDRESSES[index]);
275                                                 }
276                                         }
277                                         dbus_free_string_array(path);
278                                 }
279                         } else if (dbus_message_is_signal(msg, "org.kernel.kevent", "remove")) {
280                                 char **path = NULL;
281                                 if (!dbus_message_get_path_decomposed(msg, &path)) {
282                                         fprintf(stderr, "Can't get remove message path!\n");
283                                 } else {
284                                         unsigned int last;
285                                         for (last = 0; path[last] && last <= 6; last++);
286                                         if (last == 0 || last > 6) {
287                                                 fprintf(stderr, "Remove message has no path or path too long!\n");
288                                         } else {
289                                                 int index = finddev(path[last - 1], DEVICES);
290                                                 if (index >= 0) {
291                                                         removed(DEVICES[index], INETDEV);
292                                                 }
293                                         }
294                                         dbus_free_string_array(path);
295                                 }
296                         }
297                         dbus_message_unref(msg);
298                 }
299         }
300         /*if (!libhal_ctx_shutdown(ctx, &err)) {
301                 if (dbus_error_is_set(&err)) {
302                         fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
303                         dbus_error_free(&err);
304                 }
305         }
306         libhal_ctx_free(ctx);*/
307         dbus_connection_unref(conn);
308         return 0;
309 }