SuSE GmbH

SuSE Support-Datenbank

Titel: Dynamische IP-Nummern, ständiger Verbindungsaufbau

----------

Übersicht o Stichwortsuche o History o Versionen o Kategorien o Alle Artikel

----------

Dynamische IP-Nummern, ständiger Verbindungsaufbau

Bezieht sich auf

SuSE Linux: Versionen bis einschließlich 6.2

Jochen Roedenbeck (roe@spl-spindel.de) bietet folgende Lösung an:

Problem:

Es wird wiederholt eine Telefonverbindung zum Provider aufgebaut, ohne dass Daten uebertragen werden (sollen).

(eine) Ursache:

Bei dynamischer IP-Adress-Zuweisung werden alle (TCP-)Verbindungen ungueltig, wenn die Telefonverbindung getrennt wird. Ist die (TCP-)Verbindung nicht geschlossen worden, bauen neue Daten- pakete die Telefonverbindung wieder auf, verfehlen aber stets ihre Wirkung, da der Zielrechner den Wechsel der Absender-IP-Adresse nicht mitvollzieht. So werden sinnlos Telefonkosten verursacht.

Ziel:

Ist die Telefonverbindung getrennt, sollen keine weiteren Daten- pakete fuer die alten (TCP-)Verbindungen mehr weitergeleitet werden. Damit wird auch keine neue Telefonverbindung hergestellt.

Voraussetzungen:

Ueber einen Linux-Router sind mehrere Rechner eines lokalen Netzes an das Internet angeschlossen. Es kommt dynamische IP-Adress- Zuweisung und Masquerading zum Einsatz. Vom Router ausgehende Verbindungen werden stets noch waehrend be- stehender Telefonverbindung wieder abgebaut, d.h. das Problem geht von den im lokalen Netz angeschlossenen Rechnern aus.

Lösungsansatz:

Alle Verbindungen vom lokalen Netz ins Internet werden in /proc/net/ip_masquerade aufgelistet. Beim Abbau der Telefonverbindung wird fuer alle dort aufgefuehrten Verbindungen eine Firewall-Regel zum Zurueckweisen der Daten fuer die betreffende Verbindung eingetragen. Damit werden entsprechende Datenpakete nicht mehr an das ISDN-System weitergeleitet und koennen so auch keine Telefon- verbindung aufbauen. Neue (TCP-)Verbindungen koennen dagegen aufgebaut werden, da deren Adressangaben (Absender-, Ziel- -IP-Adresse, -Port) nicht in den Firewall-Regeln enthalten sind. Dieselben Adressangaben kommen in der Regel nicht so schnell wieder vor, da der Absender-Port dynamisch zugewiesen wird und dieselben Port-Nummern nicht so schnell wieder verwendet werden. Damit die Liste der Firewall-Regeln nicht staendig anwaechst, ist ein Timeout vorgesehen. Nach Ablauf einer gewissen Zeit werden die Firewall-Regeln wieder geloescht. Dies geschieht in der Hoffnung, dass auch auf dem Quell-Rechner der betreffenden Verbindung bis dahin irgendein Timeout zur Wirkung gekommen ist und die Verbindung geschlossen hat.

Programmnutzung:

Es sind zwei Aufrufe des Programms reject-masq noetig: In /etc/ppp/ip-down:
            /sbin/reject-masq --insert
In crontab (als root):
           4,14,24,34,44,54 * * * * /sbin/reject-masq --delete
Der Aufruf in /etc/ppp/ip-down erzeugt die Firewall-Eintraege, der Aufruf ueber cron besorgt das Loeschen. Das Programm kann jederzeit mit "reject-masq -l" aufgerufen werden, um die gespeicherten Verbindungen anzuzeigen.

Dateien:

    
    /sbin/reject-masq       : Programmdatei

    /var/run/MASQ.*         : Speicherung der Firewall-Eintraege
    
    /proc/net/ip_masquerade : Masquerading-Verbindungen

Alternativen:

Der RST-Patch von Erik Corry sollte ebenfalls benutzt werden. Allerdings löst er nicht alle Probleme.

Manche Programme schlieszen eine TCP-Verbindung nicht sofort, wenn die Daten uebertragen sind, sondern halten sie noch einige Zeit ge- oeffnet, ohne weitere Daten zu uebertragen. In der Zeit beendet das ISDN-System dann die Telefonverbindung. Wenn danach die TCP-Verbindung geschlossen wird, wird noch ein IP-Paket verschickt, um die Gegen- seite vom Verbindungsabbau zu informieren. Dabei wird die Telefonverbindung dann wieder aufgebaut und das soll das Programm verhindern. Auszerdem kann die Gegenseite dieses IP-Paket auch gar nicht der noch offenen TCP-Verbindung zuordnen, da es ja mit einer anderen (neuen) Absender-IP-Adresse kommt.

Beobachtet habe ich das Problem, wenn mit mit Netscape 3.01 unter Linux auf Web-Seiten zugreift. Beim Beenden des Netscape-Programms habe ich immer einen erneuten Verbindungsaufbau bekommen. netstat zeigt, dass die http-Verbindungen nach dem Einlesen der Seite nicht sofort geschlossen werden, sondern erst nach einigen Minuten.

Programm:

/***************************************************************************/
/*      Reject old connections after shutting down ISDN link               */
/*      Copyright (C) Jochen Roedenbeck 1998                               */
/***************************************************************************/

/*
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
            
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
*/                        

#define VERSION "0.01"

/* for testing (/sbin/ipfwadm will not be called) */
//#define DEBUG

/*
   If dynamic IP address allocation is used to connect the Internet
   all connections become invalid when the ISDN link is shut down.
   Nevertheless data for these old connections can be sent. This program
   installs firewall rules to reject these data and to prevent the ISDN
   system from calling out for a dead connection.
   
   usage:
   a) reject-masq --insert

      /proc/net/ip_masquerade is read. For each line in this file a
      forwarding firewall rule is installed to reject all packets
      for the connection. A file /var/run/MASQ.* is written containing
      the options for deleting the installed firewall rules.

      This command should be used in /etc/ppp/ip-down.

   b) reject-masq --delete [time-out value]

      /var/run/ is scanned for MASQ.* files. If creation time of the file
      is more than "time-out value" seconds ago the firewall entries 
      listed in the file are deleted by calling /sbin/ipfwadm. The file 
      is deleted, too. If no time-out value is specified 3600s (1h) is
      used.

      This command should be called periodically by a crontab entry.

   c) reject-masq --deleteall

      like b), but delete all firewall entries regardless of time-out value

   d) reject-masq -l

      list /proc/net/ip_masquerade and /var/run/MASQ.*

*/

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/syslog.h>

/* command to install firewall rules */
#define FN_IPFWADM "/sbin/ipfwadm"

#ifndef DEBUG
#define FN_IP_MASQ "/proc/net/ip_masquerade"
#define PTH_DEL_SCR "/var/run"
#else
#define FN_IP_MASQ "./ip_masq"
#define PTH_DEL_SCR "."
#endif
#define REJECT_TIME 3600

typedef unsigned short in_port;

struct t_conn
  {
    struct in_addr fromIP;
    in_port fromPort;
    struct in_addr toIP;
    in_port toPort;
    char protocol[4];
  };
  
char fn_masq[]="/MASQ.";

int next_Port(in_port *erg,char **_x)
  {
    char *x,*x1,s[16];
    x=*_x;
    *erg=0;
    while (*x==' '||*x=='\t') x++;
    x1=x;
    while (isxdigit(*x1)) x1++;
    if (x1-x<sizeof(s))
      {
        memcpy(s,x,x1-x);
        s[x1-x]='\0';
        *erg=htons(strtoul(s,x,16));
      }
    *_x=x1;
    return *erg!=0;
  }

int next_InAddr(struct in_addr *erg,char **_x)
  {
    char *x,*x1,s[16];
    x=*_x;
    erg->s_addr=INADDR_NONE;
    while (*x==' '||*x=='\t') x++;
    x1=x;
    while (isxdigit(*x1)) x1++;
    if (x1-x<sizeof(s))
      {
        memcpy(s,x,x1-x);
        s[x1-x]='\0';
        erg->s_addr=htonl(strtoul(s,x,16));
      }
    *_x=x1;
    return erg->s_addr!=INADDR_NONE;
  }

/* read line of /proc/net/ip_masquerade and convert into struct conn       */
int convFwrdLine(struct t_conn *conn,char *x)
  {
    char *x1;
    memset(conn,0,sizeof(struct t_conn));
    x1=x;
    while (isalpha(*x1)) x1++;
    memcpy(conn->protocol,x,sizeof(conn->protocol));
    conn->protocol[x1-x>=sizeof(conn->protocol)?
                          (sizeof(conn->protocol)-1):(x1-x)]='\0';
    x=x1;
    next_InAddr(&conn->fromIP,&x);
    if (*x==':')
      {
        x++;
        next_Port(&conn->fromPort,&x);
        if (*x==' ')
          {
            next_InAddr(&conn->toIP,&x);
            if (*x==':')
              {
                x++;
                next_Port(&conn->toPort,&x);
                return 0;
              }
          }
      }
    return EOF;
  }

/* convert struct conn into parameters for /sbin/ipfwadm command           */
/* char *s             - string to write                                   */
/* int cmd             - if 1, string starts with "/sbin/ipfwadm"          */
/* int del             - make command for inserting (0) or deleting (1)    */
/* struct t_conn *conn - IP addresses and ports                            */
int makeIPFWcmd(char *s,int cmd,int del,struct t_conn *conn)
  {
    char fromIP[256],toIP[256],prot[sizeof(conn->protocol)],*p;
    strcpy(fromIP,inet_ntoa(conn->fromIP));
    strcpy(toIP,inet_ntoa(conn->toIP));
    strcpy(prot,conn->protocol);
    for (p=prot;p<prot+sizeof(prot);p++) *p=tolower(*p);
    return sprintf(s,"%s -F -%c reject -P %s -S %s/32 %u -D %s/32 %u",
             cmd?(FN_IPFWADM):"",del?'d':'i',prot,
             fromIP,ntohs(conn->fromPort),
             toIP,ntohs(conn->toPort));
  }

/* convert struct conn into parameters for /sbin/ipfwadm command and       */
/* write command to file f                                                 */
int listLineIPFW(FILE *f,struct t_conn *conn,int start)
  {
    if (start)
      {
        return 0;
      }
    else
      {
        char s[512];
        makeIPFWcmd(s,1,0,conn);
        fprintf(f,"%s\n",s);
        makeIPFWcmd(s,1,1,conn);
        fprintf(f,"%s\n",s);
        return 0;
      }
  }

/* convert struct conn into parameters for /sbin/ipfwadm command, call     */
/* "/sbin/ipfwadm -F -i reject ..." and write " -F -d reject ..." to       */
/* file f                                                                  */
int insertRule(FILE *f,struct t_conn *conn,int start)
  {
    if (start)
      {
        return 0;
      }
    else
      {
        char s[512];
        makeIPFWcmd(s,1,0,conn);
        #ifndef DEBUG
        system(s);
        #else
        fprintf(stderr,"%s\n",s);
        #endif
        makeIPFWcmd(s,0,1,conn);
        fprintf(f,"%s\n",s);
        return 0;
      }
  }

/* convert struct conn to ascii and write to a file                        */
int listLine(FILE *f,struct t_conn *conn,int start)
  {
    if (start)
      {
        return fprintf(f,"Prc From                      To\n");
      }
    else
      {
        char fromIP[256],toIP[256];
        strcpy(fromIP,inet_ntoa(conn->fromIP));
        sprintf(fromIP+strlen(fromIP),":%u",ntohs(conn->fromPort));
        strcpy(toIP,inet_ntoa(conn->toIP));
        sprintf(toIP+strlen(toIP),":%u",ntohs(conn->toPort));
        return fprintf(f,"%-3s %-22s -> %-22s\n",conn->protocol,fromIP,toIP);
      }
  }

/* scan /proc/net/ip_masquerade and call _listLine() for each line of the  */
/* file                                                                    */
int list(FILE *para,int (*_listLine)(FILE*,struct t_conn*,int))
  {
    FILE *fi;
    char s[512];
    struct t_conn conn;
    int err;
    err=0;
    if ((fi=fopen(FN_IP_MASQ,"r"))!=NULL)
      {
        fgets(s,sizeof(s),fi);
        if (_listLine(para,NULL,1)!=EOF)
          {
            while (fgets(s,sizeof(s),fi)!=NULL)
              {
                if (convFwrdLine(&conn,s)) 
                  { 
                    syslog(LOG_ERR,"converting error: %s",s);
                    err=EOF; 
                    break; 
                  }
                if (_listLine(para,&conn,0)==EOF) { err=EOF; break; }
              }
          }
        else
          err=EOF;
        fclose(fi);
      }
    return err;
  }

/* scan /proc/net/ip_masquerade, call /sbin/ipfwadm for each line          */
int insertF()
  {
    FILE *f;
    char fn[256];
    int rtn;
    rtn=EOF;
    strcpy(fn,PTH_DEL_SCR);
    strcat(fn,fn_masq);
    sprintf(fn+strlen(fn),"%lX",time(NULL));
    if ((f=fopen(fn,"a"))!=NULL)
      {
        rtn=list(f,insertRule);
        fclose(f);
      }
    return rtn;
  }

