Baby_parrot
VIP Members
-
17/04/2018
-
41
-
60 bài viết
Giao thức SOCKS5 lập trình Proxy Server
Trong bài viết trước mình đã đưa ra cái nhìn tổng quát về Proxy Server cố gắng giúp các bạn trả lời được câu hỏi Proxy Server là gì? Mô hình hoạt động thế nào và phân loại nào ra sao? Bạn nào chưa đọc bài này thì có thể đọc qua để có cái nhìn tổng quan nhất về Proxy tại đây. Mình đã có làm một sản phẩm về có liên quan đến proxy server hỗ trỡ 2 giao thức là SOCKS5 và HTTP Proxy. Sản phẩm này khá có nhiều kỷ niệm với mình về kỹ thuật như ngày đầu mình cũng không thực sự hiểu và khó khăn khi tìm hiểu về giao thức SOCKS5 và cũng không bắt đầu từ đâu. Hay là kỷ niệm về bát phở có hành từ các anh trong WH và công ty, giúp đỡ mình phát triển sản phẩm từ thời gian, kỹ thuật đến bón hành hằng ngày . Hôm nay mình quay lại phân tích sâu hơn về kỹ thuật chuyển tiếp gói tin trong Proxy và cụ thể là về giao thức SOCKS5. Mình hi vọng bài viết này sẽ hữu ích với bạn nào đang phát triển và muốn lập trình về SOCKS mà cụ thể là SOCKS5.
SOCKS là một giao thức Internet tạo ra để trao đổi gói tin giữa client và server thông qua một proxy server. SOCKS phiên bản đầu tiên được thiết kế và phát triển bởi David Koblas là một trong những người quản trị hệ thống của “MIPS Computer Systems”( Công ty xây dựng kiến trúc MISP trên CPU). Giao thức SOCKS hiện tại được phát triển tới phiên bản thứ 6 là SOCKS 6.
SOCKS được phát triển đảm bảo các đặc tính của proxy như ẩn danh người dùng, về cơ bản thì proxy và VPN có những đặc tính giống nhau nhưng proxy sẽ có tốc độ nhanh hơn VPN vì proxy không phải mã hóa, giải mã gói tin gửi và nhận khi truyền mà đa phần chỉ làm nhiệm vụ chuyển tiếp gói tin trong mạng.
SOCKS hoạt động ở tầng thấp hơn giao thức HTTP Proxying (Tầng 7) SOCKS hoạt động ở tầng 5 (Tầng phiên) trong mô hình OSI hỗ trợ chuyển tiếp các gói tin TCP. Từ phiên bản SOCKS 5 trở đi thì cung cấp thêm phương thức chuyển tiếp các gói tin UDP và xác thực người dùng. SOCKS sử dụng giao thức bắt tay với client để lấy các thông tin về địa chỉ đích mà client đang muốn kết nối đến rồi thông báo cho phần mềm proxy và sau đó hoạt động gần như trong suốt với người dùng. SOCKS hoạt động được trên các proxy đảo ngược và được sử dụng rộng rãi trên môi trường internet.
Giao thức SOCKS 5 được phát triển kế thừa trên giao thức SOCKS phiên bản 4. So với giao thức SOCKS 4 thì SOCKS5 cung cấp phương thức hỗ trợ chuyển tiếp các gói tin UDP, hỗ trợ IPV6 và bổ sung các lựa chọn xác thực.
Thiết lập kết nối
Khi client muốn thiết lập một kết nối đến một đối tượng thông qua giao thức SOCKS sẽ phải tiến hành thiết lập kết nối TCP đến cổng của dịch vụ SOCKS được mở trên máy chủ SOCKS (Cổng mặc định của dịch vụ SOCKS là 1080). Nếu yêu cầu kết nối thành công Client sẽ trao đổi thống nhất phương pháp xác thực được sử dụng với server, tiến hành xác thực theo phương thức đã lựa chọn, sau đó mới gửi yêu cầu chuyển tiếp cho máy chủ SOCKS. Máy chủ SOCKS sẽ đánh giá yêu cầu kết nối và sẽ tiến hành thiết lập kết nối theo yêu cầu hoặc là từ chối kết nối.
Bắt đầu thiết lập kết nối Client gửi gói tin TCP đến server bao gồm phiên bản SOCKS được sử dụng, phương thức hỗ trợ theo định dạng sau:
Trong đó:
Các giá trị định danh của METHOD phương thức hỗ trợ trong SOCKS gồm có:
Nếu server lựa chọn phương thức không lựa phương thức không yêu cầu xác thực thì giữa client và server sẽ bỏ qua bước xác thực và tiến hành trao đổi thông tin. Với các METHOD khác được lựa chọn server và client sẽ tiến hành trao đổi xác thực theo giao thức đó
Khi phương thức xác thức được chọn là sử dụng tên đăng nhập và mật khẩu thì client và server tiến hành trao đổi xác thực. Client gửi gói tin xác thực với định dạng:
Trong đó:
Trường STATUS có giá trị 1byte là giá trị phản hồi của server. Nếu giá trị này là 0x00 có nghĩa là xác thực thành công. Còn giá trị này lớn hơn 0x00 server từ chối kết nối và client phải đóng kết nối. Sau khi client và server hoàn tất bắt tay và xác thực client sẽ gửi gói tin chi tiết yêu cầu kết nối đến máy chủ SOCKS để yêu cầu kết nối đến máy chủ đích mong muốn. Gói tin client gửi lên theo định dạng:
VER CMD RSV ATYP DST.ADDR DST.PORT
1 byte 1 byte 0x00 1 byte 2 byte
Trong đó:
Trong đó các giá trị VER, RSV, ATYP sẽ giống như mô tả như gói tin client gửi đến. Giá trị REP mà server gửi về cho client là giá trị trả lời cho client về yêu cầu kết nối. REP sẽ có các giá trị:
Khi client yêu cầu lệnh thiết lập một kết nối TCP/IP. Server trả về giá trị BND.PORT, BND.ADDR là cổng và địa chỉ IP mà máy chủ dùng để kết nối với máy đích mà client yêu cầu kết nối. Thường BND.ADDR sẽ có giá trị khác so với địa chỉ IP mà client dùng để kết nối đến máy chủ socks. Khi client yêu cầu với lệnh BIND: Sẽ có 2 gói tin được gửi từ máy chủ SOKCS đến client trong quá trình BIND. Gói tin đầu tiên được gửi sau khi máy chủ khởi tạo và đăng ký lắng nghe trên một cổng cho một socket mới. Trường BND.PORT server trả về chứa địa chỉ cổng mà server dùng để lắng nghe kết nối đến. BND.ADDR chứa địa chỉ IP. Gói tin thứ 2 gửi đi thông báo kết nối thành công hay thất bại.
Chuyển tiếp gói tin UDP
Trong giao thức SOCKS quá trình diễn ra khi Client gửi gói tin TCP yêu cầu kết nối đến server với giá trị trường CMD là 0x03. Khi nhận được yêu cầu kết nối này SOCKS server trả về gói tin với BND.PORT và BND.ADDR chứa giá trị cổng và địa chỉ mà máy chủ SOCKS mở socket UDP lắng nghe chờ client gửi gói tin UDP cần chuyển tiếp qua máy chủ SOCKS. Đến đây thì hơi rắc rối hơn và dễ bị nhầm, ngay cả mình lúc phát triển cũng mất thời gian khá lâu để hiểu cách chuyển tiếp UDP vì một lỗi ngớ ngấn là mình đang đi theo follow giống như lúc chuyển tiếp TCP và quên đi chi tiết là phải mở ra 1 cổng UDP riêng trên socks proxy server lắng nghe các kết nối UDP client gửi đến rồi tiếp nhận các yêu cầu tại đây và chuyển tiếp gói tin. Và phải lưu ý kết nối đầu tiên client gửi lên server để yêu cầu chuyển tiếp gói tin UDP là 1 gói tin TCP chứ ko phải gói tin UDP. Đây là gói tin thiết lập kết nối theo chuẩn SOCKS. Sau đó các gói tin UDP mới chuyển tiếp đến cổng UDP mà server trả về cho client sau khi tiến hành kết nối
Định dạng gói tin UDP mà client gửi tới cho server:
Trong đó:
Hi vọng bài viết này sẽ giúp các bạn trong việc phát triển Proxy dựa trên giao thức SOCKS5 và hiểu rõ hơn cách thức hoạt động chuyển tiếp gói tin của SOCKS Proxy. Thanks
SOCKS là một giao thức Internet tạo ra để trao đổi gói tin giữa client và server thông qua một proxy server. SOCKS phiên bản đầu tiên được thiết kế và phát triển bởi David Koblas là một trong những người quản trị hệ thống của “MIPS Computer Systems”( Công ty xây dựng kiến trúc MISP trên CPU). Giao thức SOCKS hiện tại được phát triển tới phiên bản thứ 6 là SOCKS 6.
SOCKS được phát triển đảm bảo các đặc tính của proxy như ẩn danh người dùng, về cơ bản thì proxy và VPN có những đặc tính giống nhau nhưng proxy sẽ có tốc độ nhanh hơn VPN vì proxy không phải mã hóa, giải mã gói tin gửi và nhận khi truyền mà đa phần chỉ làm nhiệm vụ chuyển tiếp gói tin trong mạng.
SOCKS hoạt động ở tầng thấp hơn giao thức HTTP Proxying (Tầng 7) SOCKS hoạt động ở tầng 5 (Tầng phiên) trong mô hình OSI hỗ trợ chuyển tiếp các gói tin TCP. Từ phiên bản SOCKS 5 trở đi thì cung cấp thêm phương thức chuyển tiếp các gói tin UDP và xác thực người dùng. SOCKS sử dụng giao thức bắt tay với client để lấy các thông tin về địa chỉ đích mà client đang muốn kết nối đến rồi thông báo cho phần mềm proxy và sau đó hoạt động gần như trong suốt với người dùng. SOCKS hoạt động được trên các proxy đảo ngược và được sử dụng rộng rãi trên môi trường internet.
Giao thức SOCKS 5 được phát triển kế thừa trên giao thức SOCKS phiên bản 4. So với giao thức SOCKS 4 thì SOCKS5 cung cấp phương thức hỗ trợ chuyển tiếp các gói tin UDP, hỗ trợ IPV6 và bổ sung các lựa chọn xác thực.
Thiết lập kết nối
Khi client muốn thiết lập một kết nối đến một đối tượng thông qua giao thức SOCKS sẽ phải tiến hành thiết lập kết nối TCP đến cổng của dịch vụ SOCKS được mở trên máy chủ SOCKS (Cổng mặc định của dịch vụ SOCKS là 1080). Nếu yêu cầu kết nối thành công Client sẽ trao đổi thống nhất phương pháp xác thực được sử dụng với server, tiến hành xác thực theo phương thức đã lựa chọn, sau đó mới gửi yêu cầu chuyển tiếp cho máy chủ SOCKS. Máy chủ SOCKS sẽ đánh giá yêu cầu kết nối và sẽ tiến hành thiết lập kết nối theo yêu cầu hoặc là từ chối kết nối.
Bắt đầu thiết lập kết nối Client gửi gói tin TCP đến server bao gồm phiên bản SOCKS được sử dụng, phương thức hỗ trợ theo định dạng sau:
VER | NMETHODS | METHODS |
1 byte | 1 byte | 1 - 255 byte |
- VER: Là trường phiên bản của giao thức SOCKS. Đối với giao thức SOCKS 5 thì sẽ được đặt giá trị là 5
- NMETHODS: 1byte chứa giá trị chỉ số lượng method sẽ xuất hiện trong trường METHODS
- METHODS: Trường này lần lượt sẽ chứa các bytes định danh các phương thức mà client hỗ trợ.
VER | METHOD |
1 byte | 1 byte |
- 0x00: Không yêu cầu xác thực
- 0x01: GSSAPI (Viết tắt của từ Generic Security Services Application Program Interface)
- 0x02: Đăng nhập qua tên đăng nhập và mật khẩu
- 0x03 đến 0x7F: Phương thức gán bởi IANA
- 0x80 đến 0xFE: Phương thức cho người sử dụng cá nhân.
- 0xFF Không chấp nhận phương thức nào.
Nếu server lựa chọn phương thức không lựa phương thức không yêu cầu xác thực thì giữa client và server sẽ bỏ qua bước xác thực và tiến hành trao đổi thông tin. Với các METHOD khác được lựa chọn server và client sẽ tiến hành trao đổi xác thực theo giao thức đó
Khi phương thức xác thức được chọn là sử dụng tên đăng nhập và mật khẩu thì client và server tiến hành trao đổi xác thực. Client gửi gói tin xác thực với định dạng:
VER | ULEN | UNAME | PLEN | PASSWD |
1byte | 1byte | 1 – 255 bytes | 1 byte | 1-255 bytes |
- VER: Độ dài 1byte có giá trị là 0x01 chỉ phiên bản của phương thức xác thực theo tên đăng nhập và mật khẩu.
- ULEN: Độ dài 1byte có giá trị chứa độ dài của trường UNAME
- UNAME: Tên đăng nhập có độ dài được xác định trong trường ULEN
- PLEN: Độ dài 1byte có giá trị chứa độ dài của trường PASSWD
- PASSWD: Mật khẩu có độ dài được xác định trong PLEN
VER | STATUS |
1byte | 1byte |
VER CMD RSV ATYP DST.ADDR DST.PORT
1 byte 1 byte 0x00 1 byte 2 byte
Trong đó:
- VER: Phiên bản SOCKS sử dụng đối với SOCKS 5 giá trị này là 0x05
- CMD: Giá trị lệnh điều khiển có độ dài 1byte một trong các giá trị sau:
- CONNECT: 0x01 – Thiết lập kết nối TCP/IP
- BIND: 0x02 – Thiết lập ràng buộc cổng TCP/IP
- UDP: 0x03 – Tạo liên kết một cổng UDP
- RSV: Đồ dài 1byte giá trị luôn là 0x00
- ATYP: Kiểu địa chỉ kết nối có độ dài 1byte, gồm các giá trị:
- 0x01: Địa chỉ đích là IP V4
- 0x03: Địa chỉ đích là tên miền
- 0x04: Địa chỉ đích là IP V6
- DST.ADDR: Các byte chứa địa chỉ đích mà client yêu cầu kết nối số độ dài của trường này phụ thuộc vào kiểu địa chỉ được định nghĩa trong trường ATYP:
- Nếu địa chỉ đích là IPV4 thì DST.ADDR có độ dài 4byte chứa giá trị của địa chỉ IPV4
- Nếu địa chỉ đích là tên miền thì 1byte đầu tiên sẽ chứa độ dài của tên miền, server dựa vào giá trị này sẽ lấy số byte tiếp theo để biết giá trị của tên miền
- Nếu địa chỉ đích là IPV6 thì trường DST.ADDR có độ dài 16byte chứa giá trị địa chỉ IPV6
VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
1byte | 1byte | 0x00 | 1byte | 2byte |
- 0x00: Thiết lập kết nối thành công
- 0x01: Lỗi máy chủ SOCKS
- 0x02: Kết nối không được phép
- 0x03: Không có kết nối mạng
- 0x04: Không thể truy cập đến địa chỉ
- 0x05: Kết nối bị từ chối bởi máy chủ đích
- 0x06: Hết hạn TTL
- 0x07: Lệnh không được hỗ trợ
- 0x08: Kiểu địa chỉ không được hỗ trợ
Khi client yêu cầu lệnh thiết lập một kết nối TCP/IP. Server trả về giá trị BND.PORT, BND.ADDR là cổng và địa chỉ IP mà máy chủ dùng để kết nối với máy đích mà client yêu cầu kết nối. Thường BND.ADDR sẽ có giá trị khác so với địa chỉ IP mà client dùng để kết nối đến máy chủ socks. Khi client yêu cầu với lệnh BIND: Sẽ có 2 gói tin được gửi từ máy chủ SOKCS đến client trong quá trình BIND. Gói tin đầu tiên được gửi sau khi máy chủ khởi tạo và đăng ký lắng nghe trên một cổng cho một socket mới. Trường BND.PORT server trả về chứa địa chỉ cổng mà server dùng để lắng nghe kết nối đến. BND.ADDR chứa địa chỉ IP. Gói tin thứ 2 gửi đi thông báo kết nối thành công hay thất bại.
Chuyển tiếp gói tin UDP
Trong giao thức SOCKS quá trình diễn ra khi Client gửi gói tin TCP yêu cầu kết nối đến server với giá trị trường CMD là 0x03. Khi nhận được yêu cầu kết nối này SOCKS server trả về gói tin với BND.PORT và BND.ADDR chứa giá trị cổng và địa chỉ mà máy chủ SOCKS mở socket UDP lắng nghe chờ client gửi gói tin UDP cần chuyển tiếp qua máy chủ SOCKS. Đến đây thì hơi rắc rối hơn và dễ bị nhầm, ngay cả mình lúc phát triển cũng mất thời gian khá lâu để hiểu cách chuyển tiếp UDP vì một lỗi ngớ ngấn là mình đang đi theo follow giống như lúc chuyển tiếp TCP và quên đi chi tiết là phải mở ra 1 cổng UDP riêng trên socks proxy server lắng nghe các kết nối UDP client gửi đến rồi tiếp nhận các yêu cầu tại đây và chuyển tiếp gói tin. Và phải lưu ý kết nối đầu tiên client gửi lên server để yêu cầu chuyển tiếp gói tin UDP là 1 gói tin TCP chứ ko phải gói tin UDP. Đây là gói tin thiết lập kết nối theo chuẩn SOCKS. Sau đó các gói tin UDP mới chuyển tiếp đến cổng UDP mà server trả về cho client sau khi tiến hành kết nối
Định dạng gói tin UDP mà client gửi tới cho server:
RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
2bytes | 1byte | 1byte | 2bytes |
- RSV: Giá trị 0x0000
- FRAG: Số fragment hiện tại
- ATYP: Kiểu địa chỉ kết nối
- 0x01: IPV4
- 0x03: Tên miền
- 0x04: IPV6
- DST.ADDR: Địa chỉ đích client muốn kết nối đến
- DST.PORT: Địa chỉ cổng mà client muốn kết nối
- Data: Dữ liệu client muốn gửi đi.
Hi vọng bài viết này sẽ giúp các bạn trong việc phát triển Proxy dựa trên giao thức SOCKS5 và hiểu rõ hơn cách thức hoạt động chuyển tiếp gói tin của SOCKS Proxy. Thanks
Chỉnh sửa lần cuối: