Реализация UDP-прокси

Я пытаюсь создать простые прокси TCP и UDP. С прокси TCP проблем нет, но с UDP немного сложнее. Классический сценарий прокси будет таким.

  1. Слушайте входящие пакеты от клиентов
  2. Когда пакет получен, отправьте его адресату (серверу)
  3. Слушайте возможные ответные пакеты от сервера
  4. Отправлять ответные пакеты клиентам

Хорошо, это должно быть просто. Но при попытке реализовать это с помощью Synapse или Indy у меня возникает проблема. когда я получаю пакет от клиента, я создаю внутреннего UDP-клиента для пересылки пакета по назначению. Затем я должен выслушать возможные ответы из пункта назначения. Теперь вопрос в том, какая реализация для этого лучше всего? Нет единого запроса / ответа, как в TCP. Пункт назначения может ответить несколькими ответами с течением времени или не отвечает вообще. Если я продолжу прислушиваться к ответу по одному клиентскому пакету, я пропущу другие будущие пакеты от этого или других клиентов.

Ищу хороший дизайн для этой проблемы. Вот образец сообщения для справки. Обратите внимание на несколько ответов от пункта назначения в одной точке.

- bind UDP port 40222 on interface 0.0.0.0
- ready
- add 127.0.0.1:4569

127.0.0.1:4569 -> 192.168.90.10:4569
c3 ef 00 00 00 00 00 03 00 00 06 01 0b 02 00 02   ................
02 0a 37 30 30 35 35 35 31 32 31 32 04 0d 4e 6f   ..7005551212..No
74 20 41 76 61 69 6c 61 62 6c 65 09 04 00 00 00   t Available.....
08 08 04 00 00 00 08 06 06 31 36 31 34 30 31 01   .........161401.
08 34 31 33 31 33 39 34 37 0d 08 34 31 33 31 33   .41313947..41313
39 34 37                                          947

192.168.90.10:4569 -> 127.0.0.1:4569
a9 e7 43 ef 00 00 00 09 00 01 06 08 0e 02 00 03   ..C.............
0f 09 34 31 38 32 32 31 37 38 33 06 06 31 36 31   ..418221783..161
34 30 31                                          401

127.0.0.1:4569 -> 192.168.90.10:4569
c3 ef 29 e7 00 00 00 4f 01 01 06 09 10 20 39 36   ..)....O..... 96
64 66 37 31 32 38 61 62 35 39 39 37 65 36 37 36   df7128ab5997e676
65 62 38 63 61 30 33 39 38 66 33 34 30 65         eb8ca0398f340e

192.168.90.10:4569 -> 127.0.0.1:4569
a9 e7 43 ef 00 00 00 56 01 02 06 07 09 04 00 00   ..C....V........
00 08                                             ..

127.0.0.1:4569 -> 192.168.90.10:4569
c3 ef 29 e7 00 00 00 56 02 02 06 04               ..)....V....

192.168.90.10:4569 -> 127.0.0.1:4569
a9 e7 43 ef 00 00 02 85 02 02 04 0e               ..C.........

192.168.90.10:4569 -> 127.0.0.1:4569
a9 e7 43 ef 00 00 02 96 03 02 02 08 54 54 54 54   ..C.........TTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54               TTTTTTTTTTTT

127.0.0.1:4569 -> 192.168.90.10:4569
c3 ef 29 e7 00 00 02 96 02 04 06 04               ..).........

192.168.90.10:4569 -> 127.0.0.1:4569
29 e7 02 aa 54 54 54 54 54 54 54 54 54 54 54 54   )...TTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54                                       TTTT

192.168.90.10:4569 -> 127.0.0.1:4569
29 e7 02 be 54 54 54 54 54 54 54 54 54 54 54 54   )...TTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54                                       TTTT

192.168.90.10:4569 -> 127.0.0.1:4569
29 e7 02 d2 54 54 54 54 54 54 54 54 54 54 54 54   )...TTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54                                       TTTT

192.168.90.10:4569 -> 127.0.0.1:4569
29 e7 02 e6 54 54 54 54 54 54 54 54 54 54 54 54   )...TTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54                                       TTTT

192.168.90.10:4569 -> 127.0.0.1:4569
29 e7 02 fa 54 54 54 54 54 54 54 54 54 54 54 54   )...TTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54   TTTTTTTTTTTTTTTT
54 54 54 54                                       TTTT

РЕДАКТИРОВАТЬ:

Для записи. Возможно, прокси-сервер UDP просто беспорядок в реализации, чтобы его можно было использовать. Это большая вероятность, но теоретически вполне выполнимая. Но я попробую просто для удовольствия. Если получу стабильно работающее решение, то еще лучше. Иначе я узнаю что-то новое и признаю поражение.

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


