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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * The Version 4 decode is based on SOCKS4.protocol and SOCKS4A.protocol.
28 * The Version 5 decoder is based upon rfc-1928
29 * The Version 5 User/Password authentication is based on rfc-1929.
32 * http://www.openssh.org/txt/socks4.protocol
33 * http://www.openssh.org/txt/socks4a.protocol
35 * for information on SOCKS version 4 and 4a.
39 * 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel
40 * causing heap overflow because of an infinite loop
41 * where the socks dissect was call over and over.
43 * Also remove some old code marked with __JUNK__
45 * 2001-01-08 JCFoster Fixed problem with NULL pointer for hash data.
46 * Now test and exit if hash_info is null.
49 /* Possible enhancements -
51 * Add GSS-API authentication per rfc-1961
52 * Add CHAP authentication
53 * Decode FLAG bits per
54 * http://archive.socks.permeo.com/draft/draft-ietf-aft-socks-pro-v5-04.txt
55 * In call_next_dissector, could load the destination address into
56 * pinfo->src or pinfo->dst structure before calling next dissector.
66 #include <epan/packet.h>
67 #include <epan/exceptions.h>
68 #include <epan/conversation.h>
70 #include "packet-tcp.h"
71 #include "packet-udp.h"
72 #include <epan/strutil.h>
74 #include <epan/wmem/wmem.h>
76 #define TCP_PORT_SOCKS 1080
79 /**************** Socks commands ******************/
81 #define CONNECT_COMMAND 1
82 #define BIND_COMMAND 2
83 #define UDP_ASSOCIATE_COMMAND 3
84 #define PING_COMMAND 0x80
85 #define TRACERT_COMMAND 0x81
88 /********** V5 Authentication methods *************/
90 #define NO_AUTHENTICATION 0
91 #define GSS_API_AUTHENTICATION 1
92 #define USER_NAME_AUTHENTICATION 2
93 #define CHAP_AUTHENTICATION 3
94 #define AUTHENTICATION_FAILED 0xff
96 /*********** Header field identifiers *************/
98 static int proto_socks
= -1;
100 static int ett_socks
= -1;
101 static int ett_socks_auth
= -1;
102 static int ett_socks_name
= -1;
104 static int hf_socks_ver
= -1;
105 static int hf_socks_ip_dst
= -1;
106 static int hf_socks_ip6_dst
= -1;
107 static int hf_gssapi_payload
= -1;
108 static int hf_gssapi_command
= -1;
109 static int hf_gssapi_length
= -1;
110 static int hf_v4a_dns_name
= -1;
111 static int hf_socks_dstport
= -1;
112 static int hf_socks_cmd
= -1;
113 static int hf_socks_results_4
= -1;
114 static int hf_socks_results_5
= -1;
115 static int hf_client_auth_method_count
= -1;
116 static int hf_client_auth_method
= -1;
117 static int hf_socks_reserved
= -1;
118 static int hf_socks_reserved2
= -1;
119 static int hf_client_port
= -1;
120 static int hf_server_accepted_auth_method
= -1;
121 static int hf_server_auth_status
= -1;
122 static int hf_server_remote_host_port
= -1;
123 static int hf_socks_username
= -1;
124 static int hf_socks_password
= -1;
125 static int hf_socks_remote_name
= -1;
126 static int hf_socks_address_type
= -1;
127 static int hf_socks_fragment_number
= -1;
129 /************* Dissector handles ***********/
131 static dissector_handle_t socks_handle
;
132 static dissector_handle_t socks_udp_handle
;
134 /************* State Machine names ***********/
139 clientWaitForAuthReply
,
141 clientUserNameRequest
,
142 clientGssApiAuthRequest
,
160 int in_socks_dissector_flag
;
161 enum ClientState client
;
162 enum ServerState server
;
166 enum ClientState clientState
;
167 enum ServerState serverState
;
170 int authentication_method
;
174 guint32 udp_remote_port
;
177 guint32 start_done_frame
;
181 static const value_string address_type_table
[] = {
188 /* String table for the V4 reply status messages */
190 static const value_string reply_table_v4
[] = {
192 {91, "Rejected or Failed"},
193 {92, "Rejected because SOCKS server cannot connect to identd on the client"},
194 {93, "Rejected because the client program and identd report different user-ids"},
198 /* String table for the V5 reply status messages */
200 static const value_string reply_table_v5
[] = {
202 {1, "General SOCKS server failure"},
203 {2, "Connection not allowed by ruleset"},
204 {3, "Network unreachable"},
205 {4, "Host unreachable"},
206 {5, "Connection refused"},
208 {7, "Command not supported"},
209 {8, "Address type not supported"},
213 static const value_string cmd_strings
[] = {
214 {CONNECT_COMMAND
, "Connect"},
215 {BIND_COMMAND
, "Bind"},
216 {UDP_ASSOCIATE_COMMAND
, "UdpAssociate"},
217 {PING_COMMAND
, "Ping"},
218 {TRACERT_COMMAND
, "Traceroute"},
222 static const value_string gssapi_command_table
[] = {
223 { 1, "Authentication" },
229 /************************* Support routines ***************************/
231 static const char *get_auth_method_name( guint Number
){
233 /* return the name of the authenication method */
235 if ( Number
== 0) return "No authentication";
236 if ( Number
== 1) return "GSSAPI";
237 if ( Number
== 2) return "Username/Password";
238 if ( Number
== 3) return "Chap";
239 if (( Number
>= 4) && ( Number
<= 0x7f))return "IANA assigned";
240 if (( Number
>= 0x80) && ( Number
<= 0xfe)) return "private method";
241 if ( Number
== 0xff) return "no acceptable method";
243 /* shouldn't reach here */
245 return "Bad method number (not 0-0xff)";
248 static int display_address(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
250 /* decode and display the v5 address, return offset of next byte */
252 int a_type
= tvb_get_guint8(tvb
, offset
);
254 proto_tree_add_item( tree
, hf_socks_address_type
, tvb
, offset
, 1, ENC_NA
);
259 case 1: /* IPv4 address */
260 proto_tree_add_item( tree
, hf_socks_ip_dst
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
263 case 3: /* domain name address */
268 len
= tvb_get_guint8(tvb
, offset
);
269 str
= tvb_get_string(wmem_packet_scope(), tvb
, offset
+1, len
);
270 proto_tree_add_string(tree
, hf_socks_remote_name
, tvb
, offset
, len
+1, str
);
274 case 4: /* IPv6 address */
275 proto_tree_add_item( tree
, hf_socks_ip6_dst
, tvb
, offset
, 16, ENC_NA
);
284 static int get_address_v5(tvbuff_t
*tvb
, int offset
,
285 socks_hash_entry_t
*hash_info
) {
287 /* decode the v5 address and return offset of next byte */
291 a_type
= tvb_get_guint8(tvb
, offset
);
296 case 1: /* IPv4 address */
298 TVB_SET_ADDRESS(&addr
, AT_IPv4
, tvb
, offset
, 4);
299 SE_COPY_ADDRESS(&hash_info
->dst_addr
, &addr
);
304 case 4: /* IPv6 address */
306 TVB_SET_ADDRESS(&addr
, AT_IPv6
, tvb
, offset
, 16);
307 SE_COPY_ADDRESS(&hash_info
->dst_addr
, &addr
);
312 case 3: /* domain name address */
313 offset
+= tvb_get_guint8(tvb
, offset
) + 1;
321 /********************* V5 UDP Associate handlers ***********************/
324 socks_udp_dissector(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
) {
326 /* Conversation dissector called from UDP dissector. Decode and display */
327 /* the socks header, the pass the rest of the data to the udp port */
328 /* decode routine to handle the payload. */
332 socks_hash_entry_t
*hash_info
;
333 conversation_t
*conversation
;
334 proto_tree
*socks_tree
;
337 conversation
= find_conversation( pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, pinfo
->ptype
,
338 pinfo
->srcport
, pinfo
->destport
, 0);
340 DISSECTOR_ASSERT( conversation
); /* should always find a conversation */
342 hash_info
= (socks_hash_entry_t
*)conversation_get_proto_data(conversation
, proto_socks
);
344 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Socks");
345 col_set_str(pinfo
->cinfo
, COL_INFO
, "Version: 5, UDP Associated packet");
348 ti
= proto_tree_add_protocol_format( tree
, proto_socks
, tvb
, offset
, -1, "Socks" );
350 socks_tree
= proto_item_add_subtree(ti
, ett_socks
);
352 proto_tree_add_item(socks_tree
, hf_socks_reserved2
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
355 proto_tree_add_item(socks_tree
, hf_socks_fragment_number
, tvb
, offset
, 1, ENC_NA
);
358 offset
= display_address( tvb
, offset
, socks_tree
);
359 hash_info
->udp_remote_port
= tvb_get_ntohs(tvb
, offset
);
361 proto_tree_add_uint( socks_tree
, hf_socks_dstport
, tvb
,
362 offset
, 2, hash_info
->udp_remote_port
);
366 else { /* no tree, skip past the socks header */
368 offset
= get_address_v5( tvb
, offset
, 0) + 2;
371 /* set pi src/dst port and call the udp sub-dissector lookup */
373 if ( pinfo
->srcport
== hash_info
->port
)
374 ptr
= &pinfo
->destport
;
376 ptr
= &pinfo
->srcport
;
378 *ptr
= hash_info
->udp_remote_port
;
380 decode_udp_ports( tvb
, offset
, pinfo
, tree
, pinfo
->srcport
, pinfo
->destport
, -1);
382 *ptr
= hash_info
->udp_port
;
387 new_udp_conversation( socks_hash_entry_t
*hash_info
, packet_info
*pinfo
){
389 conversation_t
*conversation
= conversation_new( pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, PT_UDP
,
390 hash_info
->udp_port
, hash_info
->port
, 0);
392 DISSECTOR_ASSERT( conversation
);
394 conversation_add_proto_data(conversation
, proto_socks
, hash_info
);
395 conversation_set_dissector(conversation
, socks_udp_handle
);
399 save_client_state(packet_info
*pinfo
, enum ClientState state
)
401 sock_state_t
* state_info
= (sock_state_t
*)p_get_proto_data(pinfo
->fd
, proto_socks
, 0);
402 if ((state_info
!= NULL
) && (state_info
->client
== clientNoInit
)) {
403 state_info
->client
= state
;
408 save_server_state(packet_info
*pinfo
, enum ServerState state
)
410 sock_state_t
* state_info
= (sock_state_t
*)p_get_proto_data(pinfo
->fd
, proto_socks
, 0);
411 if ((state_info
!= NULL
) && (state_info
->server
== serverNoInit
)) {
412 state_info
->server
= state
;
417 /**************** Protocol Tree Display routines ******************/
420 display_socks_v4(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
421 proto_tree
*tree
, socks_hash_entry_t
*hash_info
, sock_state_t
* state_info
) {
424 /* Display the protocol tree for the V4 version. This routine uses the */
425 /* stored frame information to decide what to do with the row. */
427 unsigned char ipaddr
[4];
430 /* Either there is an error, or we're done with the state machine
431 (so there's nothing to display) */
432 if (state_info
== NULL
)
435 if (hash_info
->server_port
== pinfo
->destport
) {
437 switch (state_info
->client
)
440 proto_tree_add_item( tree
, hf_socks_ver
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
443 proto_tree_add_item( tree
, hf_socks_cmd
, tvb
, offset
, 1, ENC_NA
);
447 proto_tree_add_item( tree
, hf_socks_dstport
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
450 /* Do destination address */
451 tvb_memcpy(tvb
, ipaddr
, offset
, 4);
452 proto_tree_add_item( tree
, hf_socks_ip_dst
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
455 /* display user name */
456 str_len
= tvb_strsize(tvb
, offset
);
457 proto_tree_add_item( tree
, hf_socks_username
, tvb
, offset
, str_len
, ENC_ASCII
|ENC_NA
);
460 if ( ipaddr
[0] == 0 && ipaddr
[1] == 0 &&
461 ipaddr
[2] == 0 && ipaddr
[3] != 0) {
462 /* 0.0.0.x , where x!=0 means v4a support */
463 str_len
= tvb_strsize(tvb
, offset
);
464 proto_tree_add_item( tree
, hf_v4a_dns_name
, tvb
, offset
, str_len
, ENC_ASCII
|ENC_NA
);
472 switch (state_info
->server
)
475 proto_tree_add_item( tree
, hf_socks_ver
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
477 /* Do results code */
478 proto_tree_add_item( tree
, hf_socks_results_4
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
482 proto_tree_add_item( tree
, hf_socks_dstport
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
484 /* Do remote address */
485 proto_tree_add_item( tree
, hf_socks_ip_dst
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
494 client_display_socks_v5(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
495 proto_tree
*tree
, socks_hash_entry_t
*hash_info
, sock_state_t
* state_info
) {
497 /* Display the protocol tree for the version. This routine uses the */
498 /* stored conversation information to decide what to do with the row. */
499 /* Per packet information would have been better to do this, but we */
500 /* didn't have that when I wrote this. And I didn't expect this to get */
504 const char *AuthMethodStr
;
505 sock_state_t new_state_info
;
507 /* Either there is an error, or we're done with the state machine
508 (so there's nothing to display) */
509 if (state_info
== NULL
)
512 proto_tree_add_item( tree
, hf_socks_ver
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
515 if (state_info
->client
== clientStart
)
517 proto_tree
*AuthTree
;
519 guint8 num_auth_methods
, auth
;
521 ti
= proto_tree_add_text( tree
, tvb
, offset
, -1, "Client Authentication Methods");
522 AuthTree
= proto_item_add_subtree(ti
, ett_socks_auth
);
524 num_auth_methods
= tvb_get_guint8(tvb
, offset
);
525 proto_item_set_len(ti
, num_auth_methods
+1);
527 proto_tree_add_item( AuthTree
, hf_client_auth_method_count
, tvb
, offset
, 1, ENC_NA
);
530 for( i
= 0; i
< num_auth_methods
; ++i
) {
531 auth
= tvb_get_guint8( tvb
, offset
);
532 AuthMethodStr
= get_auth_method_name(auth
);
534 proto_tree_add_uint_format(AuthTree
, hf_client_auth_method
, tvb
, offset
, 1, auth
,
535 "Method[%u]: %u (%s)", i
, auth
, AuthMethodStr
);
539 if ((num_auth_methods
== 1) &&
540 (tvb_bytes_exist(tvb
, offset
+ 2, 1)) &&
541 (tvb_get_guint8(tvb
, offset
+ 2) == 0) &&
542 (tvb_reported_length_remaining(tvb
, offset
+ 2 + num_auth_methods
) > 0)) {
543 new_state_info
.client
= clientV5Command
;
544 client_display_socks_v5(tvb
, offset
, pinfo
, tree
, hash_info
, &new_state_info
);
547 else if (state_info
->client
== clientV5Command
) {
549 proto_tree_add_item( tree
, hf_socks_cmd
, tvb
, offset
, 1, ENC_NA
);
552 proto_tree_add_item( tree
, hf_socks_reserved
, tvb
, offset
, 1, ENC_NA
);
555 offset
= display_address(tvb
, offset
, tree
);
556 proto_tree_add_item( tree
, hf_client_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
558 else if ((state_info
->client
== clientWaitForAuthReply
) &&
559 (state_info
->server
== serverInitReply
)) {
563 switch(hash_info
->authentication_method
)
565 case NO_AUTHENTICATION
:
567 case USER_NAME_AUTHENTICATION
:
568 /* process user name */
569 len
= tvb_get_guint8(tvb
, offset
);
570 str
= tvb_get_string(wmem_packet_scope(), tvb
, offset
+1, len
);
571 proto_tree_add_string(tree
, hf_socks_username
, tvb
, offset
, len
+1, str
);
574 len
= tvb_get_guint8(tvb
, offset
);
575 str
= tvb_get_string(wmem_packet_scope(), tvb
, offset
+1, len
);
576 proto_tree_add_string(tree
, hf_socks_password
, tvb
, offset
, len
+1, str
);
577 /* offset += (len+1); */
579 case GSS_API_AUTHENTICATION
:
580 proto_tree_add_item( tree
, hf_gssapi_command
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
581 proto_tree_add_item( tree
, hf_gssapi_length
, tvb
, offset
+1, 2, ENC_BIG_ENDIAN
);
582 len
= tvb_get_ntohs(tvb
, offset
+1);
584 proto_tree_add_item( tree
, hf_gssapi_payload
, tvb
, offset
+3, len
, ENC_NA
);
593 server_display_socks_v5(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
,
594 proto_tree
*tree
, socks_hash_entry_t
*hash_info _U_
, sock_state_t
* state_info
) {
596 /* Display the protocol tree for the version. This routine uses the */
597 /* stored conversation information to decide what to do with the row. */
598 /* Per packet information would have been better to do this, but we */
599 /* didn't have that when I wrote this. And I didn't expect this to get */
602 const char *AuthMethodStr
;
603 guint8 auth
, auth_status
;
606 /* Either there is an error, or we're done with the state machine
607 (so there's nothing to display) */
608 if (state_info
== NULL
)
611 proto_tree_add_item( tree
, hf_socks_ver
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
614 switch(state_info
->server
)
617 auth
= tvb_get_guint8( tvb
, offset
);
618 AuthMethodStr
= get_auth_method_name(auth
);
620 proto_tree_add_uint_format_value(tree
, hf_server_accepted_auth_method
, tvb
, offset
, 1, auth
,
621 "0x%0x (%s)", auth
, AuthMethodStr
);
624 case serverUserReply
:
625 auth_status
= tvb_get_guint8(tvb
, offset
);
626 ti
= proto_tree_add_item(tree
, hf_server_auth_status
, tvb
, offset
, 1, ENC_NA
);
628 proto_item_append_text(ti
, " (failure)");
630 proto_item_append_text(ti
, " (success)");
633 case serverGssApiReply
:
634 auth_status
= tvb_get_guint8(tvb
, offset
);
635 proto_tree_add_item( tree
, hf_gssapi_command
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
636 if (auth_status
!= 0xFF) {
639 proto_tree_add_item( tree
, hf_gssapi_length
, tvb
, offset
+1, 2, ENC_BIG_ENDIAN
);
640 len
= tvb_get_ntohs(tvb
, offset
+1);
642 proto_tree_add_item( tree
, hf_gssapi_payload
, tvb
, offset
+3, len
, ENC_NA
);
646 case serverCommandReply
:
647 proto_tree_add_item( tree
, hf_socks_results_5
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
650 proto_tree_add_item( tree
, hf_socks_reserved
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
653 offset
= display_address(tvb
, offset
, tree
);
654 proto_tree_add_item( tree
, hf_client_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
657 case serverBindReply
:
658 proto_tree_add_item( tree
, hf_socks_results_5
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
661 proto_tree_add_item( tree
, hf_socks_reserved
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
664 offset
= display_address(tvb
, offset
, tree
);
665 proto_tree_add_item( tree
, hf_server_remote_host_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
673 /**************** Decoder State Machines ******************/
677 state_machine_v4( socks_hash_entry_t
*hash_info
, tvbuff_t
*tvb
,
678 int offset
, packet_info
*pinfo
) {
680 /* Decode V4 protocol. This is done on the first pass through the */
681 /* list. Based upon the current state, decode the packet and determine */
682 /* what the next state should be. */
685 if (hash_info
->clientState
!= clientDone
)
686 save_client_state(pinfo
, hash_info
->clientState
);
688 if (hash_info
->serverState
!= serverDone
)
689 save_server_state(pinfo
, hash_info
->serverState
);
691 if (hash_info
->server_port
== pinfo
->destport
) {
692 /* Client side, only a single request */
693 col_append_str(pinfo
->cinfo
, COL_INFO
, " Connect to server request");
695 hash_info
->command
= tvb_get_guint8(tvb
, offset
+ 1);
697 /* get remote port */
698 if ( hash_info
->command
== CONNECT_COMMAND
)
699 hash_info
->port
= tvb_get_ntohs(tvb
, offset
+ 2);
701 /* get remote address */
702 TVB_SET_ADDRESS(&addr
, AT_IPv4
, tvb
, offset
, 4);
703 SE_COPY_ADDRESS(&hash_info
->dst_addr
, &addr
);
705 hash_info
->clientState
= clientDone
;
708 col_append_str(pinfo
->cinfo
, COL_INFO
, " Connect Response");
710 if (tvb_get_guint8(tvb
, offset
+ 1) == 90)
711 hash_info
->serverState
= serverDone
;
713 hash_info
->serverState
= serverError
;
718 client_state_machine_v5( socks_hash_entry_t
*hash_info
, tvbuff_t
*tvb
,
719 int offset
, packet_info
*pinfo
, gboolean start_of_frame
) {
721 /* Decode client side of V5 protocol. This is done on the first pass through the */
722 /* list. Based upon the current state, decode the packet and determine */
723 /* what the next state should be. */
726 save_client_state(pinfo
, hash_info
->clientState
);
728 if (hash_info
->clientState
== clientStart
)
730 guint8 num_auth_methods
;
731 col_append_str(pinfo
->cinfo
, COL_INFO
, " Connect to server request");
733 num_auth_methods
= tvb_get_guint8(tvb
, offset
+ 1);
734 /* skip past auth methods */
736 if ((num_auth_methods
== 0) ||
737 ((num_auth_methods
== 1) &&
738 (tvb_get_guint8(tvb
, offset
+ 2) == 0))) {
739 /* No authentication needed */
740 hash_info
->clientState
= clientV5Command
;
741 if (tvb_reported_length_remaining(tvb
, offset
+ 2 + num_auth_methods
) > 0) {
742 client_state_machine_v5(hash_info
, tvb
, offset
+ 2 + num_auth_methods
, pinfo
, FALSE
);
745 hash_info
->clientState
= clientWaitForAuthReply
;
747 } else if ((hash_info
->clientState
== clientWaitForAuthReply
) &&
748 (hash_info
->serverState
== serverInitReply
)) {
750 switch(hash_info
->authentication_method
)
752 case NO_AUTHENTICATION
:
753 hash_info
->clientState
= clientV5Command
;
754 hash_info
->serverState
= serverCommandReply
;
756 case USER_NAME_AUTHENTICATION
:
757 hash_info
->clientState
= clientV5Command
;
758 hash_info
->serverState
= serverUserReply
;
760 case GSS_API_AUTHENTICATION
:
761 hash_info
->clientState
= clientV5Command
;
762 hash_info
->serverState
= serverGssApiReply
;
765 hash_info
->clientState
= clientError
; /*Auth failed or error*/
768 } else if (hash_info
->clientState
== clientV5Command
) {
770 hash_info
->command
= tvb_get_guint8(tvb
, offset
+ 1); /* get command */
772 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Command Request - %s",
773 val_to_str_const(hash_info
->command
, cmd_strings
, "Unknown"));
775 offset
+= 3; /* skip to address type */
777 offset
= get_address_v5(tvb
, offset
, hash_info
);
779 /** temp = tvb_get_guint8(tvb, offset); XX: what was this for ? **/
781 if (( hash_info
->command
== CONNECT_COMMAND
) ||
782 ( hash_info
->command
== UDP_ASSOCIATE_COMMAND
))
783 /* get remote port */
784 hash_info
->port
= tvb_get_ntohs(tvb
, offset
);
786 hash_info
->clientState
= clientDone
;
791 server_state_machine_v5( socks_hash_entry_t
*hash_info
, tvbuff_t
*tvb
,
792 int offset
, packet_info
*pinfo
, gboolean start_of_frame
) {
794 /* Decode server side of V5 protocol. This is done on the first pass through the */
795 /* list. Based upon the current state, decode the packet and determine */
796 /* what the next state should be. */
799 save_server_state(pinfo
, hash_info
->serverState
);
801 switch (hash_info
->serverState
) {
803 col_append_str(pinfo
->cinfo
, COL_INFO
, " Connect to server response");
805 hash_info
->authentication_method
= tvb_get_guint8(tvb
, offset
+ 1);
806 hash_info
->serverState
= serverInitReply
;
808 switch (hash_info
->authentication_method
)
810 case NO_AUTHENTICATION
:
811 hash_info
->serverState
= serverCommandReply
;
813 case USER_NAME_AUTHENTICATION
:
814 hash_info
->serverState
= serverUserReply
;
816 case GSS_API_AUTHENTICATION
:
817 hash_info
->serverState
= serverGssApiReply
;
820 hash_info
->serverState
= serverError
;
824 case serverUserReply
:
825 col_append_str(pinfo
->cinfo
, COL_INFO
, " User authentication reply");
827 case serverGssApiReply
:
828 if (tvb_get_guint8(tvb
, offset
+1) == 0xFF) {
829 col_append_str(pinfo
->cinfo
, COL_INFO
, " GSSAPI Authentication failure");
830 hash_info
->serverState
= serverError
;
832 col_append_str(pinfo
->cinfo
, COL_INFO
, " GSSAPI Authentication reply");
833 if (tvb_get_ntohs(tvb
, offset
+2) == 0)
834 hash_info
->serverState
= serverCommandReply
;
837 case serverCommandReply
:
838 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Command Response - %s",
839 val_to_str_const(hash_info
->command
, cmd_strings
, "Unknown"));
841 switch(hash_info
->command
)
843 case CONNECT_COMMAND
:
845 case TRACERT_COMMAND
:
846 hash_info
->serverState
= serverDone
;
850 hash_info
->serverState
= serverBindReply
;
851 if ((tvb_get_guint8(tvb
, offset
+ 2) == 0) &&
852 (tvb_reported_length_remaining(tvb
, offset
) > 5)) {
853 offset
= display_address(tvb
, offset
, NULL
);
854 client_state_machine_v5(hash_info
, tvb
, offset
, pinfo
, FALSE
);
858 case UDP_ASSOCIATE_COMMAND
:
859 offset
+= 3; /* skip to address type */
860 offset
= get_address_v5(tvb
, offset
, hash_info
);
862 /* save server udp port and create udp conversation */
863 hash_info
->udp_port
= tvb_get_ntohs(tvb
, offset
);
865 if (!pinfo
->fd
->flags
.visited
)
866 new_udp_conversation( hash_info
, pinfo
);
871 case serverBindReply
:
872 col_append_str(pinfo
->cinfo
, COL_INFO
, " Command Response: Bind remote host info");
881 display_ping_and_tracert(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, socks_hash_entry_t
*hash_info
) {
883 /* Display the ping/trace_route conversation */
885 const guchar
*data
, *dataend
;
886 const guchar
*lineend
, *eol
;
889 /* handle the end command */
890 if ( pinfo
->destport
== TCP_PORT_SOCKS
){
891 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Terminate Request");
894 proto_tree_add_text(tree
, tvb
, offset
, 1,
895 (hash_info
->command
== PING_COMMAND
) ?
896 "Ping: End command" :
897 "Traceroute: End command");
899 else { /* display the PING or Traceroute results */
900 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Results");
903 proto_tree_add_text(tree
, tvb
, offset
, -1,
904 (hash_info
->command
== PING_COMMAND
) ?
906 "Traceroute Results");
908 data
= tvb_get_ptr(tvb
, offset
, -1);
909 dataend
= data
+ tvb_length_remaining(tvb
, offset
);
911 while (data
< dataend
) {
913 lineend
= find_line_end(data
, dataend
, &eol
);
914 linelen
= (int)(lineend
- data
);
916 proto_tree_add_text( tree
, tvb
, offset
, linelen
,
917 "%s", format_text(data
, linelen
));
925 static void clear_in_socks_dissector_flag(void *s
)
927 sock_state_t
* state_info
= (sock_state_t
*)s
;
928 state_info
->in_socks_dissector_flag
= 0; /* avoid recursive overflow */
931 static void call_next_dissector(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
932 proto_tree
*tree
, proto_tree
*socks_tree
,
933 socks_hash_entry_t
*hash_info
, sock_state_t
* state_info
, struct tcpinfo
*tcpinfo
)
936 /* Display the results for PING and TRACERT extensions or */
937 /* Call TCP dissector for the port that was passed during the */
938 /* connect process */
939 /* Load pointer to pinfo->XXXport depending upon the direction, */
940 /* change pinfo port to the remote port, call next dissecotr to decode */
941 /* the payload, and restore the pinfo port after that is done. */
944 guint16 save_can_desegment
;
945 struct tcp_analysis
*tcpd
=NULL
;
947 tcpd
=get_tcp_conversation_data(NULL
,pinfo
);
949 if (( hash_info
->command
== PING_COMMAND
) ||
950 ( hash_info
->command
== TRACERT_COMMAND
))
952 display_ping_and_tracert(tvb
, offset
, pinfo
, tree
, hash_info
);
954 else { /* call the tcp port decoder to handle the payload */
956 /*XXX may want to load dest address here */
958 if ( pinfo
->destport
== TCP_PORT_SOCKS
)
959 ptr
= &pinfo
->destport
;
961 ptr
= &pinfo
->srcport
;
963 *ptr
= hash_info
->port
;
965 /* 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel */
967 state_info
->in_socks_dissector_flag
= 1; /* avoid recursive overflow */
968 CLEANUP_PUSH(clear_in_socks_dissector_flag
, state_info
);
970 save_can_desegment
= pinfo
->can_desegment
;
971 pinfo
->can_desegment
= pinfo
->saved_can_desegment
;
972 dissect_tcp_payload(tvb
, pinfo
, offset
, tcpinfo
->seq
,
973 tcpinfo
->nxtseq
, pinfo
->srcport
, pinfo
->destport
,
974 tree
, socks_tree
, tcpd
, tcpinfo
);
975 pinfo
->can_desegment
= save_can_desegment
;
977 CLEANUP_CALL_AND_POP
;
979 *ptr
= TCP_PORT_SOCKS
;
986 dissect_socks(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
) {
989 proto_tree
*socks_tree
= NULL
;
991 socks_hash_entry_t
*hash_info
;
992 conversation_t
*conversation
;
993 sock_state_t
* state_info
;
995 struct tcpinfo
*tcpinfo
= (struct tcpinfo
*)data
;
997 state_info
= (sock_state_t
*)p_get_proto_data(pinfo
->fd
, proto_socks
, 0);
998 if (state_info
== NULL
) {
999 state_info
= wmem_new(wmem_file_scope(), sock_state_t
);
1000 state_info
->in_socks_dissector_flag
= 0;
1001 state_info
->client
= clientNoInit
;
1002 state_info
->server
= serverNoInit
;
1004 p_add_proto_data(pinfo
->fd
, proto_socks
, 0, state_info
);
1007 /* avoid recursive overflow */
1008 if (state_info
->in_socks_dissector_flag
)
1011 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
,
1012 pinfo
->ptype
, pinfo
->srcport
, pinfo
->destport
, 0);
1013 if (conversation
== NULL
) {
1014 /* If we don't already have a conversation, make sure the first
1015 byte is a valid version number */
1016 version
= tvb_get_guint8(tvb
, offset
);
1017 if ((version
!= 4) && (version
!= 5))
1020 conversation
= conversation_new(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
,
1021 pinfo
->ptype
, pinfo
->srcport
, pinfo
->destport
, 0);
1024 hash_info
= (socks_hash_entry_t
*)conversation_get_proto_data(conversation
,proto_socks
);
1025 if (hash_info
== NULL
){
1026 hash_info
= wmem_new0(wmem_file_scope(), socks_hash_entry_t
);
1027 hash_info
->start_done_frame
= G_MAXINT
;
1028 hash_info
->clientState
= clientStart
;
1029 hash_info
->serverState
= serverStart
;
1031 hash_info
->server_port
= pinfo
->destport
;
1032 hash_info
->port
= 0;
1033 hash_info
->version
= tvb_get_guint8(tvb
, offset
); /* get version*/
1035 conversation_add_proto_data(conversation
, proto_socks
, hash_info
);
1037 /* set dissector for now */
1038 conversation_set_dissector(conversation
, socks_handle
);
1041 /* display summary window information */
1042 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Socks");
1044 if (( hash_info
->version
== 4) || ( hash_info
->version
== 5)){
1045 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Version: %d",
1046 hash_info
->version
);
1048 else /* unknown version display error */
1049 col_set_str(pinfo
->cinfo
, COL_INFO
, "Unknown");
1052 if ( hash_info
->command
== PING_COMMAND
)
1053 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Ping Req");
1054 if ( hash_info
->command
== TRACERT_COMMAND
)
1055 col_append_str(pinfo
->cinfo
, COL_INFO
, ", Traceroute Req");
1057 if ( hash_info
->port
!= 0)
1058 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Remote Port: %u",
1061 /* run state machine if needed */
1062 if ((!pinfo
->fd
->flags
.visited
) &&
1063 (!((hash_info
->clientState
== clientDone
) &&
1064 (hash_info
->serverState
== serverDone
)))) {
1066 if (hash_info
->server_port
== pinfo
->destport
) {
1067 if ((hash_info
->clientState
!= clientError
) &&
1068 (hash_info
->clientState
!= clientDone
))
1070 if ( hash_info
->version
== 4) {
1071 state_machine_v4( hash_info
, tvb
, offset
, pinfo
);
1072 } else if ( hash_info
->version
== 5) {
1073 client_state_machine_v5( hash_info
, tvb
, offset
, pinfo
, TRUE
);
1077 if ((hash_info
->serverState
!= serverError
) &&
1078 (hash_info
->serverState
!= serverDone
)) {
1079 if ( hash_info
->version
== 4) {
1080 state_machine_v4( hash_info
, tvb
, offset
, pinfo
);
1081 } else if ( hash_info
->version
== 5) {
1082 server_state_machine_v5( hash_info
, tvb
, offset
, pinfo
, TRUE
);
1087 if ((hash_info
->clientState
== clientDone
) &&
1088 (hash_info
->serverState
== serverDone
)) { /* if done now */
1089 hash_info
->start_done_frame
= pinfo
->fd
->num
;
1093 /* if proto tree, decode and display */
1095 ti
= proto_tree_add_item( tree
, proto_socks
, tvb
, offset
, -1, ENC_NA
);
1096 socks_tree
= proto_item_add_subtree(ti
, ett_socks
);
1098 if (hash_info
->server_port
== pinfo
->destport
) {
1099 if ( hash_info
->version
== 4) {
1100 display_socks_v4(tvb
, offset
, pinfo
, socks_tree
, hash_info
, state_info
);
1101 } else if ( hash_info
->version
== 5) {
1102 client_display_socks_v5(tvb
, offset
, pinfo
, socks_tree
, hash_info
, state_info
);
1105 if ( hash_info
->version
== 4) {
1106 display_socks_v4(tvb
, offset
, pinfo
, socks_tree
, hash_info
, state_info
);
1107 } else if ( hash_info
->version
== 5) {
1108 server_display_socks_v5(tvb
, offset
, pinfo
, socks_tree
, hash_info
, state_info
);
1112 /* if past startup, add the faked stuff */
1113 if ( pinfo
->fd
->num
> hash_info
->start_done_frame
){
1114 /* add info to tree */
1115 ti
= proto_tree_add_uint( socks_tree
, hf_socks_cmd
, tvb
, offset
, 0, hash_info
->command
);
1116 PROTO_ITEM_SET_GENERATED(ti
);
1118 if (hash_info
->dst_addr
.type
== AT_IPv4
) {
1119 ti
= proto_tree_add_ipv4( socks_tree
, hf_socks_ip_dst
, tvb
,
1120 offset
, 0, *((guint32
*)hash_info
->dst_addr
.data
));
1121 PROTO_ITEM_SET_GENERATED(ti
);
1122 } else if (hash_info
->dst_addr
.type
== AT_IPv6
) {
1123 ti
= proto_tree_add_ipv6( socks_tree
, hf_socks_ip6_dst
, tvb
,
1124 offset
, 0, (const guint8
*)hash_info
->dst_addr
.data
);
1125 PROTO_ITEM_SET_GENERATED(ti
);
1128 /* no fake address for ping & traceroute */
1130 if (( hash_info
->command
!= PING_COMMAND
) &&
1131 ( hash_info
->command
!= TRACERT_COMMAND
)){
1132 ti
= proto_tree_add_uint( socks_tree
, hf_socks_dstport
, tvb
, offset
, 0, hash_info
->port
);
1133 PROTO_ITEM_SET_GENERATED(ti
);
1140 /* call next dissector if ready */
1141 if ( pinfo
->fd
->num
> hash_info
->start_done_frame
){
1142 call_next_dissector(tvb
, offset
, pinfo
, tree
, socks_tree
,
1143 hash_info
, state_info
, tcpinfo
);
1146 return tvb_reported_length(tvb
);
1152 proto_register_socks( void){
1154 static gint
*ett
[] = {
1160 static hf_register_info hf
[] = {
1164 { "Version", "socks.version", FT_UINT8
, BASE_DEC
, NULL
,
1169 { "Remote Address", "socks.dst", FT_IPv4
, BASE_NONE
, NULL
,
1173 { &hf_socks_ip6_dst
,
1174 { "Remote Address(ipv6)", "socks.dstV6", FT_IPv6
, BASE_NONE
, NULL
,
1178 { &hf_gssapi_payload
,
1179 { "GSSAPI data", "socks.gssapi.data", FT_BYTES
, BASE_NONE
, NULL
,
1183 { &hf_gssapi_command
,
1184 { "SOCKS/GSSAPI command", "socks.gssapi.command", FT_UINT8
, BASE_DEC
,
1185 VALS(gssapi_command_table
), 0x0, NULL
, HFILL
1188 { &hf_gssapi_length
,
1189 { "SOCKS/GSSAPI data length", "socks.gssapi.length", FT_UINT16
, BASE_DEC
, NULL
,
1194 { "SOCKS v4a Remote Domain Name", "socks.v4a_dns_name", FT_STRINGZ
, BASE_NONE
,
1195 NULL
, 0x0, NULL
, HFILL
1198 { &hf_socks_dstport
,
1199 { "Remote Port", "socks.dstport", FT_UINT16
,
1200 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1204 { "Command", "socks.command", FT_UINT8
,
1205 BASE_DEC
, VALS(cmd_strings
), 0x0, NULL
, HFILL
1208 { &hf_socks_results_4
,
1209 { "Results(V4)", "socks.results", FT_UINT8
,
1210 BASE_DEC
, VALS(reply_table_v4
), 0x0, NULL
, HFILL
1213 { &hf_socks_results_5
,
1214 { "Results(V5)", "socks.results", FT_UINT8
,
1215 BASE_DEC
, VALS(reply_table_v5
), 0x0, NULL
, HFILL
1218 { &hf_client_auth_method_count
,
1219 { "Authentication Method Count", "socks.auth_method_count", FT_UINT8
,
1220 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1223 { &hf_client_auth_method
,
1224 { "Method", "socks.auth_method", FT_UINT8
,
1225 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1228 { &hf_socks_reserved
,
1229 { "Reserved", "socks.reserved", FT_UINT8
,
1230 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1233 { &hf_socks_reserved2
,
1234 { "Reserved", "socks.reserved", FT_UINT16
,
1235 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1239 { "Port", "socks.port", FT_UINT16
,
1240 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1243 { &hf_server_accepted_auth_method
,
1244 { "Accepted Auth Method", "socks.auth_accepted_method", FT_UINT8
,
1245 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1248 { &hf_server_auth_status
,
1249 { "Status", "socks.auth_status", FT_UINT8
,
1250 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1253 { &hf_server_remote_host_port
,
1254 { "Remote Host Port", "socks.remote_host_port", FT_UINT16
,
1255 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1258 { &hf_socks_username
,
1259 { "User name", "socks.username", FT_STRING
, BASE_NONE
,
1260 NULL
, 0x0, NULL
, HFILL
1263 { &hf_socks_password
,
1264 { "Password", "socks.password", FT_STRING
, BASE_NONE
,
1265 NULL
, 0x0, NULL
, HFILL
1268 { &hf_socks_remote_name
,
1269 { "Remote name", "socks.remote_name", FT_STRING
, BASE_NONE
,
1270 NULL
, 0x0, NULL
, HFILL
1273 { &hf_socks_address_type
,
1274 { "Address Type", "socks.address_type", FT_UINT8
,
1275 BASE_DEC
, VALS(address_type_table
), 0x0, NULL
, HFILL
1278 { &hf_socks_fragment_number
,
1279 { "Fragment Number", "socks.fragment_number", FT_UINT8
,
1280 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
1285 proto_socks
= proto_register_protocol ( "Socks Protocol", "Socks", "socks");
1287 proto_register_field_array(proto_socks
, hf
, array_length(hf
));
1288 proto_register_subtree_array(ett
, array_length(ett
));
1293 proto_reg_handoff_socks(void) {
1295 /* dissector install routine */
1296 socks_udp_handle
= create_dissector_handle(socks_udp_dissector
, proto_socks
);
1297 socks_handle
= new_create_dissector_handle(dissect_socks
, proto_socks
);
1299 dissector_add_uint("tcp.port", TCP_PORT_SOCKS
, socks_handle
);
1303 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1308 * indent-tabs-mode: t
1311 * ex: set shiftwidth=4 tabstop=4 expandtab:
1312 * :indentSize=4:tabSize=4:noTabs=false: