Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-socks.c
Line
Count
Source
1
/* packet-socks.c
2
 * Routines for socks versions 4 &5  packet dissection
3
 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
4
 * Copyright 2008, Jelmer Vernooij <jelmer@samba.org>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 *
12
 *
13
 * The Version 4 decode is based on SOCKS4.protocol and SOCKS4A.protocol.
14
 * The Version 5 decoder is based upon rfc-1928
15
 * The Version 5 User/Password authentication is based on rfc-1929.
16
 *
17
 * See
18
 *  http://www.openssh.org/txt/socks4.protocol
19
 *  http://www.openssh.org/txt/socks4a.protocol
20
 *
21
 * for information on SOCKS version 4 and 4a.
22
 *
23
 * Revisions:
24
 *
25
 * 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel
26
 *          causing heap overflow because of an infinite loop
27
 *          where the socks dissect was call over and over.
28
 *
29
 *          Also remove some old code marked with __JUNK__
30
 *
31
 * 2001-01-08 JCFoster Fixed problem with NULL pointer for hash data.
32
 *          Now test and exit if hash_info is null.
33
 */
34
35
/* Possible enhancements -
36
 *
37
 * Add GSS-API authentication per rfc-1961
38
 * Add CHAP authentication
39
 * Decode FLAG bits per
40
 *  https://tools.ietf.org/html/draft-ietf-aft-socks-pro-v5-04
41
 * In call_next_dissector, could load the destination address into
42
 *  pinfo->src or pinfo->dst structure before calling next dissector.
43
*/
44
45
#include "config.h"
46
47
#include <epan/packet.h>
48
#include <epan/exceptions.h>
49
#include <epan/proto_data.h>
50
51
#include "packet-tcp.h"
52
#include "packet-udp.h"
53
#include "packet-tls.h"
54
55
#include <epan/strutil.h>
56
57
16
#define TCP_PORT_SOCKS 1080
58
59
60
/**************** Socks commands ******************/
61
62
3
#define CONNECT_COMMAND         1
63
0
#define BIND_COMMAND            2
64
2
#define UDP_ASSOCIATE_COMMAND   3
65
27
#define PING_COMMAND            0x80
66
27
#define TRACERT_COMMAND         0x81
67
68
69
/********** V5 Authentication methods *************/
70
71
0
#define NO_AUTHENTICATION           0
72
0
#define GSS_API_AUTHENTICATION      1
73
0
#define USER_NAME_AUTHENTICATION    2
74
#define CHAP_AUTHENTICATION         3
75
#define AUTHENTICATION_FAILED       0xff
76
77
void proto_register_socks(void);
78
void proto_reg_handoff_socks(void);
79
80
/*********** Header field identifiers *************/
81
82
static int proto_socks;
83
84
static int ett_socks;
85
static int ett_socks_auth;
86
static int ett_socks_name;
87
88
static int hf_socks_ver;
89
static int hf_socks_ip_dst;
90
static int hf_socks_ip6_dst;
91
static int hf_gssapi_payload;
92
static int hf_gssapi_command;
93
static int hf_gssapi_length;
94
static int hf_v4a_dns_name;
95
static int hf_socks_dstport;
96
static int hf_socks_cmd;
97
static int hf_socks_results_4;
98
static int hf_socks_results_5;
99
static int hf_client_auth_method_count;
100
static int hf_client_auth_method;
101
static int hf_socks_reserved;
102
static int hf_socks_reserved2;
103
static int hf_client_port;
104
static int hf_server_accepted_auth_method;
105
static int hf_server_auth_status;
106
static int hf_server_remote_host_port;
107
static int hf_socks_subnegotiation_version;
108
static int hf_socks_username;
109
static int hf_socks_password;
110
static int hf_socks_remote_name;
111
static int hf_socks_address_type;
112
static int hf_socks_fragment_number;
113
static int hf_socks_ping_end_command;
114
static int hf_socks_ping_results;
115
static int hf_socks_traceroute_end_command;
116
static int hf_socks_traceroute_results;
117
118
/************* Dissector handles ***********/
119
120
static dissector_handle_t socks_handle;
121
static dissector_handle_t socks_handle_tls;
122
static dissector_handle_t socks_udp_handle;
123
124
/************* State Machine names ***********/
125
126
enum ClientState {
127
    clientNoInit = -1,
128
    clientStart = 0,
129
    clientWaitForAuthReply,
130
    clientV5Command,
131
    clientUserNameRequest,
132
    clientGssApiAuthRequest,
133
    clientDone,
134
    clientError
135
};
136
137
enum ServerState {
138
    serverNoInit = -1,
139
    serverStart = 0,
140
    serverInitReply,
141
    serverCommandReply,
142
    serverUserReply,
143
    serverGssApiReply,
144
    serverBindReply,
145
    serverDone,
146
    serverError
147
};
148
149
typedef struct {
150
    int in_socks_dissector_flag;
151
    enum ClientState client;
152
    enum ServerState server;
153
} sock_state_t;
154
155
typedef struct {
156
    conversation_t *proxy_conv;
157
    enum ClientState clientState;
158
    enum ServerState serverState;
159
    int     version;
160
    int     command;
161
    int     authentication_method;
162
    uint32_t server_port;
163
    uint32_t port;
164
    uint32_t udp_port;
165
    uint32_t udp_remote_port;
166
    address dst_addr;
167
168
    uint32_t start_done_frame;
169
}socks_hash_entry_t;
170
171
172
static const value_string address_type_table[] = {
173
    {1, "IPv4"},
174
    {3, "Domain Name"},
175
    {4, "IPv6"},
176
    {0, NULL}
177
};
178
179
/* String table for the V4 reply status messages */
180
181
static const value_string reply_table_v4[] = {
182
    {90, "Granted"},
183
    {91, "Rejected or Failed"},
184
    {92, "Rejected because SOCKS server cannot connect to identd on the client"},
185
    {93, "Rejected because the client program and identd report different user-ids"},
186
    {0, NULL}
187
};
188
189
/* String table for the V5 reply status messages */
190
191
static const value_string reply_table_v5[] = {
192
    {0, "Succeeded"},
193
    {1, "General SOCKS server failure"},
194
    {2, "Connection not allowed by ruleset"},
195
    {3, "Network unreachable"},
196
    {4, "Host unreachable"},
197
    {5, "Connection refused"},
198
    {6, "TTL expired"},
199
    {7, "Command not supported"},
200
    {8, "Address type not supported"},
201
    {0, NULL},
202
};
203
204
static const value_string cmd_strings[] = {
205
    {CONNECT_COMMAND,       "Connect"},
206
    {BIND_COMMAND,          "Bind"},
207
    {UDP_ASSOCIATE_COMMAND, "UdpAssociate"},
208
    {PING_COMMAND,          "Ping"},
209
    {TRACERT_COMMAND,       "Traceroute"},
210
    {0, NULL}
211
};
212
213
static const value_string gssapi_command_table[] = {
214
    { 1,    "Authentication" },
215
    { 0xFF, "Failure" },
216
    { 0, NULL }
217
};
218
219
220
/************************* Support routines ***************************/
221
222
2.67k
static const char *get_auth_method_name( unsigned Number){
223
224
/* return the name of the authentication method */
225
226
2.67k
    if ( Number == 0) return "No authentication";
227
2.15k
    if ( Number == 1) return "GSSAPI";
228
2.03k
    if ( Number == 2) return "Username/Password";
229
1.91k
    if ( Number == 3) return "Chap";
230
1.86k
    if (( Number >= 4) && ( Number <= 0x7f))return "IANA assigned";
231
800
    if (( Number >= 0x80) && ( Number <= 0xfe)) return "private method";
232
337
    if ( Number == 0xff) return "no acceptable method";
233
234
    /* shouldn't reach here */
235
236
0
    return "Bad method number (not 0-0xff)";
237
337
}
238
239
1
static int display_address(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree) {
240
241
/* decode and display the v5 address, return offset of next byte */
242
243
1
    int a_type = tvb_get_uint8(tvb, offset);
244
245
1
    proto_tree_add_item( tree, hf_socks_address_type, tvb, offset, 1, ENC_BIG_ENDIAN);
246
1
    offset += 1;
247
248
1
    switch (a_type)
249
1
    {
250
0
    case 1: /* IPv4 address */
251
0
        proto_tree_add_item( tree, hf_socks_ip_dst, tvb, offset, 4, ENC_BIG_ENDIAN);
252
0
        offset += 4;
253
0
        break;
254
0
    case 3: /* domain name address */
255
0
        {
256
0
        uint8_t len;
257
0
        char* str;
258
259
0
        len = tvb_get_uint8(tvb, offset);
260
0
        str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+1, len, ENC_ASCII);
261
0
        proto_tree_add_string(tree, hf_socks_remote_name, tvb, offset, len+1, str);
262
0
        offset += (len+1);
263
0
        }
264
0
        break;
265
0
    case 4: /* IPv6 address */
266
0
        proto_tree_add_item( tree, hf_socks_ip6_dst, tvb, offset, 16, ENC_NA);
267
0
        offset += 16;
268
0
        break;
269
1
    }