person Runner    schedule 23.03.2011    source источник
comment
Просто примечание - TCP также не является протоколом запроса / ответа. Вы можете отправить что-то и ничего не получить в ответ. Вероятно, это протокол уровня приложения, с помощью которого вы отлаживаете свой прокси, который является протоколом запроса / ответа.   -  person Eugene Mayevski 'Callback    schedule 23.03.2011
comment
Да, я согласен, но если вы ничего не получите, значит, ответа нет. В отличие от UDP, где вы можете получить ответ после минутной задержки.   -  person Runner    schedule 23.03.2011
comment
Не могу согласиться с вашим здесь - TCP тоже не дает регулярных ответов. Никогда не знаешь, когда ответит сервер. Обычно стороны (в основном клиенты) протоколов уровня приложений (например, FTP) имеют отдельное значение тайм-аута, обычно 60–120 секунд. Таким образом, TCP и UDP снова находятся здесь в одном и том же положении.   -  person Eugene Mayevski 'Callback    schedule 23.03.2011


Ответы (2)


Эта проблема с UDP возникает не только у прокси-серверов - с ним также сталкиваются сетевые устройства, такие как межсетевые экраны с отслеживанием состояния и устройства NAT.

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

Кроме того, наличие одного текущего прокси-соединения не должно препятствовать одновременному открытию другого - ваш прокси-сервер должен справиться с этим.

person caf    schedule 23.03.2011
comment
Да, я пришел к точно такому же выводу :) Новый внутренний клиент из пула клиентов для каждого нового пакета. Затем прислушайтесь к ответу в течение определенного времени, а затем отпустите клиента. Однако может быть проблема с количеством свободных портов. - person Runner; 23.03.2011
comment
Именно поэтому я говорю, что универсальное решение невозможно. Мне повезло / мне не повезло иметь дело с большим количеством SIP-трафика, это UDP, и Linux iptables для NAT: Iptables может справиться с этим, но у него есть специальный модуль conntrack для протокола SIP. ! Я не говорю, что это невозможно сделать, если ребята из iptables не сделали этого, но это хороший знак, что это будет сложно. - person Cosmin Prund; 23.03.2011
comment
@Cosmin Prund, Да, я уверен, что это сложно. Но это делает меня еще более интересным :) Пакеты, показанные в моем вопросе, принадлежат протоколу IAX. Это другой протокол, помимо SIP, который поддерживает Asterisk VOIP. Вот почему я хочу попробовать и сделать это. Если я проиграю, никакого вреда не будет. - person Runner; 23.03.2011
comment
@Runner, чего стоит, IAX проще NAT, чем SIP, наверное, проще прокси. Повеселись! - person Cosmin Prund; 23.03.2011

Типичное общение клиент-сервер UDP может выглядеть так:

  • Клиент отправляет пакет UDP на порт 1000
  • Сервер получает пакет и отправляет ответ на порт 1001 (или порт 1000!)

Ваш прокси должен просто прослушивать пакеты на портах 1000 и 1001. Когда пакет попадает на порт 1000, отправьте его на порт 1000 на сервере. Когда пакет прибывает на порт 1001, он от сервера и должен быть отправлен через порт 1001 соответствующему клиенту. На этом самое интересное и заканчивается. UDP ничего не предлагает с точки зрения управления сеансом или подключением: все зависит от конкретного протокола UDP, который вы пытаетесь использовать прокси. Если вы получили UDP-пакеты от двух разных клиентов и получили «ответный» пакет от сервера, в самом UDP нет ничего, что могло бы сказать вам, куда пересылать этот пакет. Протоколы, построенные на основе UDP, могут иметь или не иметь какой-либо способ поддержания состояния.

Общее решение невозможно, вы можете прочитать RFC и реализовать определенные помощники для каждого протокола UDP, который вы хотите поддерживать.

person Cosmin Prund    schedule 23.03.2011
comment
Думаю, общее решение возможно. У меня может быть пул клиентов, и каждый клиент будет связываться с другим внутренним портом. Но проблема в том, что у меня могут закончиться порты или привязаться к уже подключенным портам. Да, UDP должен быть простым, но это превращает реализацию прокси в ад. Теперь я знаю, почему SSH-туннелирование поддерживает только TCP. :) Надеюсь, у кого-нибудь есть блестящее и простое решение :) - person Runner; 23.03.2011
comment
Допустим, вы решили подключиться к портам 6000-6099 для обработки 100 различных клиентов. Как убедить клиента 1 отправить на 6000, а клиента 2 - на 6001, когда оба клиента предпочли бы отправлять на порт 1000, поскольку это указано в RFC для протокола, реализуемого через UDP? - person Cosmin Prund; 23.03.2011
comment
Если у вас есть одно приложение, которое вы хотите использовать через прокси, вы запускаете прокси и слушаете, например, порт 6000. Приложение подключается к localhost через порт 6000. Для каждого пакета, получаемого прокси-сервером, он создает внутри себя UDP-клиента на новом порте и отправляет данные на адрес назначения. затем он некоторое время прислушивается к ответам. У вас всегда есть один локальный порт, который вы слушаете, и один IP / порт назначения. Если вам нужно больше, вы запускаете больше прокси на разных портах. - person Runner; 23.03.2011
comment
Я протестировал такое решение, поэтому знаю, что это возможно. linux.softpedia.com/get/Internet/ Прокси / - person Runner; 23.03.2011
comment
И нет, я не могу использовать это, потому что я хотел бы иметь шифрование между двумя такими прокси :) - person Runner; 23.03.2011