Reformat README to use Markdown
[prads.git] / src / servicefp / servicefp.c
blobc8fddd2861d4e566e107205269cff91ec55ac3cb
1 /*
2 ** Copyright (C) 2009 Redpill Linpro, AS.
3 ** Copyright (C) 2009 Edward Fjellskål <edward.fjellskaal@redpill-linpro.com>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License Version 2 as
7 ** published by the Free Software Foundation. You may not use, modify or
8 ** distribute this program under any other version of the GNU General
9 ** Public License.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 /* $Id$ */
23 /* servicefp
25 * Purpose:
27 * This file holds essential functions for the service fingerprinting
29 * Arguments:
31 * *NONE
33 * Effect:
35 * HOLDS all the stuff that needs to be initialized.
37 * Comments:
39 * Old school...
42 #include "../common.h"
43 #include "../sys_func.h"
44 #include "../prads.h"
45 #include "../config.h"
46 #include "servicefp.h"
48 extern globalconfig config;
50 servicelist *services[MAX_PORTS];
52 /* ----------------------------------------------------------
53 * FUNCTION : init_identification
54 * DESCRIPTION : This function will read the signature file
55 * : into the signature data structure.
56 * INPUT : 0 - Data Structure
57 * RETURN : -1 - Error
58 * : 0 - Normal Return
59 * ---------------------------------------------------------- */
60 int load_servicefp_file(char *sigfile, signature **db, int len)
63 FILE *fp;
64 bstring filename;
65 bstring filedata;
66 struct bstrList *lines;
67 int i;
68 (void)(len); // doesn't matter
71 * Check for a PADS_SIGNATURE_LIST file within the current directory.
73 if ((fp = fopen(TCP_SIGNATURE_LIST, "r")) != NULL) {
74 filename = bformat("%s", sigfile);
75 fclose(fp);
76 } else {
77 filename = bformat(sigfile);
81 * Open Signature File
83 if ((fp = fopen(bdata(filename), "r")) == NULL) {
84 printf("Unable to open signature file - %s\n", bdata(filename));
85 return 1;
89 * Read file into 'filedata' and process it accordingly.
91 filedata = bread((bNread) fread, fp);
92 if ((lines = bsplit(filedata, '\n')) != NULL) {
93 for (i = 0; i < lines->qty; i++) {
94 parse_raw_signature(lines->entry[i], i + 1, db);
99 * Clean Up
101 bdestroy(filename);
102 bdestroy(filedata);
103 bstrListDestroy(lines);
104 fclose(fp);
106 return 0;
109 void dump_sig_service(signature *sig, int len)
111 (void)(len); // it's a linked list, not important.
112 while(sig) {
113 // the actual regex is compiled and not available here.
114 printf("%s,v/%s/%s/%s/\n", bdata(sig->service),
115 bdata(sig->title.app), bdata(sig->title.ver), bdata(sig->title.misc));
116 sig = sig->next;
121 /* ----------------------------------------------------------
122 * FUNCTION : parse_raw_signature
123 * DESCRIPTION : This function will take a line from the
124 * : signature file and parse it into it's data
125 * : structure.
126 * INPUT : 0 - Raw Signature (bstring)
127 * : 1 - The line number this signature is on.
128 * RETURN : 0 - Success
129 * : -1 - Error
130 * ---------------------------------------------------------- */
131 int parse_raw_signature(bstring line, int lineno, signature **db)
133 struct bstrList *raw_sig = NULL;
134 struct bstrList *title = NULL;
135 signature *sig, *head;
136 sig = head = NULL;
137 bstring pcre_string = NULL;
138 const char *err = NULL; /* PCRE */
139 int erroffset; /* PCRE */
140 int ret = 0;
141 int i;
144 * Check to see if this line has something to read.
146 if (line->data[0] == '\0' || line->data[0] == '#')
147 return -1;
150 * Split Line
152 //if ((raw_sig = bsplitstr(line, bformat("||") )) == NULL)
153 if ((raw_sig = bsplit(line, ',')) == NULL)
154 return -1;
157 * Reconstruct the PCRE string. This is needed in case there are PCRE
158 * * strings containing commas within them.
160 if (raw_sig->qty < 3) {
161 ret = -1;
162 } else if (raw_sig->qty > 3) {
163 pcre_string = bstrcpy(raw_sig->entry[2]);
164 for (i = 3; i < raw_sig->qty; i++) {
165 //bstring tmp = bfromcstr("||");
166 bstring tmp = bfromcstr(",");
167 if ((bconcat(pcre_string, tmp)) == BSTR_ERR)
168 ret = -1;
169 if ((bconcat(pcre_string, raw_sig->entry[i])) == BSTR_ERR)
170 ret = -1;
171 bdestroy(tmp);
173 } else {
174 pcre_string = bstrcpy(raw_sig->entry[2]);
178 * Split Title
180 if (raw_sig->entry[1] != NULL && ret != -1)
181 title = bsplit(raw_sig->entry[1], '/');
182 if (title == NULL) {
183 bdestroy(pcre_string);
184 return -1;
186 if (title->qty < 3)
187 ret = -1;
190 * Create signature data structure for this record.
192 if (ret != -1) {
193 sig = (signature *) calloc(1, sizeof(signature));
194 sig->next = NULL;
195 sig->prev = NULL;
196 if (raw_sig->entry[0] != NULL)
197 sig->service = bstrcpy(raw_sig->entry[0]);
198 if (title->entry[1] != NULL)
199 sig->title.app = bstrcpy(title->entry[1]);
200 if (title->entry[2] != NULL)
201 sig->title.ver = bstrcpy(title->entry[2]);
202 if (title->entry[3] != NULL)
203 sig->title.misc = bstrcpy(title->entry[3]);
206 * PCRE
208 if (pcre_string != NULL) {
209 if ((sig->regex =
210 pcre_compile((char *)bdata(pcre_string), 0, &err,
211 &erroffset, NULL)) == NULL) {
212 printf("Unable to compile signature: %s at line %d (%s)",
213 err, lineno, bdata(line));
214 ret = -1;
217 if (ret != -1) {
218 sig->study = pcre_study(sig->regex, 0, &err);
219 if (err != NULL)
220 printf("Unable to study signature: %s", err);
224 * Add signature to 'signature_list' data structure.
226 if (ret != -1) {
227 if(add_service_sig(sig, db)) {
228 //dlog("SIG ADDED:%s to %d\n",(char *)bdata(sig->service),storage);
234 * Garbage Collection
236 if (raw_sig != NULL)
237 bstrListDestroy(raw_sig);
238 if (title != NULL)
239 bstrListDestroy(title);
240 if (pcre_string != NULL)
241 bdestroy(pcre_string);
243 return ret;
246 int add_service_sig(signature *sig, signature **db)
248 signature *tail;
249 tail = *db;
250 if(tail == NULL) {
251 *db = sig;
252 }else{
253 while(tail->next != NULL) {
254 tail = tail->next;
256 tail->next = sig;
258 return 1;
261 void free_signature_list (signature *head)
263 signature *tmp;
264 while (head != NULL) {
265 bdestroy(head->service);
266 bdestroy(head->title.app);
267 bdestroy(head->title.ver);
268 bdestroy(head->title.misc);
269 if (head->regex != NULL) free(head->regex);
270 if (head->study != NULL) free(head->study);
271 tmp = head->next;
272 free(head);
273 head = NULL;
274 head = tmp;
278 void del_signature_lists()
280 /* server tcp */
281 free_signature_list(config.sig_serv_tcp);
282 /* server udp */
283 free_signature_list(config.sig_serv_udp);
284 /* client tcp */
285 free_signature_list(config.sig_client_tcp);
286 /* client udp */
287 free_signature_list(config.sig_client_udp);
289 dlog("signature list memory has been cleared\n");
292 /* ----------------------------------------------------------
293 * FUNCTION : get_app_name
294 * DESCRIPTION : This function will take the results of a
295 * : pcre match and compile the application name
296 * : based off of the signature.
297 * INPUT : 0 - Signature Pointer
298 * : 1 - payload
299 * : 2 - ovector
300 * : 3 - rc (return from pcre_exec)
301 * RETURN : processed app name
302 * ---------------------------------------------------------- */
303 bstring get_app_name(signature * sig,
304 const uint8_t *payload, int *ovector, int rc)
306 char sub[512];
307 char app[5000];
308 const char *expr;
309 bstring retval;
310 int i = 0;
311 int n = 0;
312 int x = 0;
313 int z = 0;
316 * Create Application string using the values in signature[i].title.
318 if (sig->title.app != NULL) {
319 strncpy(app, bdata(sig->title.app), MAX_APP);
321 if (sig->title.ver != NULL) {
322 if (sig->title.ver->slen > 0) {
323 strcat(app, " ");
324 strncat(app, (char *)bdata(sig->title.ver), MAX_VER);
327 if (sig->title.misc != NULL) {
328 if (sig->title.misc->slen > 0) {
329 strcat(app, " (");
330 strncat(app, (char *)bdata(sig->title.misc), MAX_MISC);
331 strcat(app, ")");
336 * Replace $1, $2, etc. with the appropriate substring.
338 while (app[i] != '\0' && z < (sizeof(sub) - 1)) {
340 * Check to see if the string contains a $? mark variable.
342 if (app[i] == '$') {
344 * Yes it does, replace it with the appropriate match string.
346 i++;
347 n = atoi(&app[i]);
349 pcre_get_substring((const char *)payload, ovector, rc, n, &expr);
350 x = 0;
351 while (expr[x] != '\0' && z < (sizeof(sub) - 1)) {
352 sub[z] = expr[x];
353 z++;
354 x++;
356 pcre_free_substring (expr);
357 expr = NULL;
358 i++;
359 } else {
361 * No it doesn't, copy to new string.
363 sub[z] = app[i];
364 i++;
365 z++;
368 sub[z] = '\0';
370 retval = bfromcstr(sub);
371 return retval;
375 void load_known_ports_file(char *filename, port_t *lports)
377 /* parse file with "service,port" */
378 /* for each line of "service,port" : add_known_port() */
379 return;
382 void add_known_services(uint8_t proto, uint16_t port, const char *service_name)
384 if (services[port] == NULL) {
385 services[port] = (servicelist *) calloc(1, sizeof(servicelist));
386 services[port]->service_name = bformat(service_name);
389 if (proto == IP_PROTO_TCP) {
390 services[port]->proto |= 0x01; // TCP
391 } else if (proto == IP_PROTO_UDP) {
392 services[port]->proto |= 0x02; // UDP
396 void del_known_services()
398 int kport;
400 for (kport=0; kport < MAX_PORTS; kport++) {
401 if (services[kport] != NULL) {
402 bdestroy(services[kport]->service_name);
403 free(services[kport]);
406 dlog("known services memory has been cleared\n");
410 bstring check_known_port(uint8_t proto, uint16_t port)
412 if (services[port] == NULL) return NULL;
414 if (proto == IP_PROTO_TCP && services[port]->proto & 0x01)
415 return bstrcpy(services[port]->service_name);
416 if (proto == IP_PROTO_UDP && services[port]->proto & 0x02)
417 return bstrcpy(services[port]->service_name);
419 return NULL;
422 void init_services()
424 //bformat
425 //bfromcstr
426 add_known_services( 6, 20, "@ftp-data");
427 add_known_services( 6, 21, "@ftp");
428 add_known_services( 6, 22, "@ssh");
429 add_known_services( 6, 25, "@smtp");
430 add_known_services(17, 53, "@domain");
431 add_known_services( 6, 80, "@www");
432 add_known_services( 6, 110, "@pop3");
433 add_known_services( 6, 111, "@sunrpc");
434 add_known_services(17, 111, "@sunrpc");
435 add_known_services( 6, 113, "@auth");
436 add_known_services( 6, 115, "@sftp");
437 add_known_services( 6, 119, "@nntp");
438 add_known_services(17, 123, "@ntp");
439 add_known_services( 6, 143, "@imap2");
440 add_known_services( 6, 161, "@snmp");
441 add_known_services(17, 161, "@snmp");
442 add_known_services( 6, 162, "@snmp-trap");
443 add_known_services(17, 162, "@snmp-trap");
444 add_known_services( 6, 389, "@ldap");
445 add_known_services( 6, 443, "@https");
446 add_known_services( 6, 445, "@microsoft-ds");
447 add_known_services(17, 514, "@syslog");
448 add_known_services( 6, 554, "@rtsp");
449 add_known_services(17, 554, "@rtsp");
450 add_known_services( 6, 631, "@ipp");
451 add_known_services( 6, 990, "@ftps");
452 add_known_services( 6, 992, "@telnets");
453 add_known_services( 6, 993, "@imaps");
454 add_known_services( 6, 995, "@pop3s");
455 add_known_services(17, 1194, "@openvpn");
456 add_known_services( 6, 2049, "@nfs");
457 add_known_services(17, 2049, "@nfs");
458 add_known_services( 6, 3306, "@mysql");
459 add_known_services( 6, 6667, "@irc");