/* scan PTH_DELSCR for files MASQ.* */
int deleteF(unsigned long reject_time,int show)
  {
    DIR *f;
    struct dirent *dent;
    char fn[256];
    struct stat stt;
    time_t tm;
    unsigned long waittime;
    time(&tm);
    #ifdef DEBUG
    printf("time()=%lu reject_time=%lus\n",tm,reject_time);
    #endif
    if ((f=opendir(PTH_DEL_SCR))!=NULL)
      {
        while ((dent=readdir(f))!=NULL)
          {
            if (memcmp(dent->d_name,fn_masq+1,4)==0)
              {
                strcpy(fn,PTH_DEL_SCR);
                strcat(fn,"/");
                strcat(fn,dent->d_name);
                stat(fn,&stt);
                waittime=tm-stt.st_ctime;
                #ifdef DEBUG
                printf("%s %lu %lus %s\n",dent->d_name,stt.st_ctime,
                                waittime,waittime>reject_time?"DEL":"WAIT");
                #endif
                if (waittime>reject_time||show)
                  {
                    FILE *fi;
                    char cmd[256],*p;
                    if ((fi=fopen(fn,"r"))!=NULL)
                      {
                        while (fgets(cmd+strlen(FN_IPFWADM),sizeof(cmd)-strlen(FN_IPFWADM),fi)!=NULL)
                          {
                            strcpy(cmd,FN_IPFWADM);
                            cmd[strlen(FN_IPFWADM)]=' ';
                            if ((p=strchr(cmd,'\n'))!=NULL) *p='\0';
                            if (show)
                              {
                                printf("%s(%4lus) %s\n",
                                       waittime>reject_time?"DEL ":"WAIT",
                                       waittime,
                                       cmd+strlen(FN_IPFWADM)+1);
                              }
                            else if (memcmp(cmd+strlen(FN_IPFWADM)," -F -d reject",13)==0)
                              {
                                #ifndef DEBUG
                                system(cmd);
                                #else
                                printf("%s\n",cmd);
                                #endif
                              }
                            else
                              {
                                #ifndef DEBUG
                                syslog(LOG_WARNING,"INVALID: %s",cmd);
                                #else
                                printf("INVALID: %s\n",cmd);
                                #endif
                              }
                          }
                        fclose(fi);
                        if (!show) unlink(fn);
                      }
                  }
              }
          }
        closedir(f);
      }
    return 0;
  }
    
int main(int argc,char **argv)
  {
    int rtn;
    rtn=1;
    openlog(argv[0],LOG_PID,LOG_USER);
    umask(077);
    if (argc>1)
      {
        if (strcmp(argv[1],"-l")==0)
          {
            /* list */
            list(stdout,listLine);
            deleteF(REJECT_TIME,1);
            rtn=0;
          }
        else if (strcmp(argv[1],"--insert")==0)
          {
            /* scan /proc/net/ip_masquerade and insert new firewall rules */
            rtn=insertF()==EOF?1:0;
          }
        else if (strcmp(argv[1],"--delete")==0)
          {
            /* delete timed out firewall rules */
            unsigned long timeout;
            char *ende;
            timeout=REJECT_TIME;
            if (argc>2)
              {
                timeout=strtoul(argv[2],&ende,10);
                if (*ende=='m') 
                  timeout*=60;
                else if (*ende=='h')
                  timeout*=3600;
              }
            if (timeout==0||timeout>24L*3600L) 
              {
                fprintf(stderr,"invalid time-out: %lus\n",timeout);
                return 1;
              }
            rtn=deleteF(timeout,0)==EOF?1:0;
          }
        else if (strcmp(argv[1],"--deleteall")==0)
          {
            /* delete all */
            rtn=deleteF(0,0)==EOF?1:0;
          }
        else
          {
            list(stdout,listLineIPFW);
            rtn=0;
          }
      }
    else
      {
        printf("%s [-l] [--insert] [--delete [time-out]] [--deleteall] [-s]\n",
               argv[0]);
      }
    closelog();
    return rtn;
  }

----------

Siehe auch:

----------

Stichwörter: ISDN, DYNAMISCH, VERBINDUNG, STÄNDIG, MASQUERADE, IPPPD

----------

Kategorien: ISDN

----------

Übersicht o Stichwortsuche o History o Versionen o Kategorien o Alle Artikel

----------

SDB-dyn_masq, Copyright SuSE GmbH, Nuremberg, Germany - Version: 17. Mar 1998
SuSE GmbH - Zuletzt generiert: 24. Jan 2000 17:41:11 by stark with sdb_gen 1.00.0