Thursday, June 25, 2009

Жара доводит до ручки

Удивлялся и пялился, как в афишу коза, почему вместо ожидаемой lowercase строки, переменная t становится заполнена непечатным символом 0x01 (SOH):

int cmd_type(const char *raw)
{
    if (raw == NULL) return -1;

    char t[BUFSIZ];
    strncpy(t, raw, sizeof(t)-1);
    t[sizeof(t)-1] = '\0';

    char *p = t;
    while (*p) {
        *p = islower(*p);
        ++p;
    }

    if (strncmp(t, "help", 4) == 0) return P_CMD_HELP;
    ...
}

Распознать наконец, что вместо tolower написал islower понадобилось минут 30. Проклятое киевское лето.

Saturday, June 6, 2009

Broken DNS forwarding in VMware Workstation 6.5.2 with NAT

Это случилось на следующее утро после апгрейда с 6.0.2 на 6.5.2: прохладным, синим вечером казалось что все прошло гладко и работало чудесно, а жарким утром, когда трафик за окном начинал свой привычный тягучий стон, я открыл крышку лэптопа, и, щурясь от надоедливого солнца, обнаружил внутри виртуальной машины неспособным себя забрать почту: DNS не работал.

Сначала я подумал что мой Bind в Vista совершил харакири, но это оказалось неправдой -- в Windows резолвер общался с локальным DNS-сервером успешно как и раньше. Затем я решил что вчера совершил что-то настолько глупое с virtual network switches, что утром completely incapable это вспомнить. Короче говоря я, кхм, позорно перезагрузился и о чудо -- UTP пакеты начали бегать в машинах VMware по 53-му порту как вчера.

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

Вечером того же дня, который грозил начаться столь неудачно, yours truly smug вернулся домой, открыл лэптоп и... Не знаю как вы догадались, но обнаружил внутри виртуальной машины неспособным себя забрать почту: DNS не работал.

Черт, -- сказал я. То есть, по правде говоря, сказал что-то гораздо хуже.

Маленькое исследование с tcpdump'ом со стороны FreeBSD и с Wireshark'ом со стороны Vista показало что запрос со стороны резолвера доходит до сервера вполне успешно, формируемый ответ сервера идет на вход VMnet8 switch, но отфутболивается от него с ошибкой ICMP host unreachable, а резолвер в guest отваливается по таймауту и отчаянно плачет no servers could be reached.

Самое интересно в этой истории то, что остальные ip-пакеты по любому другому порту ходят как не в чем не бывало и если вы принудительно отключите резолвинг адресов в вашем http proxy, то таки сможете заставить броузер сходить на википидия, например. Если вы помните хотя бы один из ее ip-адресов, hehe. Или даже так: набираем в Vista "nslookup en.wikipedia.org" и используем вручную ответ в спрятанной от пагубного влияния всех DNS на свете (благодаря VMnet8) виртуальной машине. Можно даже звонить из своего кабинета секретарше и спрашивать "Сюзанна, какой там адрес у serverfault.com? Что-что? 69.59.196.213? 2... После последней точки? 212? Да? Спасибо. Кстати, если придет Самоподгаслов за деньгами -- скажи что я буду в его распоряжении за..., нет лучше на следующей неделе.".

Продолжая маленькое исследование и тщетно излопатя весь гугл мы имеем следующее: DNS отрубается после n минут лежания лэптопа в suspend. То есть, если у вас VMware Workstation вертится на обычном desktop pc, который выключается раз в 6 месяцев: вы можете этой проблемы никогда не заметить и сидеть как император Ян-ди в своем Янчжоу, кушать персики, жевать рябчиков и полностью игнорировать все происходящее.

В обратном случаи, единственно решение тут видится в перезапуске (нет, не всей Windows) сервиса VMware NAT Service каждый раз как Windows протирает глаза после suspend. Возникает естественный вопрос: как автоматизировать? Под FreeBSD или Linux такой предмет даже не выносился на повестку дня, настолько решение всем очевидно своею простотой. В Windows мы имеет очередной геморрой.

Можно написать скрипт на чем заблагорассудится, который будет а) в бесконечном цикле ждать когда Windows говорит, что проснулась и б) вызывать 2 команды:

sc stop "VMware NAT Service"
sc start "VMware NAT Service"

Так? Так, но пускать его придется под Administrator -- если вы просто запихнете вызов скрипта в автозагрузку HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -- это поможет плохо: либо придется сначала загружаться в аккаутн Administrator'ра, а потом в свой, либо найти утилиту (такие есть), которая позволить оформить вызов скрипта под root'ом без ввода каждый раз пароля.

Обойти это можно написанием daemon'а под Windows (сервиса в их булыжной терминологии), который можно стартовать и останавливать в services.msc. Я сделал иначе: Microsoft имеет wrapper-утилитку srvany.exe, которая может разговаривать с Service Control Manager самостоятельно, позволяя таким образом запускать любую программу как Windows service и не мучиться с тем API.

Готовый WSH-скрипт vmware-nat-fix.js лежит тут. Для его работы нужна srvany.exe, которую можно совершенно свободно взять из Windows Server 2003 Resource Kit Tools.

Используется фикс так: скрипт ложится в любое приличное место и сперва тестируется (под администратором) командой:

>vmware-nat-fix.js /d

Если вам показало окошко с надписью Successfully reloaded "VMware NAT Service" daemon, тогда регистрируйте скрипт как сервис вот такой командой (тоже под администратором):

>vmware-nat-fix.js /install

Если все идет хорошо, получите окошко с надписью Successfully added "VMware NAT Fix" service, иначе -- с ошибкой, где будет написано причину (например, что у вас на то не было прав).

Теперь можно пойти в services.msc чтобы запустить daemon или набрать sc start "VMware NAT Fix", если никуда идти желания нету. Когда daemon начнет тихо жужжать, тестируйте его посредством входа в suspend/hibernate и выхода оттуда. У меня VMnet8 после просыпания Vista и щелчка от vmware-nat-fix.js начинает по-человечески работать примерно через секунд 40 (остается невыясненным, почему не сразу).

Если вы решите перетащить vmware-nat-fix.js в другое приличное место, наберите под администратором:

>vmware-nat-fix.js /uninstall
>vmware-nat-fix.js /install

Чтобы обновить записи в реестре.

Local DNS (2009/07/17 update)

Далее, если вы используете локальный, например, Bind для обзывания виртуальных машин, то будьте внимательны, когда и в какой момент Vista к нему обращается. После множества утомительных манипуляций, единственно работающей конфигурацией (всегда и независимо от состояния и количества (включая 0) подключенных сетей к лэптопу), получилась такая, при которой выполнялись 2 условия:

  • прописывание своего, локального DNS-сервера в свойства каждого (а нет только VMware NAT) рабочего network adapter'а. Иначе Vista будет помнить какой был последний DNS-сервер рабочим и с козлиным упрямством слать запросы к нему, даже когда вы давно вышли за пределы той сети с тем сервером.

  • занесение в %SystemRoot%\System32\drivers\etc\resolv.conf привычного nameserver 127.0.0.1.