среда, 6 августа 2025 г.

Проксирование S3

Появилась задача проксировать посетителей сайта прямо в наш S3. Мы использовали S3 от ceph и там было всё хорошо. Использовали политику с доступом по User-Agent:
{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": [
          "s3:GetObject"
        ],
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::my-bucket-name/*",
        "Condition": {
          "StringEquals": {
          "aws:UserAgent": [
            "<какой-то рандомный токен>"
          ]
        }
        },
        "Principal": "*"
      }
    ]
}
После чего коллеги, ответственные за фронт, проксировали силами Nginx, подставляя указанный User-Agent в заголовки.

Но однажды у нас появился S3-сервер на SeaweedFS, да еще и не самой свежей версии :)
Там доступ по User-Agent сходу прикрутить не удалось.

А как вы прекрасно знаете, авторизоваться по ACCESS_KEY/SECRET_KEY не очень-то просто, вот пример со stackoverflow:
#!/bin/sh
file=path/to/file
bucket=your-bucket
resource="/${bucket}/${file}"
contentType="application/x-compressed-tar"
dateValue="`date +'%a, %d %b %Y %H:%M:%S %z'`"
stringToSign="GET
${contentType}
${dateValue}
${resource}"
s3Key=xxxxxxxxxxxxxxxxxxxx
s3Secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
signature=`/bin/echo -en "$stringToSign" | openssl sha1 -hmac ${s3Secret} -binary | base64`
curl -H "Host: ${bucket}.s3.amazonaws.com" \
-H "Date: ${dateValue}" \
-H "Content-Type: ${contentType}" \
-H "Authorization: AWS ${s3Key}:${signature}" \
https://${bucket}.s3.amazonaws.com/${file}
Конечно, такое можно прикрутить в Nginx (с помощью встроенного в Nginx модуля Perl), есть про это статья на Опеннете ("Проксирование запросов к S3 с помощью nginx и angie").
Решение показалось не изящным, плюс недостатки нашего S3-сервера пришлось бы решать коллегам из фронтенда, а перекладывание работы на других -- не наш метод.

Поэтому мы решили проксировать у себя. Прямо на S3-сервере с SeaweedFS. С помощью s3-proxy от oxyno-zeta.

Качаем бинарник (и, при желании, упаковываем в deb-пакет, если надо) отсюда https://github.com/oxyno-zeta/s3-proxy.

Кладём в /opt/s3-proxy/s3-proxy, а конфиг в /opt/s3-proxy/conf/s3proxy.yml
log:
  level: info
  format: text

metrics:
  disableRouterPath: false

server:
  listenAddr: ip-адрес-сервера
  port: 8080

authProviders:
  basic:
    provider1:
      realm: basic

targets:
  target1:
    mount:
      path:
        - /my-bucket-name/
    resources:
      - path: /my-bucket-name/*
        provider: provider1
        basic:
          credentials:
            - user: username1
              password:
                value: somePass
    bucket:
      name: my-bucket-name
      prefix:
      region: eu-west-1
      s3Endpoint: localhost:8333
      disableSSL: true
      credentials:
        accessKey:
          value: xxxXXXxxx
        secretKey:
          value: XXXxxxXXX

Готовим systemd:

[Unit]
Description=S3 Proxy
After=network.target
Documentation=https://oxyno-zeta.github.io/s3-proxy/

[Service]
Type=simple
User=root
WorkingDirectory=/opt/s3-proxy
ExecStart=/opt/s3-proxy/s3-proxy
Restart=on-failure

[Install]
WantedBy=multi-user.target

Проверяем:
$ wget http://username1:somePass@servername:8080/my-bucket-name/9.jpeg
--2025-08-06 16:59:26--  http://username1:*password*@servername:8080/my-bucket-name/9.jpeg
Распознаётся servername (servername)… 1.2.3.4
Подключение к servername (servername)|1.2.3.4|:8080... соединение установлено.
HTTP-запрос отправлен. Ожидание ответа… 401 Unauthorized
Выбранная аутентификация: Basic realm="basic"
Повторное использование соединения с servername:8080.
HTTP-запрос отправлен. Ожидание ответа… 200 OK
Длина: 197222 (193K) [image/jpeg]
Сохранение в: «9.jpeg»

9.jpeg     100%[======================================================================================================>] 192,60K  --.-KB/s    за 0,003s

2025-08-06 16:59:26 (66,9 MB/s) - «9.jpeg» сохранён [197222/197222]
s3-proxy умеет гораздо больше, на их wiki всё написано.

Теперь сообщаем коллегам, что к нам в S3 надо ходить не с User-Agent, а на новый порт 8080 с Basic Auth username1/somePass.

среда, 30 апреля 2025 г.

Запуск tcpdump на ограниченное время

А вот понадобилось снять дамп сетевого трафика строго в определенное время. Поможет связка из cron и timeout.
Достаточно поставить в крон (ну или запустить через at) команду:
50 5  * * * root timeout 15m tcpdump -Z root -C 500 -w /var/dns_dump/dns.pcap -nni eno1 port 53

суббота, 31 июля 2021 г.

Балансировка исходящего трафика

Балансировка NAT-серверов.

Расскажу, как мы раньше разделяли нагрузку между несколькими NAT-серверами.
Проблемы с исчерпанием ipv4-адресов у нас тогда не стояло, но мы решили заблаговременно настроить NAT для абонентов. Недолго думая, запустили NAT-сервер на x86 сервере, Centos 6.
Железо обычное, Xeon E3-12xx, v2 или что там было в то время. Памяти гигабайт 8. Двухпортовая десятигигабитная сетевая карта.


Сервер воткнули в бордер двумя концами и принудительной маршрутизацией (PBR) зарулили трафик тестовых серых абонентов.

Сам nat описывать нет особого смысла, там было всё штатно, NAT силами conntrack/netfilter, настроенный через iptables. Какой-то обычный тюнинг sysctl. Да драйвер для сетевой карты взяли с сайта производителя, благо он собирался в RPM пакет одной командой (производитель позаботился).

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

Воткнули второй сервер во второй бордер на другом узле, PBR заменили на динамическую маршрутизацию: сверху бордер "вещает" дефолтный маршрут в NAT, а тот его передаёт абонентам (на самом деле в тот же бордер, но уже в другой VRF, в котором обитают "серые" абоненты).
Снизу VRF с абонентами вещает в NAT серые сети абонентов, NAT'ы же анонсируют наверх в бордер свои публичные сети.

Отказоустойчивость какую-никакую, но обеспечили. А вот с балансировкой нагрузки тяжелее. Маршрутизацией её добиться довольно сложно, это ручные игры с метриками и "нарезкой" абонентов на микро VRF (чтобы анонсировать разным порциям разный дефолт -- через первый нат или через второй).

А тут уже и третий сервер пора ставить. Воткнули в первый бордер. Теперь бордер "видит" два маршрута по умолчанию. Но тут нам не удалось настроить корректную работу балансировки. В чем была беда: многие сайты держат web-интерфейс на одном сервере, а контент на другом. И эти сайты считали, что контент нужно получать с тем же SRC IP, с которым авторизовался на web-интерфейсе.

И роутер был слишком умным, чтобы выбирать маршрут основываясь только лишь на адресе абонента. Этот роутер использовал в вычислении хэша для балансировки и адрес назначения, и отключить это нам не удалось. В результате абоненты начали страдать от сайтов, потому что авторизовались на сайте с использованием одного SRC IP (через первый нат), а за контентом пришли со второго IP (через другой нат).

В тот момент у нас не было возможности поставить другой (промежуточный) роутер, который бы выбирал один из восьми (да, мы довели количество натов до восьми штук на каждом бордере) маршрут, основываясь лишь на SRC IP абонента.

Поэтому мы сделали всё сами, с помощью Linux. Мы, как и любой провайдер, знали профиль нашего трафика и решили, что на узле достаточно одного 10G балансировщика исходящего трафика. Т.е. разница между входящим и исходящим у нас была более, чем в восемь раз.

Значит маршрутизацией заманиваем исходящий от абонента трафик на такой же сервер, как и остальные NAT'ы (всё воткнуто в бордер, через промежуточный 10G-коммутатор, конечно же), на нём происходит магия, трафик от одного абонента всегда попадает на один и тот же NAT, а с NAT'а возвращается к абонентам минуя балансировщик (ведь никто же не заставляет маршрутизацию быть симметричной).

Что за магия на балансировщике? Тот же Centos и те же аппаратные характеристики.

Восемь таблиц маршрутизации (ip route table), каждая со своим статическим маршрутом по умолчанию, смотрящим в нужный нат.

Восемь правил маршрутизации (ip rule), заворачивающих трафик с определенными метками в соответствующие таблицы.

Восемь пустых сетов ipset (NAT1, NAT2, .. NAT8).

Если ip-адрес абонента уже есть в каком-то сете, то такой трафик отправляется в соответствующую сету цепочку NATx таблицы MANGLE:
-A PREROUTING -i eth3 -m set --match-set NAT1 src -j NAT1
-A PREROUTING -i eth3 -m set --match-set NAT2 src -j NAT2
-A PREROUTING -i eth3 -m set --match-set NAT3 src -j NAT3
-A PREROUTING -i eth3 -m set --match-set NAT4 src -j NAT4
-A PREROUTING -i eth3 -m set --match-set NAT5 src -j NAT5
-A PREROUTING -i eth3 -m set --match-set NAT6 src -j NAT6
-A PREROUTING -i eth3 -m set --match-set NAT7 src -j NAT7
-A PREROUTING -i eth3 -m set --match-set NAT8 src -j NAT8
Если же ip-адреса еще нет, то пакет дойдёт до этих правил и с равной вероятностью (1/8=0.125; 1/7=0.143; 1/6=0.167 и т.д.) окажется в одной из цепочек:
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.125 -j NAT1
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.143 -j NAT2
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.167 -j NAT3
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.200 -j NAT4
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.250 -j NAT5
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.333 -j NAT6
-A PREROUTING -i eth3 -m statistic --mode random --probability 0.500 -j NAT7
-A PREROUTING -i eth3 -j NAT8
А уже в этих цепочках пакет маркируется нужной меткой,..
-A NAT1 -j SET --add-set NAT1 src --exist
-A NAT1 -j MARK --set-xmark 0xa/0xffffffff
-A NAT1 -j ACCEPT
-A NAT2 -j SET --add-set NAT2 src --exist
-A NAT2 -j MARK --set-xmark 0x14/0xffffffff
-A NAT2 -j ACCEPT
-A NAT3 -j SET --add-set NAT3 src --exist
-A NAT3 -j MARK --set-xmark 0x1e/0xffffffff
-A NAT3 -j ACCEPT
-A NAT4 -j SET --add-set NAT4 src --exist
-A NAT4 -j MARK --set-xmark 0x28/0xffffffff
-A NAT4 -j ACCEPT
...
...и попадает, благодаря ip rule в нужную таблицу маршрутизации, а далее летит по нужному маршруту на нужный NAT-сервер.
Суть понятна? Если балансировщик еще не встречал этот абонентский IP, то засунет его в одну из восьми цепочек ipset благодаря mode random. Если же адрес уже нам известен (есть в каком-либо ipset), то такой трафик всегда будет лететь в нужный NAT.

Еще был написан небольшой демон, который простым пингом проверял наличие NAT-серверов за портом и выводил его из работы, динамически удаляя/добавляя правила в iptables с корректным пересчетом вероятности.

понедельник, 28 июня 2021 г.

Grafana с аутентификацией через Radius

Встала задача поднять Grafana с аутентификацией через Radius.

Сразу же была найдена статья.

Принцип работы ясен. В grafana есть специальный механизм auth.proxy, который может получать данные в виде переменных окружения. В том примере используется веб-сервер Apache, мы же воспользуемся более привычным Nginx.

Ставим grafana, nginx и libpam-radius-auth штатным для дистрибутива способом.

Настраиваем pam:

/etc/pam_radius_auth.conf
radius-server-ip:port   secret
Делаем этот файл доступным для чтения пользователю, под которым работает nginx (у меня это www-data):
chown www-data:www-data /etc/pam_radius_auth.conf
/etc/pam.d/nginx
auth    required        pam_radius_auth.so debug client_id=grafana conf=/etc/pam_radius_auth.conf
account required        pam_permit.so
session required        pam_permit.so

Настраиваем nginx:
server {
       listen 443 ssl;

       ssl_certificate /etc/ssl/cert.pem;
       ssl_certificate_key /etc/ssl/cert.key;
       ssl_protocols TLSv1.2;
       ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256;
       ssl_prefer_server_ciphers on;
       add_header Strict-Transport-Security 'max-age=604800';
       server_name grafana.example.com;

       access_log /var/log/nginx/gr.access.log;
       error_log /var/log/nginx/gr.error.log;
       location / {
           auth_pam "Auth";
           auth_pam_service_name "nginx";
           proxy_pass http://localhost:3000/;
           proxy_set_header X-WEBAUTH-USER $remote_user;
           proxy_set_header Authorization "";
       }
}

Настраиваем grafana
/etc/grafana/grafana.ini:
....
[auth.proxy]
enabled = true
....

Перезапускаем grafana-server и nginx и проверяем.

среда, 27 мая 2020 г.

Пароли в SHA256 в OpenLDAP

Понадобилось нам поднять для определенных целей OpenLDAP. С условием, что пароли, вернее хэши наших пользователей, мы будем брать из уже существующей SQL-базы. Из входящих данных у нас был SQL-запрос, вызвращающий пользователей с хэшами и утверждение нашего DBA, что пароли хешированы в SHA256.

Получаю хэш пользователя из базы, проверяю через
echo -n "test" | sha256sum
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08  -
Строка совпадает. Быстро ваяем скрипт, который заполняет нужные поля в LDAP, в том числе вставляет эту строку в качестве пароля.

Пробуем авторизоваться:
ldapwhoami -vvv -h 127.0.0.1 -p 389 -D "cn=Иванов Иван,ou=staff,dc=example,dc=com" -W
Enter LDAP Password:                                                                                             
ldap_bind: Invalid credentials (49)
Что-то не работает.

Google подтверждает, что OpenLDAP умеет в SHA256, однако разные статьи говорят, что для этого надо либо использовать сторонний модуль slapd-sha2.so, либо воспользоваться услугами самой операционной системы, ведь пароли в Linux хранятся в SHA256/SHA512.

Выбираю второй вариант. Пишут, что надо добавить префикс {CRYPT}. Чтобы указать, что это хэш sha256, делаю предположение, что надо добавить $5$:
cat ./chpass.ldif 
dn: cn=Иванов Иван,ou=staff,dc=example,dc=com
changetype: modify
replace: userPassword
userPassword: {CRYPT}$5$9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Заливаю изменение, проверяю...

ldap_bind: Invalid credentials (49)

Нахожу в OpenLDAP FAQ:
Just to state the obvious, SHA-256 and SHA-512 based "glibc" crypt algorithms $5$ and $6$ are totally different from plain (or salted) "{SHA256}" algorithms. The libc crypt variants do a lot of nonsensical transpositions to increase the computational load.

Черт, пишут что алгоритмы различаются.

Чтобы удостоверится, вставляем свой хэш из /etc/shadow в качестве пароля с префиксом {CRYPT}$6$.

Работает, конечно.

Но нам надо использовать те хэши, которые уже в базе. База уже успешно используется в другом проекте, так что хэши рабочие, чтобы "перехешировать" под наш алгоритм, нужно будет инициировать смену паролей у нескольких сотен пользователей, да еще и переписать уже существующий проект, успешно использующий имеющиеся хэши.

Параллельно в гугле находим, что идентичный команде sha256sum хэш даёт команда:
echo -n "test" | openssl dgst -sha256
(stdin)= 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
Да и онлайн сервис по распознаванию хэшей подтверждает, что это действительно sha256.
Тогда как на результат команды:
openssl passwd -5
говорит Unknown.

Ладно, читаем мануалы дальше. Различие в "соли". Passwd в Linux и в openssl делают пароль с солью, а sha256sum, понятное дело, без. И как раз-таки в OpenLDAP это должно работать, при использовании префикса {SHA256}

Видимо надо искать модуль. И находим информацию, что в актуальных версиях OpenLDAP модуль уже присутствует в системе. А файл slapd-sha2.so мы не могли найти потому, что он называется по-другому. Сотни статей по openldap+sha256 уже не актуальны, кто бы мог подумать :)

Для подтверждения этого выкачиваю исходники openldap с гита, нахожу модуль и в его Makefile'е вижу сему подтверждение. Файл на выходе действительно называется pw-sha2.la / pw-sha2.so.

Пробую просто добавить префикс {SHA256}:
cat ./chpass.ldif 
dn: cn=Иванов Иван,ou=staff,dc=example,dc=com
changetype: modify
replace: userPassword
userPassword: {SHA256}9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Заливаю, пробую, не работает.

Может модуль не подгружен?
Конфиг OpenLDAP сейчас хранится в самом OpenLDAP, так что смотрим:

# slapcat -b cn=config -a "(objectClass=olcModuleList)"
...
olcModuleLoad: {1}pw-sha2.la
...
И видим, что модуль загружен.

Кстати, у нас уже есть выкачанные исходники OpenLDAP. Без особой надежды лезу в них поковырятся, мож пойму, что ему надо. В readme модуля sha2 до сих пор сказано, что надо собрать slapd-sha2.so, скопировать его в нужное место и подключить через конфиг slapd.conf (т.е. инструкция в исходниках сама устарела, ведь и библиотека называется по-другому, и конфиг OpanLDAP уж много лет как в самом OpenLDAP).

Но в том же readme ниже нахожу команду для создания хэша для тестирования:
$ echo -n "secret" | openssl dgst -sha256 -binary | openssl enc -base64
K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=
Что ж, мы были близки. Пароль надо завернуть в base64. И это при том, что в LDAP оно еще раз заворачивается в base64. Но не строчное его представление, а "бинарное".

Делаю base64 над своим паролем, вставляю с префиксом {SHA256}:

# echo -n "test" | openssl dgst -sha256 -binary | base64
n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=

# cat ./chpass.ldif 
dn: cn=Иванов Иван,ou=staff,dc=example,dc=com
changetype: modify
replace: userPassword
userPassword: {SHA256}n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=

Заливаю, проверяю, работает!

Result: Success (0)

В скрипте это можно сделать так:
echo -n "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" | xxd -r -p | base64

суббота, 2 мая 2020 г.

Обнулить все файлы в каталоге.

Для довольно специфической задачи понадобилось обнулить все файлы в каталоге:
while read line; do bash -c "> \"$line\""; done < <(ls -1)

вторник, 19 ноября 2019 г.

Apt не хочет качать по https

А вот тут был интересный кейс. Сервер со свежеобновленным Debian 10.2 не хочет качать индексные файлы из репозитория по протоколу https:
Err https://download.docker.com/linux/debian buster Release
  Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.  Could not handshake: Error in the certificate verification. [IP: 205.251.219.17 443]
W: https://download.docker.com/linux/debian/dists/buster/InRelease: No system certificates available. Try installing ca-certificates.
W: https://download.docker.com/linux/debian/dists/buster/Release: No system certificates available. Try installing ca-certificates.
E: The repository 'https://download.docker.com/linux/debian buster Release' does not have a Release file.
E: Failed to download some files
W: Failed to fetch https://download.docker.com/linux/debian/dists/buster/Release: Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.  Could not handshake: Error in the certificate verification. [IP: 205.251.219.17 443]
E: Some index files failed to download. They have been ignored, or old ones used instead.
Проверил ссылку из браузера -- всё ок, на той стороне сертификат валидный.
Значит дело в нашем сервере. Оно и понятно, на других серверах этот же репозиторий работает нормально.

Но ни curl, ни wget не ругается на сертификат, как и openssl s_client.

Более того, подключил еще один проверенный репозиторий по https, на него валятся такие же ошибки.

За пару часов в гугле ничего не нашел. У всех с такой ошибкой какие-то проблемы с корневыми сертификатами и им предлагают произвести стандартные танцы с бубнами вокруг пакета ca-certificates. У меня же с сертификатами всё хорошо, состав и количество совпадают с "рабочими" серверами. Но именно apt не хочет работать по https.
Дело оказалось в правах на каталог /etc/ssl/certs. Кто-то ошибочно выставил на него режим 700, поэтому curl и wget, запущенные от root добрались до корневых сертификатов, а apt из-под непривилегированного пользователя не смог.

А значит решением будет:

# chmod 755 /etc/ssl/certs/

среда, 30 октября 2019 г.

Консольная утилита для управления WordPress

У нас есть сервер, на котором крутятся сайты на WordPress для других отделов. Они их как-то сами наполняют и админят, но, конечно же, обновлять и не думают.
Nginx, PHP, Mysql я им обновлю, а как быть с самими сайтами?

Можно было бы добавить себя в админы каждого сайта, но не всё так просто. На каких-то сайтах локальная аутентификация, на других LDAP, на третьих что-то ещё.

Объединяет их то, что они лежат на одном сервере. Обновить их оказалось довольно просто (имея рутовые права на сервере).

Нужна утилита wp-cli. К сожалению, её нет в официальных репах Debian'а, но эту утилиту можно скачать с её официального сайта (это один файл на php) и положить в любой каталог из переменной path. Если мы хотим, чтобы утилита могла обновлять сама себя, её надо положить в каталог, правами на запись в который должен обладать пользователь www-data (или под кем вы там запускаете web-сервер). Ну тут смотрите сами, снижаем безопасность в угоду удобству, как обычно.

Утилите надо создать каталог с правами на запись, куда она сможет скачивать обновления Вордпресса и плагинов. Он должен лежать в домашнем каталоге пользователя web-сервера, у меня это /var/www и назвать .wp-cli.

Далее, утилиту надо запускать от имени web-сервера, это www-data в Debian по умолчанию.

Например так:

От рута:
# sudo -u www-data bash
Переходим в каталог с первым сайтом:
$ cd /var/www/site1
$ wp core check-update
$ wp core update
$ wp core updatedb
$ wp plugin update --all
Переходим в следующий и повторяем, пока не кончатся сайты. Ну а дальше скрипты для автоматизации, ansible и т.д., но вы это и без меня знаете.

среда, 27 февраля 2019 г.

Создать пользователя в DJANGO через SQL

Понадобилось попасть в админку сайта на django, имя рутовый доступ к серверу. База сайта лежала в локальном sqlite. Генерируем себе пароль с помощью утилиты djpass:
$ ./djpass ololo
Hash: pbkdf2_sha256$120000$nwEK2MXzMCj7$u3ZGMBCbdGC72pNJkh8dZ79pcYbmlGNQCrDXvvG8WuA=
Эту утилиту я поставил в мусорную тестовую виртуальную машину на Debian, дабы не засорять свой комп, а уж тем более сервер, всяким непотребством. Ставится через программу cargo, которая есть в стандартных репах Debian:
# apt install cargo
$ cargo install djpass
Если что, утилита оказывается в каталоге ~/.carbo/bin С хешем наперевес идём в базу. В моём случае, как я уже сказал, это sqlite:
# sqlite3 /path/to/db/file

sqlite> INSERT INTO "auth_user" VALUES(3,"pbkdf2_sha256$120000$nwEK2MXzMCj7$u3ZGMBCbdGC72pNJkh8dZ79pcYbmlGNQCrDXvvG8WuA=
","",1,"megaadmin","","",1,1,"2019-02-27 11:32:20","");
Готово. Далее у меня была внутреняя ошибка 500, но при включенном дебаге выяснил, что просто права к базе были некорректными, nginx не мог до неё добраться.

среда, 15 марта 2017 г.

MPLS L2VPN в OpenBSD

Тестирую виртуальный роутер Cisco XRv 9000. И оказалось, что на данный момент mpls l2vpn в них не работает.
Просто из любопытства решил посмотреть, что творится на этом фронте у других ОС, которые можно было бы взгромоздить на x86-роутер.
И оказалось, что актуальная OpenBSD умеет это "из коробки".


В этом примере сервер с OpenBSD подключен интерфейсом em0 в коммутатор ядра, где в вилане 281 ходит LDP. Рабочая машина, воткнута в порт em1, должна оказаться в VPLS-бридже (виртуальный коммутатор), находящемся на маршрутизаторе где-то в далёкой серверной и получить оттуда адрес по dhcp.
Т.е. компы со всей необъятной сети, подключенные в этот бридж, "считают", что находятся за одним обычным коммутатором.


Создаём vlan-интерфейс:
# ifconfig em0 up
# ifconfig em0 mtu 2000
# ifconfig vlan281 create
# ifconfig vlan281 vlan 281 vlandev em0
# ifconfig vlan281 up mpls
# ifconfig vlan281 10.100.15.133/30
# ifconfig vlan281 mtu 1600
Для работы LDP нужен выделенный лупбек (вообще, хорошим тоном является создание на каждом маршрутизатор лупбек-интерфейса с ip-адресом, и использование это ip-адреса в качестве router-id для разных протоколов).
# ifconfig lo1 10.100.223.220/32
Создаём pseudowire-интерфейс и бриджуем его с физическим портом.
# ifconfig mpw0 create
# ifconfig mpw0 up
# ifconfig em1 up
# ifconfig bridge0 create
# ifconfig bridge0 up
# ifconfig bridge0 add em1
# ifconfig bridge0 add mpw0
Надо добавить параметр в файл /etc/pf.conf:
set reassemble no

Теперь ospf с ядром:
router-id 10.100.223.220

area 0.0.0.0 {
   interface lo1
   interface vlan281
}
Запускаем ospfd.

И наконец ldp:
router-id 10.100.223.220

l2vpn OFFICE type vpls {
  bridge bridge0
  interface em1
  pseudowire mpw0 {
     neighbor-id 10.100.223.18
     pw-id 1111
  }
}
address-family ipv4 {
   interface vlan281
}
Запускаем ldpd. Проверяем:
# ldpctl show l2vpn pseudowires
Interface   Neighbor        PWID        Status
mpw0        10.100.223.18   1111        UP

Пробуем получать на тестовой машине dhcp.

вторник, 24 мая 2016 г.

Мониторинг уровня RX/TX для оптических портов Huawei

Особенность мониторинга уровня сигнала на коммутаторе Huawei S6300 в том, что значения возвращаются не в привычных нам dbm, а в mW.

Для конвертации используется формула, в которой используются логарифмы. В той версии системы мониторинга Zabbix, которая используется у нас, я не нашел, как указать в формуле логарифм. Поэтому сбором данных с комутаторов будет заниматься внешний скрипт, а результат заливать в Zabbix через zabbix_sender.

Вот, собственно, сам скрипт:

#!/bin/bash

for HUAWEI in sw1 sw15 sw18 sw24; do
  rm -f "/tmp/huawei_rxtx_monitor_${HUAWEI}"
  /usr/bin/snmpwalk -c Secret_Community -v 2c ${HUAWEI} .1.3.6.1.2.1.47.1.1.1.1.7 > /tmp/huawei_rxtx_monitor_${HUAWEI}.txt || exit 1
  if [ -f "/tmp/huawei_rxtx_monitor_${HUAWEI}.txt" ]; then
    for port in $(/bin/sed -nr '/XGigabitEthernet/s/.*\.([0-9]+)\ .*/\1/gp' /tmp/huawei_rxtx_monitor_${HUAWEI}.txt); do
      RX=$(echo "(l($(/usr/bin/snmpget -Oqav -c Secret_Community -v 2c ${HUAWEI} .1.3.6.1.4.1.2011.5.25.31.1.1.3.1.8.${port})/1000)/l(10))*10" | /usr/bin/bc -l)
      /usr/bin/zabbix_sender -z zabbix_server_ip -k rxpower[\"${port}\"] -o $RX -s ${HUAWEI} > /dev/null
      TX=$(echo "(l($(/usr/bin/snmpget -Oqav -c Secret_Community -v 2c ${HUAWEI} .1.3.6.1.4.1.2011.5.25.31.1.1.3.1.9.${port})/1000)/l(10))*10" | /usr/bin/bc -l)
      /usr/bin/zabbix_sender -z zabbix_server_ip -k txpower[\"${port}\"] -o $TX -s ${HUAWEI} > /dev/null
    done
  fi
done
Здесь sw1, sw15, sw18, sw24 -- хостнеймы или IP-адреса коммутаторов;
          Secret_Community -- коммьюнити для чтения параметров по snmp;
          zabbix_server_ip -- адрес или хостнейм сервера Zabbix;
          rxpower[\"${port}\"], txpower[\"${port}\"] -- названия элементов в zabbix.

Осталось поместить в cron с требуемой периодичностью.

среда, 30 сентября 2015 г.

Генерация запроса на подпись ключа

Напоминалка себе, как генерировать ssl csr:
openssl genrsa -out ./domain.com.key 2048
openssl req -new -sha256 -key ./domain.com.key -out ./domain.com.csr

понедельник, 27 октября 2014 г.

Узнать каталог, из которого запущен процесс

Как узнать, кто слушает определённый порт?
# ss -tpunl | grep 3780
udp    UNCONN     2754   0           10.100.10.22:3780                  *:*      users:(("python",4313,6))
Что же это за процесс?
# ps ax|grep 4313
4313 pts/4    Rl+  29106:08 python ./server.py
Некий server.py, не ясно откуда запущенный. Что ж:
# pwdx 4313
4313: /home/username/conntrackd/conntrack-decoder
Нашли :)

P.S. Проще даже так:
# ls -l /proc/4313/cwd
lrwxrwxrwx 1 username username 0 Окт 27 14:48 /proc/4313/cwd -> /home/username/conntrackd/conntrack-decoder

пятница, 1 августа 2014 г.

Bridge с помощью iproute2

Всех админов в пределах досягаемости бью по рукам за использование ifconfig/route на linux-серверах. К счастью в новых дистрибутивах эти анахронизмы даже не установлены по умолчанию и народ рано или поздно начнёт переучиваться. Сегодня попробуем создать бридж с помощью всемогущей утилиты ip из пакета iproute2
ip l s dev eth1 up
ip l s dev eth0.1999 up
ip l add name br0 type bridge
ip l s dev eth1 master br0
ip l s dev eth0.1999 master br0
ip l s dev br0 up
That's all, folks!

вторник, 22 июля 2014 г.

FTP через TELNET

Для академических целей попробуем подключиться к FTP с использованием утилиты telnet.

Для успешного скачивания файла нам потребуется две открытые консоли и калькулятор. Вместо telnet можно использовать nc/netcat. Подключаться будем в пассивном режиме.
Авторизируемся:
$ telnet mirror.yandex.ru 21
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
220-Welcome to Yandex Mirror FTP service. Your served by: node01d.mirror.yandex.net
220 
USER anonymous
331 Please specify the password.
PASS a@b.ru
230 Login successful.
Открываем на сервере порт для "пассивного" подключения:
PASV
227 Entering Passive Mode (213,180,204,183,221,153).
Здесь мы видим параметры для ВТОРОГО подключения. Первые четыре числа -- это ip-адрес сервера, пятое и шестое -- это порт для подключения. Вычисляется по формуле: первое*256 + второе.
Не закрывая первую консоль во второй консоли пишем:
$ telnet mirror.yandex.ru 56729
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
В рамках этого соединения мы можем только получать данные. Вот примерный список FTP-команд:
    ABOR - прервать передачу
    CWD - сменить директорию
    DELE - удалить файл на сервере
    LIST - детальный список файлов на сервере
    MDTM - узнать время модификации файла
    MKD - создать каталог на сервере
    NLST - упрощенный список файлов на сервере
    PASS - отправить пароль
    PASV - перейти в пассивный режим
    PORT - заставить сервер подключиться к клиенту на определенный порт (активный режим)
    PWD - вывести название текущего каталога
    QUIT - окончить соединение
    RETR - скачать файл с сервера
    RMD - удалить каталог на сервере
    RNFR - переименовать из
    RNTO - переименовать в
    SITE - серверо-специфицеские команды
    SIZE - узнать размер файла
    STOR - залить файл на сервер
    TYPE - установить режим передачи
    USER - отправить пользовательский логин
Пользуясь командами (и переподключаясь во второй консоли каждый раз на новый порт, который нам указывает сервер, скачиваем файл. Первая консоль:
LIST
150 Here comes the directory listing.
226 Directory send OK.
CWD pub
250 Directory successfully changed.
PASV
227 Entering Passive Mode (213,180,204,183,217,235).
LIST
150 Here comes the directory listing.
226 Directory send OK.
CWD tools
250 Directory successfully changed.
PASV
227 Entering Passive Mode (213,180,204,183,230,239).
LIST
150 Here comes the directory listing.
226 Directory send OK.
CWD crosstool 
250 Directory successfully changed.
PASV
227 Entering Passive Mode (213,180,204,183,230,34).
LIST
150 Here comes the directory listing.
226 Directory send OK.
PASV
227 Entering Passive Mode (213,180,204,183,202,255).
RETR index.html
150 Opening BINARY mode data connection for index.html (6922 bytes).
226 Transfer complete.
Вторая консоль:
$ telnet mirror.yandex.ru 56729
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
drwxr-xr-x   17 ftp      ftp          4096 Jul 22 03:27 altlinux
drwxr-sr-x   20 ftp      ftp          4096 Jul 21 10:29 altlinux-beta
drwxr-xr-x    7 ftp      ftp          4096 Jul 21 10:43 altlinux-nightly
drwxr-xr-x   17 ftp      ftp          4096 Jul 22 07:38 archlinux
drwxr-xr-x    7 ftp      ftp          4096 Jul 21 10:56 archserver
drwxr-sr-x    6 ftp      ftp          4096 Sep 17  2007 asplinux-tigro
drwxr-xr-x    4 ftp      ftp          4096 Jul 21 10:56 astra
drwxr-xr-x   39 ftp      ftp          4096 Jul 21 10:35 calculate
drwxrwxr-x   38 ftp      ftp          4096 Jul 22 05:06 centos
drwxr-xr-x    8 ftp      ftp          4096 Jul 22 03:53 debian
drwxrwsr-x    6 ftp      ftp          4096 Jul 22 03:22 debian-backports
drwxr-xr-x    5 ftp      ftp          4096 Jul 22 02:36 debian-cd
drwxrwxr-x    6 ftp      ftp          4096 Jul 22 01:04 debian-multimedia
drwxrwsr-x    6 ftp      ftp          4096 Jul 21 10:34 debian-security
drwxr-sr-x    7 ftp      ftp          4096 Jul 21 20:40 epel
drwxr-xr-x    7 ftp      ftp          4096 Jul 22 05:08 fedora
drwxrwxr-x   12 ftp      ftp          4096 Jul 22 04:21 freebsd
drwxr-xr-x    6 ftp      ftp          4096 Jul 22 07:32 gentoo-distfiles
drwxrwxr-x  169 ftp      ftp          4096 Jul 22 07:32 gentoo-portage
drwxr-xr-x   10 ftp      ftp         12288 Jul 21 10:08 knoppix
drwxr-xr-x    3 ftp      ftp          4096 Jul 22 02:04 libreoffice
drwxr-xr-x    7 ftp      ftp          4096 Jul 21 10:32 linuxmint
drwxr-xr-x    5 ftp      ftp          4096 Jul 22 04:24 macports
drwxr-xr-x    6 ftp      ftp          4096 Jul 22 07:32 mageia
drwxr-xr-x   39 ftp      ftp          4096 Jun 30 09:26 mirrors
drwxr-xr-x    6 ftp      ftp          4096 Mar 11 14:53 mopslinux
drwxr-xr-x    8 ftp      ftp          4096 Jul 22 07:40 mozilla
drwxr-xr-x   48 ftp      ftp          4096 Jul 22 02:18 openbsd
drwxr-xr-x    5 ftp      ftp          4096 Jul 22 05:06 openmandriva
drwxr-xr-x    8 ftp      ftp          4096 Jul 21 17:33 opensuse
drwxr-xr-x    8 ftp      ftp          4096 Jul 22 06:07 pub
drwxr-xr-x    8 ftp      ftp          4096 Jul 21 10:31 puppyrus
drwxr-xr-x   10 ftp      ftp          4096 Jul 22 05:32 rosa
drwxr-xr-x    4 ftp      ftp          4096 Jul 21 10:33 runtu
drwxrwxr-x    5 ftp      ftp          4096 Jul 22 04:32 sabayon
drwxr-xr-x   13 ftp      ftp          4096 Jul 22 04:32 scientificlinux
drwxr-xr-x    6 ftp      ftp          4096 Apr 02 17:53 simplelinux
drwxr-xr-x   42 ftp      ftp          4096 Jul 22 00:34 slackware
drwxr-xr-x    6 ftp      ftp          4096 Jul 22 02:09 ubuntu
drwxr-xr-x   30 ftp      ftp          4096 Jul 22 04:16 ubuntu-cdimage
drwxr-xr-x   12 ftp      ftp          4096 Jul 22 06:16 ubuntu-releases
Connection closed by foreign host.

$ telnet mirror.yandex.ru 55787
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
lrwxrwxrwx    1 ftp      ftp            11 Feb 17  2013 FreeBSD -> ../freebsd/
lrwxrwxrwx    1 ftp      ftp            11 Feb 17  2013 OpenBSD -> ../openbsd/
drwxr-xr-x   13 ftp      ftp          4096 Nov 16  2011 linux
drwxrwxr-x    3 ftp      ftp          4096 Sep 23  2008 media
drwxr-xr-x   15 ftp      ftp          4096 Aug 03  2013 scm
drwxrwxr-x    2 ftp      ftp          4096 Aug 09  2013 site
drwxr-xr-x   13 ftp      ftp          4096 Nov 27  2011 software
drwxr-xr-x    3 ftp      ftp          4096 Apr 30  2008 tools
Connection closed by foreign host.

$ telnet mirror.yandex.ru 59119
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
drwxrwxr-x    3 ftp      ftp          4096 May 22  2013 crosstool
Connection closed by foreign host.

$ telnet mirror.yandex.ru 58914
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
drwxrwxr-x    5 ftp      ftp          4096 Mar 28  2012 files
-rw-rw-r--    1 ftp      ftp          6922 May 22  2013 index.html
-rw-rw-r--    1 ftp      ftp           543 May 22  2013 index.html.sign
-rw-r--r--    1 ftp      ftp           962 Apr 02 07:57 sha256sums.asc
Connection closed by foreign host.

$ telnet mirror.yandex.ru 51967
Trying 213.180.204.183...
Connected to mirror.yandex.ru.
Escape character is '^]'.
[тут вырезано содержимое получаемого файла]
Connection closed by foreign host.

четверг, 5 июня 2014 г.

Сервер vsftpd с аутентификацией через radius

Настройка сервера VSFTPD с аутентификацией через Radius в Debian:
# aptitude install vsftpd libpam-radius-auth
# cat /etc/pam.d/vsftpd
# Standard behaviour for ftpd(8).

auth    sufficient      pam_radius_auth.so client_id=openvpn
account sufficient      pam_radius_auth.so client_id=openvpn
@include common-account
@include common-session
@include common-auth
auth    required        pam_shells.so
Client_id -- это атрибут Nas-identifier в радиус-запросе.
# cat /etc/pam_radius_auth.conf
# server[:port]  shared_secret      timeout (s)
10.100.4.100    mymegasecretkey       3
# cat /etc/vsftpd.conf
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=NO
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
nopriv_user=ftp
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/private/vsftpd.pem
user_sub_token=$USER
guest_username=ftp
guest_enable=YES

среда, 4 июня 2014 г.

Сервер OpenVPN с аутентификацией через Radius

Настройка сервера OpenVPN с аутентификацией через Radius в Debian:
# aptitude install openvpn openvpn-auth-radius
# cat /etc/openvpn/radiusplugin.cnf
NAS-Identifier=openvpn
Service-Type=2
Framed-Protocol=1
NAS-Port-Type=5
NAS-IP-Address=10.100.10.85
OpenVPNConfig=/etc/openvpn/server.conf
subnet=255.255.255.0
overwriteccfiles=true
server
{
        # The UDP port for radius accounting.
        acctport=1815
        # The UDP port for radius authentication.
        authport=1812
        # The name or ip address of the radius server.
        name=10.100.4.100
        # How many times should the plugin send the if there is no response?
        retry=1
        # How long should the plugin wait for a response?
        wait=1
        # The shared secret.
        sharedsecret=mymegasecretkey
}
# cat /etc/openvpn/server.conf
local my_public_ip
port 443
proto tcp
dev tun
tun-mtu 1500
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key 
dh /etc/openvpn/keys/dh1024.pem
server 10.8.0.0 255.255.255.0
client-cert-not-required
username-as-common-name
ifconfig-pool-persist ipp.txt
push "route 10.100.0.0 255.255.0.0"
push "route 10.102.0.0 255.255.0.0"
keepalive 10 120
comp-lzo
persist-key
persist-tun
status /var/log/openvpn/status.log 1
plugin /usr/lib/openvpn/radiusplugin.so
log-append  /var/log/openvpn/openvpn.log
verb 3

пятница, 27 декабря 2013 г.

NAT через IPIP-туннель.

Понадобилось для определенного теста сымитировать выход в интернет из другого города. В том городе имеется небольшой сервер, доступный по внутренней сети (предположим, некие VPN от провайдера, сервер и тестовая машина находятся в локальных маршрутизируемых сетях).

У сервера есть белый ip-адрес и выход в интернет, у клиента такой роскоши нет.

Сервер
IP-адрес локалки: 192.168.1.1/24
IP-адрес белый: 1.2.3.4

Клиент
IP-адрес локалки: 192.168.2.2/24
Шлюз 192.168.2.1

Решение состоит из двух шагов: Поднятие туннеля между клиентом и сервером и настройка NAT на сервере.

На сервере:
ip tun add tun0 mode ipip local 192.168.1.1 remote 192.168.2.2 ttl 255
ip l s dev tun0 up
iptables -I INPUT -p 4 -s 192.168.2.2 -j ACCEPT
iptables -I FORWARD -s 192.168.2.2 -j ACCEPT
iptables -I FORWARD -d 192.168.2.2 -j ACCEPT
iptables -t nat -I POSTROUTING -s 192.168.2.2 -j MASQUERADE

На клиенте:
ip tun add tun0 mode ipip local 192.168.2.2 remote 192.168.1.1 ttl 255
ip l s dev tun0 up
ip r a 192.168.1.1 via 192.168.2.1
ip r d default
ip r a default dev tun0
Надо помнить, что здесь не используется шифрование.
Forwarding должен быть включен, а rp_filter на всякий случай выключен.

воскресенье, 15 декабря 2013 г.

Почему не запускается бинарник?

user@book:~$ /home/user/some_program/program_bin
bash: /home/user/some_program/program_bin: Нет такого файла или каталога

user@book:~$ ls -l /home/user/some_program/program_bin
-rwxr-xr-x 1 user user 286567 май 27  2012 /home/user/some_program/program_bin

user@book:~$ file /home/user/some_program/program_bin
/home/user/some_program/program_bin: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.0, not stripped

user@book:~$ /home/user/some_program/program_bin
bash: /home/user/some_program/program_bin: Нет такого файла или каталога

user@book:~$ mount | grep home
/dev/mapper/_dev_dm_3 on /home/user type ext4 (rw,relatime,data=ordered)

user@book:~$ ls -ld /home/user/some_program
drwxr-xr-x 15 user user 4096 окт 24 19:38 /home/user/some_program


user@book:~$ ld /home/user/some_program/program_bin
ld: i386 architecture of input file `/home/user/some_program/program_bin' is incompatible with i386:x86-64 output

пятница, 27 сентября 2013 г.

Пара ссылок для диагностики доступа к Youtube

Пара ссылок для диагностики доступа к Youtube, чтоб не забыть. http://redirector.c.youtube.com/report_mapping покажет, на какую ноду Гугл-кеша происходит редирект
http://www.youtube.com/my_speed статистика по скорости