Home | History | Annotate | Download | only in snoop
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright (c) 1998-1999,2001 by Sun Microsystems, Inc.
     24  * All rights reserved.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <sys/socket.h>
     31 #include <netinet/in.h>
     32 #include <string.h>
     33 #include "snoop.h"
     34 
     35 static void put_method(char *cp, int method);
     36 static void put_socks5_addr(char *cp, const unsigned char *buf, int fraglen);
     37 static void put_socks4_res(char *cp, int code);
     38 static void put_socks5_res(char *cp, int code);
     39 
     40 int
     41 interpret_socks_call(flags, line, fraglen)
     42 	int flags;
     43 	char *line;
     44 	int fraglen;
     45 {
     46 	unsigned char	*buf = (unsigned char *)line;
     47 	char		*cp;
     48 	struct in_addr	ipaddr;
     49 	int		i, n;
     50 
     51 	if (flags & F_SUM) {
     52 	cp = get_sum_line();
     53 	if (fraglen >= 2) {
     54 		switch (buf[0]) {
     55 		case 4:		/* SOCKS4 */
     56 			n = buf[1];
     57 			switch (n) {
     58 			case 1:
     59 			case 2:
     60 				if (fraglen >= 8) {
     61 					(void) memcpy(&ipaddr, &buf[4],
     62 					    sizeof (ipaddr));
     63 					(void) sprintf(cp,
     64 					    "SOCKS4 %s %s:%u",
     65 					    addrtoname(AF_INET, &ipaddr),
     66 					    (n == 1)? "CONNECT": "BIND",
     67 					    (buf[2] << 8) | buf[3]);
     68 					cp += strlen(cp);
     69 					if (fraglen > 8) {
     70 						(void) sprintf(cp, " User=");
     71 						cp += strlen(cp);
     72 						for (i = 8;
     73 							i < 40 && i < fraglen;
     74 							++i) {
     75 							if (buf[i] == '\0')
     76 								break;
     77 							*cp++ = buf[i];
     78 						}
     79 						if (i == 40) {
     80 							*cp++ = '.';
     81 							*cp++ = '.';
     82 							*cp++ = '.';
     83 						}
     84 						*cp = '\0';
     85 					}
     86 				}
     87 				break;
     88 			default:
     89 				(void) sprintf(cp, "SOCKS4 OP=%u", n);
     90 			}
     91 			break;
     92 		case 5:		/* SOCKS5 */
     93 			n = buf[1];
     94 			if (2 + n == fraglen) {
     95 				(void) sprintf(cp,
     96 					"SOCKS5 CONTACT NMETHODS=%d:", n);
     97 				cp += strlen(cp);
     98 				for (i = 0; i < n && 2 + i < fraglen; ++i) {
     99 					put_method(cp, buf[2 + i]);
    100 					cp += strlen(cp);
    101 				}
    102 			} else if (fraglen >= 6 && buf[2] == 0) {
    103 				const char	*cmd;
    104 
    105 				if (n < 1 || n > 3) {
    106 					(void) sprintf(cp,
    107 						"SOCKS (send data): %s",
    108 						show_string(line, fraglen, 20));
    109 				} else {
    110 					switch (n) {
    111 					case 1:
    112 						cmd = "CONNECT";
    113 						break;
    114 					case 2:
    115 						cmd = "BIND";
    116 						break;
    117 					case 3:
    118 						cmd = "ASSOCIATE_UDP";
    119 						break;
    120 					}
    121 					(void) sprintf(cp, "SOCKS5 %s ", cmd);
    122 					cp += strlen(cp);
    123 					put_socks5_addr(cp, &buf[3],
    124 						fraglen - 3);
    125 				}
    126 			} else {
    127 				(void) sprintf(cp, "SOCKS (send data): %s",
    128 					show_string(line, fraglen, 20));
    129 			}
    130 			break;
    131 		default:
    132 			(void) sprintf(cp, "SOCKS (send data): %s",
    133 				show_string(line, fraglen, 20));
    134 		}
    135 	} else {
    136 		(void) sprintf(cp, "SOCKS (send data): %s",
    137 			show_string(line, fraglen, 20));
    138 	}
    139 
    140 	} /* if (flags & F_SUM) */
    141 
    142 	if (flags & F_DTAIL) {
    143 		show_header("SOCKS: ", "SOCKS Header", fraglen);
    144 		show_space();
    145 		cp = get_line(0, 0);
    146 		if (fraglen >= 2) {
    147 			switch (buf[0]) {
    148 			case 4:
    149 				(void) sprintf(cp, "Version = 4");
    150 				n = buf[1];
    151 				switch (n) {
    152 				case 1:
    153 				case 2:
    154 					(void) sprintf(get_line(0, 0),
    155 					    "Operation = %s",
    156 					    (n == 1)? "CONNECT": "BIND");
    157 					if (fraglen >= 8) {
    158 						(void) memcpy(&ipaddr, &buf[4],
    159 						    sizeof (ipaddr));
    160 						(void) sprintf(get_line(0, 0),
    161 						    "Destination = %s:%u",
    162 						    addrtoname(AF_INET,
    163 						    &ipaddr),
    164 						    (buf[2] << 8) | buf[3]);
    165 						if (fraglen > 8) {
    166 							cp = get_line(0, 0);
    167 							(void) sprintf(cp,
    168 							    "User = ");
    169 							cp += strlen(cp);
    170 							for (i = 8;
    171 								i < 40; ++i) {
    172 								if
    173 								(buf[i] == '\0')
    174 									break;
    175 								*cp++ = buf[i];
    176 							}
    177 							if (i == 40) {
    178 								*cp++ = '.';
    179 								*cp++ = '.';
    180 								*cp++ = '.';
    181 							}
    182 							*cp = '\0';
    183 						}
    184 					}
    185 					break;
    186 				default:
    187 					(void) sprintf(get_line(0, 0),
    188 					    "Operation = %u (unknown)", n);
    189 				}
    190 				break;
    191 			case 5:		/* SOCKS5 */
    192 				(void) sprintf(cp, "Version = 5");
    193 				n = buf[1];
    194 				if (2 + n == fraglen) {
    195 					(void) sprintf(get_line(0, 0),
    196 					    "Number of methods = %u", n);
    197 					for (i = 0;
    198 						i < n && 2 + i < fraglen; ++i) {
    199 						cp = get_line(0, 0);
    200 						(void) sprintf(cp,
    201 							"Method %3u =", i);
    202 						cp += strlen(cp);
    203 						put_method(cp, buf[2 + i]);
    204 					}
    205 				} else if (fraglen >= 6 && buf[2] == 0) {
    206 					const char	*cmd;
    207 					if (n < 1 || n > 3) {
    208 						(void) sprintf(cp,
    209 							"SOCKS (send data): %s",
    210 							show_string(line,
    211 							fraglen, 20));
    212 					} else {
    213 						switch (n) {
    214 						case 1:
    215 							cmd = "CONNECT";
    216 							break;
    217 						case 2:
    218 							cmd = "BIND";
    219 							break;
    220 						case 3:
    221 							cmd = "ASSOCIATE_UDP";
    222 							break;
    223 						}
    224 						(void) sprintf(get_line(0, 0),
    225 						    "Operation = %s ", cmd);
    226 						put_socks5_addr(get_line(0, 0),
    227 						    &buf[3], fraglen - 3);
    228 						break;
    229 					}
    230 				} else
    231 					(void) sprintf(cp,
    232 						" SOCKS (send data): %s",
    233 						show_string(line, fraglen,
    234 						20));
    235 				break;
    236 			default:
    237 				(void) sprintf(cp,
    238 					"SOCKS (send data): %s",
    239 					show_string(line, fraglen, 20));
    240 			}
    241 			show_space();
    242 		} else
    243 			(void) sprintf(cp,
    244 				"SOCKS (send data): %s",
    245 				show_string(line, fraglen, 20));
    246 	}
    247 
    248 out:
    249 	return (fraglen);
    250 }
    251 
    252 int
    253 interpret_socks_reply(flags, line, fraglen)
    254 	int flags;
    255 	char *line;
    256 	int fraglen;
    257 {
    258 	unsigned char	*buf = (unsigned char *)line;
    259 	char		*cp;
    260 	struct in_addr	ipaddr;
    261 
    262 	if (flags & F_SUM) {
    263 		cp = get_sum_line();
    264 		if (fraglen >= 2) {
    265 			switch (buf[0]) {
    266 			case 0:
    267 				(void) sprintf(cp, "SOCKS4 ");
    268 				cp += strlen(cp);
    269 				if (fraglen >= 8) {
    270 					(void) memcpy(&ipaddr, &buf[4],
    271 					    sizeof (ipaddr));
    272 					(void) sprintf(cp, "%s:%u ",
    273 					    addrtoname(AF_INET, &ipaddr),
    274 					    (buf[2] << 8) | buf[3]);
    275 					cp += strlen(cp);
    276 				}
    277 				/* reply version, no SOCKS version in v4 */
    278 				put_socks4_res(cp, buf[1]);
    279 				break;
    280 			case 5:
    281 				(void) sprintf(cp, "SOCKS5 method accepted:");
    282 				cp += strlen(cp);
    283 				put_method(cp, buf[1]);
    284 				break;
    285 			default:
    286 				(void) sprintf(cp, "SOCKS (recv data)");
    287 			}
    288 		} else
    289 			(void) sprintf(cp, "SOCKS (recv data)");
    290 	}
    291 
    292 	if (flags & F_DTAIL) {
    293 		show_header("SOCKS: ", "SOCKS Header", fraglen);
    294 		show_space();
    295 		cp = get_line(0, 0);
    296 		if (fraglen >= 2) {
    297 			switch (buf[0]) {
    298 			case 0:
    299 				/* reply version, no SOCKS version in v4 */
    300 				(void) sprintf(cp,
    301 				    "Reply version = 0 (SOCKS version 4)");
    302 				if (fraglen >= 8) {
    303 					(void) memcpy(&ipaddr, &buf[4],
    304 					    sizeof (ipaddr));
    305 					(void) sprintf(get_line(0, 0),
    306 					    "Destination %s:%u ",
    307 					    addrtoname(AF_INET, &ipaddr),
    308 					    (buf[2] << 8) | buf[3]);
    309 				}
    310 				cp = get_line(0, 0);
    311 				(void) sprintf(cp, "Result code = %u ", buf[1]);
    312 				cp += strlen(cp);
    313 				put_socks4_res(cp, buf[1]);
    314 				break;
    315 			case 5:
    316 				(void) sprintf(cp, "Reply version = 5");
    317 				if (fraglen == 2) {
    318 					cp = get_line(0, 0);
    319 					(void) sprintf(cp, "Method accepted =");
    320 					cp += strlen(cp);
    321 					put_method(cp, buf[1]);
    322 				} else if (fraglen >= 6 && buf[2] == 0x00) {
    323 					cp = get_line(0, 0);
    324 					(void) sprintf(cp, "Status = ");
    325 					cp += strlen(cp);
    326 					put_socks5_res(cp, buf[1]);
    327 					put_socks5_addr(get_line(0, 0),
    328 					    &buf[3], fraglen - 3);
    329 				}
    330 				break;
    331 			default:
    332 				(void) sprintf(cp, "(recv data)");
    333 			}
    334 		} else
    335 			(void) sprintf(cp, "(recv data)");
    336 		show_space();
    337 	}
    338 
    339 out:
    340 	return (fraglen);
    341 }
    342 
    343 static void
    344 put_method(char *cp, int method)
    345 {
    346 	switch (method) {
    347 	case 0:
    348 		(void) sprintf(cp, " NOAUTH");
    349 		break;
    350 	case 1:
    351 		(void) sprintf(cp, " GSSAPI");
    352 		break;
    353 	case 2:
    354 		(void) sprintf(cp, " USERNAME/PASSWD");
    355 		break;
    356 	case 255:
    357 		(void) sprintf(cp, " NONE");
    358 		break;
    359 	default:
    360 		(void) sprintf(cp, " 0x%02x (unknown)", method);
    361 	}
    362 }
    363 
    364 static void
    365 put_socks5_addr(char *cp, const unsigned char *buf, int fraglen)
    366 {
    367 	struct in_addr	ipaddr;
    368 	int		i;
    369 
    370 	switch (buf[0]) {
    371 	case 1:
    372 		/* IPv4 */
    373 		(void) sprintf(cp, "Address = ");
    374 		cp += strlen(cp);
    375 		if (1 + 4 + 2 <= fraglen) {
    376 			(void) memcpy(&ipaddr, &buf[1], sizeof (ipaddr));
    377 			(void) sprintf(cp, "%s:%u",
    378 			    addrtoname(AF_INET, &ipaddr),
    379 			    (buf[5] << 8) | buf[5 + 1]);
    380 		} else
    381 			(void) strcat(cp, "(IPv4)");
    382 		break;
    383 	case 3:
    384 		/* domain name */
    385 		(void) sprintf(cp, "Domain name = ");
    386 		cp += strlen(cp);
    387 		for (i = 0; i <= buf[1] && 1 + i < fraglen; ++i)
    388 			*cp++ = buf[1 + i];
    389 		if (1 + i + 2 <= fraglen)
    390 			(void) sprintf(cp, ":%u",
    391 			    (buf[1 + i] << 8) | buf[1 + i + 1]);
    392 		else
    393 			*cp = '\0';
    394 		break;
    395 	case 4:
    396 		/* IPv6 */
    397 		(void) sprintf(cp, "Address = ");
    398 		if (1 + 16 <= fraglen) {
    399 			for (i = 0; i < 16; ++i) {
    400 				if (i > 0)
    401 					*cp++ = '.';
    402 				(void) sprintf(cp, "%u", buf[1 + i]);
    403 				cp += strlen(cp);
    404 			}
    405 			if (1 + 16 + 2 <= fraglen) {
    406 				(void) sprintf(cp, ":%u",
    407 				    (buf[1 + 16] << 8) | buf[1 + 16 + 1]);
    408 			}
    409 		} else
    410 			(void) strcat(cp, "(IPv6)");
    411 		break;
    412 	default:
    413 		(void) sprintf(cp, "Address type = 0x%02x (unknown)", buf[0]);
    414 	}
    415 }
    416 
    417 static void
    418 put_socks4_res(char *cp, int code)
    419 {
    420 	switch (code) {
    421 	case 90:
    422 		(void) sprintf(cp, "request granted");
    423 		break;
    424 	case 91:
    425 		(void) sprintf(cp, "request rejected or failed");
    426 		break;
    427 	case 92:
    428 		(void) sprintf(cp, "socksd can't connect to client's identd");
    429 		break;
    430 	case 93:
    431 		(void) sprintf(cp, "identity mismatch");
    432 		break;
    433 	default:
    434 		(void) sprintf(cp, "0x%02x (unknown)", code);
    435 	}
    436 }
    437 
    438 static void
    439 put_socks5_res(char *cp, int code)
    440 {
    441 	switch (code) {
    442 	case 0:
    443 		(void) strcpy(cp, "succeeded");
    444 		break;
    445 	case 1:
    446 		(void) strcpy(cp, "general SOCKS server failure");
    447 		break;
    448 	case 2:
    449 		(void) strcpy(cp, "connection not allowed by ruleset");
    450 		break;
    451 	case 3:
    452 		(void) strcpy(cp, "network unreachable");
    453 		break;
    454 	case 4:
    455 		(void) strcpy(cp, "host unreachable");
    456 		break;
    457 	case 5:
    458 		(void) strcpy(cp, "connection refused");
    459 		break;
    460 	case 6:
    461 		(void) strcpy(cp, "TTL expired");
    462 		break;
    463 	case 7:
    464 		(void) strcpy(cp, "command not supported");
    465 		break;
    466 	case 8:
    467 		(void) strcpy(cp, "address type not supported");
    468 		break;
    469 	default:
    470 		(void) sprintf(cp, "code 0x%02x", code);
    471 	}
    472 }
    473