Ground-Zerro / Phobos Public
Code Issues Pull requests Actions Releases View on GitHub ↗
6.0 KB go
//go:build phoboscref

/* SPDX-License-Identifier: MIT
 *
 * Phobos
 */

package cref

/*
#include <stdint.h>
#include <string.h>
#include <arpa/inet.h>
#include "masking_stun.c"
#include "masking_media.c"
#include "socks5_mask.c"

int verbose = 0;
char section_name[256] = "cref";

static s5_enc_t ref_enc;
static s5_dec_t ref_dec;

static void ref_s5_reset(void) {
    memset(&ref_enc, 0, sizeof(ref_enc));
    memset(&ref_dec, 0, sizeof(ref_dec));
}

static void ref_s5_config(obfuscator_config_t *config, uint8_t pt, uint32_t ssrc, uint16_t ts_step) {
    memset(config, 0, sizeof(*config));
    config->media_payload_type = pt;
    config->media_ssrc = ssrc;
    config->media_ts_step = ts_step;
}

static int ref_s5_encode(int mask, uint8_t pt, uint32_t ssrc, uint16_t ts_step,
                         const uint8_t *src, int src_len, uint8_t *out, int out_cap) {
    obfuscator_config_t config;
    ref_s5_config(&config, pt, ssrc, ts_step);
    return s5_mask_encode(mask, &ref_enc, &config, src, src_len, out, out_cap);
}

static int ref_s5_decode(int mask, uint8_t pt, uint32_t ssrc,
                         const uint8_t *in, int in_len, uint8_t *out, int out_cap) {
    obfuscator_config_t config;
    ref_s5_config(&config, pt, ssrc, 0);
    return s5_mask_decode(mask, &ref_dec, &config, in, in_len, out, out_cap);
}

static int ref_stun_binding_success(uint8_t *out, const uint8_t *txid, const uint8_t *ip, uint16_t port) {
    struct sockaddr_in src;
    memset(&src, 0, sizeof(src));
    src.sin_family = AF_INET;
    memcpy(&src.sin_addr.s_addr, ip, 4);
    src.sin_port = htons(port);
    return stun_build_binding_success(out, txid, &src);
}

static uint32_t ref_crc32(const uint8_t *data, int length) {
    return crc32(data, (size_t)length);
}

static int ref_stun_binding_request(uint8_t *out) {
    return stun_build_binding_request(out);
}

static uint16_t ref_media_pick_preset(uint8_t *pt_out) {
    return media_pick_preset(pt_out);
}

static int ref_stun_wrap(uint8_t *buf, int payload_length) {
    memmove(buf + STUN_DATA_IND_HEADER, buf, payload_length);
    stun_build_frame(buf, payload_length, NULL, NULL, DIR_CLIENT_TO_SERVER);
    return STUN_DATA_IND_HEADER + payload_length;
}

static int ref_stun_unwrap(uint8_t *buf, int length) {
    int n = stun_unwrap(buf, length);
    if (n < 0) return n;
    memmove(buf, buf + STUN_DATA_IND_HEADER, n);
    return n;
}

static int ref_media_wrap(uint8_t *buf, int payload_length, uint8_t pt, uint32_t ssrc, uint16_t ts_step) {
    obfuscator_config_t config;
    client_entry_t client;
    memset(&config, 0, sizeof(config));
    memset(&client, 0, sizeof(client));
    config.media_payload_type = pt;
    config.media_ssrc = ssrc;
    config.media_ts_step = ts_step;
    memmove(buf + RTP_HEADER_SIZE, buf, payload_length);
    media_build_frame(buf, payload_length, &config, &client, DIR_CLIENT_TO_SERVER);
    return RTP_HEADER_SIZE + payload_length;
}

static int ref_media_unwrap(uint8_t *buf, int length, uint8_t pt, uint32_t ssrc) {
    obfuscator_config_t config;
    client_entry_t client;
    memset(&config, 0, sizeof(config));
    memset(&client, 0, sizeof(client));
    config.media_payload_type = pt;
    config.media_ssrc = ssrc;
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    int offset = 0;
    int n = media_on_data_unwrap(buf, length, &config, &client, DIR_SERVER_TO_CLIENT,
                                 &addr, &addr, NULL, NULL, &offset);
    if (n < 0) return n;
    memmove(buf, buf + offset, n);
    return n;
}

*/
import "C"

