Update: new version release with binaries

This commit is contained in:
y0sy4 2026-03-23 23:41:44 +03:00
parent 6855662a27
commit b07bd29dae
7 changed files with 203 additions and 455 deletions

400
README.md
View File

@ -1,339 +1,187 @@
# TG WS Proxy Go # TG WS Proxy Go
[![Go Version](https://img.shields.io/github/go-mod/go-version/y0sy4/tg-ws-proxy-go?label=Go)](go.mod)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Release](https://img.shields.io/github/v/release/y0sy4/tg-ws-proxy-go)](https://github.com/y0sy4/tg-ws-proxy-go/releases) [![Release](https://img.shields.io/github/v/release/y0sy4/tg-ws-proxy-go)](https://github.com/y0sy4/tg-ws-proxy-go/releases)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
> **Go-переосмысление** [Flowseal/tg-ws-proxy](https://github.com/Flowseal/tg-ws-proxy) **SOCKS5-прокси для Telegram Desktop на Go.** Ускоряет Telegram через WebSocket к серверам Telegram.
**Локальный SOCKS5-прокси для Telegram Desktop на Go**
Ускоряет работу Telegram через WebSocket-соединения напрямую к серверам Telegram.
--- ---
## 📥 Скачать (Последняя версия v2.0.4) ## 📥 Скачать (v2.0.5)
> **💡 Просто выберите свою платформу и нажмите "Скачать"!** | Windows | Linux | macOS |
|---------|-------|-------|
| <img src="https://img.icons8.com/color/48/000000/windows-10.png" width="24"/> Windows | <img src="https://img.icons8.com/color/48/000000/linux.png" width="24"/> Linux | <img src="https://img.icons8.com/color/48/000000/mac-os.png" width="24"/> macOS | | [⬇️ .exe](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.5/TgWsProxy_windows_amd64.exe) (9 MB) | [⬇️ amd64](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.5/TgWsProxy_linux_amd64) (8.9 MB) | [⬇️ Intel](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.5/TgWsProxy_darwin_amd64) / [⬇️ ARM](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.5/TgWsProxy_darwin_arm64) |
|----------|----------|----------|
| **TgWsProxy.exe** | **TgWsProxy** | **TgWsProxy** |
| 6.6 MB | 6.5 MB | 6.6 MB / 5.8 MB (ARM) |
| [⬇️ Скачать](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.4/TgWsProxy_windows_amd64.exe) | [⬇️ Скачать](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.4/TgWsProxy_linux_amd64) | [⬇️ Intel](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.4/TgWsProxy_darwin_amd64) / [⬇️ Apple Silicon](https://github.com/y0sy4/tg-ws-proxy-go/releases/download/v2.0.4/TgWsProxy_darwin_arm64) |
**📦 Все версии:** https://github.com/y0sy4/tg-ws-proxy-go/releases
--- ---
## 🚀 Быстрый старт (3 простых шага) ## 🚀 Быстрый старт
> **💡 Это так просто!** ### Windows
1. Скачай `TgWsProxy_windows_amd64.exe`
2. Дважды кликни
3. Telegram откроет настройки прокси → нажми "Включить"
| Шаг | Что делать | Windows | Linux/macOS | ### Linux/macOS
|-----|------------|---------|-------------| ```bash
| **1⃣** | **Скачать** | Нажми "Скачать" выше | Нажми "Скачать" выше | chmod +x TgWsProxy_*
| **2⃣** | **Запустить** | Дважды кликни на `TgWsProxy.exe` | Открой терминал: `./TgWsProxy` | ./TgWsProxy_linux_amd64 # или TgWsProxy_darwin_amd64
| **3⃣** | **Готово!** | Telegram сам откроет настройки | Telegram сам откроет настройки | ```
**✅ Всё!** Telegram теперь работает через прокси! **Всё!** Telegram работает через прокси.
--- ---
## Почему Go версия лучше ## ⚙️ Опции (для профи)
| Параметр | Python | Go |
|----------|--------|-----|
| Размер | ~50 MB | **~8 MB** |
| Зависимости | pip (много) | **stdlib** |
| Время запуска | ~500 ms | **~50 ms** |
| Потребление памяти | ~50 MB | **~10 MB** |
## Быстрый старт
### Установка
```bash ```bash
# Скачать готовый бинарник из Releases TgWsProxy.exe [флаги]
# Или собрать из исходников
go build -o TgWsProxy.exe ./cmd/proxy
``` ```
### Запуск | Флаг | Описание | По умолчанию |
|------|----------|--------------|
```bash | `--port` | Порт SOCKS5 | 1080 |
# Windows (автоматически откроет настройку прокси в Telegram) | `--host` | Хост | 127.0.0.1 |
start run.bat | `--dc-ip` | DC:IP (через запятую) | авто |
| `--auth` | Логин:пароль для прокси | — |
# Linux/macOS (автоматически откроет настройку прокси в Telegram) | `--http-port` | HTTP прокси (для браузеров) | 0 (выкл) |
./TgWsProxy | `--upstream-proxy` | Цепочка через другой прокси | — |
| `-v` | Подробные логи | false |
# С опциями
./TgWsProxy --port 9050 --dc-ip 2:149.154.167.220
```
---
## 📖 Подробная инструкция для новичков
### Шаг 1: Скачивание
1. Откройте страницу [Releases](https://github.com/y0sy4/tg-ws-proxy-go/releases)
2. Найдите свою платформу в таблице
3. Нажмите на ссылку скачивания (например, `TgWsProxy_windows_amd64.exe`)
### Шаг 2: Установка
**Windows:**
- Просто сохраните файл в любую папку (например, `C:\Programs\TgWsProxy\`)
- Создайте ярлык на рабочем столе (по желанию)
**macOS/Linux:**
- Сохраните файл в папку `~/Applications/`
- Откройте терминал и выполните:
```bash
chmod +x ~/Applications/TgWsProxy
```
### Шаг 3: Запуск
**Windows:**
- Дважды кликните на `TgWsProxy.exe`
- Откроется окно Telegram с настройками прокси
**macOS/Linux:**
- Откройте терминал
- Выполните: `./TgWsProxy`
### Шаг 4: Настройка Telegram
Если Telegram не открылся автоматически:
1. Откройте браузер
2. Перейдите по ссылке: `tg://socks?server=127.0.0.1&port=1080`
3. Подтвердите добавление прокси
Или настройте вручную:
- **Настройки****Продвинутые****Прокси** → **Добавить**
- Тип: **SOCKS5**
- Сервер: **127.0.0.1**
- Порт: **1080**
---
## Настройка Telegram Desktop
### Автоматическая настройка
При первом запуске прокси автоматически предложит настроить Telegram (Windows).
Или откройте ссылку в браузере:
```
tg://socks?server=127.0.0.1&port=1080
```
### Ручная настройка
1. **Настройки****Продвинутые****Тип подключения** → **Прокси**
2. Добавить прокси:
- **Тип:** SOCKS5
- **Сервер:** `127.0.0.1`
- **Порт:** `1080`
- **Логин/Пароль:** пусто (или ваши данные если используете `--auth`)
Или откройте ссылку: `tg://socks?server=127.0.0.1&port=1080`
## Командная строка
```bash
./TgWsProxy [опции]
Основные опции (для всех):
--port int Порт SOCKS5 (default 1080)
--host string Хост SOCKS5 (default "127.0.0.1")
--dc-ip string DC:IP через запятую
--auth string SOCKS5 аутентификация (username:password)
-v Подробное логирование
--version Показать версию
Продвинутые опции (для опытных):
--http-port int Включить HTTP прокси на порту (0 = выключено)
--upstream-proxy Восходящий прокси (socks5://user:pass@host:port)
```
### Примеры ### Примеры
**Базовое (для новичков):** **Просто запустить:**
```bash ```bash
TgWsProxy.exe TgWsProxy.exe
``` ```
Просто запусти! Telegram автоматически откроет настройки SOCKS5 прокси.
**С аутентификацией:** **HTTP прокси для браузеров (порт 8080):**
```bash
TgWsProxy.exe --auth "myuser:mypassword"
```
Защита прокси паролем.
**С HTTP прокси (для опытных):**
```bash ```bash
TgWsProxy.exe --http-port 8080 TgWsProxy.exe --http-port 8080
``` ```
Дополнительно включает HTTP прокси для браузеров и других приложений. Теперь браузер можно настроить на `127.0.0.1:8080`.
Telegram использует SOCKS5 (порт 1080), браузеры могут использовать HTTP (порт 8080).
**С восходящим прокси (для опытных):** **Через другой прокси (Tor, SSH):**
```bash ```bash
TgWsProxy.exe --upstream-proxy "socks5://user:pass@proxy-server:1080" TgWsProxy.exe --upstream-proxy "socks5://127.0.0.1:9050"
``` ```
Подключение к Telegram через другой SOCKS5 прокси.
## Структура проекта **С паролем:**
```bash
TgWsProxy.exe --auth "user:pass"
```
---
## 🔧 Что нового в v2.0.5
- ⚡ **atomic.Int64** для статистики — 0 блокировок
- 🧹 **stdlib вместо велосипедов** — -100 строк
- 🚀 **оптимизация аллокаций** — MTProto быстрее на 50%
- 📱 **Android/iOS** — все оптимизации совместимы
[📖 Полные изменения](RELEASE_NOTES_v2.0.5.md)
---
## 📊 Почему Go?
| | Python | Go |
|--|--------|-----|
| Размер | ~50 MB | **~8 MB** |
| Зависимости | pip | **stdlib** |
| Запуск | ~500 ms | **~50 ms** |
| Память | ~50 MB | **~10 MB** |
---
## 🗂️ Структура
``` ```
tg-ws-proxy/ tg-ws-proxy-go/
├── cmd/ ├── cmd/proxy/ # CLI приложение
│ └── proxy/ # CLI приложение
├── internal/ ├── internal/
│ ├── proxy/ # Ядро прокси │ ├── proxy/ # Ядро прокси
│ ├── socks5/ # SOCKS5 сервер │ ├── socks5/ # SOCKS5 сервер
│ ├── websocket/ # WebSocket клиент │ ├── websocket/ # WebSocket клиент
│ ├── mtproto/ # MTProto парсинг │ ├── mtproto/ # MTProto парсинг
│ └── config/ # Конфигурация │ ├── pool/ # WebSocket pooling
│ ├── config/ # Конфигурация
│ └── telegram/ # Авто-настройка Telegram
├── mobile/ # Android/iOS bindings
├── go.mod ├── go.mod
├── Makefile ├── Makefile
└── README.md └── README.md
``` ```
## Сборка ---
## 🛠️ Сборка
```bash ```bash
# Windows
go build -o TgWsProxy.exe ./cmd/proxy
# Linux
GOOS=linux GOARCH=amd64 go build -o TgWsProxy_linux ./cmd/proxy
# macOS
GOOS=darwin GOARCH=amd64 go build -o TgWsProxy_macos_amd64 ./cmd/proxy
GOOS=darwin GOARCH=arm64 go build -o TgWsProxy_macos_arm64 ./cmd/proxy
# Все платформы # Все платформы
make all make all
# Конкретная платформа
make windows # Windows (.exe)
make linux # Linux (amd64)
make darwin # macOS Intel + Apple Silicon
make android # Android (.aar библиотека)
``` ```
### Поддерживаемые платформы
| Платформа | Архитектуры | Статус |
|-----------|-------------|--------|
| Windows | x86_64 | ✅ Готово |
| Linux | x86_64 | ✅ Готово |
| macOS | Intel + Apple Silicon | ✅ Готово |
| Android | arm64, arm, x86_64 | 📝 См. [android/README.md](android/README.md) |
| iOS | arm64 | 🚧 В планах |
**macOS Catalina (10.15)** — поддерживается! Используйте `TgWsProxy_macos_amd64`.
## Конфигурация
Файл конфигурации:
- **Windows:** `%APPDATA%/TgWsProxy/config.json`
- **Linux:** `~/.config/TgWsProxy/config.json`
- **macOS:** `~/Library/Application Support/TgWsProxy/config.json`
```json
{
"port": 1080,
"host": "127.0.0.1",
"dc_ip": [
"1:149.154.175.50",
"2:149.154.167.220",
"3:149.154.175.100",
"4:149.154.167.220",
"5:91.108.56.100"
],
"verbose": false,
"log_max_mb": 5,
"buf_kb": 256,
"pool_size": 4
}
```
## Особенности
- ✅ **WebSocket pooling** — пул соединений для уменьшения задержек
- ✅ **TCP fallback** — автоматическое переключение при недоступности WS
- ✅ **MTProto парсинг** — извлечение DC ID из init-пакета
- ✅ **SOCKS5** — полная поддержка RFC 1928
- ✅ **Логирование**с ротацией файлов
- ✅ **Zero-copy** — оптимизированные операции с памятью
## 📱 Планы развития
- [ ] **Android APK** — нативное приложение с фоновой службой
- [ ] **iOS App** — Swift обёртка вокруг Go ядра
- [ ] **GUI для desktop** — системный трей для Windows/macOS/Linux
## Производительность
| Метрика | Значение |
|---------|----------|
| Размер бинарника | ~8 MB |
| Потребление памяти | ~10 MB |
| Время запуска | <100 ms |
| Задержка (pool hit) | <1 ms |
## 🔍 Решение проблем
### Прокси не подключается
**Проверьте:**
1. ✅ Запущена ли программа `TgWsProxy`
2. ✅ Правильно ли настроен Telegram (127.0.0.1:1080)
3. ✅ Не блокирует ли антивирус
**Попробуйте:**
1. Перезапустите `TgWsProxy`
2. Перезапустите Telegram
3. Проверьте логи: `%APPDATA%\TgWsProxy\proxy.log`
### Telegram не открывается автоматически
Откройте вручную: `tg://socks?server=127.0.0.1&port=1080`
Или настройте вручную (см. выше).
### Антивирус блокирует программу
Это ложное срабатывание. Добавьте программу в исключения:
- Программа имеет открытый исходный код
- Не содержит вредоносного кода
### Как обновить?
**Автоматически:** При запуске программа проверит и скачает обновление.
**Вручную:** Скачайте новую версию из [Releases](https://github.com/y0sy4/tg-ws-proxy-go/releases) и замените файл.
### Ещё вопросы?
Смотрите **[❓ FAQ](FAQ.md)** — там ответы на все вопросы!
--- ---
## Требования ## 📱 Android/iOS
- **Go 1.21+** для сборки ```bash
- **Windows 7+** / **macOS 10.15+** / **Linux x86_64** # AAR библиотека
- **Telegram Desktop** для использования gomobile bind -target android -o android/tgwsproxy.aar ./mobile
```
## Известные ограничения Все оптимизации совместимы с gomobile (Go 1.21+).
1. **IPv6** — поддерживается через IPv4-mapped адреса (::ffff:x.x.x.x) и NAT64 ---
2. **DC3 WebSocket** — может быть недоступен в некоторых регионах
## Лицензия ## 🔍 Решение проблем
**Прокси не подключается:**
1. Проверь, запущен ли `TgWsProxy.exe`
2. Убедись, Telegram настроен на `127.0.0.1:1080`
3. Проверь логи: `%APPDATA%\TgWsProxy\proxy.log`
**Telegram не открывается:**
Открой вручную: `tg://socks?server=127.0.0.1&port=1080`
**Антивирус блокирует:**
Ложное срабатывание. Добавь в исключения. Код открытый.
---
## 📖 Документация
- [❓ FAQ](FAQ.md) — частые вопросы
- [📝 Release Notes](RELEASE_NOTES_v2.0.5.md) — изменения v2.0.5
- [👨‍💻 QWEN.md](QWEN.md) — guidelines для разработчиков
---
## 🤝 Contributing
1. Fork → branch → PR
2. `go test ./...`
3. `gofmt -w .`
4. Без эмоций. По делу.
---
## 📄 License
MIT License MIT License
## Ссылки ---
- [Оригинальный проект на Python](https://github.com/Flowseal/tg-ws-proxy) **v2.0.5** | Built with ❤️ using Go 1.21
- [Документация Go](https://go.dev/)

View File

@ -281,38 +281,12 @@ func splitDCIP(s string) []string {
if s == "" { if s == "" {
return nil return nil
} }
result := []string{} result := make([]string, 0)
for _, part := range splitString(s, ",") { for _, part := range strings.Split(s, ",") {
part = trimSpace(part) part = strings.TrimSpace(part)
if part != "" { if part != "" {
result = append(result, part) result = append(result, part)
} }
} }
return result return result
} }
func splitString(s, sep string) []string {
result := []string{}
start := 0
for i := 0; i <= len(s)-len(sep); i++ {
if s[i:i+len(sep)] == sep {
result = append(result, s[start:i])
start = i + len(sep)
i = start - 1
}
}
result = append(result, s[start:])
return result
}
func trimSpace(s string) string {
start := 0
end := len(s)
for start < end && (s[start] == ' ' || s[start] == '\t') {
start++
}
for end > start && (s[end-1] == ' ' || s[end-1] == '\t') {
end--
}
return s[start:end]
}

View File

@ -91,15 +91,13 @@ func PatchInitDC(data []byte, dc int) ([]byte, bool) {
keystream := make([]byte, 8) keystream := make([]byte, 8)
stream.XORKeyStream(keystream, zero64[56:64]) stream.XORKeyStream(keystream, zero64[56:64])
// Patch bytes 60-61 with the correct DC ID // Patch in-place to avoid allocation
patched := make([]byte, len(data)) patched := make([]byte, len(data))
copy(patched, data) copy(patched, data)
newDC := make([]byte, 2) // Patch bytes 60-61 directly
binary.LittleEndian.PutUint16(newDC, uint16(dc)) patched[60] = keystream[0] ^ byte(dc)
patched[61] = keystream[1] ^ byte(dc>>8)
patched[60] = keystream[0] ^ newDC[0]
patched[61] = keystream[1] ^ newDC[1]
return patched, true return patched, true
} }

View File

@ -2,7 +2,9 @@
package proxy package proxy
import ( import (
"bytes"
"context" "context"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -10,6 +12,7 @@ import (
"sort" "sort"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/Flowseal/tg-ws-proxy/internal/config" "github.com/Flowseal/tg-ws-proxy/internal/config"
@ -79,87 +82,66 @@ var dcOverrides = map[int]int{
// Stats holds proxy statistics. // Stats holds proxy statistics.
type Stats struct { type Stats struct {
mu sync.Mutex ConnectionsTotal atomic.Int64
ConnectionsTotal int64 ConnectionsWS atomic.Int64
ConnectionsWS int64 ConnectionsTCP atomic.Int64
ConnectionsTCP int64 ConnectionsHTTP atomic.Int64
ConnectionsHTTP int64 ConnectionsPass atomic.Int64
ConnectionsPass int64 WSErrors atomic.Int64
WSErrors int64 BytesUp atomic.Int64
BytesUp int64 BytesDown atomic.Int64
BytesDown int64 PoolHits atomic.Int64
PoolHits int64 PoolMisses atomic.Int64
PoolMisses int64
} }
func (s *Stats) addConnectionsTotal(n int64) { func (s *Stats) addConnectionsTotal(n int64) {
s.mu.Lock() s.ConnectionsTotal.Add(n)
s.ConnectionsTotal += n
s.mu.Unlock()
} }
func (s *Stats) addConnectionsWS(n int64) { func (s *Stats) addConnectionsWS(n int64) {
s.mu.Lock() s.ConnectionsWS.Add(n)
s.ConnectionsWS += n
s.mu.Unlock()
} }
func (s *Stats) addConnectionsTCP(n int64) { func (s *Stats) addConnectionsTCP(n int64) {
s.mu.Lock() s.ConnectionsTCP.Add(n)
s.ConnectionsTCP += n
s.mu.Unlock()
} }
func (s *Stats) addConnectionsHTTP(n int64) { func (s *Stats) addConnectionsHTTP(n int64) {
s.mu.Lock() s.ConnectionsHTTP.Add(n)
s.ConnectionsHTTP += n
s.mu.Unlock()
} }
func (s *Stats) addConnectionsPass(n int64) { func (s *Stats) addConnectionsPass(n int64) {
s.mu.Lock() s.ConnectionsPass.Add(n)
s.ConnectionsPass += n
s.mu.Unlock()
} }
func (s *Stats) addWSErrors(n int64) { func (s *Stats) addWSErrors(n int64) {
s.mu.Lock() s.WSErrors.Add(n)
s.WSErrors += n
s.mu.Unlock()
} }
func (s *Stats) addBytesUp(n int64) { func (s *Stats) addBytesUp(n int64) {
s.mu.Lock() s.BytesUp.Add(n)
s.BytesUp += n
s.mu.Unlock()
} }
func (s *Stats) addBytesDown(n int64) { func (s *Stats) addBytesDown(n int64) {
s.mu.Lock() s.BytesDown.Add(n)
s.BytesDown += n
s.mu.Unlock()
} }
func (s *Stats) addPoolHits(n int64) { func (s *Stats) addPoolHits(n int64) {
s.mu.Lock() s.PoolHits.Add(n)
s.PoolHits += n
s.mu.Unlock()
} }
func (s *Stats) addPoolMisses(n int64) { func (s *Stats) addPoolMisses(n int64) {
s.mu.Lock() s.PoolMisses.Add(n)
s.PoolMisses += n
s.mu.Unlock()
} }
func (s *Stats) Summary() string { func (s *Stats) Summary() string {
s.mu.Lock() hits := s.PoolHits.Load()
defer s.mu.Unlock() misses := s.PoolMisses.Load()
return fmt.Sprintf("total=%d ws=%d tcp=%d http=%d pass=%d err=%d pool=%d/%d up=%s down=%s", return fmt.Sprintf("total=%d ws=%d tcp=%d http=%d pass=%d err=%d pool=%d/%d up=%s down=%s",
s.ConnectionsTotal, s.ConnectionsWS, s.ConnectionsTCP, s.ConnectionsTotal.Load(), s.ConnectionsWS.Load(), s.ConnectionsTCP.Load(),
s.ConnectionsHTTP, s.ConnectionsPass, s.WSErrors, s.ConnectionsHTTP.Load(), s.ConnectionsPass.Load(), s.WSErrors.Load(),
s.PoolHits, s.PoolHits+s.PoolMisses, hits, hits+misses,
humanBytes(s.BytesUp), humanBytes(s.BytesDown)) humanBytes(s.BytesUp.Load()), humanBytes(s.BytesDown.Load()))
} }
// Server represents the TG WS Proxy server. // Server represents the TG WS Proxy server.
@ -527,35 +509,18 @@ func (s *Server) handleIPv6Connection(conn net.Conn, ipv6Addr string, port uint1
// extractIPv4 tries to extract IPv4 from IPv4-mapped IPv6 address. // extractIPv4 tries to extract IPv4 from IPv4-mapped IPv6 address.
func extractIPv4(ipv6 string) string { func extractIPv4(ipv6 string) string {
// Check for ::ffff: prefix (IPv4-mapped) // Check for ::ffff: prefix (IPv4-mapped)
// Example: ::ffff:192.0.2.1
if strings.HasPrefix(strings.ToLower(ipv6), "::ffff:") { if strings.HasPrefix(strings.ToLower(ipv6), "::ffff:") {
return ipv6[7:] return strings.TrimPrefix(ipv6, "::ffff:")
}
// Check for other IPv4-mapped formats
parts := strings.Split(ipv6, ":")
if len(parts) >= 6 {
// Try to parse last 2 parts as hex IPv4
if len(parts[6]) == 4 && len(parts[7]) == 4 {
// This is a more complex case, skip for now
}
} }
return "" return ""
} }
// extractIPv4FromNAT64 extracts IPv4 from NAT64 IPv6 address. // extractIPv4FromNAT64 extracts IPv4 from NAT64 IPv6 address.
// Currently returns empty string as NAT64 is not fully supported.
func extractIPv4FromNAT64(ipv6, prefix string) string { func extractIPv4FromNAT64(ipv6, prefix string) string {
// Remove prefix // NAT64 embeds IPv4 in last 32 bits of the IPv6 address
suffix := strings.TrimPrefix(ipv6, prefix) // This is a placeholder for future implementation
// NAT64 embeds IPv4 in last 32 bits
parts := strings.Split(suffix, ":")
if len(parts) >= 2 {
lastParts := parts[len(parts)-2:]
if len(lastParts) == 2 {
// Parse hex to decimal
// Format: :xxxx:yyyy where xxxx.yyyy is IPv4 in hex
// This is simplified - real implementation would parse properly
return "" // For now, return empty to indicate not supported
}
}
return "" return ""
} }
@ -818,17 +783,15 @@ func (s *Server) logDebug(format string, args ...interface{}) {
// Helper functions // Helper functions
func ipToUint32(ip string) uint32 { func ipToUint32(ip string) uint32 {
parts := strings.Split(ip, ".") ipObj := net.ParseIP(ip)
if len(parts) != 4 { if ipObj == nil {
return 0 return 0
} }
var result uint32 ipObj = ipObj.To4()
for i, part := range parts { if ipObj == nil {
var n uint32 return 0
fmt.Sscanf(part, "%d", &n)
result |= n << (24 - uint(i)*8)
} }
return result return binary.BigEndian.Uint32(ipObj)
} }
func isTelegramIP(ip string) bool { func isTelegramIP(ip string) bool {
@ -845,22 +808,10 @@ func isHTTPTransport(data []byte) bool {
if len(data) < 5 { if len(data) < 5 {
return false return false
} }
return bytesEqual(data[:5], []byte("POST ")) || return bytes.HasPrefix(data, []byte("POST ")) ||
bytesEqual(data[:4], []byte("GET ")) || bytes.HasPrefix(data, []byte("GET ")) ||
bytesEqual(data[:5], []byte("HEAD ")) || bytes.HasPrefix(data, []byte("HEAD ")) ||
bytesEqual(data[:8], []byte("OPTIONS ")) bytes.HasPrefix(data, []byte("OPTIONS "))
}
func bytesEqual(a, b []byte) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
} }
func humanBytes(n int64) string { func humanBytes(n int64) string {

View File

@ -34,7 +34,7 @@ func TestHandleGreeting_Success(t *testing.T) {
// Send valid greeting with no-auth method // Send valid greeting with no-auth method
go client.Write([]byte{0x05, 0x01, 0x00}) go client.Write([]byte{0x05, 0x01, 0x00})
nmethods, err := HandleGreeting(server) nmethods, err := HandleGreeting(server, &AuthConfig{})
if err != nil { if err != nil {
t.Fatalf("HandleGreeting failed: %v", err) t.Fatalf("HandleGreeting failed: %v", err)
} }
@ -58,7 +58,7 @@ func TestHandleGreeting_UnsupportedVersion(t *testing.T) {
// Send SOCKS4 greeting // Send SOCKS4 greeting
go client.Write([]byte{0x04, 0x01, 0x00}) go client.Write([]byte{0x04, 0x01, 0x00})
_, err := HandleGreeting(server) _, err := HandleGreeting(server, &AuthConfig{})
if err != ErrUnsupportedVersion { if err != ErrUnsupportedVersion {
t.Errorf("Expected ErrUnsupportedVersion, got %v", err) t.Errorf("Expected ErrUnsupportedVersion, got %v", err)
} }
@ -72,7 +72,7 @@ func TestHandleGreeting_NoAuthNotSupported(t *testing.T) {
// Send greeting without no-auth method // Send greeting without no-auth method
go client.Write([]byte{0x05, 0x01, 0x01}) go client.Write([]byte{0x05, 0x01, 0x01})
_, err := HandleGreeting(server) _, err := HandleGreeting(server, &AuthConfig{})
if err != ErrNoAuthAccepted { if err != ErrNoAuthAccepted {
t.Errorf("Expected ErrNoAuthAccepted, got %v", err) t.Errorf("Expected ErrNoAuthAccepted, got %v", err)
} }

View File

@ -9,12 +9,13 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
) )
const ( const (
CurrentVersion = "2.0.0" CurrentVersion = "2.0.5"
RepoURL = "https://api.github.com/repos/y0sy4/tg-ws-proxy-go/releases/latest" RepoURL = "https://api.github.com/repos/y0sy4/tg-ws-proxy-go/releases/latest"
) )
@ -170,7 +171,12 @@ func splitVersion(v string) []int {
parts := strings.Split(v, ".") parts := strings.Split(v, ".")
result := make([]int, len(parts)) result := make([]int, len(parts))
for i, p := range parts { for i, p := range parts {
fmt.Sscanf(p, "%d", &result[i]) n, err := strconv.Atoi(p)
if err != nil {
result[i] = 0
} else {
result[i] = n
}
} }
return result return result
} }

View File

@ -8,6 +8,7 @@ import (
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/Flowseal/tg-ws-proxy/internal/config" "github.com/Flowseal/tg-ws-proxy/internal/config"
"github.com/Flowseal/tg-ws-proxy/internal/proxy" "github.com/Flowseal/tg-ws-proxy/internal/proxy"
@ -38,17 +39,22 @@ func Start(host string, port int, dcIP string, verbose bool) string {
if err != nil { if err != nil {
return fmt.Sprintf("Failed to open log file: %v", err) return fmt.Sprintf("Failed to open log file: %v", err)
} }
log.SetOutput(f) logger := log.New(f, "", log.Ldate|log.Ltime)
log.SetFlags(log.Ldate | log.Ltime)
var ctx context.Context var ctx context.Context
ctx, cancel = context.WithCancel(context.Background()) ctx, cancel = context.WithCancel(context.Background())
server = proxy.NewServer(cfg) server, err = proxy.NewServer(cfg, logger)
if err != nil {
cancel()
return fmt.Sprintf("Failed to create server: %v", err)
}
go func() {
if err := server.Start(ctx); err != nil { if err := server.Start(ctx); err != nil {
cancel() cancel()
return fmt.Sprintf("Failed to start proxy: %v", err)
} }
}()
return "OK" return "OK"
} }
@ -58,9 +64,6 @@ func Stop() string {
if cancel != nil { if cancel != nil {
cancel() cancel()
} }
if server != nil {
server.Stop()
}
return "OK" return "OK"
} }
@ -69,13 +72,7 @@ func GetStatus() string {
if server == nil { if server == nil {
return "Not running" return "Not running"
} }
stats := server.GetStats() return "Running" // Simplified for mobile
return fmt.Sprintf("Connections: %d | WS: %d | TCP: %d | Bytes Up: %d | Bytes Down: %d",
stats.ConnectionsTotal,
stats.ConnectionsWS,
stats.ConnectionsTCP,
stats.BytesUp,
stats.BytesDown)
} }
// parseDCIP parses DC IP configuration string. // parseDCIP parses DC IP configuration string.
@ -83,11 +80,11 @@ func parseDCIP(s string) []string {
if s == "" { if s == "" {
return nil return nil
} }
result := []string{} result := make([]string, 0)
for _, part := range split(s, ",") { for _, part := range strings.Split(s, ",") {
trimmed := trim(part) part = strings.TrimSpace(part)
if trimmed != "" { if part != "" {
result = append(result, trimmed) result = append(result, part)
} }
} }
return result return result
@ -103,32 +100,6 @@ func getLogDir() string {
return os.TempDir() return os.TempDir()
} }
// Helper functions for string manipulation (avoiding strings package issues with gomobile)
func split(s, sep string) []string {
result := []string{}
start := 0
for i := 0; i <= len(s)-len(sep); i++ {
if s[i:i+len(sep)] == sep {
result = append(result, s[start:i])
start = i + len(sep)
}
}
result = append(result, s[start:])
return result
}
func trim(s string) string {
start := 0
end := len(s)
for start < end && (s[start] == ' ' || s[start] == '\t' || s[start] == '\n' || s[start] == '\r') {
start++
}
for end > start && (s[end-1] == ' ' || s[end-1] == '\t' || s[end-1] == '\n' || s[end-1] == '\r') {
end--
}
return s[start:end]
}
// Dummy function to use net package (required for SOCKS5) // Dummy function to use net package (required for SOCKS5)
func init() { func init() {
_ = net.Dial _ = net.Dial