Re: Запрет неправильного host для ipv6

Maxim Dounin mdounin at mdounin.ru
Tue Aug 26 22:49:52 UTC 2014


Hello!

On Tue, Aug 26, 2014 at 04:40:58PM -0400, iprok wrote:

> Maxim Dounin Wrote:
> 
> > Т.е. делать ровно так же:
> > 
> >     server {
> >         listen 80 default_server;
> >         listen [::]:80 default_server;
> >         return 444;
> >     }
> 
> Я первым делом попробовал предложенный Вами конфиг. К сожалению вот такой
> вот вариант конфига не работает, если убрать комментарий:
> 
> user  nginx;
> worker_processes  1;
> 
> error_log  /var/log/nginx/error.log warn;
> pid        /var/run/nginx.pid;
> 
> 
> events {
>     worker_connections  1024;
> }
> 
> 
> http { 
>         server {
>                 listen 8080 default_server;
>                 listen [::]:8080 default_server;
>                 return 444;
>         }
>         server {
>                 listen XXX.XX.XXX.251:8080;
> #               listen [2aXX:X:XXX:XXXX:2::6]:8080 ipv6only=on;
>                 server_name "test.local";
>         }
> }

В блоке server{} с "return 444" нужно перечислять те же 
listen-сокеты, что и в других блоках server{}.  Перечислять там 
другие сокеты - бессмысленно.  E.g., в вышеприведённом конфиге все 
запросы к XXX.XX.XXX.251:8080 будут обаботаны в сервере 
test.local.

Если в существующих серверах используются listen-сокеты 
XXX.XX.XXX.251:8080 и [2aXX:X:XXX:XXXX:2::6]:8080, то правильный 
конфиг будет выглядеть так:

    server {
        listen XXX.XX.XXX.251:8080 default_server;
        listen [2aXX:X:XXX:XXXX:2::6]:8080 default_server;
        return 444;
    }

    server {
        listen XXX.XX.XXX.251:8080;
        listen [2aXX:X:XXX:XXXX:2::6]:8080;
        server_name "test.local";
    }

Отмечу также, что начиная с 1.3.4 ipv6only=on используется по 
умолчанию, и явно его писать - не надо.

> Если конфиг с комментарием, то nginx запускается, биндясь на
> netstat -tulpn | grep nginx
> tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN  
>    16821/nginx.conf
> tcp6       0      0 :::8080                 :::*                    LISTEN  
>    16821/nginx.conf
> 
> Если комментарий убираю, то получаю ошибку:
> nginx: [emerg] bind() to [::]:8080 failed (98: Address already in use)
> nginx: [emerg] bind() to [::]:8080 failed (98: Address already in use)
> nginx: [emerg] bind() to [::]:8080 failed (98: Address already in use)
> nginx: [emerg] bind() to [::]:8080 failed (98: Address already in use)
> nginx: [emerg] bind() to [::]:8080 failed (98: Address already in use)
> nginx: [emerg] still could not bind()
>  failed!

Linux, в отличие от классических BSD-систем, не разрешает 
создавать listen-сокеты одном и том же порту на wildcard-адресе 
(0.0.0.0 для ipv4, [::] для ipv6) и на ip-адресе одновременно, 
объясняя это соображениями безопасности.

Про эти за^Wнюансы поведения Linux'а nginx знает, и при наличии в 
конфиге listen-сокетов на ip-адресах и wildcard-адресах 
одновременно - создаёт только один listen-сокет, а для правильного 
распределения входящих соединений по ip-based серверам - 
использует дополнительный системный вызов getsockname().

С приведённым конфигом, однако, из-за параметра ipv6only nginx 
создаёт отдельные сокеты, что в результате приводит к ошибке 
"Address already in use".  Если убрать параметр ipv6only=on 
(ненужный, см. выше), то nginx запустится.  Конфиг, впрочем, от 
этого правильным не станет - см. выше.

Дополнительно про всё это можно прочитать в описании директивы listen 
(в частности, её параметра bind), и в водной статье "Как nginx 
обрабатывает запросы" (имеет смысл обратить внимание на раздел 
"Определение виртуального сервера по имени и IP-адресу"):

http://nginx.org/ru/docs/http/ngx_http_core_module.html#listen
http://nginx.org/ru/docs/http/request_processing.html#mixed_name_ip_based_servers

-- 
Maxim Dounin
http://nginx.org/



Подробная информация о списке рассылки nginx-ru