- startet importing pluto ASN1 stuff
[strongswan.git] / Source / stroke / stroke.c
1 /* Stroke for charon is the counterpart to whack from pluto
2 * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
20 #include <sys/fcntl.h>
21 #include <unistd.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <linux/stddef.h>
26
27 #include "stroke.h"
28
29 static char* push_string(stroke_msg_t **strm, char *string)
30 {
31 stroke_msg_t *stroke_msg;
32 size_t string_length;
33
34 if (string == NULL)
35 {
36 return NULL;
37 }
38 stroke_msg = *strm;
39 string_length = strlen(string) + 1;
40 stroke_msg->length += string_length;
41
42 stroke_msg = realloc(stroke_msg, stroke_msg->length);
43 strcpy((char*)stroke_msg + stroke_msg->length - string_length, string);
44
45 *strm = stroke_msg;
46 return (char*)(u_int)stroke_msg->length - string_length;
47 }
48
49 static int send_stroke_msg (stroke_msg_t *msg)
50 {
51 struct sockaddr_un ctl_addr = { AF_UNIX, STROKE_SOCKET };
52 int sock;
53 char buffer[64];
54 int byte_count;
55
56 sock = socket(AF_UNIX, SOCK_STREAM, 0);
57 if (sock < 0)
58 {
59 fprintf(stderr, "Opening unix socket %s: %s\n", STROKE_SOCKET, strerror(errno));
60 return -1;
61 }
62 if (connect(sock, (struct sockaddr *)&ctl_addr,
63 offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
64 {
65 fprintf(stderr, "Connect to socket failed: %s\n", strerror(errno));
66 close(sock);
67 return -1;
68 }
69
70 /* send message */
71 if (write(sock, msg, msg->length) != msg->length)
72 {
73 fprintf(stderr, "writing to socket failed: %s\n", strerror(errno));
74 close(sock);
75 return -1;
76 }
77
78 while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0)
79 {
80 buffer[byte_count] = '\0';
81 printf("%s", buffer);
82 }
83 if (byte_count < 0)
84 {
85 fprintf(stderr, "reading from socket failed: %s\n", strerror(errno));
86 }
87
88 close(sock);
89 return 0;
90 }
91
92 static int add_connection(char *name,
93 char *my_id, char *other_id,
94 char *my_cert, char *other_cert,
95 char *my_addr, char *other_addr,
96 char *my_net, char *other_net,
97 u_int my_netmask, u_int other_netmask)
98 {
99 stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
100 int res;
101
102 msg->length = sizeof(stroke_msg_t);
103 msg->type = STR_ADD_CONN;
104
105 msg->add_conn.name = push_string(&msg, name);
106
107 msg->add_conn.me.id = push_string(&msg, my_id);
108 msg->add_conn.me.cert = push_string(&msg, my_cert);
109 msg->add_conn.me.address = push_string(&msg, my_addr);
110 msg->add_conn.me.subnet = push_string(&msg, my_net);
111 msg->add_conn.me.subnet_mask = my_netmask;
112
113 msg->add_conn.other.id = push_string(&msg, other_id);
114 msg->add_conn.other.cert = push_string(&msg, other_cert);
115 msg->add_conn.other.address = push_string(&msg, other_addr);
116 msg->add_conn.other.subnet = push_string(&msg, other_net);
117 msg->add_conn.other.subnet_mask = other_netmask;
118
119 res = send_stroke_msg(msg);
120 free(msg);
121 return res;
122 }
123
124 static int initiate_connection(char *name)
125 {
126 stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
127 int res;
128
129 msg->length = sizeof(stroke_msg_t);
130 msg->type = STR_INITIATE;
131 msg->initiate.name = push_string(&msg, name);
132 res = send_stroke_msg(msg);
133 free(msg);
134 return res;
135 }
136
137 static int terminate_connection(char *name)
138 {
139 stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
140 int res;
141
142 msg->length = sizeof(stroke_msg_t);
143 msg->type = STR_TERMINATE;
144 msg->initiate.name = push_string(&msg, name);
145 res = send_stroke_msg(msg);
146 free(msg);
147 return res;
148 }
149
150 static int show_status()
151 {
152 stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
153 int res;
154
155 msg->length = sizeof(stroke_msg_t);
156 msg->type = STR_STATUS;
157 res = send_stroke_msg(msg);
158 free(msg);
159 return res;
160 }
161
162 static int set_logtype(char *context, char *type, int enable)
163 {
164 stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
165 int res;
166
167 msg->length = sizeof(stroke_msg_t);
168 msg->type = STR_LOGTYPE;
169 msg->logtype.context = push_string(&msg, context);
170 msg->logtype.type = push_string(&msg, type);
171 msg->logtype.enable = enable;
172 res = send_stroke_msg(msg);
173 free(msg);
174 return res;
175 }
176
177 static int set_loglevel(char *context, u_int level)
178 {
179 stroke_msg_t *msg = malloc(sizeof(stroke_msg_t));
180 int res;
181
182 msg->length = sizeof(stroke_msg_t);
183 msg->type = STR_LOGLEVEL;
184 msg->loglevel.context = push_string(&msg, context);
185 msg->loglevel.level = level;
186 res = send_stroke_msg(msg);
187 free(msg);
188 return res;
189 }
190
191 static void exit_error(char *error)
192 {
193 if (error)
194 {
195 fprintf(stderr, "%s\n", error);
196 }
197 exit(-1);
198 }
199
200 static void exit_usage(char *error)
201 {
202 printf("Usage:\n");
203 printf(" Add a connection:\n");
204 printf(" stroke add NAME MY_ID OTHER_ID MY_CERT OTHER_CERT\\\n");
205 printf(" MY_ADDR OTHER_ADDR MY_NET OTHER_NET\\\n");
206 printf(" MY_NETBITS OTHER_NETBITS\n");
207 printf(" where: ID is any IKEv2 ID (currently only IPv4 adresses\n");
208 printf(" CERT is a certificate filename\n");
209 printf(" ADDR is a IPv4 address\n");
210 printf(" NET is a IPv4 address of the subnet to tunnel\n");
211 printf(" NETBITS is the size of the subnet, as the \"24\" in 192.168.0.0/24\n");
212 printf(" Initiate a connection:\n");
213 printf(" stroke up NAME\n");
214 printf(" where: NAME is a connection name added with \"stroke add\"\n");
215 printf(" Terminate a connection:\n");
216 printf(" stroke down NAME\n");
217 printf(" where: NAME is a connection name added with \"stroke add\"\n");
218 printf(" Set logtype for a logging context:\n");
219 printf(" stroke logtype CONTEXT TYPE ENABLE\n");
220 printf(" where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
221 printf(" SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
222 printf(" TYPE is CONTROL|ERROR|AUDIT|RAW|PRIVATE\n");
223 printf(" ENABLE is 0|1\n");
224 printf(" Set loglevel for a logging context:\n");
225 printf(" stroke loglevel CONTEXT LEVEL\n");
226 printf(" where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
227 printf(" SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
228 printf(" LEVEL is 0|1|2|3\n");
229 printf(" Show connection status:\n");
230 printf(" stroke status\n");
231 exit_error(error);
232 }
233
234 int main(int argc, char *argv[])
235 {
236 int res;
237
238 if (argc < 2)
239 {
240 exit_usage(NULL);
241 }
242
243 if (strcmp(argv[1], "status") == 0 ||
244 strcmp(argv[1], "statusall") == 0)
245 {
246 res = show_status();
247 }
248
249 else if (strcmp(argv[1], "up") == 0)
250 {
251 if (argc < 3)
252 {
253 exit_usage("\"up\" needs a connection name");
254 }
255 res = initiate_connection(argv[2]);
256 }
257 else if (strcmp(argv[1], "down") == 0)
258 {
259 if (argc < 3)
260 {
261 exit_usage("\"down\" needs a connection name");
262 }
263 res = terminate_connection(argv[2]);
264 }
265 else if (strcmp(argv[1], "add") == 0)
266 {
267 if (argc < 13)
268 {
269 exit_usage("\"add\" needs more parameters...");
270 }
271 res = add_connection(argv[2],
272 argv[3], argv[4],
273 argv[5], argv[6],
274 argv[7], argv[8],
275 argv[9], argv[10],
276 atoi(argv[11]), atoi(argv[12]));
277 }
278 else if (strcmp(argv[1], "logtype") == 0)
279 {
280 if (argc < 5)
281 {
282 exit_usage("\"logtype\" needs more parameters...");
283 }
284 res = set_logtype(argv[2], argv[3], atoi(argv[4]));
285 }
286 else if (strcmp(argv[1], "loglevel") == 0)
287 {
288 if (argc < 4)
289 {
290 exit_usage("\"logtype\" needs more parameters...");
291 }
292 res = set_loglevel(argv[2], atoi(argv[3]));
293 }
294 else
295 {
296 exit_usage(NULL);
297 }
298
299 if (res)
300 {
301 exit_error("communication with charon failed!\n");
302 }
303 return 0;
304 }