270
271
1
    return offset;
272
1
}
273
274
275
static int get_address_v5(tvbuff_t *tvb, int offset,
276
2
    socks_hash_entry_t *hash_info) {
277
278
    /* decode the v5 address and return offset of next byte */
279
2
    int     a_type;
280
2
    address addr;
281
282
2
    a_type = tvb_get_uint8(tvb, offset);
283
2
    offset += 1;
284
285
2
    switch(a_type)
286
2
    {
287
0
    case 1: /* IPv4 address */
288
0
        if ( hash_info) {
289
0
            set_address_tvb(&addr, AT_IPv4, 4, tvb, offset);
290
0
            copy_address_wmem(wmem_file_scope(), &hash_info->dst_addr, &addr);
291
0
        }
292
0
        offset += 4;
293
0
        break;
294
295
0
    case 4: /* IPv6 address */
296
0
        if ( hash_info) {
297
0
            set_address_tvb(&addr, AT_IPv6, 16, tvb, offset);
298
0
            copy_address_wmem(wmem_file_scope(), &hash_info->dst_addr, &addr);
299
0
        }
300
0
        offset += 16;
301
0
        break;
302
303
0
    case 3: /* domain name address */
304
0
        offset += tvb_get_uint8(tvb, offset) + 1;
305
0
        break;
306
2
    }
307
308
2
    return offset;
309
2
}
310
311
312
/********************* V5 UDP Associate handlers ***********************/
313
314
static int
315
0
socks_udp_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
316
317
/* Conversation dissector called from UDP dissector. Decode and display */
318
/* the socks header, the pass the rest of the data to the udp port  */
319
/* decode routine to  handle the payload.               */
320
321
0
    int                 offset = 0;
322
0
    uint32_t           *ptr;
323
0
    socks_hash_entry_t *hash_info;
324
0
    conversation_t     *conversation;
325
0
    proto_tree         *socks_tree;
326
0
    proto_item         *ti;
327
328
0
    conversation = find_conversation_pinfo( pinfo, 0);
329
330
0
    DISSECTOR_ASSERT( conversation);    /* should always find a conversation */
331
332
0
    hash_info = (socks_hash_entry_t *)conversation_get_proto_data(conversation, proto_socks);
333
334
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "Socks");
335
0
    col_set_str(pinfo->cinfo, COL_INFO, "Version: 5, UDP Associated packet");
336
337
0
    if ( tree) {
338
0
        ti = proto_tree_add_protocol_format( tree, proto_socks, tvb, offset, -1, "Socks" );
339
340
0
        socks_tree = proto_item_add_subtree(ti, ett_socks);
341
342
0
        proto_tree_add_item(socks_tree, hf_socks_reserved2, tvb, offset, 2, ENC_BIG_ENDIAN);
343
0
        offset += 2;
344
345
0
        proto_tree_add_item(socks_tree, hf_socks_fragment_number, tvb, offset, 1, ENC_BIG_ENDIAN);
346
0
        offset += 1;
347
348
0
        offset = display_address(pinfo, tvb, offset, socks_tree);
349
0
        hash_info->udp_remote_port = tvb_get_ntohs(tvb, offset);
350
351
0
        proto_tree_add_uint( socks_tree, hf_socks_dstport, tvb,
352
0
            offset, 2, hash_info->udp_remote_port);
353
354
0
        offset += 2;
355
0
    }
356
0
    else {      /* no tree, skip past the socks header */
357
0
        offset += 3;
358
0
        offset = get_address_v5( tvb, offset, 0) + 2;
359
0
    }
360
361
    /* set pi src/dst port and call the udp sub-dissector lookup */
362
363
0
    if ( pinfo->srcport == hash_info->port)
364
0
        ptr = &pinfo->destport;
365
0
    else
366
0
        ptr = &pinfo->srcport;
367
368
0
    *ptr = hash_info->udp_remote_port;
369
370
0
    decode_udp_ports( tvb, offset, pinfo, tree, pinfo->srcport, pinfo->destport, -1);
371
372
0
    *ptr = hash_info->udp_port;
373
0
    return tvb_captured_length(tvb);
