/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/linux/ax25ip.c (maintained by: DG9OBU) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>l4time = bufpoi->mbpc; /* Check auf Eintrag fuer die default-Route */ if (rp.callsign[0] != 1) putprintf(bufpoi, "%s", call_to_a(&rp.callsign[0])); else putstr("default", bufpoi); putspa(11, bufpoi); /* IP-Adresse ausgeben */ show_ip_addr(ntohl(rp.ip_addr), bufpoi); putspa(29, bufpoi); /* UDP-Port ausgeben wenn UDP-Port gesetzt */ if (rp.udp_port != 0) { /* Eine UDP-Route */ putstr("UDP", bufpoi); putspa(35, bufpoi); putnum(ntohs(rp.udp_port), bufpoi); } else /* Eine IP-Route */ putstr("IP", bufpoi); /* Routen-Timeout anzeigen */ if (rp.timeout != 0) { ULONG d = rp.timeout; ULONG h, m, s; /* Stunden, Minuten, Sekunden */ s = d % 60L; d /= 60L; m = d % 60L; d /= 60L; h = d % 24L; putspa(40, bufpoi); putprintf(bufpoi, " %02lu:%02lu:%02lu", h, m, s); /* hh:mm:ss */ } if (rp.hostname[0] != 0) { putspa(50, bufpoi); putprintf(bufpoi, "%s", rp.hostname); } putstr("\r", bufpoi); } /* Anzahl von IP- oder UDP-Routen in der Routingtabelle feststellen */ /* (IP-Routen haben keinen UDP-Port gesetzt) */ /* UDP = FALSE -> IP-Routen zaehlen, UDP = TRUE -> UDP-Routen zaehlen */ /* Default-Route wird beachtet */ unsigned int count_routes(BOOLEAN udp) { register unsigned int i; register unsigned int j = 0; /* Gesamte Routingtabelle durchgehen */ for (i = 0; i < (unsigned int)route_tbl_top; ++i) { if ( ((udp == TRUE) && (route_tbl[i].udp_port != 0)) /* UDP-Route */ || ((udp == FALSE) && (route_tbl[i].udp_port == 0))) /* IP-Route */ ++j; } /* Default-Route */ if (default_route.callsign[0] != 0) { if ( ((udp == TRUE) && (default_route.udp_port != 0)) /* UDP-Route */ || ((udp == FALSE) && (default_route.udp_port == 0))) /* IP-Route */ ++j; } /* Anzahl Routen melden */ return (j); } /* Timeout fuer gelernte Routen */ void route_age(void) { register unsigned int i = 0; #ifdef AXIPR_HTML /* htmlstatistik-timer. */ h_timer(); #endif /* Gesamte Routingtabelle durchgehen */ for (; i < (unsigned int)route_tbl_top; ++i) { /* Route mit laufendem Timer */ if (route_tbl[i].timeout != 0) { /* Timer laeuft jetzt ab */ if (--route_tbl[i].timeout == 0) /* Route loeschen */ route_del(route_tbl[i].callsign); } } } /* Hostname -> IP-Adressen aufloesen */ void route_update(struct route_table_entry *rtentry) { struct hostent *hstent; /* Kein Hostname, dann auch keine Umwandlung moeglich */ if (rtentry->hostname[0] == 0) return; /* Hostname im IP-Adresse konvertieren */ if ((hstent = gethostbyname((char*)&rtentry->hostname[0])) != NULL) { /* Bei Aenderung uebernehmen */ if (memcmp(&rtentry->ip_addr, &hstent->h_addr_list[0][0], 4) != 0) { /* IP-Adresse hat sich geaendert */ memcpy(&rtentry->ip_addr, &hstent->h_addr_list[0][0], 4); LOGL1("IP-adress for %s changed !", rtentry->hostname); } } #ifdef AXIPR_UDP /* Original UDP-Port setzen. */ rtentry->udp_port = rtentry->org_udp_port; #endif /* AXIPR_UDP */ } /* Partielle Frame-Analyse fuer dyn. Eintraege */ BOOLEAN route_canlearn(MBHEAD *fbp) { char *p; /* Zeiger im Header */ register int n; UBYTE ctl; rwndmb(fbp); /* Frame von vorne */ for (p = rxfhdr, n = 1; n <= L2INUM + L2VNUM; ++n) { if (!getfid(p, fbp)) /* naechstes Call lesen */ return (FALSE); p += L2IDLEN; if (*(p - 1) & L2CEOA) break; /* Ende des Addressfeldes */ } *(p - 1) &= ~L2CEOA; *p = NUL; ctl = getchr(fbp); /* Control-Byte extrahieren */ ctl &= ~L2CPF; /* Poll-Flag loeschen */ /* Nur UI, UA und SABM/SABME erzeugen einen dynamischen Eintrag */ if ( ctl == L2CUI /* UI */ || ctl == L2CUA /* UA */ || ctl == L2CSABM /* SABM */ #ifdef EAX25 || ctl == L2CSABME /* SABME (EAX.25) */ ) #endif return (TRUE); #ifndef AXIPR_UDP /* Alle anderen Kontrollcodes landen hier und bewirken keinen Eintrag */ return (FALSE); #else return (TRUE); #endif } /*************************************************************************/ /* Kommandointerface fuer Operationen auf die AX25IP-Routentabelle */ /*************************************************************************/ /* Eine Route anhand eines Calls loeschen, liefert TRUE wenn erfolgreich */ BOOLEAN route_del(unsigned char *call) { register int i; register int j; /* Soll die Default-Route geloescht werden ? */ if ((call == NULL) || (call[0] == NUL)) { /* Als unbenutzt markieren */ default_route.callsign[0] = NUL; /* Pruefen, ob Sockets noch notwendig */ ax25ip_check_down(); return (TRUE); } /* Uebergebenes Call in der Tabelle suchen */ for (i = 0; i < route_tbl_top; ++i) { if (addrmatch(call, route_tbl[i].callsign)) { /* BINGO ! */ /* Problem: die Tabelle hat keinen Merker, ob ein Eintrag gueltig ist, */ /* die Eintraege haengen einfach hintereinander. Deshalb alle */ /* Eintraege oberhalb des gefundenen Eintrages einen nach */ /* unten kopieren und den "table-top" einen herabsetzen. */ for (j = i; j < route_tbl_top; ++j) route_tbl[j] = route_tbl[j + 1]; /* Ein Tabelleneintrag weniger */ route_tbl_top--; /* Pruefen, ob Sockets noch notwendig */ ax25ip_check_down(); return(TRUE); } } return(FALSE); } static const char inv_mode[] = "Invalid Mode\r"; static const char inv_call[] = "Invalid Callsign\r"; static const char inv_ip[] = "Invalid IP adress\r"; static const char inv_par[] = "Invalid Parameter\r"; void ccpaxipr(void) { MBHEAD *mbp; int port = 0; register int i; int tmp_fd = -1; int new_udp = 0; unsigned char call[L2IDLEN]; char hostname[HNLEN + 1]; struct hostent *host = NULL; int uNewTimeout; #ifdef AXIPR_UDP char *Hostname = hostname; int NewLogLevel = FALSE; #endif #ifdef AXIPR_HTML char *timeset = set_time(); int NewHtmlStat = FALSE; #endif char cBuf[BUFLEN + 1]; unsigned int uCmd = OP_NONE; unsigned int uMode = NO_MODE; #ifdef AXIPR_HTML #define OP_HTMLSTAT 10 #endif memset(hostname, 0, sizeof(hostname)); /* AX25IP ueberhaupt aktiv ? */ if (ax25ip_active == FALSE) { putmsg("No AX25IP-interface present, nothing to configure or show !\r"); return; } /* neuen Parser verwenden ? */ if (new_parser == TRUE) { /* Sysop will aendern und noch was in der Zeile da ? */ if (issyso() && skipsp(&clicnt, &clipoi)) { /* Frischer Buffer */ memset(cBuf, 0, sizeof(cBuf)); /* Operation lesen (add, delete) */ for (i = 0; i < BUFLEN; ++i) { if ((!clicnt) || (*clipoi == ' ')) break; clicnt--; cBuf[i] = toupper(*clipoi++); } /* Zum alten Parser zurueckschalten */ if ( (strcmp(cBuf, "OLD") == 0) || (cBuf[0] == 'O') ) { new_parser = FALSE; putmsg("Switched to old axipr-parser !!!\r"); return; } /* Hinzufuegen (add oder +) */ if ( (strcmp(cBuf, "ADD") == 0) || (cBuf[0] == '+') ) uCmd = OP_ADD; /* Loeschen (delete, del oder -) */ if ( (strcmp(cBuf, "DELETE") == 0) || (strcmp(cBuf, "DEL") == 0) || (cBuf[0] == '-') ) uCmd = OP_DEL; /* eigenen UDP-Port aendern */ if (strcmp(cBuf, "MYUDP") == 0) uCmd = OP_MYUDP; /* Namensaufloesungsintervall einstellen */ if (strcmp(cBuf, "LOOKUP") == 0) uCmd = OP_HNUPD; /* Loglevel */ if ( (strcmp(cBuf, "LOGLEVEL") == 0) || (strcmp(cBuf, "LOG") == 0) ) uCmd = OP_LOG; /* Timeout fuer dynamische Routen */ if (strcmp(cBuf, "TIMEOUT") == 0) uCmd = OP_TIMEOUT; #ifdef AXIPR_HTML /* htmlstatistik */ if ( (strcmp(cBuf, "HTMLSTAT") == 0) || (strcmp(cBuf, "H") == 0)) uCmd = OP_HTMLSTAT; #endif /* Fehler bei der Auswertung ? */ if (uCmd == OP_NONE) { putmsg(inv_mode); return; } /* Hier rein, wenn der Timeout fuer dynamische Routen geaendert werden soll */ if (uCmd == OP_TIMEOUT) { int uNewTimeout; /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); putprintf(mbp, "the actual timeout for dynamic routes is : %u\r", uDynTimeout); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* Timeout lesen */ uNewTimeout = nxtlong(&clicnt, &clipoi); if ( (uNewTimeout < 0) ||(uNewTimeout > (86400))) /* max. 1 Tag */ { putmsg("error: timeout out of range (0 - 86400) !\r"); return; } /* Wert uebernehmen */ uDynTimeout = uNewTimeout; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } /* Hier rein, wenn das Intervall der Namensaufloesung geaendert werden soll */ if (uCmd == OP_HNUPD) { UWORD uNewInterval; /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); putprintf(mbp, "Hostname-update "); if (uNamesUpdate != 0) putprintf(mbp, "occurs every %u seconds.\r", uNamesUpdate / 100); else putprintf(mbp, "is disabled at the moment.\r"); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* Timeout lesen */ uNewInterval = nxtnum(&clicnt, &clipoi); if (uNewInterval > 3600) /* max. eine Stunde */ { putmsg("error: value out of range (0 - 3600 seconds) !\r"); return; } /* Wert uebernehmen */ uNamesUpdate = uNewInterval * 100; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } /* Hier rein, wenn der Loglevel geaendert werden soll */ if (uCmd == OP_LOG) { int new_loglevel; /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); putprintf(mbp, "my actual loglevel is : %u\r", loglevel); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* neues Loglevel lesen */ new_loglevel = nxtnum(&clicnt, &clipoi); if ( (new_loglevel < 0) ||(new_loglevel > 4)) { putmsg("error: loglevel out of range (0 - 4) !!!\r"); return; } /* Wert uebernehmen */ loglevel = new_loglevel; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } #ifdef AXIPR_HTML if (uCmd == OP_HTMLSTAT) { /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); #ifdef SPEECH putprintf(mbp, speech_message(347),HtmlStat); #else putprintf(mbp, "HTML-Statistic is %d\r", HtmlStat); #endif /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* Timeout lesen */ NewHtmlStat = nxtnum(&clicnt, &clipoi); if ( (NewHtmlStat < 0) ||(NewHtmlStat > 1)) { #ifdef SPEECH putmsg(speech_message(300)); #else putmsg("errors: Log level worth from 0 to 1!\r"); #endif return; } /* Wert uebernehmen */ HtmlStat = NewHtmlStat; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } #endif /* AXIPR_HTML */ /* Hier nur rein, wenn wir als naechstes eine UDP-Portnummer erwarten */ if (uCmd == OP_MYUDP) { /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); putprintf(mbp, "my actual UDP-port is : %u\r", ntohs(my_udp)); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* neue UDP-Portnummer lesen */ new_udp = nxtlong(&clicnt, &clipoi); if ( (new_udp <= 0) ||(new_udp > 65535)) { putmsg("error: UDP-port number not valid (0 - 65535) !!!\r"); return; } #ifdef AXIPR_UDP /* Neuer UDP-Port gleich MY-UDP? */ /* Keine Aenderungen durchfuehren. */ if (my_udp == htons((unsigned short)new_udp)) { /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } #endif /* AXIPR_UDP */ #ifndef AXIPR_UDP /* Laufendes UDP aendern */ if (fd_udp != -1) { #endif /* Versuchen, neuen UDP-Port anzulegen */ if ((tmp_fd = setup_udp(htons((unsigned short)new_udp))) != -1) { #ifndef AXIPR_UDP /* Neuen Descriptor eintragen und alten schliessen */ close(fd_udp); #else /* Nur wenn alter Socket noch lebt, */ if (fd_udp != EOF) /* dann schliessen wir den Socket. */ close(fd_udp); #endif /* AXIPR_UDP */ fd_udp = tmp_fd; /* Gibt es einen Eintrag. */ if (l1pp) /* Check, ob neuer Filedescriptor groesser ist */ l1pp->kisslink = max(fd_ip, fd_udp); /* Neuen UDP-Port merken */ my_udp = htons((unsigned short)new_udp); } else { putmsg("error: changing the UDP-port failed !!!\r"); return; } #ifndef AXIPR_UDP } else { /* neuen UDP-Port merken */ my_udp = htons(new_udp); } #endif /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { putmsg("syntax error: callsign missing\r"); return; } /* Frischer Buffer */ memset(cBuf, 0, sizeof(cBuf)); /* Call lesen */ for (i = 0; i < BUFLEN; ++i) { if ((!clicnt) || (*clipoi == ' ')) break; clicnt--; cBuf[i] = toupper(*clipoi++); } /* Operation auf Default-Route ? */ if (strcmp(cBuf, "DEFAULT") == 0) call[0] = NUL; /* Leere Callstring als Indikator fuer Defaultroute */ else { /* Call konvertieren und pruefen */ if (a_to_call(cBuf, call) != 0) { putmsg(inv_call); return; } } /* Wenn wir loeschen wollen, brauchen wir nichts mehr */ if (uCmd != OP_DEL) { /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { putmsg("syntax error: IP-adress missing\r"); return; } /* Frische Buffer */ memset(hostname, 0, sizeof(hostname)); /* Hostnamen / IP-Adresse lesen */ for (i = 0; i < HNLEN; ++i) { if (!clicnt || *clipoi == ' ') break; clicnt--; hostname[i] = *clipoi++; } /* eventuellen Hostnamen aufloesen */ if ((host = gethostbyname(hostname)) == NULL) { mbp = getmbp(); putprintf(mbp, "Warning: can't resolve IP for host %s ! I keep trying ...\r", hostname); prompt(mbp); seteom(mbp); } else { strncpy(hostname, host->h_name, sizeof(hostname)); } } /* if (uCmd != OP_DEL) */ /* Optionale UDP-Parameter lesen */ skipsp(&clicnt, &clipoi); /* Frischer Buffer */ memset(cBuf, 0, sizeof(cBuf)); /* Mode lesen (IP, UDP) */ for (i = 0; i < BUFLEN; ++i) { if ((!clicnt) || (*clipoi == ' ')) break; clicnt--; cBuf[i] = toupper(*clipoi++); } /* Mode bestimmen (UDP) */ /* Bei der Initialisierung wurde bereits IP eingestellt */ if ( (strcmp(cBuf, "UDP") == 0) || (cBuf[0] == 'U') ) uMode = UDP_MODE; /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) port = DEFAULT_UDP_PORT; else { /* neue UDP-Portnummer lesen */ port = nxtlong(&clicnt, &clipoi); if ( (port <= 0) ||(port > 65535)) { putmsg("error: UDP-port number not valid\r"); return; } } /* Operation ausfuehren */ switch (uCmd) { /* Route hinzufuegen */ case OP_ADD : #ifndef AXIPR_UDP route_add((unsigned char*)&hostname, host, call, (uMode == UDP_MODE ? port : 0), (call[0] == 0 ? TRUE : FALSE) break; #else if (route_add((unsigned char*)&hostname , host , call , (uMode == UDP_MODE ? (int)port : 0) , (call[0] == 0 ? TRUE : FALSE) , 0 , hostname #ifdef AXIPR_HTML , timeset , P_USER #endif /* AXIPR_HTML */ )) putmsg("Call is registerd.\r"); return; #endif /* AXIPR_UDP */ /* Route loeschen */ case OP_DEL : #ifndef AXIPR_UDP route_del(call); break; #else if (route_del(call)) putmsg("Call is deleted!\r"); else putmsg("Call no deleted!\r"); return; #endif /* AXIPR_UDP. */ default : break; } mbp = getmbp(); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } } else { /* ALTE SYNTAX */ /* Sysop will aendern und noch was in der Zeile da ? */ if (issyso() && skipsp(&clicnt, &clipoi)) { clicnt--; switch (toupper(*clipoi++)) { case 'P': /* Parser aendern */ /* wir koennen nur in den neuen Parser umschalten */ new_parser = TRUE; putmsg("Switched to new axipr-parser !!!\r"); return; break; case 'R': /* Routen-Eintrag */ /* Kommandozeile pruefen */ if (!skipsp(&clicnt, &clipoi)) { putmsg(inv_par); return; } clicnt--; switch (*clipoi++) { case '-': /* Route loeschen */ /* Call lesen */ if (getcal(&clicnt, &clipoi, TRUE, (char *)call) != YES) { invcal(); return; } /* Call konvertieren */ for (i = 0; i < L2CALEN; ++i) call[i] = call[i] << 1; #ifdef AXIPR_UDP /* und ab die Post ... */ mbp = getmbp(); if (route_del(call)) putstr("Call is delete!\r", mbp); else putstr("Call no delete!\r", mbp); prompt(mbp); seteom(mbp); return; #else /* Route loeschen */ route_del(call); break; #endif /* AXIPR_UDP. */ case '+': /* Route hinzufuegen */ /* Call lesen */ if (getcal(&clicnt, &clipoi, TRUE, (char *)call) != YES) { invcal(); return; } /* Call linksschieben */ for (i = 0; i < L2CALEN; ++i) call[i] = call[i] << 1; /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { putmsg("IP-Adress/Hostname missing\r"); return; } /* Frische Buffer */ memset(hostname, 0, sizeof(hostname)); /* Hostnamen / IP-Adresse lesen */ for (i = 0; i < HNLEN; ++i) { if (!clicnt || *clipoi == ' ') break; clicnt--; hostname[i] = *clipoi++; } /* Hostname / IP-Adresse aufloesen */ if ((host = gethostbyname(hostname)) == NULL) { putmsg(inv_ip); return; } /* Mode-Parameter vorhanden ? */ if (skipsp(&clicnt, &clipoi)) { --clicnt; switch (toupper(*clipoi++)) { case 'I': /* IP: Port steht fest */ break; case 'U': /* UDP: abweichenden Port lesen wenn vorhanden */ nextspace(&clicnt, &clipoi); if (!skipsp(&clicnt, &clipoi)) port = DEFAULT_UDP_PORT; else { port = nxtlong(&clicnt, &clipoi); if ( (port <= 0) ||(port > 65535)) { putmsg("error: UDP-port number not valid\r"); return; } } break; default: /* unbekannter Modus */ putmsg(inv_mode); return; } } /* Route hinzufuegen */ #ifndef AXIPR_UDP route_add((unsigned char*)&hostname, host, call, (int) port, FALSE, 0); break; #else if (route_add((unsigned char*)&hostname , host , call , (int) port , FALSE , 0 , hostname #ifdef AXIPR_HTML , timeset , P_USER #endif /* AXIPR_HTML */ )) putmsg("Call is registerd.\r"); return; #endif /* AXIPR_UDP */ } break; case 'D': /* Default Route aendern */ nextspace(&clicnt, &clipoi); /* Noch Eingaben da ? */ if (!skipsp(&clicnt, &clipoi)) { putmsg(inv_mode); return; } clicnt--; /* Operation bestimmen */ switch (*clipoi++) { case '-': /* Default Route loeschen */ #ifdef AXIPR_UDP /* und ab die Post ... */ mbp = getmbp(); if (route_del((unsigned char *)"")) putstr("Call is delete!\r", mbp); else putstr("Call no delete!\r", mbp); prompt(mbp); seteom(mbp); return; #else route_del((unsigned char *)""); break; #endif /* AXIPR_UDP. */ case '+': /* Default Route eingeben */ /* IP-Adresse / Hostname lesen */ if (!skipsp(&clicnt, &clipoi)) { putmsg(inv_ip); return; } /* Frische Buffer */ memset(hostname, 0, sizeof(hostname)); /* IP-Adresse / Hostname kopieren */ for (i = 0; i < HNLEN; ++i) { if (!clicnt || *clipoi == ' ') break; clicnt--; hostname[i] = *clipoi++; } /* aufloesen */ if ((host = gethostbyname(hostname)) == NULL) { putmsg(inv_ip); return; } /* Modus-Kennzeichner lesen falls vorhanden */ if (skipsp(&clicnt, &clipoi)) { --clicnt; switch (toupper(*clipoi++)) { case 'I': /* IP: Port steht fest */ break; case 'U': /* UDP: eventuell abweichenden Port lesen */ nextspace(&clicnt, &clipoi); if (!skipsp(&clicnt, &clipoi)) port = DEFAULT_UDP_PORT; else { port = nxtlong(&clicnt, &clipoi); if ( (port <= 0) ||(port > 65535)) { putmsg("error: UDP-port number not valid\r"); return; } } break; default: /* unbekannter Modus */ putmsg(inv_mode); return; } } /* Route eintragen */ #ifndef AXIPR_UDP route_add((unsigned char*)&hostname, host, NULL, (int) port, TRUE, 0); break; #else if (route_add((unsigned char*)&hostname , host , NULL , (int) port , TRUE , 0 , hostname #ifdef AXIPR_HTML , timeset , P_USER #endif /* AXIPR_HTML */ )) putmsg("Call is registerd.\r"); return; #endif /* AXIPR_UDP */ default: putmsg(inv_mode); return; } break; /* Eigenen UDP-Port aendern */ case 'U': /* neuer Port muss vorhanden sein */ if (!skipsp(&clicnt, &clipoi)) { putmsg(inv_par); return; } /* Port ermitteln. */ new_udp = nxtlong(&clicnt, &clipoi); if ( (new_udp <= 0) ||(new_udp >= 65535)) { putmsg("UDP-Port not valid, not changed !!!\r"); return; } #ifdef AXIPR_UDP /* Neuer UDP-Port gleich MY-UDP? */ /* Keine Aenderungen durchfuehren. */ if (my_udp == htons((unsigned short)new_udp)) { /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; } #endif /* AXIPR_UDP */ #ifndef AXIPR_UDP /* Laufendes UDP aendern */ if (fd_udp != -1) { #endif /* Versuchen, neuen UDP-Port anzulegen */ if ((tmp_fd = setup_udp(htons((unsigned short)new_udp))) != -1) { #ifndef AXIPR_UDP /* Neuen Descriptor eintragen und alten schliessen */ close(fd_udp); #else /* Nur wenn alter Socket noch lebt, */ if (fd_udp != EOF) /* dann schliessen wir den Socket. */ close(fd_udp); #endif /* AXIPR_UDP */ fd_udp = tmp_fd; /* Gibt es einen Eintrag. */ if (l1pp) /* Check, ob neuer Filedescriptor groesser ist */ l1pp->kisslink = max(fd_ip, fd_udp); /* Neuen UDP-Port merken */ my_udp = htons((unsigned short)new_udp); } else { putmsg("ERROR: Changing UDP-Port failed, Port not changed !!!\r"); return; } #ifndef AXIPR_UDP } else { /* neuen UDP-Port merken */ my_udp = htons(new_udp); } #endif putmsg("UDP-Port successfully changed\r"); #ifdef AXIPR_UDP return; #else break; #endif /* AXIPR_UDP. */ /* Timeout fuer dynamische Routen aendern. */ case 'T': /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); putprintf(mbp, "the actual timeout for dynamic routes is : %u\r", uDynTimeout); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* Timeout lesen */ uNewTimeout = nxtlong(&clicnt, &clipoi); if ( (uNewTimeout < 0) ||(uNewTimeout > (86400))) /* max. 1 Tag */ { putmsg("error: timeout out of range (0 - 86400) !\r"); return; } /* Wert uebernehmen */ uDynTimeout = uNewTimeout; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; #ifdef AXIPR_UDP /* Loglevel aendern. */ case 'L': /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); #ifdef SPEECH putprintf(mbp, speech_message(299),loglevel); #else putprintf(mbp, "My LogLevel: %d\r",loglevel); #endif /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* Loglevel lesen */ NewLogLevel = nxtnum(&clicnt, &clipoi); if ( (NewLogLevel < 0) ||(NewLogLevel > 4)) { #ifdef SPEECH putmsg(speech_message(300)); #else putmsg("errors: Log level worth from 0 to 4!\r"); #endif return; } /* Wert uebernehmen */ loglevel = NewLogLevel; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; #endif /* AXIPR_UDP */ #ifdef AXIPR_HTML /* htmlstatistik aendern. */ case 'H': /* Noch was da in der Kommandozeile ? */ if (!skipsp(&clicnt, &clipoi)) { mbp = getmbp(); #ifdef SPEECH putprintf(mbp, speech_message(347),HtmlStat); #else putprintf(mbp, "HTML-Statistic is %d\r", HtmlStat); #endif /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } /* Loglevel lesen */ NewHtmlStat = nxtnum(&clicnt, &clipoi); if ( (NewHtmlStat < 0) ||(NewHtmlStat > 1)) { #ifdef SPEECH putmsg(speech_message(348)); #else putmsg("Error: HTML-Statistic worth from 0 to 1!\r\r"); #endif return; } /* Wert uebernehmen */ HtmlStat = NewHtmlStat; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); return; #endif /* Unbekannte Kommandos */ default: putmsg(inv_par); return; } } } mbp = putals("AXIP-Routes:\rCall-------IP----------------Mode--Port--Timeout--IP/Hostname----\r"); /* Alle Routingtabelleneintraege durchgehen und ausgeben */ for (i = 0; i < route_tbl_top; ++i) show_rt_entry(route_tbl[i], mbp); /* Default-Route ausgeben wenn vorhanden */ if (default_route.callsign[0] == 1) show_rt_entry(default_route, mbp); putprintf(mbp, "-----------------------------------------------------------------\r"); /* Eigenen UDP-Port ausgeben */ putprintf(mbp, "UDP-port (%u): ", ntohs(my_udp)); putprintf(mbp, "%s", (fd_udp != -1 ? "active" : "not active")); /* IP-Status ausgeben */ putprintf(mbp, ", IP-protocol (family %u): ", IPPROTO_AX25); putprintf(mbp, "%s", (fd_ip != -1 ? "active" : "not active")); /* Timeout des dynamischen Routenlerners ausgeben */ putprintf(mbp, "\rTimeout for dynamically learned routes is %u seconds.\r", uDynTimeout); /* Hostname -> IP-Adresse Aktualisierungsintervall ausgeben */ putprintf(mbp, "Hostname-to-IP-adress conversion "); if (uNamesUpdate != 0) putprintf(mbp, "occurs every %u seconds.\r", uNamesUpdate / 100); else putprintf(mbp, "is disabled.\r"); #ifdef AXIPR_UDP #ifdef SPEECH putprintf(mbp, speech_message(299), loglevel); #else putprintf(mbp, "My LOGLevel is %u.\r", loglevel); #endif /* SPEECH */ #endif /* AXIPR_UDP */ #ifdef AXIPR_HTML #ifdef SPEECH putprintf(mbp, speech_message(347), HtmlStat); #else putprintf(mbp, "My HTML-Statistic is %d.\r", HtmlStat); #endif /* SPEECH */ #endif /* AXIPR_HTML */ /* und ab die Post ... */ prompt(mbp); seteom(mbp); } /* Routeneintraege fuer parms.tnb ausgeben */ void dump_ax25ip(MBHEAD* mbp) { register int i; putstr(";\r; AX25IP Routes\r;\r", mbp); if (ax25ip_active == FALSE) return; if (new_parser == TRUE) { putstr("; WARNING: this section is written using the new syntax of the AXIPR-command,\r", mbp); putstr("; DO NOT USE with older TNNs compiled only for old style syntax !!!\r;\r", mbp); /* Falls wir noch im alten Parser sind, dann umschalten */ putprintf(mbp, "AXIPR P\r"); /* eigenen UDP-Port ausgeben */ putprintf(mbp, "AXIPR MYUDP %u\r", ntohs(my_udp)); /* Timeout fuer dynamische Routen ausgeben */ putprintf(mbp, "AXIPR TIMEOUT %u\r", uDynTimeout); /* Intervall fuer Hostnamen-Update ausgeben */ putprintf(mbp, "AXIPR LOOKUP %u\r", uNamesUpdate); } #ifdef AXIPR_UDP /* eigenen UDP-Port ausgeben */ putprintf(mbp, "AXIPR U %u\r", ntohs(my_udp)); /* Timeout fuer dynamische Routen ausgeben */ putprintf(mbp, "AXIPR T %u\r", uDynTimeout); putprintf(mbp, "AXIPR L %d\r",loglevel); #ifdef AXIPR_HTML putprintf(mbp, "AXIPR H %d\r",HtmlStat); #endif /* AXIPR_HTML */ #endif /* AXIPR_UDP */ /* alle Routingtabelleneintraege durchgehen und ausgeben */ for (i = 0; i < route_tbl_top; ++i) { /* Dynamisch gelernte Routen werden inaktiv zur Information geschrieben ! */ if (route_tbl[i].timeout != 0) continue; /* putprintf(mbp, "; ");*/ /* Eintrag einer Route erzeugen */ putprintf(mbp, (new_parser == FALSE ? "AXIPR R + %s " : "AXIPR ADD %s ") , call_to_a(&route_tbl[i].callsign[0])); /* Den Hostnamen ausgeben */ putprintf(mbp, "%s", route_tbl[i].hostname); /* Mode und ggf. Port ausgeben wenn UDP */ if (route_tbl[i].udp_port != 0) { putstr((new_parser == FALSE ? " U " : " UDP "), mbp); putnum(ntohs(route_tbl[i].udp_port), mbp); } putstr("\r", mbp); } /* Die Defaultroute ausgeben wenn gesetzt */ if (default_route.callsign[0] == 1) { /* Kommandokopf schreiben */ putstr((new_parser == FALSE ? "AXIPR D + " : "AXIPR ADD DEFAULT "), mbp); /* Den Hostnamen ausgeben */ putprintf(mbp, "%s", default_route.hostname); /* Mode und ggf. Port ausgeben wenn UDP */ if (default_route.udp_port != 0) { putstr((new_parser == FALSE ? " U " : " UDP "), mbp); putnum(ntohs(default_route.udp_port), mbp); } putstr("\r", mbp); } } /************************************************************************/ /* AX25IP Initialisierung */ /************************************************************************/ BOOLEAN ax25ip_l1init(int l2port) { if (ax25ip_active == TRUE) return(TRUE); /* Socketstrukturen initialisieren */ memset((char*)&to, 0, sizeof(to)); memset((char*)&from, 0, sizeof(from)); ax25ip_port = l2port; l1pp = &l1port[l1ptab[l2port]]; l2flp = (LHEAD *) &txl2fl[l2port]; /* Routingtabelle initialisieren */ route_init(); /* Konfiguration einlesen */ if (config_read() == FALSE) return(FALSE); /* Notwendige Sockets anlegen */ #ifndef AXIPR_UDP ax25ip_check_up(); #endif /* Wir sind fertig */ ax25ip_active = TRUE; return(TRUE); } /* Einen Filedescriptor fuer IP anlegen */ int setup_ip(void) { /* Temporaerer Filedescriptor */ int tmp_fd = -1; /* Adressstruktur loeschen */ memset((char*)&ipbind, 0, sizeof(ipbind)); /* Rohen IP-Socket anlegen */ if ((tmp_fd = socket(AF_INET, SOCK_RAW, IPPROTO_AX25)) < 0) { xprintf("AX25IP : cannot create ip raw-socket: %s\n", strerror(errno)); LOGL2("AX25IP : cannot create ip raw-socket: %s\n", strerror(errno)); return(-1); } /* Nonblocking-IO */ if (fcntl(tmp_fd, F_SETFL, FNDELAY) < 0) { xprintf("AX25IP : cannot set non-blocking I/O on ip raw-socket\n"); LOGL2("AX25IP : cannot set non-blocking I/O on ip raw-socket\n"); close(tmp_fd); return(-1); } /* Adressstruktur mit notwendigen Werten fuellen */ ipbind.sin_family = AF_INET; ipbind.sin_addr.s_addr = htonl(INADDR_ANY); return (tmp_fd); } /* Einen Filedescriptor fuer UDP anlegen */ /* Es muss der UDP-Port angegeben werden, auf dem wir hoeren wollen */ /* (Achtung: UDP-Port in Network-Byteorder) */ int setup_udp(unsigned short udp_port) { /* Temporaerer Filedescriptor */ int tmp_fd = -1; /* Port-Check */ if (udp_port == 0) return(-1); /* Adressstruktur loeschen */ memset((char*)&udpbind, 0, sizeof(udpbind)); /* UDP-Socket anlegen */ if ((tmp_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { xprintf("AX25IP : cannot create socket: %s\n", strerror(errno)); LOGL2("AX25IP : cannot create socket: %s\n", strerror(errno)); return(-1); } /* Nonblocking-IO */ if (fcntl(tmp_fd, F_SETFL, FNDELAY) < 0) { xprintf("AX25IP : cannot set non-blocking I/O on udp socket\n"); LOGL2("AX25IP : cannot set non-blocking I/O on udp socket\n"); close(tmp_fd); return(-1); } /* Socket-Optionen fuer UDP einstellen */ /* SO_KEEPALIVE einschalten */ if (sockopt_keepalive == TRUE) { int iFlag = 1; if (setsockopt(tmp_fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&iFlag, sizeof(int)) < 0) { xprintf("AX25IP : cannot set SO_KEEPALIVE for udp : %s\n", strerror(errno)); LOGL2("AX25IP : cannot set SO_KEEPALIVE for udp : %s\n", strerror(errno)); } } /* Socket auf max. Durchsatz */ if (sockopt_throughput == TRUE) { int iFlag = IPTOS_THROUGHPUT; if (setsockopt(tmp_fd, IPPROTO_IP, IP_TOS, (const char *)&iFlag, sizeof(IPTOS_THROUGHPUT)) < 0) { xprintf("AX25IP : cannot set IPTOS_THROUGHPUT for udp : %s\n", strerror(errno)); LOGL2("AX25IP : cannot set IPTOS_THROUGHPUT for udp : %s\n", strerror(errno)); } } /* Adressstruktur fuellen */ udpbind.sin_addr.s_addr = htonl(INADDR_ANY); udpbind.sin_port = udp_port; udpbind.sin_family = AF_INET; /* Adresse und Port binden */ if (bind(tmp_fd, (struct sockaddr *)&udpbind, sizeof(udpbind)) < 0) { xprintf("AX25IP : cannot bind udp socket: %s\n", strerror(errno)); LOGL2("AX25IP : cannot bind udp socket: %s\n", strerror(errno)); close(tmp_fd); return(-1); } return(tmp_fd); } /* Pruefen, ob schon Sockets angelegt sind, wenn nicht, dann notwendige */ /* Sockets oeffnen */ void ax25ip_check_up(void) { /* IP notwendig ? */ if ((count_routes(FALSE) != 0) && (fd_ip == -1)) fd_ip = setup_ip(); /* IP starten */ /* UDP notwendig ? */ if ((count_routes(TRUE) != 0) && (fd_udp == -1)) fd_udp = setup_udp(my_udp); /* UDP starten */ #ifdef AXIPR_UDP if (l1pp != NULL) #endif /* Markieren, ob IP oder UDP laufen */ l1pp->kisslink = max(fd_ip, fd_udp); } /* Pruefen, ob Sockets angelegt sind und diese noch benoetigt werden. */ /* Falls nicht, Sockets schliessen */ void ax25ip_check_down(void) { /* IP notwendig ? */ if ((count_routes(FALSE) == 0) && (fd_ip != -1)) { close(fd_ip); fd_ip = -1; } /* UDP notwendig ? */ if ((count_routes(TRUE) == 0) && (fd_udp != -1)) { close(fd_udp); fd_udp = -1; } /* Gibt es einen Eintrag. */ if (l1pp) /* Markieren, ob IP oder UDP laufen */ l1pp->kisslink = max(fd_ip, fd_udp); } /*************************************************************************/ /* AX25IP Pakete empfangen */ /*************************************************************************/ void ax25ip_recv(void) { struct iphdr *ipptr; struct timeval tv; int l = 0; int iDescriptorsReady = 0; register int i = 0; register int max_fd = -1; socklen_t fromlen = sizeof(from); int hdr_len = 0; UBYTE buf[MAX_FRAME+1]; UBYTE *bufptr; MBHEAD *rxfhd; BOOLEAN UDP_Frame = FALSE; fd_set rmask; #ifdef AXIPR_UDP if (LookAX25IP) return; #endif /* AX25IP_UDP */ FD_ZERO(&rmask); /* IP-Filedescriptor eintragen */ if (fd_ip != -1) { FD_SET((unsigned int)fd_ip, &rmask); if (fd_ip > max_fd - 1) max_fd = fd_ip + 1; } /* UDP-Filedescriptor eintragen */ if (fd_udp != -1) { FD_SET((unsigned int)fd_udp, &rmask); if (fd_udp > max_fd - 1) max_fd = fd_udp + 1; } /* ist was aktiv ? */ if (max_fd == -1) return; tv.tv_usec = 0; tv.tv_sec = 0; iDescriptorsReady = select(max_fd, &rmask, NULL, NULL, &tv); /* nix da */ if (iDescriptorsReady == 0) return; /* Fehler */ if (iDescriptorsReady == -1) { LOGL2("select()-Error %i: %s", errno, strerror(errno)); return; } /* RX fuer IP */ if ((fd_ip != -1) && (FD_ISSET(fd_ip, &rmask))) { l = recvfrom(fd_ip, (UBYTE *)(bufptr = buf), MAX_FRAME, 0, (struct sockaddr *) &from, &fromlen); if (l > 0) { if (l > (signed)sizeof(struct iphdr*)) { ipptr = (struct iphdr*)buf; hdr_len = 20; if (!ok_crc(buf + hdr_len, l - hdr_len)) { /* stimmt die CRC ? */ LOGL2("IP-RX: CRC-Error, frame dropped"); return; /* Fehler */ } } else { LOGL2("IP-RX: frame too short, frame dropped"); return; /* Fehler */ } } i = hdr_len; } /* RX fuer UDP, aber nur, wenn nicht schon TCP was empfangen hat */ if ((fd_udp != -1) && (FD_ISSET(fd_udp, &rmask) && (l == 0))) { l = recvfrom(fd_udp, (UBYTE *)(bufptr = buf), MAX_FRAME, 0, (struct sockaddr *) &from, &fromlen); if (l > 0) { if (!ok_crc(buf, l)) { /* stimmt die CRC ? */ LOGL2("UDP-RX: CRC-Error, frame dropped"); return; /* Fehler */ } } UDP_Frame = TRUE; } /* Ab hier gemeinsame Behandlung */ /* Erst mal gucken, ob was gekommen ist */ if (l == 0) return; /* nix da */ l -= 2; /* CRC abschneiden */ if (l < 15) { LOGL2("AX25IP: RX frame dropped, length wrong, frame is too short !"); return; } /* Hier angekommen haben wir (hoffentlich) ein gueltiges Frame. Die */ /* weitere Behandlung ist fuer IP und UDP nahezu identisch. */ /* Frame in Buffer umkopieren und Empfangsport eintragen */ rxfhd = cpyflatmb((char*)&buf[i], l - i); rxfhd->l2port = ax25ip_port; /* Frame in die L2-RX-Kette einhaengen */ relink((LEHEAD *)rxfhd, (LEHEAD *)rxfl.tail); /* Jetzt noch das Frame an den Routenlerner zur Analyse */ if (route_canlearn(rxfhd)) { /* Frame kann zum Lernen benutzt werden */ /* Absenderrufzeichen ermitteln und konvertieren */ /* Wir brauchen hier nicht den eigentlichen Absender, */ /* sondern den, der als letztes gedigipeated hat. */ struct in_addr ipaddr; #ifndef AXIPR_UDP struct route_table_entry* rtptr; #endif /* AXIPR_UDP */ unsigned char srccall[L2IDLEN + 1]; cpyid((char *)srccall, dheardcall(rxfhdr)); /* Call linksschieben */ for (i = 0; i < L2CALEN; ++i) srccall[i] = srccall[i] << 1; /* Gibt es schon eine IP fuer dieses Call, dann kann sich die IP */ /* geaendert haben. Falls ja und es sich um einen dynamischen Eintrag */ /* handelt, dann loeschen und neuen Eintrag anlegen. */ #ifndef AXIPR_UDP if ((rtptr = call_to_ip(srccall)) != NULL) { if (( (rtptr->ip_addr != from.sin_addr.s_addr) || (rtptr->udp_port != (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0))) && (rtptr->timeout != 0)) route_del(srccall); /* Route loeschen */ else { if (rtptr != &default_route) return; /* Adresse unveraendert */ } } #endif /* AXIPR_UDP */ ipaddr.s_addr = from.sin_addr.s_addr; #ifndef AXIPR_UDP /* Route eintragen */ route_add((unsigned char*)inet_ntoa(ipaddr), NULL, srccall, (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0), FALSE, uDynTimeout); #else route_analyse(ipaddr, srccall, (UDP_Frame == TRUE ? ntohs(from.sin_port) : 0)); } #endif /* AXIPR_UDP */ } /*************************************************************************/ /* AX25IP Pakete senden */ /*************************************************************************/ void ax25ip_send(void) { unsigned char buf[MAX_FRAME]; int len = 0; int fd = -1; MBHEAD *txfhdl; struct route_table_entry *rt; struct hostent *hstent; unsigned char *call; if (kick[ax25ip_port]) /* haben wir was zu senden ? */ { /* Sicherheitsabfrage, da kick[] auch manipuliert werden kann */ if (l2flp->head == l2flp) { kick[ax25ip_port] = FALSE; return; } ulink((LEHEAD *)(txfhdl = (MBHEAD *) l2flp->head));/*Zeiger holen*/ /* Daten aus den internen Puffern in einen linearen Puffer uebertragen */ len = cpymbflat((char*)&buf[0], txfhdl); relink((LEHEAD *)txfhdl, /* als gesendet betrachten und in */ (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ kick[ax25ip_port] = ((LHEAD *)l2flp->head != l2flp); /* Naechstes Call der Digipeaterkette holen */ call = next_addr(buf); /* IP-Adresse des naechsten Digipeaters ermitteln */ rt = call_to_ip(call); if (rt == NULL) /* wir kennen das Ziel nicht */ { #ifdef AXIPR_UDP if ((rt = search_route(call)) == NULL) { #endif LOGL2("no route for %s, can't send", call_to_a(call)); return; } #ifdef AXIPR_UDP } #endif /* Ein Host, zu dem bisher keine IP-Adresse aufgeloest werden konnte */ if (rt->ip_addr == 0L) { /* Versuchen, jetzt eine IP-Adresse zu bestimmen */ if ((hstent = gethostbyname((char*)rt->hostname)) != NULL) memcpy((unsigned char*)&rt->hostname, (unsigned char *)&hstent->h_addr_list[0][0], 4); } /* Checksumme anhaengen */ add_ax25crc(buf, len); /* CRC-Bytes sind dazugekommen */ len += 2; /* Ziel-IP-Adresse in Sendestruktur eintragen */ memcpy((char *) &to.sin_addr, (char *)&rt->ip_addr, 4); /* Ziel-Port nur bei UDP eintragen */ if (rt->udp_port != 0) memcpy((char *) &to.sin_port, (char *)&rt->udp_port, 2); else to.sin_port = 0; /* bei IP kein Port */ to.sin_family = AF_INET; /* Unterscheidung IP oder UDP */ if (to.sin_port == 0) fd = fd_ip; else fd = fd_udp; if (fd == -1) { LOGL2("error: no descriptor, can't send !!!"); return; } if (sendto(fd, (char *)buf, len, 0, (struct sockaddr *)&to, sizeof(to)) < 0) LOGL2("error: sendto failed, fd=%u error=%s", fd, strerror(errno)); } } /*************************************************************************/ /* AX25IP Deinitialisierung, Port und Sockets schliessen */ /*************************************************************************/ void ax25ip_l1exit(void) { /* Nur wenn aktiv */ if (ax25ip_active == FALSE) return; /* IP-Socket schliessen wenn offen */ if (fd_ip != -1) { close(fd_ip); fd_ip = -1; } /* UDP-Socket schliessen wenn offen */ if (fd_udp != -1) { close(fd_udp); fd_udp = -1; } /* AX25IP nicht mehr aktiv */ ax25ip_active = FALSE; /* Gibt es einen Eintrag. */ if (l1pp) l1pp->kisslink = -1; } void ax25ip_l1ctl(int req, int port) { /* nur eigene Ports bearbeiten */ if ((ax25ip_active == FALSE) || (kissmode(port) != KISS_AXIP)) return; switch (req) { /* Testpattern auf dem Port senden (wird unterdrueckt) */ case L1CTST : testflag[port] = FALSE; kick[port] = FALSE; break; default : break; } } void ax25ip_hwstr(int port, MBHEAD *mbp) { #ifdef AXIPR_UDP putstr(" ", mbp); /* My UDP-Port ausgeben. */ putprintf(mbp,"%u", ntohs(my_udp)); #endif } BOOLEAN ax25ip_dcd(int port) { return (FALSE); } /* routing.c Routing table manipulation routines * * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc. * This software may be freely used, distributed, or modified, providing * this header is not removed. * * Modified for use in TNN by DG1KWA & DG9OBU */ /* Initialize the routing table */ void route_init(void) { /* Defaultroute initialisieren */ memset(&default_route, 0 , sizeof(struct route_table_entry)); /* Routen initialisieren */ memset(&route_tbl, 0, (TABLE_SIZE * sizeof(struct route_table_entry))); } /* Add a new route entry */ #ifndef AXIPR_UDP static void route_add(unsigned char* hostname, struct hostent *hstent, unsigned char *call, int udpport, int default_rt, int timeout) #else static BOOLEAN route_add(unsigned char *host, struct hostent *hstent, unsigned char *call, int udpport, int default_rt, int timeout, char *hostname #ifdef AXIPR_HTML , char *timeset, UWORD protokoll #endif /* AXIPR_HTML */ ) #endif /* AXIPR_UDP */ { register unsigned int i = 0; struct route_table_entry *rtptr; struct hostent *hst; /* Eintrag soll Defaultroute sein */ if (default_rt) { for (i = 1; i < 7 ;++i) default_route.callsign[i] = 0; if (hstent != NULL) memcpy(&default_route.ip_addr, (unsigned char *)&hstent->h_addr_list[0][0], 4); else memset(&default_route.ip_addr, 0, 4); default_route.udp_port = htons((unsigned short)udpport); default_route.timeout = 0; /* Defaultroute ohne Timeout */ if (hostname != NULL) strncpy((char*)&default_route.hostname, (char*)hostname, HNLEN); default_route.callsign[0] = 1; /* mark valid */ /* Socket ggf. installieren */ ax25ip_check_up(); #ifndef AXIPR_UDP return; #else return(TRUE); #endif /* AXIPR_UDP */ } /* Normale Routen nur wenn Call vorhanden */ if (call == NULL) #ifndef AXIPR_UDP return; #else return(FALSE); #endif /* AXIPR_UDP */ /* Check auf doppelte Eintraege, Eintrag wird nur angenommen wenn */ /* es noch noch keinen Eintrag unter diesem Call gibt. */ if (((rtptr = call_to_ip(call)) != NULL) && (rtptr->ip_addr != default_route.ip_addr)) { #ifndef AXIPR_UDP putmsg("A route to this callsign is already set up, delete it first.\r"); return; #else #ifndef AXIPR_HTML UpdateRoute(call, udpport, timeout, hostname); #else UpdateRoute(call, udpport, timeout, hostname, timeset, protokoll); #endif /* AXIPR_HTML */ return(FALSE); #endif /* AXIPR_UDP */ } /* Passt noch ein Eintrag in die Tabelle ? */ if (route_tbl_top >= TABLE_SIZE) { xprintf("Routing table is full; entry ignored.\n"); LOGL2("Routing table is full; entry ignored"); putmsg("Routing table is full, entry ignored\r"); #ifndef AXIPR_UDP return; #else return(FALSE); #endif /* AXIPR_UDP */ } /* Call eintragen */ for (i = 0; i < 6; ++i) route_tbl[route_tbl_top].callsign[i] = call[i] & 0xfe; /* SSID eintragen */ route_tbl[route_tbl_top].callsign[6] = (call[6] & 0x1e) | 0x60; if (hstent != NULL && hstent->h_length != 0) { memcpy((unsigned char*)&route_tbl[route_tbl_top].ip_addr, (unsigned char *)&hstent->h_addr_list[0][0], 4); } else memset(&route_tbl[route_tbl_top].ip_addr, 0, sizeof(route_tbl[route_tbl_top].ip_addr)); route_tbl[route_tbl_top].udp_port = htons((unsigned short)udpport); route_tbl[route_tbl_top].timeout = timeout; if (hostname != NULL) { memcpy(&route_tbl[route_tbl_top].hostname, hostname, strlen((char*)hostname)); /* Keine Adressaufloesung bisher, dann probieren wir es noch einmal */ if (hstent == NULL) { if ((hst = gethostbyname((char*)hostname)) != NULL) memcpy((unsigned char*)&route_tbl[route_tbl_top].ip_addr, &hst->h_addr_list[0][0], 4); } } #ifdef AXIPR_UDP /* Original UDP-Port eintragen. */ route_tbl[route_tbl_top].org_udp_port = htons((UWORD)udpport); #endif #ifdef AXIPR_HTML /* Hostname eintragen. */ (void)memcpy(route_tbl[route_tbl_top].timeset, timeset, 17); /* Protokoll eintragen. */ route_tbl[route_tbl_top].protokoll = P_USER; /* Route als offline markieren. */ route_tbl[route_tbl_top].online = FALSE; #endif /* Ein Routeneintrag mehr */ route_tbl_top++; /* Socket ggf. installieren */ ax25ip_check_up(); #ifndef AXIPR_UDP return; #else return(TRUE); #endif /* AXIPR_UDP */ } /* * Return an IP address and port number given a callsign. * We return a pointer to the route structure for this callsign * or a NULL-pointer if no route was found. */ struct route_table_entry* call_to_ip(unsigned char *call) { register int i; unsigned char mycall[7]; /* Leere Calls koennen nicht verarbeitet werden */ if (call == NULL) return (NULL); /* Call-Bytes kopieren, letztes Bit abschneiden (entspricht >> 1 & 7F) */ for (i = 0; i < 6; ++i) mycall[i] = call[i] & 0xfe; /* SSID kopieren */ mycall[6] = (call[6] & 0x1e) | 0x60; /* Routingtabelle durchsuchen */ for (i = 0; i < route_tbl_top; ++i) { if (addrmatch(mycall , route_tbl[i].callsign)) { /* Aktivitaet auf diesem Eintrag, dann Timeout erneuern */ if (route_tbl[i].timeout) route_tbl[i].timeout = uDynTimeout; return (&route_tbl[i]); /* Eintrag gefunden */ } } /* Kein Routingeintrag vorhanden, Default-Route melden wenn vorhanden */ if (default_route.callsign[0]) return (&default_route); /* Kein Routingeintrag gefunden, keine Defaultroute */ return (NULL); } /* * tack on the CRC for the frame. Note we assume the buffer is long * enough to have the two bytes tacked on. */ void add_ax25crc(unsigned char *buf, int l) { unsigned short int u = compute_crc(buf, l); buf[l] = u & 0xff; /* lsb first */ buf[l + 1] = (u >> 8) & 0xff; /* msb next */ } /* ********************************************************************** * The following code was taken from Appendix B of RFC 1171 * (Point-to-Point Protocol) * * The RFC credits the following sources for this implementation: * * Perez, "Byte-wise CRC Calculations", IEEE Micro, June, 1983. * * Morse, G., "Calculating CRC's by Bits and Bytes", Byte, * September 1986. * * LeVan, J., "A Fast CRC", Byte, November 1987. * * * The HDLC polynomial: x**0 + x**5 + x**12 + x**16 */ /* * u16 represents an unsigned 16-bit number. Adjust the typedef for * your hardware. */ /*typedef unsigned short u16;*/ /* * FCS lookup table as calculated by the table generator in section 2. */ static UWORD fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; #define PPPINITFCS 0xffff /* Initial FCS value */ #define PPPGOODFCS 0xf0b8 /* Good final FCS value */ /* * Calculate a new fcs given the current fcs and the new data. */ UWORD pppfcs(register UWORD fcs, register unsigned char *cp, register int len) { while (len--) fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; return(fcs); } /* * End code from Appendix B of RFC 1171 ********************************************************************** */ /* * The following routines are simply convenience routines... * I'll merge them into the mainline code when suitably debugged */ /* Return the computed CRC */ UWORD compute_crc(unsigned char *buf, int l) { UWORD fcs = (pppfcs(PPPINITFCS, buf, l) ^ 0xFFFF); return (fcs); } /* Return true if the CRC is correct */ BOOLEAN ok_crc(unsigned char *buf, int l) { UWORD fcs = pppfcs(PPPINITFCS, buf, l); return (fcs == PPPGOODFCS); } /* return true if the addresses supplied match */ int addrmatch(unsigned char *a, unsigned char *b) { if ((*a == '\0') || (*b == '\0')) return(0); if ((*a++ ^ *b++) & 0xfe) return(0); /* "K" */ if ((*a++ ^ *b++) & 0xfe) return(0); /* "A" */ if ((*a++ ^ *b++) & 0xfe) return(0); /* "9" */ if ((*a++ ^ *b++) & 0xfe) return(0); /* "W" */ if ((*a++ ^ *b++) & 0xfe) return(0); /* "S" */ if ((*a++ ^ *b++) & 0xfe) return(0); /* "B" */ if ((*a++ ^ *b++) & 0x1e) return(0); /* ssid */ return(1); } /* return pointer to the next station to get this packet */ unsigned char *next_addr(unsigned char *f) { unsigned char *a; /* If no digis, return the destination address */ if (NO_DIGIS(f)) return(f); /* check each digi field. The first one that hasn't seen it is the one */ a = f + 7; do { a += 7; if (NOTREPEATED(a)) return(a); } while (NOT_LAST(a)); /* all the digis have seen it. return the destination address */ return(f); } /* Open and read the config file */ int config_read(void) { FILE *cf; char buf[256], cbuf[256]; int errflag = 0; int e = 0; int lineno = 0; char cfgfile[256]; strcpy(cfgfile, confpath); strcat(cfgfile, CONFIG_FILE); if ((cf = fopen(cfgfile, "r")) == NULL) { #ifdef INIPATH strcpy(cfgfile, INIPATH); strcat(cfgfile, CONFIG_FILE); if ((cf = fopen(cfgfile, "r")) == NULL) { #endif #ifdef AXIPR_UDP /* AX25IP.CFG ist nicht mehr noetig, */ /* kann aber weiterhin benutzt werden. */ return(TRUE); #endif xprintf("AX25IP: Config file %s not found or could not be opened\n", CONFIG_FILE); return(FALSE); #ifdef INIPATH } #endif } while (fgets(buf, 255, cf) != NULL) { (void)strcpy(cbuf, buf); ++lineno; if ((e = parse_line(buf)) < 0) { xprintf("Config error at line %d: ", lineno); switch (e) { case -1 : xprintf("Missing argument\n"); break; case -2 : xprintf("Bad callsign format\n"); break; case -3 : xprintf("Bad option - on/off\n"); break; case -4 : xprintf("Bad option - tnc/digi\n"); break; case -5 : xprintf("Host not known\n"); break; case -6 : xprintf("Unknown command\n"); break; case -7 : xprintf("Text string too long\n"); break; case -8 : xprintf("Bad option - every/after\n"); break; case -9 : xprintf("Bad option - ip/udp\n"); break; default: xprintf("Unknown error\n"); break; } xprintf("%s", cbuf); ++errflag; } } if (errflag) exit(1); if (mode == NO_MODE) { xprintf("Must specify ip and/or udp sockets\n"); return(FALSE); } fclose(cf); return(TRUE); } /* Process each line from the config file. The return value is encoded. */ int parse_line(char *buf) { char *p; char *q; char hostname[HNLEN]; unsigned char tcall[7]; struct hostent hstent; struct hostent *he; int i = 0; int uport = 0; int dfalt = 0; #ifdef AXIPR_HTML char *timeset = set_time(); #endif p = strtok(buf, " \t\n\r"); memset(&hstent, 0, sizeof(hstent)); /* Leere Zeilen */ if (p == NULL) return(0); /* Kommentarzeilen nicht auswerten */ if (*p == '#') return(0); if (strcmp(p, "socket") == 0) { q = strtok(NULL, " \t\n\r"); if (q == NULL) return(-1); if (strcmp(q, "ip") == 0) mode = IP_MODE; else if (strcmp(q, "udp") == 0) { mode = UDP_MODE; my_udp = htons(DEFAULT_UDP_PORT); /* Bei UDP optionale Portnummer lesen */ q = strtok(NULL, " \t\n\r"); /* Nummer war vorhanden, auswerten */ if (q != NULL) { i = atoi(q); /* Nummer ist gueltig, uebernehmen */ if (i > 0) my_udp = htons((unsigned short)i); } } else return(-9); return(0); } else if (strcmp(p, "socketoption") == 0) { q = strtok(NULL, " \t\n\r"); /* Pruefung auf leere Zeile */ if (q == NULL) return(-1); if (strcmp(q, "SO_KEEPALIVE") == 0) { sockopt_keepalive = TRUE; } else if (strcmp(q, "IPTOS_THROUGHPUT") == 0) { sockopt_throughput = TRUE; } else return(-9); return(0); } else if (strcmp(p, "loglevel") == 0) { q = strtok(NULL, " \t\n\r"); if (q == NULL) return(-1); loglevel = atoi(q); return(0); } else if (strcmp(p, "route") == 0) { uport = 0; dfalt = 0; q = strtok(NULL, " \t\n\r"); /* Pruefung auf leere Zeile */ if (q == NULL) return(-1); /* Pruefung auf default-Route */ if (strcmp(q, "default") == 0) dfalt = 1; else { /* Ziel der Route pruefen */ if (a_to_call(q, tcall) != 0) return(-2); } /* Hostnamen holen, dies kann auch eine IP-Adresse sein */ q = strtok(NULL, " \t\n\r"); if (q == NULL) return(-1); he = gethostbyname(q); /* Keine gueltige IP-Adresse ? */ if (he == NULL) { /* Da route_add() eine hostent-Struktur braucht, bauen wir ihm eine. */ /* Den Hostname sichern und den Zeiger auf den Puffer im hostent eintragen. */ strncpy(hostname, q, HNLEN); he = &hstent; he->h_name = hostname; } q = strtok(NULL, " \t\n\r"); if (q != NULL) { if (strcmp(q, "udp") == 0) { uport = DEFAULT_UDP_PORT; q = strtok(NULL, " \t\n\r"); if (q != NULL) { i = atoi(q); if (i > 0) uport = i; } } } #ifndef AXIPR_UDP route_add((unsigned char*)he->h_name, he, tcall, uport, dfalt, 0); #else route_add((unsigned char*)he->h_name, he, tcall, uport, dfalt, 0, (char*)he->h_name #ifdef AXIPR_HTML , timeset, P_USER #endif /* AXIPR_HTML */ ); #endif /* AXIPR_UDP */ return(0); } return(-999); } /* Convert ascii callsign to internal format */ int a_to_call(char *text, unsigned char *tcall) { register size_t i = 0; int ssid = 0; unsigned char c; if (strlen(text) == 0) return(-1); for (i = 0; i < 6; ++i) tcall[i] = (' ' << 1); tcall[6] = '\0'; for (i = 0; i < strlen(text); ++i) { c = text[i]; if (c == '-') { ssid = atoi(&text[i + 1]); if (ssid > 15) return(-1); tcall[6] = (ssid << 1); return(0); } if (islower(c)) c = toupper(c); if (i > 5) return(-1); tcall[i] = (c << 1); } return(0); } /* Convert internal callsign to printable format */ char *call_to_a(unsigned char *tcall) { int i = 0; int ssid = 0; char *tptr; static char t[10]; for (i = 0, tptr = t; i < 6; ++i) { if (tcall[i] == (' ' << 1)) break; *tptr = tcall[i] >> 1; tptr++; } ssid = (tcall[6] >> 1) & 0x0f; if (ssid > 0) { *tptr = '-'; tptr++; if (ssid > 9) { *tptr = '1'; tptr++; ssid -= 10; } *tptr = '0' + ssid; tptr++; } *tptr = '\0'; return(&t[0]); } void write_log(const char *format, ...) { FILE *fp; va_list arg_ptr; struct tm *lt; fp = fopen("ax25ip.log", "a+"); if (fp != NULL) { lt = localtime(&sys_time); fprintf(fp, "%16.16s:", ctime(&sys_time)); va_start(arg_ptr, format); vfprintf(fp, format, arg_ptr); va_end(arg_ptr); fprintf(fp, "\n"); fclose(fp); } else loglevel = 0; /* Logging aus da Fehler mit der Logdatei */ } #ifdef AXIPR_UDP /* AX25IP-Frame untersuchen, wenn Aenderungen */ /* z.B. UDP-Port, IP-Adresse in TBL Aktualisieren.*/ void route_analyse(struct in_addr ip, unsigned char *call, int uport) { register int i; char mycall[7]; #ifdef AXIPR_HTML char *timeset = set_time(); #endif /* AXIPR_HTML */ /* Leere Calls koennen nicht verarbeitet werden */ if (call[0] == FALSE) return; /* Call-Bytes kopieren, letztes Bit abschneiden (entspricht >> 1 & 7F) */ for (i = 0; i < 6; ++i) mycall[i] = call[i] & 0xfe; /* SSID kopieren */ mycall[6] = (call[6] & 0x1e) | 0x60; /* Routingtabelle durchsuchen */ for (i = 0; i < route_tbl_top; ++i) { if (addrmatch((unsigned char *)mycall , route_tbl[i].callsign)) { /* Bei Aenderung uebernehmen */ if (memcmp(&ip, &route_tbl[i].ip_addr, 4) != 0) /* IP-Adresse hat sich geaendert */ memcpy(&route_tbl[i].ip_addr, &ip, 4); /* UDP-Port unterschiedlich? */ if (route_tbl[i].udp_port != htons((UWORD)uport)) /* UDP-Port updaten. */ route_tbl[i].udp_port = htons((UWORD)uport); #ifdef AXIPR_HTML /* Route ggf. auf online setzen. */ if (!route_tbl[i].online) route_tbl[i].online = TRUE; #endif /* Aktivitaet auf diesem Eintrag, dann Timeout erneuern */ if (route_tbl[i].timeout) route_tbl[i].timeout = uDynTimeout; /* Aktualisierung beendet. */ return; } } #ifndef AXIPR_HTML /* Auto-Route eintragen */ route_add((unsigned char*)inet_ntoa(ip), NULL, call,uport, FALSE, uDynTimeout, (char*)inet_ntoa(ip)); #else /* Auto-Route eintragen */ route_add((unsigned char*)inet_ntoa(ip), NULL, call,uport, FALSE, uDynTimeout, (char*)inet_ntoa(ip), timeset, P_USER); #endif /* AXIPR_HTML */ } /* Per Rufzeichen, ohne die SSID zubeachten, einen */ /* Routeneintrag suchen. Gibt es keinen Eintrag, */ /* wird sofort abgebrochen, ansonsten werden die */ /* routeneintraege IP-Adresse und UDP-Port ueber- */ /* nommen und das neue Rufzeichen wird eingetragen.*/ struct route_table_entry *search_route(unsigned char *call) { register int i; char srccall[10]; #ifdef AXIPR_HTML char *timeset = set_time(); #endif /* AXIPR_HTML */ /* Konvertiere Rufzeichen. */ callss2str((char *)srccall, call_to_a(call)); /* TB durchgehen. */ for (i = 0; i < route_tbl_top; ++i) { /* Suche Rufzeichen. */ if (cmpcal(srccall, call_to_a(&route_tbl[i].callsign[0]))) { #ifndef AXIPR_HTML /* Auto-Route eintragen */ route_add((unsigned char *)&route_tbl[i].ip_addr, NULL, (unsigned char *)call, htons(route_tbl[i].org_udp_port), FALSE, uDynTimeout, (char *)route_tbl[i].hostname); #else /* Auto-Route eintragen */ route_add((unsigned char *)&route_tbl[i].ip_addr, NULL, (unsigned char *)call, htons(route_tbl[i].org_udp_port), FALSE, uDynTimeout, (char *)route_tbl[i].hostname, timeset, P_USER); #endif /* AXIPR_HTML */ /* Aktuellen Eintrag weiterreichen. */ return (&route_tbl[i]); /* Eintrag gefunden */ } } /* Kein Rufzeichen gefunden. */ return (NULL); } /* Eine AX-Route Updaten. */ void UpdateRoute(unsigned char *srccall, int udpport, int timeout, char *hostname #ifdef AXIPR_HTML , char *timeset , UWORD protokoll #endif /* AXIPR_HTML */ ) { MBHEAD *mbp; register int i; /* TB durchgehen. */ for (i = 0; i < route_tbl_top; ++i) { /* Suche Rufzeichen. */ if (addrmatch((unsigned char *)srccall , route_tbl[i].callsign)) { route_tbl[i].org_udp_port = route_tbl[i].udp_port = htons((unsigned short)udpport); /* Hostname eintragen. */ (void)memcpy(route_tbl[i].hostname, hostname, HNLEN); /* ggf. Timeout setzen. */ route_tbl[i].timeout = timeout; #ifdef AXIPR_HTML /* Hostname eintragen. */ (void)memcpy(route_tbl[i].timeset, timeset, 17); /* Protokoll eintragen. */ route_tbl[i].protokoll = P_USER; #endif /* AXIPR_HTML */ mbp = getmbp(); /* und ab die Post ... */ prompt(mbp); seteom(mbp); return; } } } #ifdef AXIPR_HTML /* Protokoll fuer HTML-Ausgabe setzen. */ void SetHTML(int port, char *call, PEER *pp, BOOLEAN flag) { register int i; char srccall[10 + 1]; call2str(srccall, call); /* Routingtabelle durchsuchen */ for (i = 0; i < route_tbl_top; ++i) { if (!strcmp(srccall , call_to_a(&route_tbl[i].callsign[0]))) { /* Protokoll setzen. */ set_status(i, port, pp); /* Route auf online/offline stellen. */ route_tbl[i].online = flag; break; } } } /* Aktualisiere Loginzeit fuer TB */ char *set_time(void) { time_t go; struct tm *zeit; static char c[17]; char *timeset = c; /* aktuelle Kalenderzeit */ time(&go); /* konvertiert Datum und Uhrzeit. */ zeit = localtime(&go); /* Formatiere eine Zeit-/Datumsangabe */ strftime(c,17,"%d-%b-%H:%M:%S",zeit); /* Aktuelle Login Date/Time */ return(timeset); } /* Protokoll setzen. */ void set_status(register int a, int port, PEER *pp) { if (pp == NULL) /* Route wird ausgetragen. */ { route_tbl[a].protokoll = P_OFFLINE; /* Route auf OFFLINE setzen. */ route_tbl[a].online = FALSE; return; } switch(pp->typ) /* Protokol-TYP. */ { case INP : /* INP-TYP. */ route_tbl[a].protokoll = P_INP; /* INP-TYP setzen. */ break; case TNN : /* TNN-TYP */ case THENET : /* THENET-TYP. */ route_tbl[a].protokoll = P_THENET; /* TNN/THENET-TYP setzen. */ break; case FLEXNET: /* FLEXNET-TYP. */ route_tbl[a].protokoll = P_FLEXNET; /* FLEXNET-TYP setzen. */ break; default: route_tbl[a].protokoll = P_OFFLINE; /* Route auf OFFLINE setzen. */ route_tbl[a].online = FALSE; return; } route_tbl[a].online = TRUE; } /* Timer fuer htmlstatistik. */ void h_timer(void) { static LONG h_Timer = 0L; /* Timer abgelaufen. */ if (h_Timer <= 0L) { /* Timer neu setzen. */ /* fest auf 60 sec. */ h_Timer = 60L; /* html auf Platte schreiben. */ w_statistik(); } /* Timer runter zaehlen. */ h_Timer--; } /* Hiermit checken wir ob die rstat.css existiert. */ /* FALSE = keine rstat.css gefunden */ /* TRUE = es existiert eine rstat.css */ static int check_css_file(void) { char cssfile[255]; /* Path kopieren. */ strcpy(cssfile, htmlpath); /* CSS-Dateiname anhaengen. */ strcat(cssfile, CSS_RFILE); /* Pruefe ob Datei existiert.*/ if (!access(cssfile,FALSE)) /* Datei existiert. */ return(TRUE); else /* Nix gefunden! */ return(FALSE); } /* Eine default RSTAT.CSS schreiben */ static void rstat_css_default_file(void) { FILE *fp; char cfgfile[255]; if (HtmlStat == FALSE) return; strcpy(cfgfile, htmlpath); strcat(cfgfile, CSS_RFILE); if ((fp = fopen(cfgfile, "w+t")) == NULL) return; fprintf(fp,"BODY {\n" " BACKGROUND-IMAGE: url('bg.jpg');\n" " BACKGROUND-COLOR: #000080;\n" " COLOR: #FFFFFF;\n" " FONT-FAMILY: Verdana, Arial;\n" " FONT-SIZE: 12;\n" "}\n"); fprintf(fp,"H1 {\n" " FONT-SIZE: 18; COLOR: #FFCC00;\n" "}\n"); fprintf(fp,"H2 {\n" " FONT-SIZE: 12; COLOR: #FFFFFF;\n" "}\n"); fprintf(fp,"a:link, a:visited {\n" " COLOR: #FFFFFF;\n" " text-weight: bold;\n" " text-decoration: none;\n" "}\n"); fprintf(fp,"a:hover {\n" " COLOR: #FF6600;\n" " text-weight: bold;\n" " text-decoration: none;\n" "}\n" ".info {\n" " FONT-SIZE: 12; COLOR: #99CCFF;\n" "}\n"); fprintf(fp,"table.box {\n" " background-color: #ffbb00;\n" " backcolor: #220000;\n" " backcolorlight: #00ff00;\n" " backcolordark: #000000;\n" " border-width: 0px;\n" " width: 95%%;\n" " border-style: outset;\n" " border-spacing: 2px;\n" " border-padding: 8px;\n" "}\n"); fprintf(fp,".status {\n" " FONT-SIZE: 10; BACKGROUND: #000000; COLOR: #FFCC00; TEXT-ALIGN: center;\n" "}\n"); fprintf(fp,".off {\n" " FONT-SIZE: 10; BACKGROUND: #000000; COLOR: #ffffff;\n" "}"); fprintf(fp,".offline {\n" " FONT-SIZE: 10; BACKGROUND: #9f00FF; COLOR: #ffffff;\n" "}"); fprintf(fp,".user {\n" " FONT-SIZE: 10; BACKGROUND: #E06060; COLOR: #ffffff;\n" "}\n"); fprintf(fp,".thenet {\n" " FONT-SIZE: 10; BACKGROUND: #E00060; COLOR: #ffffff;\n" "}\n"); fprintf(fp,".inp {\n" " FONT-SIZE: 10; BACKGROUND: #0070C0; COLOR: #ffffff;\n" "}\n"); fprintf(fp,".Flexnet {\n" " FONT-SIZE: 10; BACKGROUND: #006060; COLOR: #ffffff;\n" "}\n"); fprintf(fp,".about {\n" " FONT-SIZE: 13; COLOR: #ffffff;\n" "}\n"); fclose(fp); } /* Wie viel Ports sind nich frei ? */ static int free_ports(void) { int free = FALSE; return(free = TABLE_SIZE - route_tbl_top); } /* Wie viel L2-Links (USER) - sind aktiv ? */ static int activ_user(void) { register int a; int user = FALSE; /* TB durchgehen */ for (a = 0; a < route_tbl_top; a++) /* nur die als User markiert sind */ if ( route_tbl[a].protokoll == P_USER /* und online sind !!! */ && route_tbl[a].online > 0) /* Alle USER zaehlen */ user++; return(user); } /* Wie viel L2/L4_links sind aktiv ? */ static int activ_links(void) { register int a; int links = FALSE; /* TB durchgehen */ for (a = 0; a < route_tbl_top; a++) /* L2/L4-Link online ? */ if ( route_tbl[a].online > 0 /* wir zaehlen alle Protokolle, ausser USER */ && route_tbl[a].protokoll != 1) links++; return(links); } /* Die Aktuelle Uhrzeit fuer HTML ausgeben */ static char *puttim_stat(void) { struct tm *p; static char tim[20]; time_t timet; char *atime = tim; time(&timet); p = localtime(&timet); sprintf(tim,"%02i.%02i.%02i %02i:%02i:%02i", p->tm_mday, p->tm_mon+1, p->tm_year % 100, p->tm_hour, p->tm_min, p->tm_sec); return(atime); } static char *set_class(UWORD flag, register int a) { static char o[8]; char *protokoll = o; switch(flag) { case P_OFFLINE : if (!route_tbl[a].online) strcpy(o, "offline"); break; case P_USER : if (route_tbl[a].online) strcpy(o, "user"); else strcpy(o, "offline"); break; case P_THENET : if (route_tbl[a].online) strcpy(o, "thenet"); else strcpy(o, "offline"); break; case P_INP : if (route_tbl[a].online) strcpy(o, "inp"); else strcpy(o, "offline"); break; case P_FLEXNET : if (route_tbl[a].online) strcpy(o, "flexnet"); else strcpy(o, "offline"); break; default: strcpy(o, "unknown"); break; } return(protokoll); } static char *set_pname(register int a) { static char p[8]; char *protokoll = p; switch(route_tbl[a].protokoll) { case P_USER : strcpy(p, "L2"); break; case P_THENET : strcpy(p, "THENET"); break; case P_INP : strcpy(p, "INP"); break; case P_FLEXNET : strcpy(p, "FLEXNET"); break; default: strcpy(p, "UNKNOWN"); break; } return(protokoll); } static void all_route(FILE *fp, UWORD flag, register int a) { char *pclass = set_class(flag, a); char *protokoll = set_pname(a); /* Nummer einer Route. */ fprintf(fp,"
%d\n" , pclass, a); /* Rufzeichen. */ fprintf(fp," %s\n" , pclass , call_to_a(&route_tbl[a].callsign[0])); /* IP-Adresse. */ fprintf(fp," " " %s\n" , pclass , route_tbl[a].hostname , route_tbl[a].hostname); /* Hostname/IP-Adresse. */ fprintf(fp,"
%s\n" , pclass , route_tbl[a].hostname); /* UDP-Port */ fprintf(fp,"
%d\n" , pclass , htons(route_tbl[a].udp_port)); /* Loginzeit */ fprintf(fp,"
%s\n" , pclass , route_tbl[a].timeset); if (route_tbl[a].timeout) /* Timeout */ fprintf(fp,"
%d\n" , pclass , route_tbl[a].timeout); else /* Statische Route */ fprintf(fp,"
Statisch\n" , pclass); /* Protokoll */ fprintf(fp,"
%s\n" , pclass , protokoll); } static void show_route(FILE *fp, UWORD flag, register int a) { switch(flag) { case P_OFFLINE : if (!route_tbl[a].online) fprintf(fp," \n"); break; case P_USER : if ( route_tbl[a].protokoll == flag && route_tbl[a].online) fprintf(fp," \n"); else fprintf(fp," \n"); break; case P_THENET : if ( route_tbl[a].protokoll == flag && route_tbl[a].online) fprintf(fp," \n"); else fprintf(fp," \n"); break; case P_INP : if ( route_tbl[a].protokoll == flag && route_tbl[a].online) fprintf(fp," \n"); else fprintf(fp," \n"); break; case P_FLEXNET : if ( route_tbl[a].protokoll == flag && route_tbl[a].online) fprintf(fp," \n"); else fprintf(fp," \n"); break; default: if ( route_tbl[a].protokoll == flag && route_tbl[a].online) fprintf(fp," \n"); else fprintf(fp," \n"); break; } all_route(fp, flag, a); } /* Schreibe htmlstatistik auf Platte. */ void w_statistik(void) { FILE *fp; char cfgfile[255],mycall[10]; char *atime = puttim_stat(); register int a; char runtime[8 + 1]; #ifndef CONNECTTIME unsigned long upt, upd, uph; #endif /* CONNECTTIME */ /* Pruefe, ob htmlstatistik eingeschaltet ist. */ if (HtmlStat == FALSE) /* Ist nicht eingeschaltet, abbruch. */ return; else { /* Pruefe ob CSS-Datei exisiert. */ if (!check_css_file()) /* Nein, dann neuschreiben. */ rstat_css_default_file(); } strcpy(cfgfile,htmlpath ); strcat(cfgfile, HTML_RFILE); if ((fp = fopen(cfgfile,"w+t")) == NULL) return; call2str(mycall,myid); #ifndef CONNECTTIME upt = sys_time - start_time; /* Uptime in seconds */ upd = upt / SECONDS_PER_DAY; /* Uptime days */ upt %= SECONDS_PER_DAY; uph = upt / SECONDS_PER_HOUR; /* Uptime hours */ upt %= SECONDS_PER_HOUR; if (upd > 0) sprintf(runtime, "%2lud,%2luh", upd, uph); else if (uph > 0) sprintf(runtime, "%2luh,%2lus", uph, upt); else if (upt > 0) sprintf(runtime, " %2lus", upt); else sprintf(runtime, " "); #else sprintf(runtime, "%s", ConnectTime(tic10 / 100)); #endif /* CONNECTTIME */ fprintf(fp,"" "\n" "\n" "AXIPR-Statistik\n" "\n" "\n\n",HTML_INV); fprintf(fp,"
\n" "

%s%s)

