



package mainimport ("encoding/binary""fmt""net")type NetworkConnection struct {Magic uint16ClientAddr net.IPProxyAddr net.IPClientPort uint16ProxyPort uint16}func handleConn(conn *net.UDPConn) {buf := make([]byte, 1024) // バッファを作成しますn, addr, err := conn.ReadFromUDP(buf) // 接続からデータパケットを読み取りますif err != nil {fmt.Println("Error reading from UDP connection:", err)return}// 受信したバイトをNetworkConnection構造体に変換しますnc := NetworkConnection{Magic: binary.BigEndian.Uint16(buf[0:2]),ClientAddr: make(net.IP, net.IPv6len),ProxyAddr: make(net.IP, net.IPv6len),}if nc.Magic == 0x56EC {copy(nc.ClientAddr, buf[2:18])copy(nc.ProxyAddr, buf[18:34])nc.ClientPort = binary.BigEndian.Uint16(buf[34:36])nc.ProxyPort = binary.BigEndian.Uint16(buf[36:38])// sppヘッダー情報を出力します。これにはmagic、クライアントの実際のipとポート、プロキシのipとポートが含まれますfmt.Printf("Received packet:\\n")fmt.Printf("\\tmagic: %x\\n", nc.Magic)fmt.Printf("\\tclient address: %s\\n", nc.ClientAddr.String())fmt.Printf("\\tproxy address: %s\\n", nc.ProxyAddr.String())fmt.Printf("\\tclient port: %d\\n", nc.ClientPort)fmt.Printf("\\tproxy port: %d\\n", nc.ProxyPort)// 実際の有効なペイロードを出力しますfmt.Printf("\\tdata: %v\\n\\tcount: %v\\n", string(buf[38:n]), n)} else {// 実際の有効なペイロードを出力しますfmt.Printf("\\tdata: %v\\n\\tcount: %v\\n", string(buf[0:n]), n)}// パケットを返します。注意:SPP 38バイト長をそのまま返す必要がありますresponse := make([]byte, n)copy(response, buf[0:n])_, err = conn.WriteToUDP(response, addr) // データを送信しますif err != nil {fmt.Println("Write to udp failed, err: ", err)}}func main() {localAddr, _ := net.ResolveUDPAddr("udp", ":6666") // ローカルアドレスとポートを使用してUDPアドレスを作成しますconn, err := net.ListenUDP("udp", localAddr) // リスナーを作成しますif err != nil {panic("Failed to listen for UDP connections:" + err.Error())}defer conn.Close() // 終了時に接続を閉じますfor {handleConn(conn) // 受信した接続を処理します}}
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/socket.h>#define BUF_SIZE 1024struct NetworkConnection {uint16_t magic;struct in6_addr clientAddr;struct in6_addr proxyAddr;uint16_t clientPort;uint16_t proxyPort;};void handleConn(int sockfd) {struct sockaddr_in clientAddr;socklen_t addrLen = sizeof(clientAddr);unsigned char buf[BUF_SIZE];ssize_t n = recvfrom(sockfd, buf, BUF_SIZE, 0, (struct sockaddr *)&clientAddr, &addrLen);if (n < 0) {perror("Error reading from UDP connection");return;}// 受信したバイトをNetworkConnection構造体に変換しますstruct NetworkConnection nc;nc.magic = ntohs(*(uint16_t *)buf);if (nc.magic == 0x56EC) { // Magicが0x56ECの場合はSPPヘッダーを表しますmemcpy(&nc.clientAddr, buf + 2, 16);memcpy(&nc.proxyAddr, buf + 18, 16);nc.clientPort = ntohs(*(uint16_t *)(buf + 34));nc.proxyPort = ntohs(*(uint16_t *)(buf + 36));printf("Received packet:\\n");printf("\\tmagic: %x\\n", nc.magic);char clientIp[INET6_ADDRSTRLEN];char proxyIp[INET6_ADDRSTRLEN];inet_ntop(AF_INET6, &nc.clientAddr, clientIp, INET6_ADDRSTRLEN);inet_ntop(AF_INET6, &nc.proxyAddr, proxyIp, INET6_ADDRSTRLEN);// sppヘッダー情報を出力します。これにはmagic、クライアントの実際のipとポート、プロキシのipとポートが含まれますprintf("\\tclient address: %s\\n", clientIp);printf("\\tproxy address: %s\\n", proxyIp);printf("\\tclient port: %d\\n", nc.clientPort);printf("\\tproxy port: %d\\n", nc.proxyPort);// 実際の有効なペイロードを出力しますprintf("\\tdata: %.*s\\n\\tcount: %zd\\n", (int)(n - 38), buf + 38, n);} else {printf("\\tdata: %.*s\\n\\tcount: %zd\\n", (int)n, buf, n);}// パケットを返します。注意:SPP 38バイト長をそのまま返す必要がありますsendto(sockfd, buf, n, 0, (struct sockaddr *)&clientAddr, addrLen);}int main() {int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("Failed to create socket");exit(EXIT_FAILURE);}// ローカルアドレスとポートを使用してUDPアドレスを作成しますstruct sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = INADDR_ANY;serverAddr.sin_port = htons(6666);if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {perror("Failed to bind");exit(EXIT_FAILURE);}while (1) {handleConn(sockfd);}}
echo "Hello Server" | nc -w 1 -u <IP/DOMAIN> <PORT>



フィードバック