374
0
}
375
376
377
static void
378
0
new_udp_conversation( socks_hash_entry_t *hash_info, packet_info *pinfo){
379
380
0
    conversation_t *conversation = conversation_new( pinfo->num, &pinfo->src, &pinfo->dst, CONVERSATION_UDP,
381
0
            hash_info->udp_port, hash_info->port, 0);
382
383
0
    DISSECTOR_ASSERT( conversation);
384
385
0
    conversation_add_proto_data(conversation, proto_socks, hash_info);
386
0
    conversation_set_dissector(conversation, socks_udp_handle);
387
0
}
388
389
static void
390
save_client_state(packet_info *pinfo, enum ClientState state)
391
26
{
392
26
    sock_state_t* state_info = (sock_state_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_socks, 0);
393
26
    if ((state_info != NULL) && (state_info->client == clientNoInit)) {
394
26
        state_info->client = state;
395
26
    }
396
26
}
397
398
static void
399
save_server_state(packet_info *pinfo, enum ServerState state)
400
26
{
401
26
    sock_state_t* state_info = (sock_state_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_socks, 0);
402
26
    if ((state_info != NULL) && (state_info->server == serverNoInit)) {
403
26
        state_info->server = state;
404
26
    }
405
26
}
406
407
408
/**************** Protocol Tree Display routines  ******************/
409
410
static void
411
display_socks_v4(tvbuff_t *tvb, int offset, packet_info *pinfo,
412
1
    proto_tree *tree, socks_hash_entry_t *hash_info, sock_state_t* state_info) {
413
414
415
/* Display the protocol tree for the V4 version. This routine uses the  */
416
/* stored frame information to decide what to do with the row.  */
417
418
1
    unsigned char ipaddr[4];
419
1
    unsigned      str_len;
420
421
    /* Either there is an error, or we're done with the state machine
422
      (so there's nothing to display) */
423
1
    if (state_info == NULL)
424
0
        return;
425
426
1
    if (hash_info->server_port == pinfo->destport) {
427
        /* Client side */
428
1
        switch (state_info->client)
429
1
        {
430
1
        case clientStart:
431
1
            proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
432
1
            offset += 1;
433
434
1
            proto_tree_add_item( tree, hf_socks_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
435
1
            offset += 1;
436
437
            /* Do remote port */
438
1
            proto_tree_add_item( tree, hf_socks_dstport, tvb, offset, 2, ENC_BIG_ENDIAN);
439
1
            offset += 2;
440
441
            /* Do destination address */
442
1
            tvb_memcpy(tvb, ipaddr, offset, 4);
443
1
            proto_tree_add_item( tree, hf_socks_ip_dst, tvb, offset, 4, ENC_BIG_ENDIAN);
444
1
            offset += 4;
445
446
            /* display user name */
447
1
            str_len = tvb_strsize(tvb, offset);
448
1
            proto_tree_add_item( tree, hf_socks_username, tvb, offset, str_len, ENC_ASCII);
449
1
            offset += str_len;
450
451
1
            if ( ipaddr[0] == 0 && ipaddr[1] == 0 &&
452
0
                 ipaddr[2] == 0 && ipaddr[3] != 0) {
453
                /* 0.0.0.x , where x!=0 means v4a support */
454
0
                str_len = tvb_strsize(tvb, offset);
455
0
                proto_tree_add_item( tree, hf_v4a_dns_name, tvb, offset, str_len, ENC_ASCII);
456
0
            }
457
1
            break;
458
0
        default:
459
0
            break;
460
1
        }
461
1
    } else {
462
        /* Server side */
463
0
        switch (state_info->server)
464
0
        {
465
0
        case serverStart:
466
0
            proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
467
0
            offset += 1;
468
                            /* Do results code */
469
0
            proto_tree_add_item( tree, hf_socks_results_4, tvb, offset, 1, ENC_BIG_ENDIAN);
470
0
            offset += 1;
471
472
                            /* Do remote port */
473
0
            proto_tree_add_item( tree, hf_socks_dstport, tvb, offset, 2, ENC_BIG_ENDIAN);
474
0
            offset += 2;
475
                            /* Do remote address */
476
0
            proto_tree_add_item( tree, hf_socks_ip_dst, tvb, offset, 4, ENC_BIG_ENDIAN);
477
0
            break;
478
0
        default:
479
0
            break;
480
0
        }
481
0
    }
482
1
}
483
484
static void
485
// NOLINTNEXTLINE(misc-no-recursion)
486
client_display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
487
26
    proto_tree *tree, socks_hash_entry_t *hash_info, sock_state_t* state_info) {
488
489
/* Display the protocol tree for the version. This routine uses the */
490
/* stored conversation information to decide what to do with the row.   */
491
/* Per packet information would have been better to do this, but we */
492
/* didn't have that when I wrote this. And I didn't expect this to get  */
493
/* so messy.                                */
494
495
26
    unsigned int  i;
496
26
    const char   *AuthMethodStr;
497
26
    sock_state_t  new_state_info;
498
26
    proto_item *ti;
499
500
    /* Either there is an error, or we're done with the state machine
501
      (so there's nothing to display) */
502
26
    if (state_info == NULL)
503
0
        return;
504
505
26
    if (state_info->client == clientStart)
506
24
    {
507
24
        proto_tree      *AuthTree;
508
24
        uint8_t num_auth_methods, auth;
509
510
24
        col_append_str(pinfo->cinfo, COL_INFO, " Connect to server request");
511
512
24
        proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
513
24
        offset += 1;
514
515
24
        AuthTree = proto_tree_add_subtree( tree, tvb, offset, -1, ett_socks_auth, &ti, "Client Authentication Methods");
516
517
24
        num_auth_methods = tvb_get_uint8(tvb, offset);
518
24
        proto_item_set_len(ti, num_auth_methods+1);
519
520
24
        proto_tree_add_item( AuthTree, hf_client_auth_method_count, tvb, offset, 1, ENC_BIG_ENDIAN);
521
24
        offset += 1;
522
523
2.71k
        for( i = 0; i  < num_auth_methods; ++i) {
524
2.68k
            auth = tvb_get_uint8( tvb, offset);
525
2.68k
            AuthMethodStr = get_auth_method_name(auth);
526
527
2.68k
            proto_tree_add_uint_format(AuthTree, hf_client_auth_method, tvb, offset, 1, auth,
528
2.68k
                                        "Method[%u]: %u (%s)", i, auth, AuthMethodStr);
529
2.68k
            offset += 1;
530
2.68k
        }
531
532
24
        if ((num_auth_methods == 1) &&
533
1
            (tvb_bytes_exist(tvb, offset + 2, 1)) &&
534
1
            (tvb_get_uint8(tvb, offset + 2) == 0) &&
535
1
            (tvb_reported_length_remaining(tvb, offset + 2 + num_auth_methods) > 0)) {
536
1
                new_state_info.client = clientV5Command;
537
1
                increment_dissection_depth(pinfo);
538
1
                client_display_socks_v5(tvb, offset, pinfo, tree, hash_info, &new_state_info);
539
1
                decrement_dissection_depth(pinfo);
540
1
        }
541
24
    }
542
2
    else if (state_info->client == clientV5Command) {
543
1
        col_append_fstr(pinfo->cinfo, COL_INFO, " Command Request - %s",
544
1
                val_to_str_const(hash_info->command, cmd_strings, "Unknown"));
545
546
1
        proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
547
1
        offset += 1;
548
549
1
        proto_tree_add_item( tree, hf_socks_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
550
1
        offset += 1;
551
552
1
        proto_tree_add_item( tree, hf_socks_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
553
1
        offset += 1;
554
555
1
        offset = display_address(pinfo, tvb, offset, tree);
556
1
        proto_tree_add_item( tree, hf_client_port, tvb, offset, 2, ENC_BIG_ENDIAN);
557
1
    }
558
1
    else if ((state_info->client == clientWaitForAuthReply) &&
559
1
             (state_info->server == serverInitReply)) {
560
0
        uint16_t len;
561
0
        char* str;
562
563
0
        ti = proto_tree_add_uint( tree, hf_socks_ver, tvb, offset, 0, 5);
564
0
        proto_item_set_generated(ti);
565
566
0
        proto_tree_add_item( tree, hf_socks_subnegotiation_version, tvb, offset, 1, ENC_BIG_ENDIAN);
567
0
        offset += 1;
568
569
0
        switch(hash_info->authentication_method)
570
0
        {
571
0
        case NO_AUTHENTICATION:
572
0
            break;
573
0
        case USER_NAME_AUTHENTICATION:
574
0
            col_append_str(pinfo->cinfo, COL_INFO, " User authentication request");
575
576
            /* process user name */
577
0
            len = tvb_get_uint8(tvb, offset);
578
0
            str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+1, len, ENC_ASCII);
579
0
            proto_tree_add_string(tree, hf_socks_username, tvb, offset, len+1, str);
580
0
            offset += (len+1);
581
582
0
            len = tvb_get_uint8(tvb, offset);
583
0
            str = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset+1, len, ENC_ASCII);
584
0
            proto_tree_add_string(tree, hf_socks_password, tvb, offset, len+1, str);
585
            /* offset += (len+1); */
586
0
            break;
587
0
        case GSS_API_AUTHENTICATION:
588
0
            col_append_str(pinfo->cinfo, COL_INFO, " GSSAPI authentication request");
589
590
0
            proto_tree_add_item( tree, hf_gssapi_command, tvb, offset, 1, ENC_BIG_ENDIAN);
591
0
            proto_tree_add_item( tree, hf_gssapi_length, tvb, offset+1, 2, ENC_BIG_ENDIAN);
592
0
            len = tvb_get_ntohs(tvb, offset+1);
593
0
            if (len > 0)
594
0
                proto_tree_add_item( tree, hf_gssapi_payload, tvb, offset+3, len, ENC_NA);
595
0
            break;
596
0
        default:
597
0
            break;
598
0
        }
599
0
    }
600
1
    else {
601
1
        if (hash_info->port != 0)
602
0
            col_append_fstr(pinfo->cinfo, COL_INFO, ", Remote Port: %u",
603
0
                hash_info->port);
604
1
    }
605
26
}
606
607
static void
608
server_display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
609
0
    proto_tree *tree, socks_hash_entry_t *hash_info _U_, sock_state_t* state_info) {
610
611
/* Display the protocol tree for the version. This routine uses the */
612
/* stored conversation information to decide what to do with the row.   */
613
/* Per packet information would have been better to do this, but we */
614
/* didn't have that when I wrote this. And I didn't expect this to get  */
615
/* so messy.                                */
616
617
0
    const char *AuthMethodStr;
618
0
    uint8_t     auth, auth_status;
619
0
    proto_item *ti;
620
621
    /* Either there is an error, or we're done with the state machine
622
      (so there's nothing to display) */
623
0
    if (state_info == NULL)
624
0
        return;
625
626
0
    switch(state_info->server)
627
0
    {
628
0
    case serverStart:
629
0
        col_append_str(pinfo->cinfo, COL_INFO, " Connect to server response");
630
631
0
        proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
632
0
        offset += 1;
633
634
0
        auth = tvb_get_uint8( tvb, offset);
635
0
        AuthMethodStr = get_auth_method_name(auth);
636
637
0
        proto_tree_add_uint_format_value(tree, hf_server_accepted_auth_method, tvb, offset, 1, auth,
638
0
                                        "0x%0x (%s)", auth, AuthMethodStr);
639
0
        break;
640
641
0
    case serverUserReply:
642
0
        col_append_str(pinfo->cinfo, COL_INFO, " User authentication reply");
643
644
0
        ti = proto_tree_add_uint( tree, hf_socks_ver, tvb, offset, 0, 5);
645
0
        proto_item_set_generated(ti);
646
647
0
        proto_tree_add_item( tree, hf_socks_subnegotiation_version, tvb, offset, 1, ENC_BIG_ENDIAN);
648
0
        offset += 1;
649
650
0
        ti = proto_tree_add_item_ret_uint8(tree, hf_server_auth_status, tvb, offset, 1, ENC_BIG_ENDIAN, &auth_status);
651
0
        if(auth_status != 0)
652
0
            proto_item_append_text(ti, " (failure)");
653
0
        else
654
0
            proto_item_append_text(ti, " (success)");
655
0
        break;
656
657
0
    case serverGssApiReply:
658
0
        col_append_str(pinfo->cinfo, COL_INFO, " GSSAPI authentication reply");
659
660
0
        ti = proto_tree_add_uint( tree, hf_socks_ver, tvb, offset, 0, 5);
661
0
        proto_item_set_generated(ti);
662
663
0
        proto_tree_add_item( tree, hf_socks_subnegotiation_version, tvb, offset, 1, ENC_BIG_ENDIAN);
664
0
        offset += 1;
665
666
0
        auth_status = tvb_get_uint8(tvb, offset);
667
0
        proto_tree_add_item( tree, hf_gssapi_command, tvb, offset, 1, ENC_BIG_ENDIAN);
668
0
        if (auth_status != 0xFF) {
669
0
            uint16_t len;
670
671
0
            proto_tree_add_item( tree, hf_gssapi_length, tvb, offset+1, 2, ENC_BIG_ENDIAN);
672
0
            len = tvb_get_ntohs(tvb, offset+1);
673
0
            if (len > 0)
674
0
                proto_tree_add_item( tree, hf_gssapi_payload, tvb, offset+3, len, ENC_NA);
675
0
        }
676
0
        break;
677
678
0
    case serverCommandReply:
679
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " Command Response - %s",
680
0
                val_to_str_const(hash_info->command, cmd_strings, "Unknown"));
681
682
0
        proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
683
0
        offset += 1;
684
685
0
        proto_tree_add_item( tree, hf_socks_results_5, tvb, offset, 1, ENC_BIG_ENDIAN);
686
0
        offset += 1;
687
688
0
        proto_tree_add_item( tree, hf_socks_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
689
0
        offset += 1;
690
691
0
        offset = display_address(pinfo, tvb, offset, tree);
692
0
        proto_tree_add_item( tree, hf_client_port, tvb, offset, 2, ENC_BIG_ENDIAN);
693
0
        break;
694
695
0
    case serverBindReply:
696
0
        col_append_str(pinfo->cinfo, COL_INFO, " Command Response: Bind remote host info");
697
698
0
        proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
699
0
        offset += 1;
700
701
0
        proto_tree_add_item( tree, hf_socks_results_5, tvb, offset, 1, ENC_BIG_ENDIAN);
702
0
        offset += 1;
703
704
0
        proto_tree_add_item( tree, hf_socks_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
705
0
        offset += 1;
706
707
0
        offset = display_address(pinfo, tvb, offset, tree);
708
0
        proto_tree_add_item( tree, hf_server_remote_host_port, tvb, offset, 2, ENC_BIG_ENDIAN);
709
0
        break;
710
711
0
    default:
712
0
        if ( hash_info->port != 0)
713
0
            col_append_fstr(pinfo->cinfo, COL_INFO, ", Remote Port: %u",
714
0
                hash_info->port);
715
716
0
        break;
717
0
    }
718
0
}
719
720
721
/**************** Decoder State Machines ******************/
722
723
724
static void
725
state_machine_v4( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
726
1
    int offset, packet_info *pinfo) {
727
728
/* Decode V4 protocol.  This is done on the first pass through the  */
729
/* list.  Based upon the current state, decode the packet and determine */
730
/* what the next state should be.  */
731
1
    address addr;
732
733
1
    if (hash_info->clientState != clientDone)
734
1
        save_client_state(pinfo, hash_info->clientState);
735
736
1
    if (hash_info->serverState != serverDone)
737
1
        save_server_state(pinfo, hash_info->serverState);
738
739
1
    if (hash_info->server_port == pinfo->destport) {
740
        /* Client side, only a single request */
741
1
        col_append_str(pinfo->cinfo, COL_INFO, " Connect to server request");
742
743
1
        hash_info->command = tvb_get_uint8(tvb, offset + 1);
744
745
        /* get remote port */
746
1
        if ( hash_info->command == CONNECT_COMMAND)
747
0
            hash_info->port =  tvb_get_ntohs(tvb, offset + 2);
748
749
        /* get remote address */
750
1
        set_address_tvb(&addr, AT_IPv4, 4, tvb, offset);
751
1
        copy_address_wmem(wmem_file_scope(), &hash_info->dst_addr, &addr);
752
753
1
        hash_info->clientState = clientDone;
754
1
    }
755
0
    else {
756
0
        col_append_str(pinfo->cinfo, COL_INFO, " Connect Response");
757
758
0
        if (tvb_get_uint8(tvb, offset + 1) == 90)
759
0
            hash_info->serverState = serverDone;
760
0
        else
761
0
            hash_info->serverState = serverError;
762
0
    }
763
1
}
764
765
static void
766
// NOLINTNEXTLINE(misc-no-recursion)
767
client_state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
768
27
    int offset, packet_info *pinfo, bool start_of_frame) {
769
770
/* Decode client side of V5 protocol.  This is done on the first pass through the   */
771
/* list.  Based upon the current state, decode the packet and determine */
772
/* what the next state should be. */
773
774
27
    if (start_of_frame) {
775
25
        save_client_state(pinfo, hash_info->clientState);
776
25
        save_server_state(pinfo, hash_info->serverState);
777
25
    }
778
779
27
    if (hash_info->clientState == clientStart)
780
24
    {
781
24
        uint8_t num_auth_methods;
782
783
24
        num_auth_methods = tvb_get_uint8(tvb, offset + 1);
784
                        /* skip past auth methods */
785
786
24
        if ((num_auth_methods == 0) ||
787
23
            ((num_auth_methods == 1) &&
788
2
             (tvb_get_uint8(tvb, offset + 2) == 0))) {
789
            /* No authentication needed */
790
2
            hash_info->clientState = clientV5Command;
791
2
            if (tvb_reported_length_remaining(tvb, offset + 2 + num_auth_methods) > 0) {
792
2
                increment_dissection_depth(pinfo);
793
2
                client_state_machine_v5(hash_info, tvb, offset + 2 + num_auth_methods, pinfo, false);
794
2
                decrement_dissection_depth(pinfo);
795
2
            }
796
22
        } else {
797
22
            hash_info->clientState = clientWaitForAuthReply;
798
22
        }
799
24
    } else if ((hash_info->clientState == clientWaitForAuthReply) &&
800
1
               (hash_info->serverState == serverInitReply)) {
801
802
0
        switch(hash_info->authentication_method)
803
0
        {
804
0
        case NO_AUTHENTICATION:
805
0
            hash_info->clientState = clientV5Command;
806
0
            hash_info->serverState = serverCommandReply;
807
0
            break;
808
0
        case USER_NAME_AUTHENTICATION:
809
0
            hash_info->clientState = clientV5Command;
810
0
            hash_info->serverState = serverUserReply;
811
0
            break;
812
0
        case GSS_API_AUTHENTICATION:
813
0
            hash_info->clientState = clientV5Command;
814
0
            hash_info->serverState = serverGssApiReply;
815
0
            break;
816
0
        default:
817
0
            hash_info->clientState = clientError;   /*Auth failed or error*/
818
0
            break;
819
0
        }
820
3
    } else if (hash_info->clientState == clientV5Command) {
821
2
        hash_info->command = tvb_get_uint8(tvb, offset + 1); /* get command */
822
823
2
        offset += 3;            /* skip to address type */
824
825
2
        offset = get_address_v5(tvb, offset, hash_info);
826
827
        /** temp = tvb_get_uint8(tvb, offset);  XX: what was this for ? **/
828
829
2
        if (( hash_info->command == CONNECT_COMMAND) ||
830
2
            ( hash_info->command == UDP_ASSOCIATE_COMMAND))
831
                        /* get remote port  */
832
0
            hash_info->port =  tvb_get_ntohs(tvb, offset);
833
834
2
        hash_info->clientState = clientDone;
835
2
    }
836
27
}
837
838
static void
839
server_state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
840
0
    int offset, packet_info *pinfo, bool start_of_frame) {
841
842
/* Decode server side of V5 protocol.  This is done on the first pass through the   */
843
/* list.  Based upon the current state, decode the packet and determine */
844
/* what the next state should be. */
845
846
0
    if (start_of_frame)
847
0
        save_server_state(pinfo, hash_info->serverState);
848
849
0
    switch (hash_info->serverState) {
850
0
    case serverStart:
851
0
        hash_info->authentication_method = tvb_get_uint8(tvb, offset + 1);
852
0
        switch (hash_info->authentication_method)
853
0
        {
854
0
        case NO_AUTHENTICATION:
855
            /* If there is no authentication, client should expect command immediately */
856
0
            hash_info->serverState = serverCommandReply;
857
0
            hash_info->clientState = clientV5Command;
858
0
            break;
859
0
        case USER_NAME_AUTHENTICATION:
860
0
            hash_info->serverState = serverInitReply;
861
0
            break;
862
0
        case GSS_API_AUTHENTICATION:
863
0
            hash_info->serverState = serverInitReply;
864
0
            break;
865
0
        default:
866
0
            hash_info->serverState = serverError;
867
0
            break;
868
0
        }
869
0
        break;
870
0
    case serverUserReply:
871
0
        hash_info->serverState = serverCommandReply;
872
0
        break;
873
0
    case serverGssApiReply:
874
0
        if (tvb_get_uint8(tvb, offset+1) == 0xFF) {
875
0
            hash_info->serverState = serverError;
876
0
        } else {
877
0
            if (tvb_get_ntohs(tvb, offset+2) == 0)
878
0
                hash_info->serverState = serverCommandReply;
879
0
        }
880
0
        break;
881
0
    case serverCommandReply:
882
0
        switch(hash_info->command)
883
0
        {
884
0
        case CONNECT_COMMAND:
885
0
        case PING_COMMAND:
886
0
        case TRACERT_COMMAND:
887
0
            hash_info->serverState = serverDone;
888
0
            break;
889
890
0
        case BIND_COMMAND:
891
0
            hash_info->serverState = serverBindReply;
892
0
            if ((tvb_get_uint8(tvb, offset + 2) == 0) &&
893
0
                (tvb_reported_length_remaining(tvb, offset) > 5)) {
894
0
                    offset = display_address(pinfo, tvb, offset, NULL);
895
0
                    client_state_machine_v5(hash_info, tvb, offset, pinfo, false);
896
0
            }
897
0
            break;
898
899
0
        case UDP_ASSOCIATE_COMMAND:
900
0
            offset += 3;        /* skip to address type */
901
0
            offset = get_address_v5(tvb, offset, hash_info);
902
903
            /* save server udp port and create udp conversation */
904
0
            hash_info->udp_port =  tvb_get_ntohs(tvb, offset);
905
906
0
            if (!pinfo->fd->visited)
907
0
                new_udp_conversation( hash_info, pinfo);
908
909
0
            break;
910
0
        }
911
0
        break;
912
0
    case serverBindReply:
913
0
        break;
914
0
    default:
915
0
        break;
916
0
    }
917
0
}
918
919
920
static void
921
0
display_ping_and_tracert(tvbuff_t *tvb, unsigned offset, packet_info *pinfo, proto_tree *tree, socks_hash_entry_t *hash_info) {
922
923
/* Display the ping/trace_route conversation */
924
925
0
    unsigned      linelen;
926
927
                /* handle the end command */
928
0
    if ( pinfo->destport == pinfo->match_uint){
929
0
        col_append_str(pinfo->cinfo, COL_INFO, ", Terminate Request");
930
931
0
        proto_tree_add_item(tree, (hash_info->command  == PING_COMMAND) ? hf_socks_ping_end_command : hf_socks_traceroute_end_command, tvb, offset, 1, ENC_NA);
932
0
    }
933
0
    else {      /* display the PING or Traceroute results */
934
0
        col_append_str(pinfo->cinfo, COL_INFO, ", Results");
935
936
0
        if ( tree){
937
0
            proto_tree_add_item(tree, (hash_info->command  == PING_COMMAND) ? hf_socks_ping_results : hf_socks_traceroute_results, tvb, offset, -1, ENC_NA);
938
939
0
            while (tvb_captured_length_remaining(tvb, offset)) {
940
0
                unsigned next_offset;
941
0
                tvb_find_line_end_remaining(tvb, offset, NULL, &next_offset);
942
                /* Use the linelen including the line terminator. */
943
0
                linelen = next_offset - offset;
944
945
0
                proto_tree_add_format_text( tree, tvb, offset, linelen);
946
0
                offset = next_offset;
947
0
            }
948
0
        }
949
0
    }
950
0
}
951
952
static void clear_in_socks_dissector_flag(void *s)
953
0
{
954
0
    sock_state_t* state_info = (sock_state_t*)s;
955
0
    state_info->in_socks_dissector_flag = 0; /* avoid recursive overflow */
956
0
}
957
958
static void call_next_dissector(tvbuff_t *tvb, int offset, packet_info *pinfo,
959
    proto_tree *tree, proto_tree *socks_tree,
960
    socks_hash_entry_t *hash_info, sock_state_t* state_info, struct tcpinfo *tcpinfo)
961
0
{
962
963
/* Display the results for PING and TRACERT extensions or       */
964
/* Call TCP dissector for the port that was passed during the           */
965
/* connect process                                  */
966
/* Load pointer to pinfo->XXXport depending upon the direction,     */
967
/* change pinfo port to the remote port, call next dissector to decode  */
968
/* the payload, and restore the pinfo port after that is done.      */
969
970
0
    uint32_t *ptr;
971
0
    uint16_t save_port;
972
0
    uint16_t save_can_desegment;
973
0
    struct tcp_analysis *tcpd=NULL;
974
975
976
0
    if (( hash_info->command  == PING_COMMAND) ||
977
0
        ( hash_info->command  == TRACERT_COMMAND))
978
979
0
        display_ping_and_tracert(tvb, offset, pinfo, tree, hash_info);
980
981
0
    else {      /* call the tcp port decoder to handle the payload */
982
983
/*XXX may want to load dest address here */
984
985
0
        if (pinfo->destport == pinfo->match_uint) {
986
0
            ptr = &pinfo->destport;
987
0
        } else {
988
0
            ptr = &pinfo->srcport;
989
0
        }
990
991
0
        save_port = *ptr;
992
0
        *ptr = hash_info->port;
993
994
0
        if (hash_info->proxy_conv == NULL) {
995
0
            hash_info->proxy_conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
996
0
                CONVERSATION_TCP /* CONVERSATION_SOCKS? */, pinfo->srcport, pinfo->destport, 0);
997
0
        }
998
999
0
        tcpd = get_tcp_conversation_data(hash_info->proxy_conv, pinfo);
1000
1001
0
        state_info->in_socks_dissector_flag = 1; /* avoid recursive overflow */
1002
0
        CLEANUP_PUSH(clear_in_socks_dissector_flag, state_info);
1003
1004
0
        save_can_desegment = pinfo->can_desegment;
1005
0
        pinfo->can_desegment = pinfo->saved_can_desegment;
1006
0
        dissect_tcp_payload(tvb, pinfo, offset, tcpinfo->seq,
1007
0
            tcpinfo->nxtseq, pinfo->srcport, pinfo->destport,
1008
0
            tree, socks_tree, tcpd, tcpinfo);
1009
0
        pinfo->can_desegment = save_can_desegment;
1010
1011
0
        CLEANUP_CALL_AND_POP;
1012
1013
0
        *ptr = save_port;
1014
0
    }
