Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

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

Anna | 24.06.2014 | нет комментариев

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

1-й этап — сборка. О том, как поднять у себя на машине среду сборки хорошо написано на самом сайте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 пишут, что конечный байт нужно легко прибавить к сумме, но на самом деле это не так. Прибавлять нужно не конечный байт, а два байта, 2-й из которых 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)
    {
        uint16_t last = *(unsigned char *)data16;
        last <<= 8;

        sum  = ntohs(last);
    }
    while (sum >> 16)
        sum = (sum >> 16)   (sum & 0xffff);

    return ~sum;

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

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB