2014-06-28 1 views
-1

Je fais un serveur et j'ai remarqué qu'il a une fuite de mémoire un peu étrange. Sur mon serveur, j'ai limité le nombre total de connexions qu'une adresse IP peut faire à 8. Cela fonctionne parfaitement.StreamLire ReadLine Memory Leak

Toutefois, lorsque j'utilise LOIC pour DoS mon serveur, je remarque que même s'il crée seulement 8 instances de la classe réseau, la méthode ReadLine de StreamReader occupe une grande partie de la mémoire.

An image of the VS Analyse

J'ai vérifié à l'aide Console.WriteLine qu'aucune donnée ne soit effectivement reçu, il attend simplement à cette méthode. Et la mémoire augmente et remplit tout mon 16Go. Juste pour noter, il y a seulement 8 instances de cette classe d'une IP et comme je suis DoS'ing et non DDoSing il seulement vient jamais de mon IP (j'ai vérifié ceci).

Quelle est la cause de ce problème et comment puis-je le réparer?

EDIT:
Le code pertinent est:

 string data; 
     Dictionary<string, string> variables = null; 
     try { 

      while (_listen) { 

       data = null; 

       while ((data = _reader.ReadLine()) != null) { 
+0

Si vous n'envoyez pas de retour à la ligne ('\ r \ n'), la ligne continuera à augmenter –

+0

@LucasTrzesniewski Je ne choisis pas ce qui est envoyé. C'est une attaque DoS que je cours contre mon serveur. – Brodie

+0

Je sais, ce n'était qu'une explication de la raison pour laquelle la chose consomme de la mémoire. J'impliquais que vous ne devriez pas utiliser 'ReadLine' si vous vous souciez des attaques DoS. –

Répondre

0

La fonction ReadLine en mémoire tampon les données dans une chaîne util rencontre un \r\n (seul \n ne sera pas le faire). Il utilise un StringBuilder pour cela. Ainsi, si les données que vous recevez ne contiennent pas la séquence \r\n, elles finiront par allouer beaucoup de mémoire pour une seule chaîne.

Vous avez ici une solution simple: vous devez limiter la longueur de chaîne maximale que votre serveur est prêt à lire. Ceci est nécessaire pour traiter les données malveillantes - ne faites jamais confiance aux données que vous recevez si votre serveur peut être victime d'attaques DoS.

Ainsi, la solution, en tant que méthode d'extension TextReader:

public static String ReadLineSafe(this TextReader reader, int maxLength) 
{ 
    var sb = new StringBuilder(); 
    while (true) { 
     int ch = reader.Read(); 
     if (ch == -1) break; 
     if (ch == '\r' || ch == '\n') 
     { 
      if (ch == '\r' && reader.Peek() == '\n') reader.Read(); 
      return sb.ToString(); 
     } 
     sb.Append((char)ch); 

     // Safety net here 
     if (sb.Length > maxLength) 
      throw new InvalidOperationException("Line is too long"); 
    } 
    if (sb.Length > 0) return sb.ToString(); 
    return null; 
} 

Voici le code ReadLine original, avec le contrôle de sécurité.

Oh, et vous devriez envelopper votre NetworkStream dans un BufferedStream pour les lectures netowrk, afin d'éviter d'appeler recv sur chaque octet.

+0

Juste une question rapide. Que faire si la longueur des données reçues est imprévisible. Dire que j'ai un type d'utilisateur dans une description, si j'ai spécifié 512 comme maxLength, est-ce qu'il lirait tous les 2048 octets de données? – Brodie

+0

En fonction de votre cas d'utilisation, vous devez réfléchir à une limite supérieure raisonnable pour les données que vous prévoyez recevoir. Par exemple, il est peu probable qu'un utilisateur tape 1 Mo de texte dans un champ. Ensuite, ajoutez une marge de sécurité et utilisez-la. Mais les limites que vous devez définir sont spécifiques à l'application. La fonction ci-dessus ne lira pas plus que les caractères 'maxLength'. –

+0

Très bien, merci. Je vais utiliser ce code. Je vais le marquer comme la réponse si cela fonctionne bien. – Brodie