2014-08-30 5 views
1

Я столкнулся с проблемой утечки сокета в Mac OS X Я не могу объяснить. У меня есть демон open source (olad), который слушает 9010 (tcp), 9090 (tcp) и 6454 (udp) среди других портов. При выходе из демона, NetStat показывает порт 6454 по-прежнему открыт и прослушивания:Bizarre Firewall Связанный сокет Утечка на Mac OS X

$ netstat -f inet -n | grep 6454 
<nothing> 
$ olad/olad 
<exit server> 
$ netstat -f inet -n | grep 6454 
udp4  0  0 *.6454     *.* 

Однако Lsof не показывает гнездо:

$ lsof -i 4 -P | grep 6454 
<nothing> 

Когда система находится в этом состоянии, посылая пакеты порт можно увидеть увеличение счетчика очереди:

$ netstat -f inet -n | grep 6454 
udp4  612  0 *.6454     *.* 

Это происходит только тогда, когда брандмауэр приложений включена в Настройки -> Безопасность & Конфиденциальность и это первый запуск двоичного файла. То есть, если я отключу брандмауэр, утечка не произойдет. Или, если брандмауэр включен, после первого запуска, где появляется диалоговое окно, и я нажимаю кнопку «Принять», проблема больше не возникает.

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

Я подтвердил, что я вызываю close() во всех сокетах до выхода программы, и нет вызовов fork() или новых потоков.

Я пытаюсь сузить регистр ошибок, но, похоже, это достаточно сложное взаимодействие между pipe(), socket(), bind(), listen(), ioctl(), fnctl() и select(). Изменение порядка вызовов и удаление прослушиваний на портах 9010 и 9090 приводит к исчезновению проблемы.

Есть ли у кого-нибудь предложение о том, как продолжить отладку или руководство по работе с брандмауэром Mac-приложений?

+0

Если вы снова запустите сервер, приложение успешно восстановит и откроет сокет во всех связанных портах? Что происходит, когда вы вводите 'netstat' с опцией' -p', чтобы показать связанную программу с соединением? – selbie

+0

Если включить SO_REUSEPORT, функция bind() будет успешной, но приложение не получит никаких данных. Счетчики очереди продолжают увеличиваться. Если SO_REUSEPORT не включен, сбой не выполняется. На mac параметр -p для netstat не отображает процесс. –

ответ

1

Как выясняется, брандмауэр «запоминает» параметры сокета ранее связанного UDP-порта даже после того, как процесс с его использованием был отключен. Это приводит к тому, что порт UDP, указанный в «netstat -n -f inet», не получает никакого процесса от него. С этого момента любая попытка связать сокет с этим портом будет, как и ожидалось, все в порядке, когда брандмауэр выключен.

Как вы уже выяснили, OS-X требует SO_REUSEPORT вместо SO_REUSEADDR, чтобы избежать этой странной проблемы с брандмауэром. Кроме того, единственный способ сбросить состояние брандмауэра - перезагрузить. Интересно, что вам нужно пройти пару минут, прежде чем запускать сервер после перезагрузки. По какой-то причине я не хотел исследовать дальше, если вы запустите сервер до того, как брандмауэр завершит свою инициализацию, вы не получите всплывающее окно брандмауэра с просьбой разрешить доступ, и ваш сервер останется «навсегда» (т.е. до следующего перезапуска или до тех пор, пока вы не восстановите двоичный файл сервера), заблокированные брандмауэром.