1015
0
}
1016
1017
1018
1019
static int
1020
27
dissect_socks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
1021
1022
27
    int                 offset     = 0;
1023
27
    proto_tree         *socks_tree = NULL;
1024
27
    proto_item         *ti;
1025
27
    socks_hash_entry_t *hash_info;
1026
27
    conversation_t     *conversation;
1027
27
    sock_state_t*       state_info;
1028
27
    uint8_t             version;
1029
27
    struct tcpinfo     *tcpinfo    = (struct tcpinfo*)data;
1030
1031
27
    state_info = (sock_state_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_socks, 0);
1032
27
    if (state_info == NULL) {
1033
27
        state_info = wmem_new(wmem_file_scope(), sock_state_t);
1034
27
        state_info->in_socks_dissector_flag = 0;
1035
27
        state_info->client = clientNoInit;
1036
27
        state_info->server = serverNoInit;
1037
1038
27
        p_add_proto_data(wmem_file_scope(), pinfo, proto_socks, 0, state_info);
1039
27
    }
1040
1041
    /* avoid recursive overflow */
1042
27
    if (state_info->in_socks_dissector_flag)
1043
0
        return 0;
1044
1045
27
    conversation = find_conversation_pinfo(pinfo, 0);
1046
27
    if (conversation == NULL) {
1047
        /* If we don't already have a conversation, make sure the first
1048
           byte is a valid version number */
1049
0
        version = tvb_get_uint8(tvb, offset);
1050
0
        if ((version != 4) && (version != 5))
1051
0
            return 0;
1052
1053
0
        conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
1054
0
                                        conversation_pt_to_conversation_type(pinfo->ptype), pinfo->srcport, pinfo->destport, 0);
