Call me

written on Saturday, October 27, 2012

Библиотека re продолжает радовать загадками. Кривой фрейминг я поборол в предыдущей серии - пакеты перестали застревать в буфере, но звонок так нормально и не установился.

Происходит следующее безобразие:

При этом никаких натов между абонентами нету, они вообще живут на одной машине. Если звонить не через проксю, а сразу лезть напрямую - все срабатывает, ACK доходит, обе стороны считают, что соединение установилось.

Кто-то тут врет

Звонок через проксю - это такой же звонок, как напрямую, но через проксю. Прокся данные не подменяет, только форвардит. Третья сторона и тупое сетевое оборудование вмешаться не могут, потомучто трафик закруглен в SSL.

Сверять пакеты на входе прокси и на выходе я не стал, а решил сразу выяснить, куда пытается слать ACK вызывающий абонент. Вроде бы ничего подозрительного - коннект на локальный адрес, какой-то рендомный порт.

Начинаю думать на SSL - может сертификат куда-то не туда? Повышаю дебаг, но никакой ругани в логах не вижу, более того, на вызываемой стороне даже не срабатывает accept.

Начинаю внимательно смотреть на номер порта, в который ломится коннектом вызывающая сторона. Порт существует, но внезапно оказывается в состоянии ESTABLISHED, а не LISTEN, при чем второй стороной этого соединения оказывается прокся, а в состоянии LISTEN находится совершенно другой сокет.

WTF?

Начинаю разбираться, откуда взялся этот номер. Поскольку он рандомный, то вызывающая сторона его не сама придумала, а получила от отвечающей, которая не этом порту висит к проксе. Почему вместо адреса порта, на котором ожидаются коннекты, шлется какая-то левая фигня?

Лезу смотреть, как же формируется хедер Contact, нахожу фееричный ад. Если упростить, то хедер формируется так:

fmt("Contact: <sip:%s@%J%s>\r\n", sess->cuser, &msg->dst)

В msg->dst указан адрес, на который пришло сообщение, а сообщение пришло даунстримом по прямому коннекту от прокси - половинки жопы сомкнулись и наступила истина. Вместо того, чтобы бегать и выяснять, какой у нас там в глобальной стейте был запрошен адрес, авторы решили схалявить. В случае UDP это бы даже сработало, потомучто там для всего используется один сокет - и для получения датаграмм от других абонентов, и для посылки сообщений регистару и для получения ответов. Если на UDP-шный порт что-то уже пришло, то можно смело утверждать, что любой другой пир может туда тоже что-то послать и оно так же дойдет.

Для TCP это не верно - для приема коннектов один порт, для связи с каждым из пиров - другой.

Почему работало напрямую? А напрямую вообще всю дорого реюзалось одно установленное соединение - по нему ходила и установка связи и послеюущий ACK.

This entry was tagged c, code and voip