Как стать автором
Обновить

Чиним hanstunnel на openwrt (вычисление контрольной суммы сетевого пакета)

Время на прочтение5 мин
Количество просмотров5.6K
Всем привет. Наверное, многие тут знают прогу hanstunnel, которая позволяет поднять туннель поверх ICMP, а точнее поверх пингов. Решил я поставить ее себе на роутер под openwrt. Собрал, завел… Не работает. Симптомы были простые — пакет уходит с роутера во внешнюю сеть, а на адресата не приходит, при этом в домашней локалке все работает. При этом тот же hans, запущенный на домашнем компе подключается наружу без вопросов. Кому интересно, как собрать пакет hans под openwrt и как заставить его работать — велком под кат.



Первый этап — сборка. О том, как поднять у себя на машине среду сборки неплохо написано на самом сайте openwrt, а так же в куче разных статей, поэтому данный кусок я оставлю за кадром. Предположим, что у нас есть среда с собранным toolchain'ом и она умеет собирать стандартные пакеты openwrt.
Для сборки пакета нам понадобится исходник hanstunnel, который можно взять тут, а также Makefile с описанием пакета, файл конфига и файл init-скрипта. Последние три случайно я нашел тут в виде описания патчей. Может, кто-нибудь найдет прямые ссылки, но мне и так подошло. Для сборки своих пакетов создаем какую-нибудь папку, например custom, в нее кладем папки будущих пакетов и наводим на них ссылки из package/feeds/packages. Я слегка подпилил Makefile для пакета, чтобы он собирал исходники их папки src, лежащей рядом,
вот, что получилось

# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 6008 2007-01-06 18:39:10Z nbd $

include $(TOPDIR)/rules.mk

PKG_NAME:=hanstunnel
PKG_VERSION:=0.4.3
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

include $(INCLUDE_DIR)/package.mk

define Package/hanstunnel
        SECTION:=net
        CATEGORY:=Network
        SUBMENU:=Firewall Tunnel
        DEPENDS:=+libstdcpp +kmod-tun
        TITLE:=Hans IP over ICMP
        URL:=http://code.gerade.org/hans/
endef

define Package/hanstunnel/description
        Hans makes it possible to tunnel IPv4 through ICMP echo packets,
        so you could call it a ping tunnel. This can be useful when you
        find yourself in the situation that your Internet access is
        firewalled, but pings are allowed. endef
endef

