2 ** Copyright (C) 2009 Redpill Linpro, AS.
3 ** Copyright (C) 2009 Edward Fjellskål <edward.fjellskaal@redpill-linpro.com>
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
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.
27 * This file holds essential functions for the service fingerprinting
35 * HOLDS all the stuff that needs to be initialized.
42 #include "../common.h"
43 #include "../sys_func.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
59 * ---------------------------------------------------------- */
60 int load_servicefp_file(char *sigfile
, signature
**db
, int len
)
66 struct bstrList
*lines
;
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
);
77 filename
= bformat(sigfile
);
83 if ((fp
= fopen(bdata(filename
), "r")) == NULL
) {
84 printf("Unable to open signature file - %s\n", bdata(filename
));
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
);
103 bstrListDestroy(lines
);
109 void dump_sig_service(signature
*sig
, int len
)
111 (void)(len
); // it's a linked list, not important.
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
));
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
126 * INPUT : 0 - Raw Signature (bstring)
127 * : 1 - The line number this signature is on.
128 * RETURN : 0 - Success
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
;
137 bstring pcre_string
= NULL
;
138 const char *err
= NULL
; /* PCRE */
139 int erroffset
; /* PCRE */
144 * Check to see if this line has something to read.
146 if (line
->data
[0] == '\0' || line
->data
[0] == '#')
152 //if ((raw_sig = bsplitstr(line, bformat("||") )) == NULL)
153 if ((raw_sig
= bsplit(line
, ',')) == NULL
)
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) {
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
)
169 if ((bconcat(pcre_string
, raw_sig
->entry
[i
])) == BSTR_ERR
)
174 pcre_string
= bstrcpy(raw_sig
->entry
[2]);
180 if (raw_sig
->entry
[1] != NULL
&& ret
!= -1)
181 title
= bsplit(raw_sig
->entry
[1], '/');
183 bdestroy(pcre_string
);
190 * Create signature data structure for this record.
193 sig
= (signature
*) calloc(1, sizeof(signature
));
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]);
208 if (pcre_string
!= NULL
) {
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
));
218 sig
->study
= pcre_study(sig
->regex
, 0, &err
);
220 printf("Unable to study signature: %s", err
);
224 * Add signature to 'signature_list' data structure.
227 if(add_service_sig(sig
, db
)) {
228 //dlog("SIG ADDED:%s to %d\n",(char *)bdata(sig->service),storage);
237 bstrListDestroy(raw_sig
);
239 bstrListDestroy(title
);
240 if (pcre_string
!= NULL
)
241 bdestroy(pcre_string
);
246 int add_service_sig(signature
*sig
, signature
**db
)
253 while(tail
->next
!= NULL
) {
261 void free_signature_list (signature
*head
)
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
);
278 void del_signature_lists()
281 free_signature_list(config
.sig_serv_tcp
);
283 free_signature_list(config
.sig_serv_udp
);
285 free_signature_list(config
.sig_client_tcp
);
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
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
)
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) {
324 strncat(app
, (char *)bdata(sig
->title
.ver
), MAX_VER
);
327 if (sig
->title
.misc
!= NULL
) {
328 if (sig
->title
.misc
->slen
> 0) {
330 strncat(app
, (char *)bdata(sig
->title
.misc
), MAX_MISC
);
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.
344 * Yes it does, replace it with the appropriate match string.
349 pcre_get_substring((const char *)payload
, ovector
, rc
, n
, &expr
);
351 while (expr
[x
] != '\0' && z
< (sizeof(sub
) - 1)) {
356 pcre_free_substring (expr
);
361 * No it doesn't, copy to new string.
370 retval
= bfromcstr(sub
);
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() */
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()
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
);
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");