使用GCDAsyncSocket通过套接字进行Telnet

owe*_*rig 7 telnet objective-c

我正在尝试通过telnet从目标c连接到Cisco C40编解码器.在我的电脑上使用终端时,我得到:

密码:

但是,在进行套接字连接时,需要进行telnet协商.我是哪个但由于某种原因,我无法进入上面的"密码:"提示.

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSLog(@"RECEIVE BUFFER %@",data);

    //store read bytes to rawData
    self.rawData = [[NSMutableData alloc] initWithData:data];

    //cast bytes
    const uint8_t *bytes = [self.rawData bytes];

    //go through rawdata format and save it to networkbuffer
    for (int i =0; i < [self.rawData length]; i++)
    {
        if (![[NSString stringWithFormat:@"%02X", bytes[i]]isEqual:@"0D"])
        {
            [self.networkBuffer addObject:[NSString stringWithFormat:@"%02X", bytes[i]]];
        }
    }

    //negotiate any telnet protocal stuff (just accept options )
    //example:
    //FF:FD:18 returns FF:FB:18
    while([[self.networkBuffer objectAtIndex:0]isEqualToString:@"FF"] && [[self.networkBuffer objectAtIndex:1]isEqualToString:@"FD"] ) {
//        NSLog(@"HERE");

        NSData * tempData =[data subdataWithRange:NSMakeRange(0, 3)];

        NSMutableData * tempMutData = [NSMutableData dataWithData:tempData];

        const unsigned char replacement[] = {
                0xFC
            };

        [tempMutData replaceBytesInRange:NSMakeRange(1, 1) withBytes:replacement];

        [self sendCommand:tempMutData];

        data = [data subdataWithRange:NSMakeRange(3, [data length]-3)];

        self.networkBuffer = [NSMutableArray arrayWithArray:[self.networkBuffer subarrayWithRange:NSMakeRange(3, [self.networkBuffer count]-3)]];

//        NSLog(@"network buffer after removal: %@", data);

        if ([self.networkBuffer count]<3) {
            [self.networkBuffer insertObject:@" " atIndex:0];
        }
    }

    //decode from bytes to text
    for ( NSString * component in self.networkBuffer)
    {
        int value = 0;
        sscanf([component cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
        [self.dataString appendFormat:@"%c", (char)value];
        NSLog(@"data byte: %c",(char)value);
    }
    [self telnetResponse:self.dataString];

    [self.networkBuffer removeAllObjects];
    [self.socket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];//CRLFData
}
Run Code Online (Sandbox Code Playgroud)

以下是接收和发送的telnet协商选项的细分:

服务器发送给我:

FF,FD,18(0x18 = 24dec)(做终端类型)

FF,FD,20(0x20 = 32dec)(终端速度)

FF,FD,23(0x23 = 35dec)(做X显示位置)

FF,FD,27(0x27 = 39dec)(做新环境选项)

我尝试的响应不起作用(没有提示进一步输入):

FF,FC,18(0x18 = 24dec)(不是终端类型)

FF,FC,20(0x20 = 32dec)(终端速度不高)

FF,FC,23(0x23 = 35dec)(不显示X显示位置)

FF,FC,27(0x27 = 39dec)(不适用新环境选项)

如果您查看代码,您将看到我正在检查FF,如果是这样响应类似的字节(用FC替换FD),希望不会接受选项,但这似乎不起作用.

帮助我的链接:

/sf/answers/203979401/

Telnet IAC命令(NSStream套接字)

http://www.iprodeveloper.com/forums/aft/52910

UPDATE

我用命令shell和cisco编解码器做了一个wireshark.之后我复制了那些协商设置/数据包.现在唯一的问题是我只能得到回声.所以我什么也得不到,发送一个命令,然后得到一个提示加上我的文字.(例子.什么都没有 - 发送用户名"admin" - 回来"登录:admin")因此我的意思是只获得回声.我应该得到一个提示"登录:"然后发送"管理员"然后它应该提示我输入密码.

这是我在连接上发送的谈判选项:

//will terminal type
    //will negotiate about window size
    const unsigned char nineteen[] = {
        0xFF, 0xFB, 0x18, 0xFF, 0xFB, 0x1F
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:nineteen length:sizeof(nineteen)];
    [self sendCommand:self.dataToBeSent];

    //wont terminal speed
    //wont X display location
    //will new environment option
    const unsigned char twenty[] = {
        0xFF, 0xFC, 0x20, 0xFF, 0xFC, 0x23, 0xFF, 0xFB, 0x27
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twenty length:sizeof(twenty)];
    [self sendCommand:self.dataToBeSent];

    //Suboption being: negotiate about window size
    //end
    const unsigned char twentyOne[] = {
        //0xFF,0xFC, 0x18
        0xFF, 0xFA, 0x1F, 0x00, 0x50, 0x00, 0x19, 0xFF, 0xF0
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentyOne length:sizeof(twentyOne)];
    [self sendCommand:self.dataToBeSent];

    //new enviroment option
    //end
    const unsigned char twentyThree[] = {
        0xFF,0xFA, 0x27, 0x00, 0xFF, 0xF0
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentyThree length:sizeof(twentyThree)];
    [self sendCommand:self.dataToBeSent];

    //Terminal Type (ANSI)
    //end
    const unsigned char twentySeven[] = {
        0xFF,0xFA, 0x18, 0x00, 0x41, 0x4E, 0x53, 0x49, 0xFF, 0xF0
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentySeven length:sizeof(twentySeven)];
    [self sendCommand:self.dataToBeSent];

    //do suppress go ahead
    const unsigned char twentyEight[] = {
        0xFF, 0xFD, 0x03
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentyEight length:sizeof(twentyEight)];
    [self sendCommand:self.dataToBeSent];

    //will echo
    //dont status
    //wont remote flow control
    const unsigned char twentyFour[] = {
        0xFF, 0xFB, 0x01, 0xFF, 0xFE, 0x05, 0xFF,0xFC, 0x21
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentyFour length:sizeof(twentyFour)];
    [self sendCommand:self.dataToBeSent];

    //wont echo
    const unsigned char twentyFive[] = {
        0xFF, 0xFC, 0x01
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentyFive length:sizeof(twentyFive)];
    [self sendCommand:self.dataToBeSent];

    //Do echo
    const unsigned char twentySix[] = {
        0xFF,0xFD, 0x01
    };
    self.dataToBeSent = [[NSData alloc]initWithBytes:twentySix length:sizeof(twentySix)];
    [self sendCommand:self.dataToBeSent];
Run Code Online (Sandbox Code Playgroud)

owe*_*rig 1

因此,一个大问题来自于提示(登录名:或密码:)没有以 CR NL (0D:0A) 结束行。我正在做

[self.socket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];

所以我从来没有阅读包含提示的数据(一个大问题也是wireshark无法工作(我自己也修复了这个问题))。一旦我弄清楚了这一点,我将上面的行更改为:

[self.socket readDataWithTimeout:-1 tag:0];
Run Code Online (Sandbox Code Playgroud)

这成功地给了我提示。以下是我为达到这一点而发送的谈判以及最初的问题所涉及的内容(与更新中的上述内容相同):

将终端类型 - 0xFF、0xFB、0x18

将协商窗口大小 - 0xFF、0xFB、0x1F

不会终端速度 - 0xFF、0xFC、0x20

不会 X 显示位置 - 0xFF、0xFC、0x23

将新的环境选项 - 0xFF、0xFB、0x27

子选项

 negotiate about window size - 0xFF, 0xFA, 0x1F, 0x00, 0x50, 0x00, 0x19
 end - 0xFF, 0xF0

 new enviroment option - 0xFF,0xFA, 0x27, 0x00, 
 end - 0xFF, 0xF0

 Terminal Type (ANSI) -  0xFF,0xFA, 0x18, 0x00, 0x41, 0x4E, 0x53, 0x49, 
 end - 0xFF, 0xF0
Run Code Online (Sandbox Code Playgroud)

禁止继续 - 0xFF、0xFD、0x03

将回显 - 0xFF、0xFB、0x01

无状态 - 0xFF、0xFE、0x05

不会远程流量控制 - 0xFF、0xFC、0x21

不会回显 - 0xFF、0xFC、0x01

执行回显 - 0xFF、0xFD、0x01

这也可能有帮助。它从流中删除协商字节,因此当您编码生成字符串时,它不包含协商字节。

while([[self.networkBuffer objectAtIndex:0]isEqualToString:@"FF"])
    {
        if ([[self.networkBuffer objectAtIndex:1]isEqualToString:@"FD"] || [[self.networkBuffer objectAtIndex:1]isEqualToString:@"FB"] || [[self.networkBuffer objectAtIndex:1]isEqualToString:@"FE"] || [[self.networkBuffer objectAtIndex:1]isEqualToString:@"FA"]) {

            //most negotiation options are 3 bytes long
            int indexToRemoveFromBuffer = 3;

            //if FA then they are longer then 3 bytes
            if ([[self.networkBuffer objectAtIndex:1]isEqualToString:@"FA"]) {
                //look for indicator of END (F0)
                indexToRemoveFromBuffer = [self.networkBuffer indexOfObject:@"F0"]+1;

            }

            //remove these bytes from networkbuffer
            self.networkBuffer = [NSMutableArray arrayWithArray:[self.networkBuffer subarrayWithRange:NSMakeRange(indexToRemoveFromBuffer, [self.networkBuffer count]-indexToRemoveFromBuffer)]];

            if ([self.networkBuffer count] == 0) {
                if (self.isLoggedIn) {
                    [self.socket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];//CRLFData
                }else{
                    [self.socket readDataWithTimeout:-1 tag:0];
                }
                return;
            }
        }else{
            break;
        }
}
Run Code Online (Sandbox Code Playgroud)