\n",signon,mycall); fprintf(fp,"

Date/Time: %s Runtime: %s, %d Frei

\n\n",atime, runtime, free_ports()); fprintf(fp," %d L2/L4-LINKS\n",activ_links()); fprintf(fp,"\n"); fprintf(fp," \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n"); /* TB durchgehen. */ for (a = 0; a < route_tbl_top; a++) { /* Nur aktive Routen zeigen. */ if (route_tbl[a].online == FALSE) /* zum naechsten Eintrag. */ continue; /* Nur INP- oder FLEXNET-Routen bearbeiten */ if (route_tbl[a].protokoll > P_USER) /* und anzeigen. */ show_route(fp, route_tbl[a].protokoll, a); } fprintf(fp,"
Nr.RufzeichenIP-AdresseDYNDNSUDPLoginTimeoutProtokoll


\n"); fprintf(fp,"%d USER\n",activ_user()); fprintf(fp,"\n"); fprintf(fp," \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n"); /* TB durchgehen */ for (a = 0; a < route_tbl_top; a++) { /* Nur aktive Routen zeigen. */ if (route_tbl[a].online == FALSE) /* zum naechsten Eintrag. */ continue; /* Nur USER-Routen bearbeiten */ if (route_tbl[a].protokoll == P_USER) /* und anzeigen. */ show_route(fp, route_tbl[a].protokoll, a); } fprintf(fp,"
Nr.RufzeichenIP-AdresseDYNDNSUDPLoginTimeoutProtokoll
\n\n"); fprintf(fp,"
My UDP-Port: %u\n",htons(my_udp)); fprintf(fp,"\n"); fclose(fp); } #endif /* AXIPR_HTML */ #endif /* AXIPR_UDP */ #endif /* End of os/win32/ax25ip.c */