1055
0
    }
1056
1057
27
    hash_info = (socks_hash_entry_t *)conversation_get_proto_data(conversation,proto_socks);
1058
27
    if (hash_info == NULL){
1059
26
        hash_info = wmem_new0(wmem_file_scope(), socks_hash_entry_t);
1060
26
        hash_info->start_done_frame = INT_MAX;
1061
26
        hash_info->clientState = clientStart;
1062
26
        hash_info->serverState = serverStart;
1063
1064
26
        hash_info->server_port = pinfo->destport;
1065
26
        hash_info->port = 0;
1066
26
        hash_info->version = tvb_get_uint8(tvb, offset); /* get version*/
1067
1068
26
        conversation_add_proto_data(conversation, proto_socks, hash_info);
1069
1070
                        /* set dissector for now */
1071
26
        if (conversation_get_dissector(conversation, pinfo->num) != NULL) {
1072
0
            conversation_set_dissector(conversation, socks_handle);
1073
0
        }
1074
26
    }
1075
1076
    /* display summary window information  */
1077
27
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "Socks");
1078
1079
27
    if (( hash_info->version == 4) || ( hash_info->version == 5)){
1080
26
        col_add_fstr(pinfo->cinfo, COL_INFO, "Version: %d",
1081
26
            hash_info->version);
1082
26
    }
