java socks5 구현
10656 단어 socks5
socks5의 기초 지식
socks5에 대한 정의]https://www.ietf.org/rfc/rfc1928.txt[/b[b] socks5 계정 비밀번호 인증 방식https://www.ietf.org/rfc/rfc1929.txt
socks5 상호 작용 프로세스
1.socks5 서버 오픈 포트
2. 클라이언트가 sockets 서버에 연결
3. 클라이언트가 Hello 메시지를 보내는데 구조는 다음과 같다.
VER
NMETHODS
METHODS
1바이트
1바이트
최대 255바이트
X05는 socks5를 나타내며, 임의의 identifier일 수도 있습니다.
세 번째 필드를 나타내는 데이터 길이(byte 수)
클라이언트가 지원하는 검증 방식, 모든 방법이 바이트를 차지한다
그 중에서 X02는 계정 비밀번호 검증을 표시하는데, 우리는 여기에서 이 방법만 실현할 수 있다
ClientHelloInfo clientHelloInfo = new ClientHelloInfo();
clientHelloInfo.setVer(inputStream.read());
clientHelloInfo.setNmethods(inputStream.read());
if(clientHelloInfo.getNmethods() > 0) {
clientHelloInfo.setMethods(read(clientHelloInfo.getNmethods()));
}
4. 서비스 측은 다음과 같은 메시지에 회답해야 한다
VER
METHOD
1바이트
1바이트
X05는 socks5를 나타냅니다.
서비스 측이 선택한 검증 방법
METHODS
o X'00' NO AUTHENTICATION REQUIRED
o X'01' GSSAPI
o X'02' USERNAME/PASSWORD
o X'03' to X'7F' IANA ASSIGNED
o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
o X'FF' NO ACCEPTABLE METHODS
만약에 서비스 측이 마지막으로 X'FF'를 선택했다면 적합한 검증 방법이 없고 클라이언트와 서비스 측의 검증 방안이 일치하지 않는다는 것을 의미한다. 이런 상황은 닫힐 수밖에 없다는 것을 의미한다.
public void writeDatas(ServerHelloInfo serverHelloInfo) throws IOException {
outputStream.write(serverHelloInfo.getVer());
outputStream.write(serverHelloInfo.getMethod());
outputStream.flush();
}
5. 클라이언트가 계정 암호 메시지를 보냅니다(계정 암호 인증이 아닌 경우 건너뛰기)
VER
ULEN
UNAME
PLEN
PASSWD
1바이트, 여기는 SOCKS 버전이 아닙니다.
1바이트, 사용자 이름이 몇 바이트인지 지정합니다.
최대 255바이트
암호 바이트 지정
최대 255바이트
public ClientUserPasswordInfo readDatas() throws IOException {
ClientUserPasswordInfo clientUserPasswordInfo = new ClientUserPasswordInfo();
clientUserPasswordInfo.setVer(read());
clientUserPasswordInfo.setUlen(read());
clientUserPasswordInfo.setUname(new String(read(clientUserPasswordInfo.getUlen())));
clientUserPasswordInfo.setPlen(read());
clientUserPasswordInfo.setPassword(new String(read(clientUserPasswordInfo.getPlen())));
return clientUserPasswordInfo;
}
6. 서버 반환 (계정 암호 인증이 아닌 경우 건너뛰기)
VER
STATUS
현재 SOCKS5의 암호 인증 프로토콜 버전이 1이므로 1바이트만 지원됩니다.
0X00은 올바른, 다른 것은 비밀번호 오류, 연결 닫기
public void writeDatas(ServerUserPasswordInfo serverUserPasswordInfo) throws IOException {
outputStream.write(serverUserPasswordInfo.getVer());
outputStream.write(serverUserPasswordInfo.getStatus());
outputStream.flush();
}
7. 클라이언트 요청 에이전트 대상
VER
CMD
RSV
ATYP
DST.ADDR
DST.PORT
1바이트
1바이트
X'00'
2바이트
대상 IP
대상 포트 2바이트
.RSV 보존
IP4 모드, 4바이트
IP6 모드, 16바이트
도메인 이름 모드, 주소 첫 번째 필드는 도메인 이름 길이(255 최대)를 나타냅니다.
주소 포트 확인
포트 2 바이트
package com.lsiding.nat.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.SocketTimeoutException;
import com.lsiding.nat.core.InOutModel;
public class UtilSocks5 {
/**
* byte int 4
*
* @param bytes
* @return
*/
public int byte2Int(Byte[] bytes) {
return (bytes[0] & 0xff) << 24 | (bytes[1] & 0xff) << 16
| (bytes[2] & 0xff) << 8 | (bytes[3] & 0xff);
}
/**
* 2 int
*
* @throws IOException
*/
public static final int byte2ToInteger(InOutModel> inOutModel)
throws IOException {
byte[] bs = inOutModel.read(2);
return ((bs[0] & 0xff) << 8 | (bs[1] & 0xff));
}
/**
* byte 0-255, byte 127 -128, 129, 127 -128 ,
* 129==--127
*
* @return liyixing
* @throws IOException
* @throws SocketTimeoutException
*/
public static final String getAddress(int type, InOutModel> inOutModel)
throws SocketTimeoutException, IOException {
if (type == 3) {
//
int len = inOutModel.readLength();
byte[] bs = inOutModel.read(len);
return new String(bs);
} else if (type == 1) {
// ip 4
byte[] bs = inOutModel.read(4);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 4; i++) {
if (i != 0) {
sb.append(".");
}
int a = bs[i];
if (a < 0) {
a = 256 + a;
}
sb.append(a);
}
return sb.toString();
} else if (type == 4) {
// ip6 16
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 8; i++) {
if (i != 0) {
sb.append(":");
}
int a = byte2ToInteger(inOutModel);
// a & 0xffff 4 16 ,a & 0xff 2 16
String x = String.format("%02x", new Integer(a & 0xffff))
.toUpperCase();
while (true) {
if (x.length() < 4) {
x = "0" + x;
} else {
break;
}
}
sb.append(x);
}
return sb.toString();
}
return null;
}
/**
* int byte 4
*
* @param bytes
* @return
*/
public byte[] intToByte(int num) {
byte[] bytes = new byte[4];
bytes[0] = (byte) ((num >> 24) & 0xff);
bytes[1] = (byte) ((num >> 16) & 0xff);
bytes[2] = (byte) ((num >> 8) & 0xff);
bytes[3] = (byte) (num & 0xff);
return bytes;
}
/**
* int 2 byte
*
* @param i
* @return liyixing
*/
public static byte[] intTo2ByteArray(int i) {
byte[] result = new byte[2];
result[0] = (byte) ((i >> 8));
result[1] = (byte) (i & 0xff);
return result;
}
/**
* byte
*
* @param type
* @param ip
* @return liyixing
*/
public static final byte[] getAddressBytes(int type, String ip) {
if (type == 3) {
//
byte[] bs = ip.getBytes();
int len = bs.length + 1;
byte[] rs = new byte[len];
rs[0] = (byte) bs.length;
for (int index = 0; index < bs.length; index++) {
rs[index + 1] = bs[index];
}
return rs;
} else if (type == 1) {
// ip 4
String[] ips = ip.split("\\.");
byte[] rs = new byte[4];
for (int index = 0; index < 4; index++) {
rs[index] = (byte) Integer.valueOf(ips[index]).intValue();
}
return rs;
} else if (type == 4) {
// ip 4
String[] ips = ip.split(":");
byte[] rs = new byte[16];
for (int index = 0; index < 8; index++) {
String ipOne = ips[index];
byte[] tm = intTo2ByteArray(Integer.valueOf(ipOne, 16));
rs[index * 2] = tm[0];
rs[index * 2 + 1] = tm[1];
}
return rs;
}
return null;
}
public static void main(String[] args) throws IOException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
intTo2ByteArray(26381));
InOutModel inOutModel = new InOutModel(
byteArrayInputStream);
System.out.println(byte2ToInteger(inOutModel));
byteArrayInputStream = new ByteArrayInputStream(getAddressBytes(3,
"www.lsiding.com"));
inOutModel = new InOutModel(byteArrayInputStream);
System.out.println(getAddress(3, inOutModel));
byteArrayInputStream = new ByteArrayInputStream(getAddressBytes(1,
"192.168.0.103"));
inOutModel = new InOutModel(byteArrayInputStream);
System.out.println(getAddress(1, inOutModel));
System.out.println("2001:0DB8:0000:0023:1008:0800:200C:0001");
byteArrayInputStream = new ByteArrayInputStream(getAddressBytes(4,
"2001:0DB8:0000:0023:1008:0800:200C:0001"));
inOutModel = new InOutModel(byteArrayInputStream);
System.out.println(getAddress(4, inOutModel));
}
}
public RequestInfo readDatas() throws IOException {
RequestInfo requestInfo = new RequestInfo();
requestInfo.setVer(read());
requestInfo.setCmd(read());
requestInfo.setRsv(read());
requestInfo.setAtyp(read());
String ip = UtilSocks5.getAddress(requestInfo.getAtyp(), this);
requestInfo.setDstAddr(ip);
requestInfo.setPort(UtilSocks5.getProt(this));
return requestInfo;
}
8. 서버 응답
VER
REP
RSV
ATYP
BND.ADDR
BND.PORT
1바이트
1바이트
X'00'
1바이트
Variable
2바이트
연결 모드
BND.ADDR BND.PORT 및 DST.ADDR 및 DST.PORT 동일
BIND 모드, 새로 열린 서버의 포트, IP
UDP 모드, 지원 준비 없음, 자세히 보기https://www.ietf.org/rfc/rfc1928.txt
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Python requests 라 이브 러 리 인 코딩 socks 5 에이전트 문제 해결관련 자 료 를 찾 아 보고 requests 의 소스 코드 를 보 았 습 니 다.서버 가 응답 하 는 머리 에 만 Content-Type 이 포함 되 어 있 고 그 안에 charset 정보 가 있 습 니 다.requ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.