Set a better default ciphers list if none was specified.
[pound.git] / poundctl.c
1 /*
2  * Pound - the reverse-proxy load-balancer
3  * Copyright (C) 2002-2010 Apsis GmbH
4  *
5  * This file is part of Pound.
6  *
7  * Pound is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  * 
12  * Pound is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  * Contact information:
21  * Apsis GmbH
22  * P.O.Box
23  * 8707 Uetikon am See
24  * Switzerland
25  * EMail: roseg@apsis.ch
26  */
27 #define NO_EXTERNALS 1
28 #include    "pound.h"
29
30 static int  xml_out = 0;
31 static int  host_names = 0;
32
33 static void
34 usage(const char *arg0)
35 {
36     fprintf(stderr, "Usage: %s -c /control/socket [ -X ] cmd\n", arg0);
37     fprintf(stderr, "\twhere cmd is one of:\n");
38     fprintf(stderr, "\t-L n - enable listener n\n");
39     fprintf(stderr, "\t-l n - disable listener n\n");
40     fprintf(stderr, "\t-S n m - enable service m in service n (use -1 for global services)\n");
41     fprintf(stderr, "\t-s n m - disable service m in service n (use -1 for global services)\n");
42     fprintf(stderr, "\t-B n m r - enable back-end r in service m in listener n\n");
43     fprintf(stderr, "\t-b n m r - disable back-end r in service m in listener n\n");
44     fprintf(stderr, "\t-N n m k r - add a session with key k and back-end r in service m in listener n\n");
45     fprintf(stderr, "\t-n n m k - remove a session with key k r in service m in listener n\n");
46     fprintf(stderr, "\n");
47     fprintf(stderr, "\tentering the command without arguments lists the current configuration.\n");
48     fprintf(stderr, "\tthe -X flag results in XML output.\n");
49     fprintf(stderr, "\tthe -H flag shows symbolic host names instead of addresses.\n");
50     exit(1);
51 }
52
53 /*
54  * Translate inet/inet6 address/port into a string
55  */
56 static char *
57 prt_addr(const struct addrinfo *addr)
58 {
59     static char res[UNIX_PATH_MAX];
60     char        buf[UNIX_PATH_MAX];
61     int         port;
62     void        *src;
63
64     memset(buf, 0, UNIX_PATH_MAX);
65 #ifdef  HAVE_INET_NTOP
66     switch(addr->ai_family) {
67     case AF_INET:
68         src = (void *)&((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr;
69         port = ntohs(((struct sockaddr_in *)addr->ai_addr)->sin_port);
70         if(host_names && !getnameinfo(addr->ai_addr, addr->ai_addrlen, buf, UNIX_PATH_MAX - 1, NULL, 0, 0))
71             break;
72         if(inet_ntop(AF_INET, src, buf, UNIX_PATH_MAX - 1) == NULL)
73             strncpy(buf, "(UNKNOWN)", UNIX_PATH_MAX - 1);
74         break;
75     case AF_INET6:
76         src = (void *)&((struct sockaddr_in6 *)addr->ai_addr)->sin6_addr.s6_addr;
77         port = ntohs(((struct sockaddr_in6 *)addr->ai_addr)->sin6_port);
78         if(host_names && !getnameinfo(addr->ai_addr, addr->ai_addrlen, buf, UNIX_PATH_MAX - 1, NULL, 0, 0))
79             break;
80         if(inet_ntop(AF_INET6, src, buf, UNIX_PATH_MAX - 1) == NULL)
81             strncpy(buf, "(UNKNOWN)", UNIX_PATH_MAX - 1);
82         break;
83     case AF_UNIX:
84         strncpy(buf, (char *)addr->ai_addr, UNIX_PATH_MAX - 1);
85         port = 0;
86         break;
87     default:
88         strncpy(buf, "(UNKNOWN)", UNIX_PATH_MAX - 1);
89         port = 0;
90         break;
91     }
92     snprintf(res, UNIX_PATH_MAX - 1, "%s:%d", buf, port);
93 #else
94 #error "Pound needs inet_ntop()"
95 #endif
96     return res;
97 }
98
99 static void
100 be_prt(const int sock)
101 {
102     BACKEND be;
103     struct  sockaddr_storage    a, h;
104     int     n_be;
105
106     n_be = 0;
107     while(read(sock, (void *)&be, sizeof(BACKEND)) == sizeof(BACKEND)) {
108         if(be.disabled < 0)
109             break;
110         read(sock, &a, be.addr.ai_addrlen);
111         be.addr.ai_addr = (struct sockaddr *)&a;
112         if(be.ha_addr.ai_addrlen > 0) {
113             read(sock, &h, be.ha_addr.ai_addrlen);
114             be.ha_addr.ai_addr = (struct sockaddr *)&h;
115         }
116         if(xml_out)
117             printf("<backend index=\"%d\" address=\"%s\" avg=\"%.3f\" priority=\"%d\" alive=\"%s\" status=\"%s\" />\n",
118                 n_be++,
119                 prt_addr(&be.addr), be.t_average / 1000000, be.priority, be.alive? "yes": "DEAD",
120                 be.disabled? "DISABLED": "active");
121         else
122             printf("    %3d. Backend %s %s (%d %.3f sec) %s\n", n_be++, prt_addr(&be.addr),
123                 be.disabled? "DISABLED": "active", be.priority, be.t_average / 1000000, be.alive? "alive": "DEAD");
124     }
125     return;
126 }
127
128 static void
129 sess_prt(const int sock)
130 {
131     TABNODE     sess;
132     int         n_be, n_sess, cont_len;
133     char        buf[KEY_SIZE + 1], escaped[KEY_SIZE * 2 + 1];
134
135     n_sess = 0;
136     while(read(sock, (void *)&sess, sizeof(TABNODE)) == sizeof(TABNODE)) {
137         if(sess.content == NULL)
138             break;
139         read(sock, &n_be, sizeof(n_be));
140         read(sock, &cont_len, sizeof(cont_len));
141         memset(buf, 0, KEY_SIZE + 1);
142         /* cont_len is at most KEY_SIZE */
143         read(sock, buf, cont_len);
144         if(xml_out) {
145             int     i, j;
146             char    escaped[KEY_SIZE * 2 + 1];
147
148             for(i = j = 0; buf[i]; i++)
149                 if(buf[i] == '"') {
150                     escaped[j++] = '\\';
151                     escaped[j++] = '"';
152                 } else
153                     escaped[j++] = buf[i];
154             escaped[j] = '\0';
155             printf("<session index=\"%d\" key=\"%s\" backend=\"%d\" />\n", n_sess++, escaped, n_be);
156         } else
157             printf("    %3d. Session %s -> %d\n", n_sess++, buf, n_be);
158     }
159     return;
160 }
161
162 static void
163 svc_prt(const int sock)
164 {
165     SERVICE     svc;
166     int         n_svc;
167
168     n_svc = 0;
169     while(read(sock, (void *)&svc, sizeof(SERVICE)) == sizeof(SERVICE)) {
170         if(svc.disabled < 0)
171             break;
172         if(xml_out) {
173             if(svc.name[0])
174                 printf("<service index=\"%d\" name=\"%s\" status=\"%s\">\n",
175                     n_svc++, svc.name, svc.disabled? "DISABLED": "active");
176             else
177                 printf("<service index=\"%d\"%s>\n", n_svc++, svc.disabled? " DISABLED": "");
178         } else {
179             if(svc.name[0])
180                 printf("  %3d. Service \"%s\" %s (%d)\n", n_svc++, svc.name, svc.disabled? "DISABLED": "active",
181                     svc.tot_pri);
182             else
183                 printf("  %3d. Service %s (%d)\n", n_svc++, svc.disabled? "DISABLED": "active", svc.tot_pri);
184         }
185         be_prt(sock);
186         sess_prt(sock);
187         if(xml_out)
188             printf("</service>\n");
189     }
190     return;
191 }
192
193 static int
194 get_sock(const char *sock_name)
195 {
196     struct sockaddr_un  ctrl;
197     int                 res;
198
199     memset(&ctrl, 0, sizeof(ctrl));
200     ctrl.sun_family = AF_UNIX;
201     strncpy(ctrl.sun_path, sock_name, sizeof(ctrl.sun_path) - 1);
202     if((res = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
203         perror("socket create");
204         exit(1);
205     }
206     if(connect(res, (struct sockaddr *)&ctrl, (socklen_t)sizeof(ctrl)) < 0) {
207         perror("connect");
208         exit(1);
209     }
210     return res;
211 }
212
213 int
214 main(const int argc, char **argv)
215 {
216     CTRL_CMD    cmd;
217     int         sock, n_lstn, n_svc, n_be, n_sess, i;
218     char        *arg0, *sock_name, buf[KEY_SIZE + 1];
219     int         c_opt, en_lst, de_lst, en_svc, de_svc, en_be, de_be, a_sess, d_sess, is_set;
220     LISTENER    lstn;
221     SERVICE     svc;
222     BACKEND     be;
223     TABNODE     sess;
224     struct  sockaddr_storage    a;
225
226     arg0 = *argv;
227     sock_name = NULL;
228     en_lst = de_lst = en_svc = de_svc = en_be = de_be = is_set = a_sess = d_sess = 0;
229     memset(&cmd, 0, sizeof(cmd));
230     opterr = 0;
231     i = 0;
232     while(!i && (c_opt = getopt(argc, argv, "c:LlSsBbNnXH")) > 0)
233         switch(c_opt) {
234         case 'c':
235             sock_name = optarg;
236             break;
237         case 'X':
238             xml_out = 1;
239             break;
240         case 'L':
241             if(is_set)
242                 usage(arg0);
243             en_lst = is_set = 1;
244             break;
245         case 'l':
246             if(is_set)
247                 usage(arg0);
248             de_lst = is_set = 1;
249             break;
250         case 'S':
251             if(is_set)
252                 usage(arg0);
253             en_svc = is_set = 1;
254             break;
255         case 's':
256             if(is_set)
257                 usage(arg0);
258             de_svc = is_set = 1;
259             break;
260         case 'B':
261             if(is_set)
262                 usage(arg0);
263             en_be = is_set = 1;
264             break;
265         case 'b':
266             if(is_set)
267                 usage(arg0);
268             de_be = is_set = 1;
269             break;
270         case 'N':
271             if(is_set)
272                 usage(arg0);
273             a_sess = is_set = 1;
274             break;
275         case 'n':
276             if(is_set)
277                 usage(arg0);
278             d_sess = is_set = 1;
279             break;
280         case 'H':
281             host_names = 1;
282             break;
283         default:
284             if(optopt == '1') {
285                 optind--;
286                 i = 1;
287             } else {
288                 fprintf(stderr, "bad flag -%c", optopt);
289                 usage(arg0);
290             }
291             break;
292         }
293
294     if(sock_name == NULL)
295         usage(arg0);
296     if(en_lst || de_lst) {
297         if(optind != (argc - 1))
298             usage(arg0);
299         cmd.cmd = (en_lst? CTRL_EN_LSTN: CTRL_DE_LSTN);
300         cmd.listener = atoi(argv[optind++]);
301     }
302     if(en_svc || de_svc) {
303         if(optind != (argc - 2))
304             usage(arg0);
305         cmd.cmd = (en_svc? CTRL_EN_SVC: CTRL_DE_SVC);
306         cmd.listener = atoi(argv[optind++]);
307         cmd.service = atoi(argv[optind++]);
308     }
309     if(en_be || de_be) {
310         if(optind != (argc - 3))
311             usage(arg0);
312         cmd.cmd = (en_be? CTRL_EN_BE: CTRL_DE_BE);
313         cmd.listener = atoi(argv[optind++]);
314         cmd.service = atoi(argv[optind++]);
315         cmd.backend = atoi(argv[optind++]);
316     }
317     if(a_sess) {
318         if(optind != (argc - 4))
319             usage(arg0);
320         cmd.cmd = CTRL_ADD_SESS;
321         cmd.listener = atoi(argv[optind++]);
322         cmd.service = atoi(argv[optind++]);
323         memset(cmd.key, 0, KEY_SIZE + 1);
324         strncpy(cmd.key, argv[optind++], KEY_SIZE);
325         cmd.backend = atoi(argv[optind++]);
326     }
327     if(d_sess) {
328         if(optind != (argc - 3))
329             usage(arg0);
330         cmd.cmd = CTRL_DEL_SESS;
331         cmd.listener = atoi(argv[optind++]);
332         cmd.service = atoi(argv[optind++]);
333         strncpy(cmd.key, argv[optind++], KEY_SIZE);
334     }
335     if(!is_set) {
336         if(optind != argc)
337             usage(arg0);
338         cmd.cmd = CTRL_LST;
339     }
340
341     sock = get_sock(sock_name);
342     write(sock, &cmd, sizeof(cmd));
343
344     if (!is_set) {
345         int n;
346
347         n_lstn = 0;
348         if(xml_out)
349             printf("<pound>\n");
350         if(read(sock, &n, sizeof(n)) == sizeof(n))
351             if(xml_out)
352                 printf("<queue size=\"%d\"/>\n", n);
353             else
354                 printf("Requests in queue: %d\n", n);
355         while(read(sock, (void *)&lstn, sizeof(LISTENER)) == sizeof(LISTENER)) {
356             if(lstn.disabled < 0)
357                 break;
358             read(sock, &a, lstn.addr.ai_addrlen);
359             lstn.addr.ai_addr = (struct sockaddr *)&a;
360             if(xml_out)
361                 printf("<listener index=\"%d\" protocol=\"%s\" address=\"%s\" status=\"%s\">\n",
362                     n_lstn++, lstn.ctx? "HTTPS": "http",
363                     prt_addr(&lstn.addr), lstn.disabled? "DISABLED": "active");
364             else
365                 printf("%3d. %s Listener %s %s\n", n_lstn++, lstn.ctx? "HTTPS" : "http",
366                     prt_addr(&lstn.addr), lstn.disabled? "*D": "a");
367             svc_prt(sock);
368             if(xml_out)
369                 printf("</listener>\n");
370         }
371         if(!xml_out)
372             printf(" -1. Global services\n");
373         svc_prt(sock);
374         if(xml_out)
375             printf("</pound>\n");
376     }
377     return 0;
378 }