define Build/Prepare
        echo PREPARE PREPARE
        mkdir -p $(PKG_BUILD_DIR)
        cp -r ./src/* $(PKG_BUILD_DIR)/
endef

define Build/Compile 
        $(MAKE) -C $(PKG_BUILD_DIR) GCC=$(TARGET_CC) GPP=$(TARGET_CXX)
endef 

 
define Package/hanstunnel/install
        $(INSTALL_DIR) $(1)/usr/sbin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/hans $(1)/usr/sbin/
        $(INSTALL_DIR) $(1)/etc/init.d
        $(INSTALL_BIN) ./files/hans.init $(1)/etc/init.d/hans
        $(INSTALL_DIR) $(1)/etc/config
        $(INSTALL_CONF) ./files/hans.config $(1)/etc/config/hans
endef

$(eval $(call BuildPackage,hanstunnel))



Шапку Makefile'а сборки тоже пришлось чуть-чуть подпилить
Makefile сборки
#LDFLAGS += `sh osflags ld $(MODE)`
CFLAGS += -c -g -DLINUX -DHAVE_LINUX_IF_TUN_H
TUN_DEV_FILE = src/tun_dev_linux.c
#GCC = gcc
#GPP = g++

.PHONY: directories

all: hans

directories: build_dir

build_dir:
	mkdir -p build

tunemu.o: directories build/tunemu.o

hans: directories build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o
	$(GPP) -o hans build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o $(LDFLAGS)

build/utility.o: src/utility.cpp src/utility.h
	$(GPP) -c src/utility.cpp -o $@ -o $@ $(CFLAGS)

build/exception.o: src/exception.cpp src/exception.h
	$(GPP) -c src/exception.cpp -o $@ $(CFLAGS)

build/echo.o: src/echo.cpp src/echo.h src/exception.h
	$(GPP) -c src/echo.cpp -o $@ $(CFLAGS)

build/tun.o: src/tun.cpp src/tun.h src/exception.h src/utility.h src/tun_dev.h
	$(GPP) -c src/tun.cpp -o $@ $(CFLAGS)

build/tun_dev.o:
	$(GCC) -c $(TUN_DEV_FILE) -o build/tun_dev.o -o $@ $(CFLAGS)

build/sha1.o: src/sha1.cpp src/sha1.h
	$(GPP) -c src/sha1.cpp -o $@ $(CFLAGS)

build/main.o: src/main.cpp src/client.h src/server.h src/exception.h src/worker.h src/auth.h src/time.h src/echo.h src/tun.h src/tun_dev.h
	$(GPP) -c src/main.cpp -o $@ $(CFLAGS)

build/client.o: src/client.cpp src/client.h src/server.h src/exception.h src/config.h src/worker.h src/auth.h src/time.h src/echo.h src/tun.h src/tun_dev.h
	$(GPP) -c src/client.cpp -o $@ $(CFLAGS)

build/server.o: src/server.cpp src/server.h src/client.h src/utility.h src/config.h src/worker.h src/auth.h src/time.h src/echo.h src/tun.h src/tun_dev.h
	$(GPP) -c src/server.cpp -o $@ $(CFLAGS)

build/auth.o: src/auth.cpp src/auth.h src/sha1.h src/utility.h
	$(GPP) -c src/auth.cpp -o $@ $(CFLAGS)

build/worker.o: src/worker.cpp src/worker.h src/tun.h src/exception.h src/time.h src/echo.h src/tun_dev.h src/config.h
	$(GPP) -c src/worker.cpp -o $@ $(CFLAGS)

build/time.o: src/time.cpp src/time.h
	$(GPP) -c src/time.cpp -o $@ $(CFLAGS)

clean:
	rm -f build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o build/tunemu.o hans
	rm -df build

build/tunemu.o: src/tunemu.h src/tunemu.c
	$(GCC) -c src/tunemu.c -o build/tunemu.o



Раскладываем файлы по местам, должно получиться что-то типа:

$ls -R custom 
custom:
hanstunnel

custom/hanstunnel:
files  Makefile  src

custom/hanstunnel/files:
hans.config  hans.init

custom/hanstunnel/src:
Makefile  osflags  src

custom/hanstunnel/src/src:
auth.cpp    client.h  echo.h         main.cpp    sha1.cpp          time.cpp  tun_dev_darwin_emu.c  tun_dev.h          tun_dev_svr4.c  tun.h        worker.cpp
auth.h      config.h  exception.cpp  server.cpp  sha1.h            time.h    tun_dev_freebsd.c     tun_dev_linux.c    tunemu.c        utility.cpp  worker.h
client.cpp  echo.cpp  exception.h    server.h    sha1_license.txt  tun.cpp   tun_dev_generic.c     tun_dev_openbsd.c  tunemu.h        utility.h


Дальше идем в корень buildroot и радостно набираем
$make package/feeds/packages/hanstunnel/compile -j5
 make[1] package/feeds/packages/hanstunnel/compile
 make[2] -C package/kernel/linux compile
 make[2] -C package/libs/toolchain compile
 make[2] -C custom/hanstunnel compile


Все, пакет готов, лежит он в папке bin рядом с остальными.

Осталось проверить. Вот тут меня ждал облом. С моим компом в домашней локалке туннель поднялся сразу без вопросов. Только я обрадовался и пошел проверять подключение снаружи, но, как описано выше, пакеты с openwrt уходили, а адресат их не видел. Та же ситуация возникала, если запустить hans на роутере в режиме клиента. После долгих раздумий я догадался снять дамп ICMP и поискать разницу между подключением с роутера и с моего компа. Проблема оказалась в контрольной сумме ICMP, о чем мне радостно сообщил wireshark. Я честно взял калькулятор и пошел сам вручную считать сумму по алгоритму, прописанному в echo.cpp, который очень похож на официальный. Получалось что угодно, но не то, что нужно. В итоге оказалось, что проблема в нечетной длине пакета и MIPS архитектуре. Добрые люди в RFC пишут, что последний байт надо просто прибавить к сумме, но на самом деле это не так. Прибавлять надо не последний байт, а два байта, второй из которых 0, что на Big-endian архитектурах означает прибавку нашего байта, помноженного на 256.
Вот какая в итоге получилась функция icmpChecksum:

uint16_t Echo::icmpChecksum(const char *data, int length)
{
    uint16_t *data16 = (uint16_t *)data;
    uint32_t sum = 0;

    for (sum = 0; length > 1; length -= 2)
        sum += *data16++;


    if (length == 1)
    {
        unsigned char tail[2] = {*(unsigned char *)data16, 0};
        sum += *(uint16_t *)tail;
    }
    while (sum >> 16)
        sum = (sum >> 16) + (sum & 0xffff);

    return ~sum;
}


С ней наконец-то все заработало как надо. Happy end.

UPD: поправил хвост на более красивый вариант от jcmvbkbc
Теги:
Хабы:
Всего голосов 11: ↑11 и ↓0+11
Комментарии25

Публикации

Истории

Работа

Программист C++
136 вакансий
QT разработчик
8 вакансий

Ближайшие события