git ssb

0+

cel / sslh



Tree: 9bcb2cdd7a920ebc78b59d0b5797d678424aa93a

Files: 9bcb2cdd7a920ebc78b59d0b5797d678424aa93a / probe.c

6284 bytesRaw
1/*
2# probe.c: Code for probing protocols
3#
4# Copyright (C) 2007-2012 Yves Rutschle
5#
6# This program is free software; you can redistribute it
7# and/or modify it under the terms of the GNU General Public
8# License as published by the Free Software Foundation; either
9# version 2 of the License, or (at your option) any later
10# version.
11#
12# This program is distributed in the hope that it will be
13# useful, but WITHOUT ANY WARRANTY; without even the implied
14# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more
16# details.
17#
18# The full text for the General Public License is here:
19# http://www.gnu.org/licenses/gpl.html
20*/
21
22#include <regex.h>
23#include "probe.h"
24
25
26
27static int is_ssh_protocol(const char *p, int len, struct proto*);
28static int is_openvpn_protocol(const char *p, int len, struct proto*);
29static int is_tinc_protocol(const char *p, int len, struct proto*);
30static int is_xmpp_protocol(const char *p, int len, struct proto*);
31static int is_http_protocol(const char *p, int len, struct proto*);
32static int is_true(const char *p, int len, struct proto* proto) { return 1; }
33
34/* Table of protocols that have a built-in probe
35 */
36static struct proto builtins[] = {
37 /* description service saddr probe */
38 { "ssh", "sshd", NULL, is_ssh_protocol},
39 { "openvpn", NULL, NULL, is_openvpn_protocol },
40 { "tinc", NULL, NULL, is_tinc_protocol },
41 { "xmpp", NULL, NULL, is_xmpp_protocol },
42 { "http", NULL, NULL, is_http_protocol },
43 { "ssl", NULL, NULL, is_true }
44};
45
46static struct proto *protocols;
47
48struct proto* get_builtins(void) {
49 return builtins;
50}
51
52int get_num_builtins(void) {
53 return ARRAY_SIZE(builtins);
54}
55
56/* Returns the protocol to connect to in case of timeout; conventionaly this is
57 * the first protocol specified (but maybe we'll make it more explicit some
58 * day)
59 */
60struct proto* timeout_protocol(void) {
61 return protocols;
62}
63
64/* returns the first protocol (caller can then follow the *next pointers) */
65struct proto* get_first_protocol(void)
66{
67 return protocols;
68}
69
70void set_protocol_list(struct proto* prots)
71{
72 protocols = prots;
73}
74
75/* Is the buffer the beginning of an SSH connection? */
76static int is_ssh_protocol(const char *p, int len, struct proto *proto)
77{
78 if (!strncmp(p, "SSH-", 4)) {
79 return 1;
80 }
81 return 0;
82}
83
84/* Is the buffer the beginning of an OpenVPN connection?
85 * (code lifted from OpenVPN port-share option)
86 */
87static int is_openvpn_protocol (const char*p,int len, struct proto *proto)
88{
89#define P_OPCODE_SHIFT 3
90#define P_CONTROL_HARD_RESET_CLIENT_V2 7
91 if (len >= 3)
92 {
93 return p[0] == 0
94 && p[1] >= 14
95 && p[2] == (P_CONTROL_HARD_RESET_CLIENT_V2<<P_OPCODE_SHIFT);
96 }
97 else if (len >= 2)
98 {
99 return p[0] == 0 && p[1] >= 14;
100 }
101 else
102 return 0;
103}
104
105/* Is the buffer the beginning of a tinc connections?
106 * (protocol is undocumented, but starts with "0 " in 1.0.15)
107 * */
108static int is_tinc_protocol( const char *p, int len, struct proto *proto)
109{
110 return !strncmp(p, "0 ", 2);
111}
112
113/* Is the buffer the beginning of a jabber (XMPP) connections?
114 * (Protocol is documented (http://tools.ietf.org/html/rfc6120) but for lazy
115 * clients, just checking first frame containing "jabber" in xml entity)
116 * */
117static int is_xmpp_protocol( const char *p, int len, struct proto *proto)
118{
119 return strstr(p, "jabber") ? 1 : 0;
120}
121
122static int probe_http_method(const char *p, const char *opt)
123{
124 return !strcmp(p, opt);
125}
126
127/* Is the buffer the beginning of an HTTP connection? */
128static int is_http_protocol(const char *p, int len, struct proto *proto)
129{
130 /* If it's got HTTP in the request (HTTP/1.1) then it's HTTP */
131 if (strstr(p, "HTTP"))
132 return 1;
133
134 /* Otherwise it could be HTTP/1.0 without version: check if it's got an
135 * HTTP method (RFC2616 5.1.1) */
136 probe_http_method(p, "OPTIONS");
137 probe_http_method(p, "GET");
138 probe_http_method(p, "HEAD");
139 probe_http_method(p, "POST");
140 probe_http_method(p, "PUT");
141 probe_http_method(p, "DELETE");
142 probe_http_method(p, "TRACE");
143 probe_http_method(p, "CONNECT");
144
145 return 0;
146}
147
148
149static int regex_probe(const char *p, int len, struct proto *proto)
150{
151 regex_t** probe_list = (regex_t**)(proto->data);
152 int i=0;
153
154 while (probe_list[i]) {
155 if (!regexec(probe_list[i], p, 0, NULL, 0)) {
156 return 1;
157 }
158 i++;
159 }
160 return 0;
161}
162
163/*
164 * Read the beginning of data coming from the client connection and check if
165 * it's a known protocol. Then leave the data on the defered
166 * write buffer of the connection and returns a pointer to the protocol
167 * structure
168 */
169struct proto* probe_client_protocol(struct connection *cnx)
170{
171 char buffer[BUFSIZ];
172 struct proto *p;
173 int n;
174
175 n = read(cnx->q[0].fd, buffer, sizeof(buffer));
176 /* It's possible that read() returns an error, e.g. if the client
177 * disconnected between the previous call to select() and now. If that
178 * happens, we just connect to the default protocol so the caller of this
179 * function does not have to deal with a specific failure condition (the
180 * connection will just fail later normally). */
181 if (n > 0) {
182 defer_write(&cnx->q[1], buffer, n);
183
184 for (p = protocols; p; p = p->next) {
185 if (p->probe(buffer, n, p)) {
186 return p;
187 }
188 }
189 }
190
191 /* If none worked, return the first one affected (that's completely
192 * arbitrary) */
193 return protocols;
194}
195
196/* Returns the probe for specified protocol:
197 * parameter is the description in builtins[], or "regex"
198 * */
199T_PROBE* get_probe(const char* description) {
200 int i;
201
202 for (i = 0; i < ARRAY_SIZE(builtins); i++) {
203 if (!strcmp(builtins[i].description, description)) {
204 return builtins[i].probe;
205 }
206 }
207 /* Special case of "regex" probe (we don't want to set it in builtins
208 * because builtins is also used to build the command-line options and
209 * regexp is not legal on the command line)*/
210 if (!strcmp(description, "regex"))
211 return regex_probe;
212
213 return NULL;
214}
215
216
217

Built with git-ssb-web