forked from freifunk-gluon/ddhcpd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hook.c
149 lines (116 loc) · 3.09 KB
/
hook.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "hook.h"
#include "logger.h"
#include "tools.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
ATTR_NONNULL_ALL void hook_address(uint8_t type, struct in_addr* address, uint8_t* chaddr, ddhcp_config* config) {
#if LOG_LEVEL_LIMIT >= LOG_DEBUG
char* hwaddr = hwaddr2c(chaddr);
DEBUG("hook_address(type:%i,addr:%s,chaddr:%s,config)\n", type, inet_ntoa(*address), hwaddr);
free(hwaddr);
#endif
if (!config->hook_command) {
DEBUG("hook_address(...): No hook command set\n");
return;
}
int pid;
char* action = NULL;
switch (type) {
case HOOK_LEASE:
action = (char*)"lease";
break;
case HOOK_RELEASE:
action = (char*)"release";
break;
default:
break;
}
if (!action) {
DEBUG("hook_address(...): unknown hook type: %i\n", type);
return;
}
pid = fork();
if (pid < 0) {
// TODO: Include errno from fork
FATAL("hook_address(...): Failed to fork() for hook command execution (errno: %i).\n", pid);
return;
}
if (pid != 0) {
//Nothing to do as the parent
return;
}
int err = execl(
// Binary to execute
"/bin/sh",
// Arguments to pass
"/bin/sh", //Be pedantic about executing /bin/sh
"-e", // Terminate on error return
"--", // Terminate argument parsing
config->hook_command, // Our actual command to run
action, // The action we notify about
inet_ntoa(*address), // The affected IP address
hwaddr2c(chaddr), // The affected MAC address
(char*) NULL // End of command line
);
if (err < 0) {
// TODO: Logging from the child should be synchronized
FATAL("hook_address(...): Command could not be executed (errno: %i).\n", err);
}
exit(1);
}
ATTR_NONNULL_ALL void hook(uint8_t type, ddhcp_config* config) {
DEBUG("hook(type:%i,config)\n", type);
if (!config->hook_command) {
DEBUG("hook_address(...): No hook command set\n");
return;
}
int pid;
char* action = NULL;
switch (type) {
case HOOK_LEARNING_PHASE_END:
action = (char*)"endlearning";
break;
default:
break;
}
if (!action) {
DEBUG("hook(...): unknown hook type: %i\n", type);
return;
}
pid = fork();
if (pid < 0) {
// TODO: Include errno from fork
FATAL("hook(...): Failed to fork() for hook command execution (errno: %i).\n", pid);
return;
}
if (pid != 0) {
//Nothing to do as the parent
return;
}
int err = execl(
// Binary to execute
"/bin/sh",
// Arguments to pass
"/bin/sh", //Be pedantic about executing /bin/sh
"-e", // Terminate on error return
"--", // Terminate argument parsing
config->hook_command, // Our actual command to run
action, // The action we notify about
(char*) NULL // End of command line
);
if (err < 0) {
// TODO: Logging from the child should be synchronized
FATAL("hook(...): Command could not be executed (errno: %i).\n", err);
}
exit(1);
}
void cleanup_process_table(int signum)
{
UNUSED(signum);
DEBUG("cleanup_process_table(...): Got signal %i\n", signum);
wait(NULL);
}
void hook_init() {
signal(SIGCHLD, cleanup_process_table);
}