1083
1
    else            /* unknown version display error */
1084
1
        col_set_str(pinfo->cinfo, COL_INFO, "Unknown");
1085
1086
1087
27
    if ( hash_info->command == PING_COMMAND)
1088
0
        col_append_str(pinfo->cinfo, COL_INFO, ", Ping Req");
1089
27
    if ( hash_info->command == TRACERT_COMMAND)
1090
0
        col_append_str(pinfo->cinfo, COL_INFO, ", Traceroute Req");
1091
1092
    /* run state machine if needed */
1093
27
    if ((!pinfo->fd->visited) &&
1094
27
        (!((hash_info->clientState == clientDone) &&
1095
27
           (hash_info->serverState == serverDone)))) {
1096
1097
27
        if (hash_info->server_port == pinfo->destport) {
1098
27
            if ((hash_info->clientState != clientError) &&
1099
27
                (hash_info->clientState != clientDone))
1100
27
            {
1101
27
                if ( hash_info->version == 4) {
1102
1
                    state_machine_v4( hash_info, tvb, offset, pinfo);
1103
26
                } else if ( hash_info->version == 5) {
1104
25
                    client_state_machine_v5( hash_info, tvb, offset, pinfo, true);
1105
25
                }
1106
27
            }
1107
27
        } else {
1108
0
            if ((hash_info->serverState != serverError) &&
1109
0
                (hash_info->serverState != serverDone)) {
1110
0
                if ( hash_info->version == 4) {
1111
0
                    state_machine_v4( hash_info, tvb, offset, pinfo);
1112
0
                } else if ( hash_info->version == 5) {
1113
0
                    server_state_machine_v5( hash_info, tvb, offset, pinfo, true);
1114
0
                }
1115
0
            }
1116
0
        }
1117
1118
27
        if ((hash_info->clientState == clientDone) &&
1119
3
            (hash_info->serverState == serverDone)) {   /* if done now  */
1120
0
            hash_info->start_done_frame = pinfo->num;
1121
0
        }
1122
27
    }
1123
1124
    /* if proto tree, decode and display */
1125
27
    if (tree) {
1126
27
        ti = proto_tree_add_item( tree, proto_socks, tvb, offset, -1, ENC_NA );
1127
27
        socks_tree = proto_item_add_subtree(ti, ett_socks);
1128
1129
        /* if past startup, add the faked stuff */
1130
27
        if ( pinfo->num > hash_info->start_done_frame){
1131
                        /*  add info to tree */
1132
0
            ti = proto_tree_add_uint( socks_tree, hf_socks_ver, tvb, offset, 0, hash_info->version);
1133
0
            proto_item_set_generated(ti);
1134
1135
0
            ti = proto_tree_add_uint( socks_tree, hf_socks_cmd, tvb, offset, 0, hash_info->command);
1136
0
            proto_item_set_generated(ti);
1137
1138
0
            if (hash_info->dst_addr.type == AT_IPv4) {
1139
0
                ti = proto_tree_add_ipv4( socks_tree, hf_socks_ip_dst, tvb,
1140
0
                    offset, 0, *((const uint32_t*)hash_info->dst_addr.data));
1141
0
                proto_item_set_generated(ti);
1142
0
            } else if (hash_info->dst_addr.type == AT_IPv6) {
1143
0
                ti = proto_tree_add_ipv6( socks_tree, hf_socks_ip6_dst, tvb,
1144
0
                    offset, 0, (const ws_in6_addr *)hash_info->dst_addr.data);
1145
0
                proto_item_set_generated(ti);
1146
0
            }
1147
1148
                /* no fake address for ping & traceroute */
1149
1150
0
            if (( hash_info->command != PING_COMMAND) &&
1151
0
                ( hash_info->command != TRACERT_COMMAND)){
1152
0
                ti = proto_tree_add_uint( socks_tree, hf_socks_dstport, tvb, offset, 0, hash_info->port);
1153
0
                proto_item_set_generated(ti);
1154
0
            }
1155
27
        } else {
1156
27
            if (hash_info->server_port == pinfo->destport) {
1157
27
                if ( hash_info->version == 4) {
1158
1
                    display_socks_v4(tvb, offset, pinfo, socks_tree, hash_info, state_info);
1159
26
                } else if ( hash_info->version == 5) {
1160
25
                    client_display_socks_v5(tvb, offset, pinfo, socks_tree, hash_info, state_info);
1161
25
                }
1162
27
            } else {
1163
0
                if ( hash_info->version == 4) {
1164
0
                    display_socks_v4(tvb, offset, pinfo, socks_tree, hash_info, state_info);
1165
0
                } else if ( hash_info->version == 5) {
1166
0
                    server_display_socks_v5(tvb, offset, pinfo, socks_tree, hash_info, state_info);
1167
0
                }
1168
0
            }
1169
27
        }
1170
1171
27
    }
1172
1173
1174
    /* call next dissector if ready */
1175
27
    if ( pinfo->num > hash_info->start_done_frame){
1176
0
        call_next_dissector(tvb, offset, pinfo, tree, socks_tree,
1177
0
            hash_info, state_info, tcpinfo);
1178
0
    }
1179
1180
27
    return tvb_reported_length(tvb);
1181
27
}
1182
1183
1184
static int
1185
0
dissect_socks_tls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
1186
0
    if (data != NULL) {
1187
0
        return dissect_socks(tvb, pinfo, tree, data);
1188
0
    } else {
1189
        /* lets fake a tcpinfo, which TLS does not give us */
1190
0
        struct tcpinfo tmp;
1191
0
        tmp.flags = 0;
1192
0
        tmp.is_reassembled = false;
1193
0
        tmp.lastackseq = 0;
1194
0
        tmp.nxtseq = 0;
1195
0
        tmp.seq = 0;
1196
0
        tmp.urgent_pointer = 0;
1197
0
        return dissect_socks(tvb, pinfo, tree, &tmp);
1198
0
    }