import (
	"bytes"

	"net/netip"
	"unsafe"
)

func StunBindingSuccess(txid []byte, addr netip.AddrPort) []byte {
	out := make([]byte, 128)
	ip := addr.Addr().As4()
	n := C.ref_stun_binding_success(
		(*C.uint8_t)(unsafe.SliceData(out)),
		(*C.uint8_t)(unsafe.SliceData(txid)),
		(*C.uint8_t)(&ip[0]),
		C.uint16_t(addr.Port()),
	)
	if n < 0 {
		return nil
	}
	return out[:int(n)]
}

func Socks5Reset() {
	C.ref_s5_reset()
}

func Socks5Encode(mask int, payloadType uint8, ssrc uint32, timestampStep uint16, src []byte, capacity int) []byte {
	out := make([]byte, capacity)
	n := C.ref_s5_encode(C.int(mask), C.uint8_t(payloadType), C.uint32_t(ssrc), C.uint16_t(timestampStep),
		(*C.uint8_t)(unsafe.SliceData(src)), C.int(len(src)),
		(*C.uint8_t)(unsafe.SliceData(out)), C.int(capacity))
	if n < 0 {
		return nil
	}
	return out[:int(n)]
}

func Socks5Decode(mask int, payloadType uint8, ssrc uint32, in []byte, capacity int) []byte {
	out := make([]byte, capacity)
	n := C.ref_s5_decode(C.int(mask), C.uint8_t(payloadType), C.uint32_t(ssrc),
		(*C.uint8_t)(unsafe.SliceData(in)), C.int(len(in)),
		(*C.uint8_t)(unsafe.SliceData(out)), C.int(capacity))
	if n < 0 {
		return nil
	}
	return out[:int(n)]
}

func CRC32(data []byte) uint32 {
	return uint32(C.ref_crc32((*C.uint8_t)(unsafe.SliceData(data)), C.int(len(data))))
}

func StunBindingRequest() []byte {
	out := make([]byte, 128)
	return out[:int(C.ref_stun_binding_request((*C.uint8_t)(unsafe.SliceData(out))))]
}

func PickMediaPreset(payloadType *uint8) uint16 {
	return uint16(C.ref_media_pick_preset((*C.uint8_t)(payloadType)))
}

func StunWrap(payload []byte, capacity int) []byte {
	buf := make([]byte, capacity)
	copy(buf, payload)
	n := C.ref_stun_wrap((*C.uint8_t)(unsafe.SliceData(buf)), C.int(len(payload)))
	return buf[:int(n)]
}

func StunUnwrap(frame []byte) []byte {
	buf := bytes.Clone(frame)
	n := C.ref_stun_unwrap((*C.uint8_t)(unsafe.SliceData(buf)), C.int(len(buf)))
	if n < 0 {
		return nil
	}
	return buf[:int(n)]
}

func MediaWrap(payload []byte, payloadType uint8, ssrc uint32, timestampStep uint16, capacity int) []byte {
	buf := make([]byte, capacity)
	copy(buf, payload)
	n := C.ref_media_wrap((*C.uint8_t)(unsafe.SliceData(buf)), C.int(len(payload)),
		C.uint8_t(payloadType), C.uint32_t(ssrc), C.uint16_t(timestampStep))
	return buf[:int(n)]
}

func MediaUnwrap(frame []byte, payloadType uint8, ssrc uint32) []byte {
	buf := bytes.Clone(frame)
	n := C.ref_media_unwrap((*C.uint8_t)(unsafe.SliceData(buf)), C.int(len(buf)),
		C.uint8_t(payloadType), C.uint32_t(ssrc))
	if n < 0 {
		return nil
	}
	return buf[:int(n)]
}