SSH-Client Buffer Problem



  • Hallo,

    Bin dabei einen kleinen SSH - Client für mich zu schreiben, soweit so gut, habe mir bei OpenSSH die RFC's durchgelesen und auch ein "bischen" im Quellcode geschnuppert. Nun hab ich versucht Schritt für Schritt vorzugehen, als erstes der "Version Exchange". Ich melde mich an, empfange z.b "SSH-2.0-OpenSSH_3.9" und versuche nun meinen zu senden (SSH-2.0-OpenSSH_3.9). Jetzt will ich aber wissen, ob der auch angekommen ist, bzw auch richtig. Dazu habe ich nun meinen Code hier unten mal reingestellt:

    char *
    ssh_get_version(int peer) {
      short i = 0;
      ssize_t byte;
      char buf[MAX_VERSION_LEN], *ptr;  // rfc, 255 bytes inklusiv \r\n
    
      ptr = buf;
    
      while (i < MAX_VERSION_LEN) {
        byte = read(peer, ptr + i, 1);
    
        if (byte <= 0) {
          return NULL;
        }
    
        if (*(ptr + i) == '\r') {
          *(ptr + i) = '\0';
        }
    
        if (*(ptr + i) == '\n') {
          *(ptr + i) = '\0';
          return ptr;
        }
        i++;
      }
      return NULL;
    }
    

    Jetzt hab ich den oben genannten Version String in "buf"...

    ssize_t
    ssh_send_version(int peer, char *buf) {
      ssize_t r;
      size_t len;
      char r_buf[1024];
    
      printf("%s", buf);   // wird richtig ausgegeben, "SSH-2.0-OpenSSH_3.9"
      len = strlen(buf) + 1; 
      printf("%s", buf);   // jetzt komischerweise nicht mehr, kommt nur noch müll
    
      *(buf + (len++)) = '\r';
      *(buf + (len++)) = '\n';
    
      if (len + 2 > MAX_VERSION_LEN) {
        return -1;
      }
    
      r = write(peer, buf, len);
    
      if (r <= 0) {
        return 0;
      }
    
    //  read(peer, r_buf, sizeof(r_buf));
    //  r_buf[1024+1] ='\0';
    //  printf("%s", r_buf);
    
      return r;
    }
    

    Nun, da ja erstens oben nach der strlen Funktion nur noch Muell in "buf" steht, wird der string wohl auch nicht richtig gesendet. Hab das dann auch ohne die Funktion gemacht und mal direkt mit write gesendet. Als Antwort kam allerdings auch nichts gescheites, nur "Speicher Müll". Als Anwort sollte afaik ein Int wert kommen, der das erfolgreiche senden representiert oder halt nicht.

    1. Woran liegt es, das der wert von "buf" nach strlen() sich ändert?
    2. Muss ich direkt nach dem senden des Banners, nach der Network Byte Order einlesen? Das hab ich aus dem rfc nicht richtig verstehen können.

    Anbei noch ein Debug Output vom "richtigem" OpenSSH Client:

    debug1: Remote protocol version 2.0, remote software version OpenSSH_3.9
    debug1: match: OpenSSH_3.9 pat OpenSSH*
    debug1: Enabling compatibility mode for protocol 2.0
    debug1: Local version string SSH-2.0-OpenSSH_3.9 <-
    debug2: fd 4 setting O_NONBLOCK
    debug1: SSH2_MSG_KEXINIT sent

    Hoffe mir kann da einer auf die Sprünge helfen...



  • Überprüf mal ob der Buffer wirklich terminiert wird. Wenn du kein \r oder \n einliest, wird dies ja nicht gemacht! Dann erzeugt strlen undefined behaviour.

    Ansonsten ist es nicht klever mit read immer nur 1 byte zu lesen. Versuch immer so viele Daten wie möglich zu lesen, da read ein Systemcall und dementsprechend `teuer` ist.

    Also lieber so

    ssize_t bytes=read(peer, ptr, MAX_VERSION_LEN);
    
    if(ptr[bytes-2]=='\r')
      ptr[bytes-2]=0;
    else if(ptr[bytes-1]=='\n')
      ptr[bytes-1]=0;
    else
      ptr[bytes]=0;
    


  • Danke für den Tip, hab dein Bsp. mal eingebaut und noch ein paar printfs...

    if (ptr[bytes-2]=='\r') {
        ptr[bytes-2]=0;
        printf("return found\n");
      }
      else if (ptr[bytes-1]=='\n') {
        ptr[bytes-1]=0;
        printf("new line found\n");
      }
      else {
        ptr[bytes]=0;
        printf("str end.\n");
      }
    

    ...er gibt mir allerdings nur "new line found" aus.



  • Demanach muss ptr/buf null terminiert sein. Aber das Problem mit strlen besteht komischer weise weiterhin. 😕


Anmelden zum Antworten