1199
0
}
1200
1201
void
1202
16
proto_register_socks( void){
1203
1204
16
    static int *ett[] = {
1205
16
        &ett_socks,
1206
16
        &ett_socks_auth,
1207
16
        &ett_socks_name
1208
16
    };
1209
1210
16
    static hf_register_info hf[] = {
1211
1212
1213
16
        { &hf_socks_ver,
1214
16
            { "Version", "socks.version", FT_UINT8, BASE_DEC, NULL,
1215
16
                0x0, NULL, HFILL
1216
16
            }
1217
16
        },
1218
16
        { &hf_socks_ip_dst,
1219
16
            { "Remote Address", "socks.dst", FT_IPv4, BASE_NONE, NULL,
1220
16
                0x0, NULL, HFILL
1221
16
            }
1222
16
        },
1223
16
        { &hf_socks_ip6_dst,
1224
16
            { "Remote Address(ipv6)", "socks.dstV6", FT_IPv6, BASE_NONE, NULL,
1225
16
                0x0, NULL, HFILL
1226
16
            }
1227
16
        },
1228
16
        { &hf_gssapi_payload,
1229
16
            { "GSSAPI data", "socks.gssapi.data", FT_BYTES, BASE_NONE, NULL,
1230
16
                0x0, NULL, HFILL
1231
16
            }
1232
16
        },
1233
16
        { &hf_gssapi_command,
1234
16
            { "SOCKS/GSSAPI command", "socks.gssapi.command", FT_UINT8, BASE_DEC,
1235
16
                VALS(gssapi_command_table), 0x0, NULL, HFILL
1236
16
            }
1237
16
        },
1238
16
        { &hf_gssapi_length,
1239
16
            { "SOCKS/GSSAPI data length", "socks.gssapi.length", FT_UINT16, BASE_DEC, NULL,
1240
16
                0x0, NULL, HFILL
1241
16
            }
1242
16
        },
1243
16
        { &hf_v4a_dns_name,
1244
16
            { "SOCKS v4a Remote Domain Name", "socks.v4a_dns_name", FT_STRINGZ, BASE_NONE,
1245
16
                NULL, 0x0, NULL, HFILL
1246
16
            }
1247
16
        },
1248
16
        { &hf_socks_dstport,
1249
16
            { "Remote Port", "socks.dstport", FT_UINT16,
1250
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1251
16
            }
1252
16
        },
1253
16
        { &hf_socks_cmd,
1254
16
            { "Command", "socks.command", FT_UINT8,
1255
16
                BASE_DEC,  VALS(cmd_strings), 0x0, NULL, HFILL
1256
16
            }
1257
16
        },
1258
16
        { &hf_socks_results_4,
1259
16
            { "Results(V4)", "socks.results", FT_UINT8,
1260
16
                BASE_DEC, VALS(reply_table_v4), 0x0, NULL, HFILL
1261
16
            }
1262
16
        },
1263
16
        { &hf_socks_results_5,
1264
16
            { "Results(V5)", "socks.results", FT_UINT8,
1265
16
                BASE_DEC, VALS(reply_table_v5), 0x0, NULL, HFILL
1266
16
            }
1267
16
        },
1268
16
        { &hf_client_auth_method_count,
1269
16
            { "Authentication Method Count", "socks.auth_method_count", FT_UINT8,
1270
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1271
16
            }
1272
16
        },
1273
16
        { &hf_client_auth_method,
1274
16
            { "Method", "socks.auth_method", FT_UINT8,
1275
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1276
16
            }
1277
16
        },
1278
16
        { &hf_socks_reserved,
1279
16
            { "Reserved", "socks.reserved", FT_UINT8,
1280
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1281
16
            }
1282
16
        },
1283
16
        { &hf_socks_reserved2,
1284
16
            { "Reserved", "socks.reserved", FT_UINT16,
1285
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1286
16
            }
1287
16
        },
1288
16
        { &hf_client_port,
1289
16
            { "Port", "socks.port", FT_UINT16,
1290
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1291
16
            }
1292
16
        },
1293
16
        { &hf_server_accepted_auth_method,
1294
16
            { "Accepted Auth Method", "socks.auth_accepted_method", FT_UINT8,
1295
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1296
16
            }
1297
16
        },
1298
16
        { &hf_server_auth_status,
1299
16
            { "Status", "socks.auth_status", FT_UINT8,
1300
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1301
16
            }
1302
16
        },
1303
16
        { &hf_server_remote_host_port,
1304
16
            { "Remote Host Port", "socks.remote_host_port", FT_UINT16,
1305
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1306
16
            }
1307
16
        },
1308
16
        { &hf_socks_subnegotiation_version,
1309
16
            { "Subnegotiation Version", "socks.subnegotiation_version", FT_UINT8, BASE_DEC, NULL,
1310
16
                0x0, NULL, HFILL
1311
16
            }
1312
16
        },
1313
16
        { &hf_socks_username,
1314
16
            { "User name", "socks.username", FT_STRING, BASE_NONE,
1315
16
                NULL, 0x0, NULL, HFILL
1316
16
            }
1317
16
        },
1318
16
        { &hf_socks_password,
1319
16
            { "Password", "socks.password", FT_STRING, BASE_NONE,
1320
16
                NULL, 0x0, NULL, HFILL
1321
16
            }
1322
16
        },
1323
16
        { &hf_socks_remote_name,
1324
16
            { "Remote name", "socks.remote_name", FT_STRING, BASE_NONE,
1325
16
                NULL, 0x0, NULL, HFILL
1326
16
            }
1327
16
        },
1328
16
        { &hf_socks_address_type,
1329
16
            { "Address Type", "socks.address_type", FT_UINT8,
1330
16
                BASE_DEC, VALS(address_type_table), 0x0, NULL, HFILL
1331
16
            }
1332
16
        },
1333
16
        { &hf_socks_fragment_number,
1334
16
            { "Fragment Number", "socks.fragment_number", FT_UINT8,
1335
16
                BASE_DEC, NULL, 0x0, NULL, HFILL
1336
16
            }
1337
16
        },
1338
16
        { &hf_socks_ping_end_command,
1339
16
            { "Ping: End command", "socks.ping_end_command", FT_NONE,
1340
16
                BASE_NONE, NULL, 0x0, NULL, HFILL
1341
16
            }
1342
16
        },
1343
16
        { &hf_socks_ping_results,
1344
16
            { "Ping Results", "socks.ping_results", FT_NONE,
1345
16
                BASE_NONE, NULL, 0x0, NULL, HFILL
1346
16
            }
1347
16
        },
1348
16
        { &hf_socks_traceroute_end_command,
1349
16
            { "Traceroute: End command", "socks.traceroute_end_command", FT_NONE,
1350
16
                BASE_NONE, NULL, 0x0, NULL, HFILL
1351
16
            }
1352
16
        },
1353
16
        { &hf_socks_traceroute_results,
1354
16
            { "Traceroute Results", "socks.traceroute_results", FT_NONE,
1355
16
                BASE_NONE, NULL, 0x0, NULL, HFILL
1356
16
            }
1357
16
        },
1358
16
    };
1359
1360
16
    proto_socks = proto_register_protocol ( "Socks Protocol", "Socks", "socks");
1361
1362
16
    proto_register_field_array(proto_socks, hf, array_length(hf));
1363
16
    proto_register_subtree_array(ett, array_length(ett));
1364
1365
16
    socks_udp_handle = register_dissector_with_description("socks_udp", "SOCKS over UDP", socks_udp_dissector, proto_socks);
1366
16
    socks_handle = register_dissector_with_description("socks_tcp", "SOCKS over TCP", dissect_socks, proto_socks);
1367
16
    socks_handle_tls = register_dissector_with_description("socks_tls", "SOCKS over TLS", dissect_socks_tls, proto_socks);
1368
16
}
1369
1370
1371
void
1372
16
proto_reg_handoff_socks(void) {
1373
1374
    /* dissector install routine */
1375
1376
16
    dissector_add_uint_with_preference("tcp.port", TCP_PORT_SOCKS, socks_handle);
1377
1378
16
    ssl_dissector_add(0, socks_handle_tls);
1379
16
}
1380
1381
/*
1382
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1383
 *
1384
 * Local variables:
1385
 * c-basic-offset: 4
1386
 * tab-width: 8
1387
 * indent-tabs-mode: nil
1388
 * End:
1389
 *
1390
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1391
 * :indentSize=4:tabSize=8:noTabs=true:
1392
 */