Cygwin最新版のSSHが魔改造版のWindows 2000でエラーになる件

去年1年ほど前にこの現象に気付いたのだが、原因がわからないまま放置していたので調べてみました

問題の個所1

    if (hostfile_ipaddr != NULL) {
        if (options.proxy_command == NULL) {
            if (getnameinfo(hostaddr, addrlen,
                ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
            fatal("%s: getnameinfo failed", __func__);
            *hostfile_ipaddr = put_host_port(ntop, port);
        } else {
            *hostfile_ipaddr = xstrdup("<no hostip for proxy "
                "command>");
        }
    }

getnameinfo でクラッシュしてるらしい

Administrator@mofmof /usr/src
$ ssh -vvv -F config mof -i id_rsa
OpenSSH_6.8p1, OpenSSL 1.0.2a 19 Mar 2015
debug1: Reading configuration data config
debug1: config line 1: Applying options for mof
debug2: ssh_connect: needpriv 0
ssh_connect: getnameinfo failed
ssh: connect to host 55.123.200.200 port w\314\240": Bad address

というかポート番号が化けてる。
いままで、getnameinfo の実装にバグがあると思ってたけど、実は GetNameInfoW なんじゃないかと…。

とりあえずテストコード書いてみた

#include <stdio.h>

#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib,"ws2_32.lib")
#define _In_  
#define _Out_  

typedef INT(WSAAPI * _GetNameInfoW)(
  _In_   const SOCKADDR *pSockaddr,
  _In_   socklen_t SockaddrLength,
  _Out_  PWCHAR pNodeBuffer,
  _In_   DWORD NodeBufferSize,
  _Out_  PWCHAR pServiceBuffer,
  _In_   DWORD ServiceBufferSize,
  _In_   INT Flags
);
typedef INT(WSAAPI * _GetAddrInfoW)(
    const wchar_t *node,
    const wchar_t *service,
    const struct addrinfo *hints,
    struct addrinfo **res
);
_GetNameInfoW ww;
_GetAddrInfoW xx;
int _tmain(int argc, _TCHAR* argv[])
{
#define STRMAX 255
    WSAData wsaData;
    struct sockaddr *sa;
    socklen_t salen;
    struct sockaddr_in sun;
    char name[STRMAX+1];
    char serv[STRMAX+1];
    wchar_t tname[STRMAX+1];
    wchar_t tserv[STRMAX+1];
    int err;
     WSAStartup(MAKEWORD(2,0), &wsaData);
    memset(name, 0,STRMAX+1);
    memset(serv, 0,STRMAX+1);
    sa = (struct sockaddr*)&sun;
    salen = sizeof(sun);
    sun.sin_family      = AF_INET;
    sun.sin_port        = htons(3000);
    sun.sin_addr.s_addr = INADDR_ANY;
    salen = sizeof(SOCKADDR_STORAGE);
    err = getnameinfo(sa, salen, name, STRMAX, serv, STRMAX, 0);
    printf("salen: %d, err: %d, name: '%s', serv: '%s'\n",
           salen, err, name, serv);
    HINSTANCE hL = 0;
    hL = LoadLibraryA("ws2_32.dll");
    ww=(_GetNameInfoW)GetProcAddress(hL,"GetNameInfoW");
    err = ww(sa, salen, tname, STRMAX, tserv, STRMAX, 0);
    wprintf(L"salen: %d, err: %d, name: '%s', serv: '%s'\n",
           salen, err, tname, tserv);

赤字の箇所でクラッシュした!
というわけでごにょごにょして直した。

続き

    debug3("%s: type %d wildcard %d addr %s", __func__,
        type, wildcard, (addr == NULL) ? "NULL" : addr);

    /*
     * getaddrinfo returns a loopback address if the hostname is
     * set to NULL and hints.ai_flags is not AI_PASSIVE
     */
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = IPv4or6;
    hints.ai_flags = wildcard ? AI_PASSIVE : 0;
    hints.ai_socktype = SOCK_STREAM;
    snprintf(strport, sizeof strport, "%d", fwd->listen_port);
    if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
        if (addr == NULL) {
            /* This really shouldn't happen */
            packet_disconnect("getaddrinfo: fatal error: %s",
                ssh_gai_strerror(r));

        } else {
            error("%s: getaddrinfo(%.64s): %s", __func__, addr,
                ssh_gai_strerror(r));
        }
        return 0;
    }

なぜか赤字の処理に飛ぶ。
調べてみると、GetAddrInfoW の第一引数がNULLの時何も処理せずエラー扱いになっていた。

debug1: channel 2: new [client-session]
debug3: ssh_session2_open: channel_new: 2
debug2: channel 2: send open
debug1: Entering interactive session.
debug2: callback start
debug2: fd 3 setting TCP_NODELAY
debug3: ssh_packet_set_tos: set IP_TOS 0x10
debug2: client_session2_setup: id 2
debug2: channel 2: request pty-req confirm 1
debug2: channel 2: request shell confirm 1
debug2: callback done
debug2: channel 2: open confirm rwindow 0 rmax 32768
debug2: channel_input_status_confirm: type 100 id 2
PTY allocation request failed on channel 2
debug2: channel 2: rcvd adjust 131072
debug2: channel_input_status_confirm: type 99 id 2
debug2: shell request accepted on channel 2
debug2: channel 2: rcvd ext data 39

Type in help if you are really lost

stty: standard input: Invalid argument
debug2: channel 2: written 39 to efd 8

直したところ無事つながった・ω・!

拡張カーネルv2.4eから修正済みです。
なお、
・d3d9.dllの吉里吉里Z対応
・GDI+のセキュリティ更新
も含んでいます

Windows 2000 Kernel32 改造計画【BM】

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です