diff --git a/openslp.SuSEfirewall2 b/openslp.SuSEfirewall2 new file mode 100644 index 0000000..35936f9 --- /dev/null +++ b/openslp.SuSEfirewall2 @@ -0,0 +1,6 @@ +## Name: Openslp server (SLP) +## Description: Enables Openslp server to advertise services + +# space separated list of allowed ports +TCP="427" +UDP="427" diff --git a/openslp.changes b/openslp.changes index a7623bb..7cf642e 100644 --- a/openslp.changes +++ b/openslp.changes @@ -1,3 +1,44 @@ +------------------------------------------------------------------- +Tue Oct 12 17:46:47 CEST 2010 - mls@suse.de + +- fix extension parsing code, CVE-2010-3609 [bnc#642571] + +------------------------------------------------------------------- +Fri Oct 1 13:36:48 CEST 2010 - mls@suse.de + +- ignore leading and trailing spaces when comparing strings + [bnc#626444] + +------------------------------------------------------------------- +Thu Sep 30 12:35:54 CEST 2010 - mls@suse.de + +- change DA pull code to not use the pulled-from-de prediacte, but + instead don't overwrite non-pulled registrations + +------------------------------------------------------------------- +Thu Jul 29 13:28:41 CEST 2010 - mls@suse.de + +- add DABackupLocalReg option to enable backup of local services + [bnc#597215] + +------------------------------------------------------------------- +Tue May 11 18:09:09 CEST 2010 - jeffm@suse.de + +- avoid CPU usage spike while while reading /proc/net/tcp + on systems with many connections (bnc#601002) + +------------------------------------------------------------------- +Wed Apr 28 17:03:14 CEST 2010 - mls@suse.de + +- do not ignore DA answers if active and passive DA detection is off + [bnc#564504] +- add DASyncReg and isDABackup options for OES folks + +------------------------------------------------------------------- +Fri Mar 12 13:55:47 UTC 2010 - kkaempf@novell.com + +- Add SuSEfirewall2 description file + ------------------------------------------------------------------- Mon Dec 14 17:04:29 CET 2009 - jengelh@medozas.de diff --git a/openslp.discovery.diff b/openslp.discovery.diff new file mode 100644 index 0000000..5e010c1 --- /dev/null +++ b/openslp.discovery.diff @@ -0,0 +1,58 @@ +--- slpd/slpd_outgoing.c.orig 2009-12-22 15:23:09.000000000 +0000 ++++ slpd/slpd_outgoing.c 2009-12-22 15:47:35.000000000 +0000 +@@ -420,6 +420,24 @@ SLPDSocket* SLPDOutgoingConnect(struct i + } + + /*=========================================================================*/ ++int SLPDHaveOutgoingConnectedSocket(struct in_addr* addr) ++/* Check if there is an outgoing socket for the specified address */ ++/* */ ++/* addr (IN) the address of the peer to check */ ++/*=========================================================================*/ ++{ ++ SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head; ++ while ( sock ) ++ { ++ if (sock->state >= STREAM_CONNECT_IDLE && ++ sock->peeraddr.sin_addr.s_addr == addr->s_addr) ++ return 1; ++ sock = (SLPDSocket*)sock->listitem.next; ++ } ++ return 0; ++} ++ ++/*=========================================================================*/ + void SLPDOutgoingDatagramWrite(SLPDSocket* sock) + /* Add a ready to write outgoing datagram socket to the outgoing list. */ + /* The datagram will be written then sit in the list until it ages out */ +--- slpd/slpd_outgoing.h.orig 2009-12-22 15:43:52.000000000 +0000 ++++ slpd/slpd_outgoing.h 2009-12-22 15:45:26.000000000 +0000 +@@ -107,6 +107,13 @@ SLPDSocket* SLPDOutgoingConnect(struct i + /* returns: pointer to socket or null on error */ + /*=========================================================================*/ + ++/*=========================================================================*/ ++int SLPDHaveOutgoingConnectedSocket(struct in_addr* addr); ++/* Check if there is an outgoing socket for the specified address */ ++/* */ ++/* addr (IN) the address of the peer to check */ ++/*=========================================================================*/ ++ + + /*=========================================================================*/ + int SLPDOutgoingInit(); +--- slpd/slpd_process.c.orig 2009-12-22 15:01:43.000000000 +0000 ++++ slpd/slpd_process.c 2009-12-22 15:43:20.000000000 +0000 +@@ -1120,7 +1120,11 @@ int ProcessDAAdvert(SLPMessage message, + if(G_SlpdProperty.DAActiveDiscoveryInterval == 0 && + message->header.xid != 0) + { +- goto RESPOND; ++ /* do not ignore replys of our DiscoveryRequests made for ++ * static and dhcp configured DAs. For now we check this by ++ * testing if the sockaddr is on the outgoing socket list */ ++ if (!SLPDHaveOutgoingConnectedSocket(&message->peer.sin_addr)) ++ goto RESPOND; + } + + /*-------------------------------*/ diff --git a/openslp.ignorespaces.diff b/openslp.ignorespaces.diff new file mode 100644 index 0000000..dd6a7fe --- /dev/null +++ b/openslp.ignorespaces.diff @@ -0,0 +1,19 @@ +--- common/slp_compare.c.orig 2010-10-01 11:17:13.000000000 +0000 ++++ common/slp_compare.c 2010-10-01 11:26:52.000000000 +0000 +@@ -105,6 +105,16 @@ int SLPCompareString(int str1len, + /* <0 if s1 is less than str2 */ + /*=========================================================================*/ + { ++ /* strip leading/trailing while space */ ++ while (str1len && (*str1 == ' ' || *str1 == '\t' || *str1 == '\r' || *str1 == '\n')) ++ str1++, str1len--; ++ while (str1len && (str1[str1len - 1] == ' ' || str1[str1len - 1] == '\t' || str1[str1len - 1] == '\r' || str1[str1len - 1] == '\n')) ++ str1len--; ++ while (str2len && (*str2 == ' ' || *str2 == '\t' || *str2 == '\r' || *str2 == '\n')) ++ str2++, str2len--; ++ while (str2len && (str2[str2len - 1] == ' ' || str2[str2len - 1] == '\t' || str2[str2len - 1] == '\r' || str2[str2len - 1] == '\n')) ++ str2len--; ++ + /* TODO: fold whitespace and handle escapes*/ + if(str1len == str2len) + { diff --git a/openslp.initda.diff b/openslp.initda.diff new file mode 100644 index 0000000..c298521 --- /dev/null +++ b/openslp.initda.diff @@ -0,0 +1,1448 @@ +--- ./common/Makefile.am.orig 2010-09-30 10:42:25.789407000 +0000 ++++ ./common/Makefile.am 2010-09-30 10:43:08.404049000 +0000 +@@ -48,6 +48,7 @@ libcommonslpd_la_SOURCES = \ + slp_predicate.c \ + slp_dhcp.c \ + slp_mdns.c \ ++ slp_network.c \ + $(slp_v1message_SRCS) \ + $(slp_security_SRCS) + +--- ./common/slp_message.h.orig 2010-09-30 10:42:26.243407000 +0000 ++++ ./common/slp_message.h 2010-09-30 10:43:08.413054000 +0000 +@@ -170,6 +170,7 @@ typedef UINT32* PUINT32; + #define SLP_REG_SOURCE_REMOTE 1 /* from a remote host */ + #define SLP_REG_SOURCE_LOCAL 2 /* from localhost or IPC */ + #define SLP_REG_SOURCE_STATIC 3 /* from the slp.reg file */ ++#define SLP_REG_SOURCE_PULL_PEER_DA 4 /* from another DA pulled at startup */ + + #define SLP_REG_WATCH_TCP (1<<0) + #define SLP_REG_WATCH_UDP (1<<1) +--- ./common/slp_property.c.orig 2010-09-30 10:42:25.817415000 +0000 ++++ ./common/slp_property.c 2010-09-30 10:43:08.422048000 +0000 +@@ -213,6 +213,10 @@ int SetDefaultValues() + #else /* UNIX */ + result |= SLPPropertySet("net.slp.OpenSLPVersion", VERSION); + #endif ++ result |= SLPPropertySet("net.slp.DASyncReg","false"); ++ result |= SLPPropertySet("net.slp.isDABackup","false"); ++ result |= SLPPropertySet("net.slp.DABackupInterval","900"); ++ result |= SLPPropertySet("net.slp.DABackupLocalReg","false"); + + return result; + } +--- ./etc/slp.conf.orig 2002-06-11 17:25:40.000000000 +0000 ++++ ./etc/slp.conf 2010-09-30 10:43:08.426050000 +0000 +@@ -40,6 +40,20 @@ + # if isDA is false. + ;net.slp.DAHeartBeat = 10800 + ++# Enables backup of registrations to /etc/slp.reg.d/slpd/DABackup. ++;net.slp.isDABackup = true ++ ++# A 32 bit integer giving the number of seconds for the DABackup file update. ++# Default is 15 minutes (900 seconds). Ignored if isDA is false. ++;net.slp.DABackupInterval = 900 ++ ++# Include local registrations in the backup, too. The default is false. ++;net.slp.DABackupLocalReg = true ++ ++# Enables slpd to sync service registration between SLP DAs on startup ++# Default is false ++;net.slp.DASyncReg = true ++ + + #---------------------------------------------------------------------------- + # SA Specific Configuration +--- ./slpd/Makefile.am.orig 2010-09-30 10:42:25.901413000 +0000 ++++ ./slpd/Makefile.am 2010-09-30 10:43:08.432047000 +0000 +@@ -39,6 +39,7 @@ slpd_knownda.c \ + slpd_incoming.c \ + slpd_outgoing.c \ + slpd_mdns.c \ ++slpd_initda.c \ + slpd.h \ + slpd_knownda.h \ + slpd_process.h \ +@@ -51,6 +52,7 @@ slpd_outgoing.h \ + slpd_regfile.h \ + slpd_incoming.h \ + slpd_mdns.h \ ++slpd_initda.h \ + slpd_socket.h + + slpd_LDADD = ../common/libcommonslpd.la \ +--- ./slpd/slpd_database.c.orig 2010-09-30 10:42:26.270411000 +0000 ++++ ./slpd/slpd_database.c 2010-09-30 10:43:37.168731000 +0000 +@@ -76,6 +76,7 @@ FILE *regfileFP; + /* standard header files */ + /*=========================================================================*/ + #include ++#include + #include + #include + #include +@@ -212,6 +213,7 @@ int SLPDDatabaseReg(SLPMessage msg, SLPB + /* Check to ensure the source addr is the same */ + /* as the original */ + if ( G_SlpdProperty.checkSourceAddr && ++ entryreg->source != SLP_REG_SOURCE_PULL_PEER_DA && + memcmp(&(entry->msg->peer.sin_addr), + &(msg->peer.sin_addr), + sizeof(struct in_addr)) ) +@@ -228,6 +230,13 @@ int SLPDDatabaseReg(SLPMessage msg, SLPB + return SLP_ERROR_AUTHENTICATION_FAILED; + } + #endif ++ if (reg->source == SLP_REG_SOURCE_PULL_PEER_DA && entryreg->source != SLP_REG_SOURCE_PULL_PEER_DA) ++ { ++ /* Do not update not-pulled registrations with pulled ones */ ++ SLPDatabaseClose(dh); ++ return 0; ++ } ++ + /* Remove the identical entry */ + SLPDatabaseRemove(dh,entry); + break; +@@ -322,6 +331,7 @@ int SLPDDatabaseDeReg(SLPMessage msg) + /* Check to ensure the source addr is the same as */ + /* the original */ + if ( G_SlpdProperty.checkSourceAddr && ++ entry->msg->body.srvreg.source != SLP_REG_SOURCE_PULL_PEER_DA && + memcmp(&(entry->msg->peer.sin_addr), + &(msg->peer.sin_addr), + sizeof(struct in_addr)) ) +@@ -465,6 +475,12 @@ int SLPDDatabaseSrvRqstStart(SLPMessage + } + } + #endif ++ if (srvrqst->predicatelen == 29 && !strncmp(srvrqst->predicate, "(!(openslp-pulled-from-da=*))", 29)) ++ { ++ /* this is the special "no pulled entries" predicate used in DA syncing */ ++ if (entryreg->source == SLP_REG_SOURCE_PULL_PEER_DA) ++ continue; /* skip it */ ++ } + if ( (*result)->urlcount + 1 > G_SlpdDatabase.urlcount ) + { + /* Oops we did not allocate a big enough result */ +@@ -1203,7 +1219,7 @@ int SLPDDatabaseReInit() + if ( regfileFP ) + { + rewind(regfileFP); +- while ( SLPDRegFileReadSrvReg(regfileFP, &msg, &buf) == 0 ) ++ while ( SLPDRegFileReadSrvReg(regfileFP, SLP_REG_SOURCE_STATIC, &msg, &buf) == 0 ) + { + SLPDDatabaseReg(msg, buf); + } +@@ -1223,7 +1239,7 @@ int SLPDDatabaseReInit() + strcmp(filename+strlen(filename)-4, ".reg") == 0 && + (fd=fopen(filename,"rb")) ) + { +- while ( SLPDRegFileReadSrvReg(fd, &msg, &buf) == 0 ) ++ while ( SLPDRegFileReadSrvReg(fd, SLP_REG_SOURCE_STATIC, &msg, &buf) == 0 ) + { + SLPDDatabaseReg(msg, buf); + } +@@ -1238,6 +1254,69 @@ int SLPDDatabaseReInit() + return 0; + } + ++/*=========================================================================*/ ++void SLPDDatabaseReadDABackup(FILE *fp) ++/*=========================================================================*/ ++{ ++ SLPMessage msg; ++ SLPBuffer buf; ++ time_t timediff; ++ long l; ++ ++ SLPDLog("Reading registration backup file...\n"); ++ rewind(fp); ++ if (fscanf(fp, "# Update timestamp: %ld\n", &l) != 1) ++ return; ++ timediff = time(NULL) - (time_t)l; ++ if (timediff < 0) ++ timediff = 0; ++ while (SLPDRegFileReadSrvReg(fp, SLP_REG_SOURCE_REMOTE, &msg, &buf) == 0) ++ { ++ if (!G_SlpdProperty.DABackupLocalReg && msg->body.srvreg.source == SLP_REG_SOURCE_LOCAL) ++ { ++ SLPMessageFree(msg); ++ SLPBufferFree(buf); ++ continue; ++ } ++ msg->body.srvreg.urlentry.lifetime -= timediff; ++ if (msg->body.srvreg.urlentry.lifetime > 0) ++ SLPDDatabaseReg(msg, buf); ++ else ++ { ++ SLPMessageFree(msg); ++ SLPBufferFree(buf); ++ } ++ } ++} ++ ++/*=========================================================================*/ ++void SLPDDatabaseWriteDABackup(FILE *fp) ++/*=========================================================================*/ ++{ ++ SLPDatabaseHandle dh; ++ SLPDatabaseEntry* entry; ++ ++ SLPDLog("Writing registration backup file...\n"); ++ rewind(fp); ++ (void)ftruncate(fileno(fp), 0); ++ fprintf(fp, "# Update timestamp: %ld\n\n", (long)time(NULL)); ++ dh = SLPDatabaseOpen(&G_SlpdDatabase.database); ++ if (dh) ++ { ++ while ((entry = SLPDatabaseEnum(dh)) != NULL) ++ { ++ if (entry->msg->body.srvreg.source == SLP_REG_SOURCE_STATIC) ++ continue; ++ if (!G_SlpdProperty.DABackupLocalReg && entry->msg->body.srvreg.source == SLP_REG_SOURCE_LOCAL) ++ continue; ++ SLPDRegFileWriteSrvReg(fp, entry->msg); ++ } ++ SLPDatabaseClose(dh); ++ } ++ fflush(fp); ++} ++ ++ + #ifdef DEBUG + /*=========================================================================*/ + void SLPDDatabaseDeinit(void) +--- ./slpd/slpd_database.h.orig 2010-09-30 10:42:25.916410000 +0000 ++++ ./slpd/slpd_database.h 2010-09-30 10:43:08.464052000 +0000 +@@ -286,6 +286,14 @@ int SLPDDatabaseReInit(); + + void SLPDDatabaseWatcher(void); + ++/*=========================================================================*/ ++void SLPDDatabaseReadDABackup(FILE *fp); ++/*=========================================================================*/ ++ ++/*=========================================================================*/ ++void SLPDDatabaseWriteDABackup(FILE *fp); ++/*=========================================================================*/ ++ + #ifdef DEBUG + /*=========================================================================*/ + void SLPDDatabaseDeinit(void); +--- ./slpd/slpd_initda.c.orig 2010-09-30 10:43:08.469052000 +0000 ++++ ./slpd/slpd_initda.c 2010-09-30 10:43:08.472049000 +0000 +@@ -0,0 +1,407 @@ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define SLP_NETWORK_TIMED_OUT -19 ++#define SLP_MEMORY_ALLOC_FAILED -21 ++#define SLP_NETWORK_ERROR -23 ++ ++/*=========================================================================*/ ++static int SLPDUnicastRqstRply(int sock, ++ struct sockaddr_in* destaddr, ++ const char* langtag, ++ char* buf, ++ char buftype, ++ int bufsize, ++ int (*callback)(SLPMessage message, void *cookie), ++ void * cookie) ++/*=========================================================================*/ ++{ ++ struct timeval timeout; ++ SLPBuffer sendbuf = 0; ++ SLPBuffer recvbuf = 0; ++ SLPMessage message = 0; ++ int result = 0; ++ int langtaglen = 0; ++ int xid = 0; ++ int mtu = 0; ++ int size = 0; ++ int maxwait = 0; ++ int timeouts[1]; ++ ++ /*----------------------------------------------------*/ ++ /* Save off a few things we don't want to recalculate */ ++ /*----------------------------------------------------*/ ++ langtaglen = strlen(langtag); ++ xid = SLPXidGenerate(); ++ mtu = SLPPropertyAsInteger(SLPPropertyGet("net.slp.MTU")); ++ sendbuf = SLPBufferAlloc(mtu); ++ if(sendbuf == 0) ++ { ++ result = SLP_MEMORY_ALLOC_FAILED; ++ goto FINISHED; ++ } ++ maxwait = SLPPropertyAsInteger(SLPPropertyGet("net.slp.unicastMaximumWait")); ++ SLPPropertyAsIntegerVector(SLPPropertyGet("net.slp.unicastTimeouts"), timeouts, 1); ++ timeout.tv_sec = timeouts[0] / 1000; ++ timeout.tv_usec = (timeouts[0] % 1000) * 1000; ++ size = 16 + langtaglen + bufsize; ++ if((sendbuf = SLPBufferRealloc(sendbuf,size)) == 0) ++ { ++ result = SLP_MEMORY_ALLOC_FAILED; ++ goto FINISHED; ++ } ++ /*-----------------------------------*/ ++ /* Add the header to the send buffer */ ++ /*-----------------------------------*/ ++ /*version*/ ++ *(sendbuf->start) = 2; ++ /*function id*/ ++ *(sendbuf->start + 1) = buftype; ++ /*length*/ ++ ToUINT24(sendbuf->start + 2, size); ++ /*flags*/ ++ ToUINT16(sendbuf->start + 5, SLP_FLAG_UCAST); /*this is a unicast */ ++ /*ext offset*/ ++ ToUINT24(sendbuf->start + 7,0); ++ /*xid*/ ++ ToUINT16(sendbuf->start + 10,xid); ++ /*lang tag len*/ ++ ToUINT16(sendbuf->start + 12,langtaglen); ++ /*lang tag*/ ++ memcpy(sendbuf->start + 14, langtag, langtaglen); ++ sendbuf->curpos = sendbuf->start + langtaglen + 14 ; ++ ToUINT16(sendbuf->curpos,0); ++ sendbuf->curpos = sendbuf->curpos + 2; ++ /*-----------------------------*/ ++ /* Add the rest of the message */ ++ /*-----------------------------*/ ++ memcpy(sendbuf->curpos, buf, bufsize); ++ /*----------------------*/ ++ /* send the send buffer */ ++ /*----------------------*/ ++ ++ result = SLPNetworkSendMessage(sock, SOCK_STREAM, sendbuf, destaddr, &timeout); ++ if (result != 0) ++ { ++ result = errno == ETIMEDOUT ? SLP_NETWORK_TIMED_OUT : SLP_NETWORK_ERROR; ++ goto FINISHED; ++ } ++ result = SLPNetworkRecvMessage(sock, SOCK_STREAM, &recvbuf, destaddr, &timeout); ++ if (result != 0) ++ { ++ result = errno == ETIMEDOUT ? SLP_NETWORK_TIMED_OUT : SLP_NETWORK_ERROR; ++ goto FINISHED; ++ } ++ if(AsUINT16(recvbuf->start+10) != xid) ++ { ++ result = SLP_NETWORK_ERROR; ++ goto FINISHED; ++ } ++ message = SLPMessageAlloc(); ++ result = SLPMessageParseBuffer(destaddr, recvbuf, message); ++ if (result == 0) ++ { ++ result = callback(message, cookie); ++ } ++FINISHED: ++ SLPMessageFree(message); ++ SLPBufferFree(sendbuf); ++ SLPBufferFree(recvbuf); ++ return result; ++} ++ ++typedef struct SLPURL { ++ struct SLPURL *next; ++ struct SLPURL *last; ++ char *serviceURL; ++ char *attrs; ++ char* scopelist; ++ char* serviceType; ++ unsigned short ltime; ++} SLPUrl; ++ ++ ++//Cache collection structure ++typedef struct SLPUrlList { ++ char *services; /* list of all services */ ++ SLPUrl *slpUrl; /* linked list of URLs for all services */ ++ SLPUrl *currentSLPUrl; /* next location to be used for update */ ++ char* currentScope; ++ char* currentServiceType; ++} SLPUrlList; ++ ++static SLPUrl* AllocateSLPUrl() ++{ ++ SLPUrl* slpUrl = (SLPUrl*)malloc(sizeof(SLPUrl)); ++ slpUrl->serviceURL = NULL; ++ slpUrl->ltime = 0; ++ slpUrl->scopelist = NULL; ++ slpUrl->serviceType = NULL; ++ slpUrl->attrs = NULL; ++ slpUrl->next = NULL; ++ slpUrl->last = NULL; ++ return slpUrl; ++} ++ ++ ++static void CleanUpSLPUrlList(SLPUrlList* slpUrlList) ++{ ++ SLPUrl* slpUrl,*slpUrlNext; ++ ++ slpUrl = slpUrlList->slpUrl; ++ while(slpUrl) ++ { ++ if (slpUrl->serviceURL) ++ free(slpUrl->serviceURL); ++ if (slpUrl->scopelist) ++ free(slpUrl->scopelist); ++ if (slpUrl->serviceType) ++ free(slpUrl->serviceType); ++ if (slpUrl->attrs) ++ free(slpUrl->attrs); ++ slpUrlNext = slpUrl->next; ++ free(slpUrl); ++ slpUrl = slpUrlNext; ++ } ++ slpUrlList->slpUrl = NULL; ++ if (slpUrlList->currentScope != NULL) ++ free(slpUrlList->currentScope); ++ if(slpUrlList->services != NULL) ++ free(slpUrlList->services); ++ if(slpUrlList->currentServiceType != NULL) ++ free(slpUrlList->currentServiceType); ++ free(slpUrlList); ++} ++ ++static int SLPSrvTCallBack(SLPMessage message, void* cookie) ++{ ++ if (message->header.functionid != SLP_FUNCT_SRVTYPERPLY) ++ return SLP_NETWORK_ERROR; ++ if (message->body.srvtyperply.errorcode != 0) ++ return message->body.srvtyperply.errorcode; ++ /* null terminate as in libslp */ ++ ((char *)message->body.srvtyperply.srvtypelist)[message->body.srvtyperply.srvtypelistlen] = 0; ++ ((SLPUrlList*)cookie)->services = strdup(message->body.srvtyperply.srvtypelist); ++ return 0; ++} ++ ++static int SLPSrvCallBack(SLPMessage message, void* cookie) ++{ ++ SLPUrl *slpUrl = NULL; ++ char scopelist[4096]; ++ int i; ++ SLPUrlEntry *srvurl; ++ ++ if (message->header.functionid != SLP_FUNCT_SRVRPLY) ++ return SLP_NETWORK_ERROR; ++ if (message->body.srvrply.errorcode != 0) ++ return message->body.srvrply.errorcode; ++ for (i=0;ibody.srvrply.urlcount;i++) ++ { ++ srvurl = message->body.srvrply.urlarray + i; ++ /* null terminate url as in libslp, overwrites authcount */ ++ ((char *)srvurl->url)[srvurl->urllen] = 0; ++ for(slpUrl = ((SLPUrlList*)cookie)->slpUrl; slpUrl ; slpUrl = slpUrl->next) ++ { ++ /* Check whether the same service URL is available as part of different scope*/ ++ if( (slpUrl->serviceURL != NULL) && ( strcasecmp( slpUrl->serviceURL,srvurl->url) == 0)) ++ break; ++ } ++ if (slpUrl) ++ { ++ snprintf(scopelist,sizeof(scopelist),"%s,%s",slpUrl->scopelist,((SLPUrlList*)cookie)->currentScope); ++ free(slpUrl->scopelist); ++ slpUrl->scopelist = strdup(scopelist); ++ } ++ else ++ { ++ slpUrl = AllocateSLPUrl(); ++ slpUrl->serviceURL = strdup(srvurl->url); ++ slpUrl->ltime = srvurl->lifetime; ++ slpUrl->scopelist = strdup(((SLPUrlList*)cookie)->currentScope); ++ slpUrl->serviceType = strdup(((SLPUrlList*)cookie)->currentServiceType); ++ slpUrl->attrs = NULL; ++ slpUrl->next = ((SLPUrlList*)cookie)->slpUrl; ++ if(((SLPUrlList*)cookie)->slpUrl) ++ ((SLPUrlList*)cookie)->slpUrl->last = slpUrl; ++ ((SLPUrlList*)cookie)->slpUrl= slpUrl; ++ } ++ } ++ return 0; ++} ++ ++static int SLPSrvAttrCallBack(SLPMessage message, void* cookie) ++{ ++ SLPUrl *lslpUrl = ((SLPUrlList*)cookie)->currentSLPUrl; ++ if (message->header.functionid != SLP_FUNCT_ATTRRPLY) ++ return SLP_NETWORK_ERROR; ++ if (message->body.attrrply.errorcode != 0) ++ return message->body.attrrply.errorcode; ++ ++ /* null terminate as in libslp */ ++ ((char *)message->body.attrrply.attrlist)[message->body.attrrply.attrlistlen] = 0; ++ lslpUrl->attrs = strdup(message->body.attrrply.attrlist); ++ return 0; ++} ++ ++static char *createreq(int *sizep, char *url, char *scope, char *predicate, char *spi) ++{ ++ char *buf, *cur; ++ int urllen = url ? strlen(url) : 0; ++ int scopelen = scope ? strlen(scope) : 0; ++ int predicatelen = predicate ? strlen(predicate) : 0; ++ int spilen = spi ? strlen(spi) : 0; ++ buf = malloc(2 + urllen + 2 + scopelen + 2 + predicatelen + 2 + spilen); ++ cur = buf; ++ if (url) ++ { ++ ToUINT16(cur, urllen); ++ cur += 2; ++ memcpy(cur, url, urllen); ++ cur += urllen; ++ } ++ if (scope) ++ { ++ ToUINT16(cur, scopelen); ++ cur += 2; ++ memcpy(cur, scope, scopelen); ++ cur += scopelen; ++ } ++ if (predicate) ++ { ++ ToUINT16(cur, predicatelen); ++ cur += 2; ++ memcpy(cur, predicate, predicatelen); ++ cur += predicatelen; ++ } ++ if (spi) ++ { ++ ToUINT16(cur, spilen); ++ cur += 2; ++ memcpy(cur, spi, spilen); ++ cur += spilen; ++ } ++ *sizep = cur - buf; ++ return buf; ++} ++ ++ ++/*=========================================================================*/ ++int getSLPServiceURLs(int sock, struct sockaddr_in *destaddr) ++/*=========================================================================*/ ++{ ++ char *strng, *services; ++ int gresult = 0, result; ++ SLPUrl* slpUrl; ++ char *scope = NULL, *scopelist = NULL; ++ char scopeptr[4096],serviceptr[4096]; ++ SLPMessage msg; ++ SLPBuffer buf; ++ const char *langtag; ++ char *outbuf; ++ int bufsize; ++ char *srvtype, *srvtype_end; ++ ++ SLPUrlList* slpUrlList = (SLPUrlList*)malloc(sizeof(SLPUrlList)); ++ slpUrlList->slpUrl = NULL; ++ slpUrlList->services = NULL; ++ slpUrlList->currentServiceType = NULL; ++ slpUrlList->currentScope = NULL; ++ ++ langtag = SLPPropertyGet("net.slp.locale"); ++ ++ scopelist = strdup(G_SlpdProperty.useScopes); ++ ++ for(scope = strtok_r(scopelist,",",(char**)&scopeptr); scope ; scope = strtok_r(NULL,",",(char**)&scopeptr)) ++ { ++ slpUrlList->currentScope = strdup(scope); ++ outbuf = createreq(&bufsize, "", scope, NULL, NULL); ++ ToUINT16(outbuf, 0xffff); /* 0xffff indicates all service types */ ++ result = SLPDUnicastRqstRply(sock, destaddr, langtag, outbuf, SLP_FUNCT_SRVTYPERQST, bufsize, SLPSrvTCallBack, slpUrlList); ++ free(outbuf); ++ if (result) ++ { ++ gresult = result; /* remember error with that scope */ ++ SLPDLog("Error: SLPFindSrvTypes %d\n",result); ++ continue; ++ } ++ if(slpUrlList->services) ++ { ++ services = strdup(slpUrlList->services); ++ for(strng = strtok_r(services, ",",(char**)&serviceptr); strng ; strng = strtok_r(NULL, ",",(char**)&serviceptr)) ++ { ++ slpUrlList->currentServiceType = strdup(strng); ++ outbuf = createreq(&bufsize, strng, scope, "", ""); ++ result = SLPDUnicastRqstRply(sock, destaddr, langtag, outbuf, SLP_FUNCT_SRVRQST, bufsize, SLPSrvCallBack, slpUrlList); ++ free(outbuf); ++ free(slpUrlList->currentServiceType); ++ slpUrlList->currentServiceType = NULL; ++ if(result != 0) ++ { ++ SLPDLog("Error: SLPFindSrvs %d\n", result); ++ continue; ++ } ++ } ++ free(services); ++ } ++ if (slpUrlList->currentScope != NULL) ++ { ++ free(slpUrlList->currentScope); ++ slpUrlList->currentScope = NULL; ++ } ++ if(slpUrlList->services != NULL) ++ { ++ free(slpUrlList->services); ++ slpUrlList->services = NULL; ++ } ++ } ++ ++ /* we now have collected all services, fetch the attributes */ ++ ++ for(slpUrl = slpUrlList->slpUrl; slpUrl ; slpUrl = slpUrl->next) ++ { ++ slpUrl->attrs = NULL; ++ slpUrlList->currentSLPUrl = slpUrl; ++ outbuf = createreq(&bufsize, slpUrl->serviceURL, slpUrl->scopelist, "", ""); ++ result = SLPDUnicastRqstRply(sock, destaddr, langtag, outbuf, SLP_FUNCT_ATTRRQST, bufsize, SLPSrvAttrCallBack, slpUrlList); ++ free(outbuf); ++ if(result != 0) ++ { ++ SLPDLog("Error: SLPFindAttrs %d\n", result); ++ continue; ++ } ++ srvtype = strdup(slpUrl->serviceURL); ++ srvtype_end = strstr(srvtype, "://"); ++ if (srvtype_end) ++ *srvtype_end = 0; ++ if (SLPDCreateSrvReg(SLP_REG_SOURCE_PULL_PEER_DA, ++ strlen(slpUrl->serviceURL), slpUrl->serviceURL, ++ strlen(langtag), (char *)langtag, ++ strlen(srvtype), srvtype, ++ strlen(slpUrl->scopelist), slpUrl->scopelist, ++ slpUrl->attrs ? strlen(slpUrl->attrs) : 0, slpUrl->attrs, ++ slpUrl->ltime, &msg, &buf) == 0) ++ { ++ msg->peer = *destaddr; ++ SLPDDatabaseReg(msg, buf); ++ } ++ free(srvtype); ++ } ++ ++ CleanUpSLPUrlList(slpUrlList); ++ if(scopelist != NULL) ++ free(scopelist); ++ return gresult; ++} ++ +--- ./slpd/slpd_initda.h.orig 2010-09-30 10:43:08.475048000 +0000 ++++ ./slpd/slpd_initda.h 2010-09-30 10:43:08.476048000 +0000 +@@ -0,0 +1,16 @@ ++#ifndef SLPD_INITDA_H_INCLUDE ++#define SLPD_INITDA_H_INCLUDE ++ ++#include "slpd.h" ++ ++/*=========================================================================*/ ++/* common code includes */ ++/*=========================================================================*/ ++#include "slpd_socket.h" ++ ++ ++/*=========================================================================*/ ++int getSLPServiceURLs(int sock, struct sockaddr_in *destaddr); ++/*=========================================================================*/ ++ ++#endif +--- ./slpd/slpd_log.c.orig 2010-09-30 10:42:25.931413000 +0000 ++++ ./slpd/slpd_log.c 2010-09-30 10:43:08.484053000 +0000 +@@ -476,6 +476,9 @@ void SLPDLogRegistration(const char* pre + case SLP_REG_SOURCE_STATIC: + SLPDLog("static (slp.reg)\n"); + break; ++ case SLP_REG_SOURCE_PULL_PEER_DA: ++ SLPDLog("pulled from peer DA (%s)\n", inet_ntoa(entry->msg->peer.sin_addr)); ++ break; + } + SLPDLogBuffer(" service-url = ", + entry->msg->body.srvreg.urlentry.urllen, +--- ./slpd/slpd_main.c.orig 2010-09-30 10:42:26.098408000 +0000 ++++ ./slpd/slpd_main.c 2010-09-30 10:43:08.493052000 +0000 +@@ -63,6 +63,7 @@ + #ifdef ENABLE_SLPv2_SECURITY + #include "slpd_spi.h" + #endif ++#include "slpd_initda.h" + + /*=========================================================================*/ + /* common code includes */ +@@ -76,12 +77,34 @@ int G_SIGALRM; + int G_SIGTERM; + int G_SIGHUP; + char *reg_file_dir; ++FILE *DABackupfp; + + #ifdef DEBUG + int G_SIGINT; /* Signal being used for dumping registrations */ + #endif + /*==========================================================================*/ + ++ ++/*-------------------------------------------------------------------------*/ ++static void SLPDOpenDABackupFile() ++/*-------------------------------------------------------------------------*/ ++{ ++ FILE *fp; ++ char filename[1024]; ++ snprintf(filename, sizeof(filename), "%s/slpd/%s", reg_file_dir, "DABackup"); ++ ++ fp = fopen(filename, "a+"); ++ if (!DABackupfp && !fp) ++ SLPDLog("Could not open DABackup file\n"); ++ if (fp) ++ { ++ if (DABackupfp) ++ fclose(DABackupfp); ++ DABackupfp = fp; ++ } ++} ++ ++ + #ifdef HAVE_POLL + + /*-------------------------------------------------------------------------*/ +@@ -239,6 +262,10 @@ void HandleSigTerm() + SLPDLog("SLPD daemon shutting down\n"); + SLPDLog("****************************************\n"); + ++ /* write backup file if configured */ ++ if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp) ++ SLPDDatabaseWriteDABackup(DABackupfp); ++ + /* close all incoming sockets */ + SLPDIncomingDeinit(); + #ifdef ENABLE_MDNS_SLPD +@@ -301,6 +328,10 @@ void HandleSigHup() + SLPDLog("SLPD daemon reset by SIGHUP\n"); + SLPDLog("****************************************\n\n"); + ++ if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp) ++ { ++ SLPDDatabaseWriteDABackup(DABackupfp); ++ } + /* unregister with all DAs */ + SLPDKnownDADeinit(); + +@@ -322,6 +353,11 @@ void HandleSigHup() + /* Re-read the static registration file (slp.reg)*/ + SLPDDatabaseReInit(); + ++ if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp) ++ { ++ SLPDDatabaseReadDABackup(DABackupfp); ++ } ++ + /* Rebuild Known DA database */ + SLPDKnownDAInit(); + +@@ -654,6 +690,9 @@ int main(int argc, char* argv[]) + SLPDLog("Agent Interfaces = %s\n",G_SlpdProperty.interfaces); + SLPDLog("Agent URL = %s\n",G_SlpdProperty.myUrl); + ++ if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup) ++ SLPDOpenDABackupFile(); ++ + /*---------------------------*/ + /* init watcher */ + /*---------------------------*/ +@@ -675,6 +714,43 @@ int main(int argc, char* argv[]) + SLPDFatal("Error setting up signal handlers.\n"); + } + ++ if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp) ++ { ++ SLPDDatabaseReadDABackup(DABackupfp); ++ } ++ ++ if((G_SlpdProperty.isDA) && (G_SlpdProperty.DASyncReg)) ++ { ++ /* HACK: at that point in time all outgoing sockets are DA connections ++ * and the incoming sockets are our interfaces */ ++ SLPDLog("Pulling service list from other DAs...\n"); ++ SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head; ++ while (sock) ++ { ++ SLPDSocket* isock = (SLPDSocket*)G_IncomingSocketList.head; ++ ++ /* make sure we're not connecting to ourself */ ++ while (isock) ++ { ++ if (sock->peeraddr.sin_addr.s_addr == isock->peeraddr.sin_addr.s_addr) ++ break; ++ isock = (SLPDSocket*)isock->listitem.next; ++ } ++ if (!isock) ++ { ++ int s = SLPNetworkConnectStream(&sock->peeraddr, 0); ++ if (s >= 0) ++ { ++ int result = getSLPServiceURLs(s, &sock->peeraddr); ++ close(s); ++ if (result == 0) ++ break; ++ } ++ } ++ sock = (SLPDSocket*)sock->listitem.next; ++ } ++ } ++ + /*------------------------------*/ + /* Set up alarm to age database */ + /*------------------------------*/ +@@ -753,6 +829,22 @@ int main(int argc, char* argv[]) + } + #endif + ++ if (G_SlpdProperty.isDA && G_SlpdProperty.isDABackup && DABackupfp) ++ { ++ static time_t lastbck; ++ time_t now; ++ ++ now = time(NULL); ++ if (!lastbck) ++ lastbck = now; ++ if (now - lastbck > G_SlpdProperty.DABackupInterval) ++ { ++ SLPDLog("Updating registration backup file\n"); ++ SLPDDatabaseWriteDABackup(DABackupfp); ++ lastbck = now; ++ } ++ } ++ + } /* End of main loop */ + + /* Got SIGTERM */ +--- ./slpd/slpd_property.c.orig 2010-09-30 10:42:26.221408000 +0000 ++++ ./slpd/slpd_property.c 2010-09-30 10:43:08.500046000 +0000 +@@ -232,6 +232,11 @@ int SLPDPropertyInit(const char* conffil + G_SlpdProperty.nextActiveDiscovery = 0; /* ensures xmit on first call to SLPDKnownDAActiveDiscovery() */ + G_SlpdProperty.nextPassiveDAAdvert = 0; /* ensures xmit on first call to SLPDKnownDAPassiveDiscovery()*/ + ++ G_SlpdProperty.DASyncReg = SLPPropertyAsBoolean(SLPPropertyGet("net.slp.DASyncReg")); ++ G_SlpdProperty.DASyncReg = SLPPropertyAsBoolean(SLPPropertyGet("net.slp.DASyncReg")); ++ G_SlpdProperty.isDABackup = SLPPropertyAsBoolean(SLPPropertyGet("net.slp.isDABackup")); ++ G_SlpdProperty.DABackupInterval = SLPPropertyAsInteger(SLPPropertyGet("net.slp.DABackupInterval")); ++ G_SlpdProperty.DABackupLocalReg = SLPPropertyAsBoolean(SLPPropertyGet("net.slp.DABackupLocalReg")); + return 0; + } + +--- ./slpd/slpd_property.h.orig 2010-09-30 10:42:26.216411000 +0000 ++++ ./slpd/slpd_property.h 2010-09-30 10:43:08.507046000 +0000 +@@ -96,6 +96,10 @@ typedef struct _SLPDProperty + int DAHeartBeat; + int oversizedUDP; + int allowDoubleEqualInPredicate; ++ int DASyncReg; ++ int isDABackup; ++ int DABackupInterval; ++ int DABackupLocalReg; + }SLPDProperty; + + +--- ./slpd/slpd_regfile.c.orig 2010-09-30 10:42:25.984413000 +0000 ++++ ./slpd/slpd_regfile.c 2010-09-30 10:43:08.516048000 +0000 +@@ -128,19 +128,213 @@ char* RegFileReadLine(FILE* fd, char* li + return line; + } + ++ + /*=========================================================================*/ +-int SLPDRegFileReadSrvReg(FILE* fd, +- SLPMessage* msg, +- SLPBuffer* buf) +-/* A really big and nasty function that reads an service registration from */ +-/* from a file. Don't look at this too hard or you'll be sick. This is by */ ++int SLPDCreateSrvReg(int source, ++ int urllen, ++ char* url, ++ int langtaglen, ++ char* langtag, ++ int srvtypelen, ++ char* srvtype, ++ int scopelistlen, ++ char* scopelist, ++ int attrlistlen, ++ char* attrlist, ++ int lifetime, ++ SLPMessage* msg, ++ SLPBuffer* buf) ++/* Create a SrcReg Message from given data. */ ++/* Don't look at this too hard or you'll be sick. This is by far */ + /* the most horrible code in OpenSLP. Please volunteer to rewrite it! */ + /* */ + /* "THANK GOODNESS this function is only called at startup" -- Matt */ + /* */ ++/* Note: Eventually the caller needs to call SLPBufferFree() and */ ++/* SLPMessageFree() to free memory */ ++/*=========================================================================*/ ++{ ++ int result = 0; ++ int bufsize = 0; ++ struct sockaddr_in peer; ++#ifdef ENABLE_SLPv2_SECURITY ++ unsigned char* urlauth = 0; ++ int urlauthlen = 0; ++ unsigned char* attrauth = 0; ++ int attrauthlen = 0; ++#endif ++ ++#ifdef ENABLE_SLPv2_SECURITY ++ /*--------------------------------*/ ++ /* Generate authentication blocks */ ++ /*--------------------------------*/ ++ if(G_SlpdProperty.securityEnabled) ++ { ++ ++ SLPAuthSignUrl(G_SlpdSpiHandle, ++ 0, ++ 0, ++ urllen, ++ url, ++ &urlauthlen, ++ &urlauth); ++ ++ SLPAuthSignString(G_SlpdSpiHandle, ++ 0, ++ 0, ++ attrlistlen, ++ attrlist, ++ &attrauthlen, ++ &attrauth); ++ } ++#endif ++ ++ ++ /*----------------------------------------*/ ++ /* Allocate buffer for the SrvReg Message */ ++ /*----------------------------------------*/ ++ bufsize = 14 + langtaglen; /* 14 bytes for header */ ++ bufsize += urllen + 6; /* 1 byte for reserved */ ++ /* 2 bytes for lifetime */ ++ /* 2 bytes for urllen */ ++ /* 1 byte for authcount */ ++ bufsize += srvtypelen + 2; /* 2 bytes for len field */ ++ bufsize += scopelistlen + 2;/* 2 bytes for len field */ ++ bufsize += attrlistlen + 2; /* 2 bytes for len field */ ++ bufsize += 1; /* 1 byte for authcount */ ++ #ifdef ENABLE_SLPv2_SECURITY ++ bufsize += urlauthlen; ++ bufsize += attrauthlen; ++ #endif ++ *buf = SLPBufferAlloc(bufsize); ++ if(*buf == 0) ++ { ++ result = SLP_ERROR_INTERNAL_ERROR; ++ goto CLEANUP; ++ } ++ ++ /*------------------------------*/ ++ /* Now build the SrvReg Message */ ++ /*------------------------------*/ ++ /*version*/ ++ *((*buf)->start) = 2; ++ /*function id*/ ++ *((*buf)->start + 1) = SLP_FUNCT_SRVREG; ++ /*length*/ ++ ToUINT24((*buf)->start + 2, bufsize); ++ /*flags*/ ++ ToUINT16((*buf)->start + 5, 0); ++ /*ext offset*/ ++ ToUINT24((*buf)->start + 7,0); ++ /*xid*/ ++ ToUINT16((*buf)->start + 10, 0); ++ /*lang tag len*/ ++ ToUINT16((*buf)->start + 12,langtaglen); ++ /*lang tag*/ ++ memcpy((*buf)->start + 14, langtag, langtaglen); ++ (*buf)->curpos = (*buf)->start + langtaglen + 14 ; ++ /* url-entry reserved */ ++ *(*buf)->curpos= 0; ++ (*buf)->curpos = (*buf)->curpos + 1; ++ /* url-entry lifetime */ ++ ToUINT16((*buf)->curpos,lifetime); ++ (*buf)->curpos = (*buf)->curpos + 2; ++ /* url-entry urllen */ ++ ToUINT16((*buf)->curpos,urllen); ++ (*buf)->curpos = (*buf)->curpos + 2; ++ /* url-entry url */ ++ memcpy((*buf)->curpos,url,urllen); ++ (*buf)->curpos = (*buf)->curpos + urllen; ++ /* url-entry authblock */ ++#ifdef ENABLE_SLPv2_SECURITY ++ if(urlauth) ++ { ++ /* authcount */ ++ *(*buf)->curpos = 1; ++ (*buf)->curpos = (*buf)->curpos + 1; ++ /* authblock */ ++ memcpy((*buf)->curpos,urlauth,urlauthlen); ++ (*buf)->curpos = (*buf)->curpos + urlauthlen; ++ } ++ else ++#endif ++ { ++ /* authcount */ ++ *(*buf)->curpos = 0; ++ (*buf)->curpos += 1; ++ } ++ /* service type */ ++ ToUINT16((*buf)->curpos,srvtypelen); ++ (*buf)->curpos = (*buf)->curpos + 2; ++ memcpy((*buf)->curpos,srvtype,srvtypelen); ++ (*buf)->curpos = (*buf)->curpos + srvtypelen; ++ /* scope list */ ++ ToUINT16((*buf)->curpos,scopelistlen); ++ (*buf)->curpos = (*buf)->curpos + 2; ++ memcpy((*buf)->curpos,scopelist,scopelistlen); ++ (*buf)->curpos = (*buf)->curpos + scopelistlen; ++ /* attr list */ ++ ToUINT16((*buf)->curpos,attrlistlen); ++ (*buf)->curpos = (*buf)->curpos + 2; ++ memcpy((*buf)->curpos,attrlist,attrlistlen); ++ (*buf)->curpos = (*buf)->curpos + attrlistlen; ++ /* attribute auth block */ ++#ifdef ENABLE_SLPv2_SECURITY ++ if(attrauth) ++ { ++ /* authcount */ ++ *(*buf)->curpos = 1; ++ (*buf)->curpos = (*buf)->curpos + 1; ++ /* authblock */ ++ memcpy((*buf)->curpos,attrauth,attrauthlen); ++ (*buf)->curpos = (*buf)->curpos + attrauthlen; ++ } ++ else ++#endif ++ { ++ /* authcount */ ++ *(*buf)->curpos = 0; ++ (*buf)->curpos = (*buf)->curpos + 1; ++ } ++ ++ /*------------------------------------------------*/ ++ /* Ok Now comes the really stupid (and lazy part) */ ++ /*------------------------------------------------*/ ++ *msg = SLPMessageAlloc(); ++ if(*msg == 0) ++ { ++ SLPBufferFree(*buf); ++ *buf=0; ++ result = SLP_ERROR_INTERNAL_ERROR; ++ goto CLEANUP; ++ } ++ peer.sin_addr.s_addr = htonl(LOOPBACK_ADDRESS); ++ result = SLPMessageParseBuffer(&peer,*buf,*msg); ++ (*msg)->body.srvreg.source = source; ++ ++ ++CLEANUP: ++#ifdef ENABLE_SLPv2_SECURITY ++ if(urlauth) xfree(urlauth); ++ if(attrauth) xfree(attrauth); ++#endif ++ ++ return result; ++} ++ ++ ++/*=========================================================================*/ ++int SLPDRegFileReadSrvReg(FILE* fd, ++ int source, ++ SLPMessage* msg, ++ SLPBuffer* buf) ++/* A really big and nasty function that reads an service registration from */ ++/* from a file. */ + /* */ + /* fd (IN) file to read from */ + /* */ ++/* source (IN) registration type (SLP_REG_SOURCE_STATIC) */ ++/* */ + /* msg (OUT) message describing the SrvReg in buf */ + /* */ + /* buf (OUT) buffer containing the SrvReg */ +@@ -156,9 +350,7 @@ int SLPDRegFileReadSrvReg(FILE* fd, + char* p; + char line[4096]; + +- struct sockaddr_in peer; + int result = 0; +- int bufsize = 0; + int langtaglen = 0; + char* langtag = 0; + int scopelistlen = 0; +@@ -170,14 +362,9 @@ int SLPDRegFileReadSrvReg(FILE* fd, + char* srvtype = 0; + int attrlistlen = 0; + char* attrlist = 0; +-#ifdef ENABLE_SLPv2_SECURITY +- unsigned char* urlauth = 0; +- int urlauthlen = 0; +- unsigned char* attrauth = 0; +- int attrauthlen = 0; +-#endif +- int watchport = 0; +- int watchflags = 0; ++ int watchport = 0; ++ int watchflags = 0; ++ char* peerip = 0; + + + /*-------------------------------------------*/ +@@ -217,14 +404,17 @@ int SLPDRegFileReadSrvReg(FILE* fd, + } + + /* replace "$HOSTNAME" string in url */ +- while ((p = strchr(url, '$')) && !strncmp(p, "$HOSTNAME", 9)) ++ if (source == SLP_REG_SOURCE_STATIC) + { +- char *_url = (char*)malloc(strlen(url) - 9 + G_SlpdProperty.myHostnameLen + 1); +- strncpy(_url, url, p - url); +- strncpy(_url + (p - url), G_SlpdProperty.myHostname, G_SlpdProperty.myHostnameLen); +- strcpy(_url + (p - url) + G_SlpdProperty.myHostnameLen, url + (p - url) + 9); +- free(url); +- url = _url; ++ while ((p = strchr(url, '$')) && !strncmp(p, "$HOSTNAME", 9)) ++ { ++ char *_url = (char*)malloc(strlen(url) - 9 + G_SlpdProperty.myHostnameLen + 1); ++ strncpy(_url, url, p - url); ++ strncpy(_url + (p - url), G_SlpdProperty.myHostname, G_SlpdProperty.myHostnameLen); ++ strcpy(_url + (p - url) + G_SlpdProperty.myHostnameLen, url + (p - url) + 9); ++ free(url); ++ url = _url; ++ } + } + urllen = strlen(url); + +@@ -310,6 +500,7 @@ int SLPDRegFileReadSrvReg(FILE* fd, + /*-------------------------------------------------*/ + /* Read all the attributes including the scopelist */ + /*-------------------------------------------------*/ ++ + *line=0; + while(1) + { +@@ -363,6 +554,15 @@ int SLPDRegFileReadSrvReg(FILE* fd, + } + } + } ++ else if(strncasecmp(slider1,"slp-source",10) == 0 && source != SLP_REG_SOURCE_STATIC) ++ { ++ slider2 = strchr(slider1,'='); ++ if(slider2) ++ { ++ slider2++; ++ peerip=xstrdup(TrimWhitespace(slider2)); ++ } ++ } + else if(strncasecmp(slider1,"tcp-port",8) == 0 || strncasecmp(slider1,"watch-port-tcp",14) == 0) + { + slider2 = strchr(slider1,'='); +@@ -407,7 +607,7 @@ int SLPDRegFileReadSrvReg(FILE* fd, + + /* we need special case for keywords (why do we need these) */ + /* they seem like a waste of code. Why not just use booleans */ +- if(strchr(slider1,'=')) ++ if(strchr(slider1,'=') && source == SLP_REG_SOURCE_STATIC) + { + /* normal attribute (with '=') */ + strcat(attrlist,"("); +@@ -436,157 +636,26 @@ int SLPDRegFileReadSrvReg(FILE* fd, + scopelistlen = G_SlpdProperty.useScopesLen; + } + +- +-#ifdef ENABLE_SLPv2_SECURITY +- /*--------------------------------*/ +- /* Generate authentication blocks */ +- /*--------------------------------*/ +- if(G_SlpdProperty.securityEnabled) +- { +- +- SLPAuthSignUrl(G_SlpdSpiHandle, +- 0, +- 0, +- urllen, +- url, +- &urlauthlen, +- &urlauth); +- +- SLPAuthSignString(G_SlpdSpiHandle, +- 0, +- 0, +- attrlistlen, +- attrlist, +- &attrauthlen, +- &attrauth); +- } +-#endif +- ++ result = SLPDCreateSrvReg(source, urllen, url, langtaglen, langtag, srvtypelen, srvtype, scopelistlen, scopelist, attrlistlen, attrlist, lifetime, msg, buf); ++ if (result) ++ goto CLEANUP; + +- /*----------------------------------------*/ +- /* Allocate buffer for the SrvReg Message */ +- /*----------------------------------------*/ +- bufsize = 14 + langtaglen; /* 14 bytes for header */ +- bufsize += urllen + 6; /* 1 byte for reserved */ +- /* 2 bytes for lifetime */ +- /* 2 bytes for urllen */ +- /* 1 byte for authcount */ +- bufsize += srvtypelen + 2; /* 2 bytes for len field */ +- bufsize += scopelistlen + 2;/* 2 bytes for len field */ +- bufsize += attrlistlen + 2; /* 2 bytes for len field */ +- bufsize += 1; /* 1 byte for authcount */ +- #ifdef ENABLE_SLPv2_SECURITY +- bufsize += urlauthlen; +- bufsize += attrauthlen; +- #endif +- *buf = SLPBufferAlloc(bufsize); +- if(*buf == 0) +- { +- result = SLP_ERROR_INTERNAL_ERROR; +- goto CLEANUP; +- } +- +- /*------------------------------*/ +- /* Now build the SrvReg Message */ +- /*------------------------------*/ +- /*version*/ +- *((*buf)->start) = 2; +- /*function id*/ +- *((*buf)->start + 1) = SLP_FUNCT_SRVREG; +- /*length*/ +- ToUINT24((*buf)->start + 2, bufsize); +- /*flags*/ +- ToUINT16((*buf)->start + 5, 0); +- /*ext offset*/ +- ToUINT24((*buf)->start + 7,0); +- /*xid*/ +- ToUINT16((*buf)->start + 10, 0); +- /*lang tag len*/ +- ToUINT16((*buf)->start + 12,langtaglen); +- /*lang tag*/ +- memcpy((*buf)->start + 14, langtag, langtaglen); +- (*buf)->curpos = (*buf)->start + langtaglen + 14 ; +- /* url-entry reserved */ +- *(*buf)->curpos= 0; +- (*buf)->curpos = (*buf)->curpos + 1; +- /* url-entry lifetime */ +- ToUINT16((*buf)->curpos,lifetime); +- (*buf)->curpos = (*buf)->curpos + 2; +- /* url-entry urllen */ +- ToUINT16((*buf)->curpos,urllen); +- (*buf)->curpos = (*buf)->curpos + 2; +- /* url-entry url */ +- memcpy((*buf)->curpos,url,urllen); +- (*buf)->curpos = (*buf)->curpos + urllen; +- /* url-entry authblock */ +-#ifdef ENABLE_SLPv2_SECURITY +- if(urlauth) +- { +- /* authcount */ +- *(*buf)->curpos = 1; +- (*buf)->curpos = (*buf)->curpos + 1; +- /* authblock */ +- memcpy((*buf)->curpos,urlauth,urlauthlen); +- (*buf)->curpos = (*buf)->curpos + urlauthlen; +- } +- else +-#endif +- { +- /* authcount */ +- *(*buf)->curpos = 0; +- (*buf)->curpos += 1; +- } +- /* service type */ +- ToUINT16((*buf)->curpos,srvtypelen); +- (*buf)->curpos = (*buf)->curpos + 2; +- memcpy((*buf)->curpos,srvtype,srvtypelen); +- (*buf)->curpos = (*buf)->curpos + srvtypelen; +- /* scope list */ +- ToUINT16((*buf)->curpos,scopelistlen); +- (*buf)->curpos = (*buf)->curpos + 2; +- memcpy((*buf)->curpos,scopelist,scopelistlen); +- (*buf)->curpos = (*buf)->curpos + scopelistlen; +- /* attr list */ +- ToUINT16((*buf)->curpos,attrlistlen); +- (*buf)->curpos = (*buf)->curpos + 2; +- memcpy((*buf)->curpos,attrlist,attrlistlen); +- (*buf)->curpos = (*buf)->curpos + attrlistlen; +- /* attribute auth block */ +-#ifdef ENABLE_SLPv2_SECURITY +- if(attrauth) +- { +- /* authcount */ +- *(*buf)->curpos = 1; +- (*buf)->curpos = (*buf)->curpos + 1; +- /* authblock */ +- memcpy((*buf)->curpos,attrauth,attrauthlen); +- (*buf)->curpos = (*buf)->curpos + attrauthlen; +- } +- else +-#endif ++ if (source == SLP_REG_SOURCE_STATIC) + { +- /* authcount */ +- *(*buf)->curpos = 0; +- (*buf)->curpos = (*buf)->curpos + 1; ++ (*msg)->body.srvreg.watchflags = watchflags ? (watchflags | SLP_REG_WATCH_DEAD) : 0; ++ (*msg)->body.srvreg.watchport = watchport; + } +- +- /*------------------------------------------------*/ +- /* Ok Now comes the really stupid (and lazy part) */ +- /*------------------------------------------------*/ +- *msg = SLPMessageAlloc(); +- if(*msg == 0) ++ if (peerip && source != SLP_REG_SOURCE_STATIC) + { +- SLPBufferFree(*buf); +- *buf=0; +- result = SLP_ERROR_INTERNAL_ERROR; +- goto CLEANUP; ++ if (!strncmp(peerip, "pulled-from-da-", 15)) { ++ inet_aton(peerip + 15, &(*msg)->peer.sin_addr); ++ (*msg)->body.srvreg.source = SLP_REG_SOURCE_PULL_PEER_DA; ++ } else if (!strcmp(peerip, "local")) { ++ (*msg)->body.srvreg.source = SLP_REG_SOURCE_LOCAL; ++ } else { ++ inet_aton(peerip, &(*msg)->peer.sin_addr); ++ } + } +- peer.sin_addr.s_addr = htonl(LOOPBACK_ADDRESS); +- result = SLPMessageParseBuffer(&peer,*buf,*msg); +- (*msg)->body.srvreg.source = SLP_REG_SOURCE_STATIC; +- (*msg)->body.srvreg.watchflags = watchflags ? (watchflags | SLP_REG_WATCH_DEAD) : 0; +- (*msg)->body.srvreg.watchport = watchport; +- + + CLEANUP: + +@@ -612,11 +681,39 @@ CLEANUP: + if(scopelist) xfree(scopelist); + if(url) xfree(url); + if(srvtype) xfree(srvtype); +- if(attrlist)xfree(attrlist); +-#ifdef ENABLE_SLPv2_SECURITY +- if(urlauth) xfree(urlauth); +- if(attrauth) xfree(attrauth); +-#endif ++ if(attrlist) xfree(attrlist); ++ if(peerip) xfree(peerip); + + return result; + } ++ ++/*=========================================================================*/ ++int SLPDRegFileWriteSrvReg(FILE* fd, ++ SLPMessage msg) ++/* Write a service registration to a file */ ++/* */ ++/* fd (IN) file to write to */ ++/* */ ++/* msg (in) message describing the SrvReg */ ++/* */ ++/*=========================================================================*/ ++{ ++ int result = 0; ++ if (fd) ++ { ++ fprintf(fd, "%s,%s,%d\n", msg->body.srvreg.urlentry.url, msg->header.langtag, msg->body.srvreg.urlentry.lifetime); ++ if (msg->body.srvreg.source == SLP_REG_SOURCE_PULL_PEER_DA) ++ fprintf(fd, "slp-source=pulled-from-da-%s\n", inet_ntoa(msg->peer.sin_addr)); ++ else if (msg->body.srvreg.source == SLP_REG_SOURCE_LOCAL) ++ fprintf(fd, "slp-source=local\n"); ++ else ++ fprintf(fd, "slp-source=%s\n", inet_ntoa(msg->peer.sin_addr)); ++ if (msg->body.srvreg.scopelistlen) ++ fprintf(fd, "scopes=%.*s\n", msg->body.srvreg.scopelistlen, msg->body.srvreg.scopelist); ++ if(msg->body.srvreg.attrlistlen) ++ fprintf(fd, "%.*s\n", msg->body.srvreg.attrlistlen, msg->body.srvreg.attrlist); ++ fprintf(fd, "\n"); ++ } ++ return result; ++} ++ +--- ./slpd/slpd_regfile.h.orig 2001-05-10 15:04:19.000000000 +0000 ++++ ./slpd/slpd_regfile.h 2010-09-30 10:43:08.522049000 +0000 +@@ -61,18 +61,42 @@ + + + /*=========================================================================*/ +-int SLPDRegFileReadSrvReg(FILE* fd, +- SLPMessage* msg, +- SLPBuffer* buf); +-/* A really big and nasty function that reads an service registration from */ +-/* from a file. Don't look at this too hard or you'll be sick. This is by */ ++int SLPDCreateSrvReg(int source, ++ int urllen, ++ char* url, ++ int langtaglen, ++ char* langtag, ++ int srvtypelen, ++ char* srvtype, ++ int scopelistlen, ++ char* scopelist, ++ int attrlistlen, ++ char* attrlist, ++ int lifetime, ++ SLPMessage* msg, ++ SLPBuffer* buf); ++/* Create a SrcReg Message from given data. */ ++/* Don't look at this too hard or you'll be sick. This is by far */ + /* the most horrible code in OpenSLP. Please volunteer to rewrite it! */ + /* */ + /* "THANK GOODNESS this function is only called at startup" -- Matt */ + /* */ ++/* Note: Eventually the caller needs to call SLPBufferFree() and */ ++/* SLPMessageFree() to free memory */ ++/*=========================================================================*/ ++ ++/*=========================================================================*/ ++int SLPDRegFileReadSrvReg(FILE* fd, ++ int source, ++ SLPMessage* msg, ++ SLPBuffer* buf); ++/* A really big and nasty function that reads an service registration from */ ++/* from a file. */ + /* */ + /* fd (IN) file to read from */ + /* */ ++/* source (IN) registration type (SLP_REG_SOURCE_STATIC) */ ++/* */ + /* msg (OUT) message describing the SrvReg in buf */ + /* */ + /* buf (OUT) buffer containing the SrvReg */ +@@ -83,5 +107,16 @@ int SLPDRegFileReadSrvReg(FILE* fd, + /* SLPMessageFree() to free memory */ + /*=========================================================================*/ + ++/*=========================================================================*/ ++int SLPDRegFileWriteSrvReg(FILE* fd, ++ SLPMessage msg); ++/* Write a service registration to a file */ ++/* */ ++/* fd (IN) file to write to */ ++/* */ ++/* msg (in) message describing the SrvReg */ ++/* */ ++/*=========================================================================*/ ++ + + #endif diff --git a/openslp.parseext.diff b/openslp.parseext.diff new file mode 100644 index 0000000..0588742 --- /dev/null +++ b/openslp.parseext.diff @@ -0,0 +1,22 @@ +--- ./common/slp_message.c.orig 2010-10-12 15:42:23.439823000 +0000 ++++ ./common/slp_message.c 2010-10-12 15:45:44.936750000 +0000 +@@ -872,10 +872,19 @@ int ParseExtension(SLPBuffer buffer, SLP + int extid; + int nextoffset; + int result = SLP_ERROR_OK; ++ int bufsz = (int)(buffer->end - buffer->start); + + nextoffset = message->header.extoffset; + while(nextoffset) + { ++ /* check for circular reference in list ++ * if the size gets below zero, we know we're ++ * reprocessing extensions in a loop. ++ */ ++ bufsz -= 5; ++ if (bufsz <= 0) ++ return SLP_ERROR_PARSE_ERROR; ++ + buffer->curpos = buffer->start + nextoffset; + if(buffer->curpos + 5 >= buffer->end) + { diff --git a/openslp.spec b/openslp.spec index 682c275..d19eeed 100644 --- a/openslp.spec +++ b/openslp.spec @@ -21,8 +21,8 @@ Name: openslp BuildRequires: bison flex openssl-devel Summary: An OpenSLP Implementation of Service Location Protocol V2 Version: 1.2.0 -Release: 175 -License: BSD3c(or similar) ; GPLv2+ +Release: 182 +License: BSD3c Group: System/Daemons Url: http://www.openslp.org/ # bug437293 @@ -38,7 +38,8 @@ Source3: openslp.desktop Source4: openslp-devel.desktop Source5: openslp.logrotate Source6: slpd.xml -Source7: baselibs.conf +Source7: openslp.SuSEfirewall2 +Source8: baselibs.conf Patch1: openslp.diff Patch2: openslp.audit.diff Patch3: extensions.diff @@ -56,6 +57,11 @@ Patch14: openslp.dereg.diff Patch15: openslp.fixaddrcheck.diff Patch16: openslp.fixdsareturn.diff Patch17: openslp.clrflags.diff +Patch18: openslp.use-TCPDIAG-for-checking-listeners +Patch19: openslp.discovery.diff +Patch20: openslp.initda.diff +Patch21: openslp.ignorespaces.diff +Patch22: openslp.parseext.diff %description Service Location Protocol is an IETF standards track protocol that @@ -79,7 +85,7 @@ Authors: Praveen Kumar Amritaluru %package server -License: BSD3c(or similar) +License: BSD3c Group: System/Daemons Summary: The OpenSLP Implementation of the Service Location Protocol V2 PreReq: %fillup_prereq %insserv_prereq @@ -107,7 +113,7 @@ Authors: Praveen Kumar Amritaluru %package devel -License: BSD3c(or similar) +License: BSD3c Requires: openssl-devel openslp = %version Group: System/Daemons Summary: OpenSLP Development SDK @@ -159,6 +165,11 @@ Authors: %patch15 %patch16 %patch17 +%patch18 -p1 +%patch19 +%patch20 +%patch21 +%patch22 %build autoreconf -fiv @@ -169,6 +180,7 @@ autoreconf -fiv %install mkdir -p ${RPM_BUILD_ROOT}/etc/slp.reg.d +mkdir -p ${RPM_BUILD_ROOT}/etc/slp.reg.d/slpd cp etc/slp.conf ${RPM_BUILD_ROOT}/etc cp etc/slp.reg ${RPM_BUILD_ROOT}/etc cp etc/slp.spi ${RPM_BUILD_ROOT}/etc @@ -205,6 +217,9 @@ install -m 0644 %SOURCE6 $RPM_BUILD_ROOT/usr/share/omc/svcinfo.d %suse_update_desktop_file $RPM_BUILD_ROOT/usr/share/susehelp/meta/Development/Libraries/openslp-devel.desktop %endif %{__rm} -f %{buildroot}%{_libdir}/*.la +%if 0%{?suse_version} +install -D -m 644 %{S:7} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/openslp +%endif %post -p /sbin/ldconfig @@ -252,6 +267,7 @@ rm -rf $RPM_BUILD_ROOT %doc %_defaultdocdir/%name/rfc %doc /usr/share/susehelp/meta/Administration/openslp.desktop %dir /etc/slp.reg.d/ +%dir /etc/slp.reg.d/slpd /usr/sbin/rcopenslp /usr/sbin/rcslpd /usr/sbin/slpd @@ -259,6 +275,9 @@ rm -rf $RPM_BUILD_ROOT %config(noreplace) /etc/slp.reg %config(noreplace) /etc/logrotate.d/openslp-server /usr/share/omc/svcinfo.d/slpd.xml +%if 0%{?suse_version} > 0 +%config %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/openslp +%endif %files devel %defattr(-,root,root) diff --git a/openslp.use-TCPDIAG-for-checking-listeners b/openslp.use-TCPDIAG-for-checking-listeners new file mode 100644 index 0000000..a8a72e5 --- /dev/null +++ b/openslp.use-TCPDIAG-for-checking-listeners @@ -0,0 +1,237 @@ +From: Jeff Mahoney +Subject: openslp: Use TCPDIAG for checking listeners +References: bnc#601002 + + The use of /proc/net/tcp is deprecated and can cause performance issues on + large systems. The issue is that there are a great many locks that must + be claimed and released in order to produce the contents of the proc file. + + The replacement mechanism is to use the INETDIAG/TCPDIAG interface to + get the results. This has the advantage of using in-kernel filtering as + well as a binary interface so that the parsing of the proc file is + unnecessary. + + Support is limited to TCP so the use of /proc/net/udp is still required. + + If for whatever reason the netlink connection is lost and can't be + re-established, we fall back to reading /proc/net/tcp until the daemon + is restarted. + +Signed-off-by: Jeff Mahoney +--- + slpd/slpd_database.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 176 insertions(+), 3 deletions(-) + +--- a/slpd/slpd_database.c ++++ b/slpd/slpd_database.c +@@ -76,6 +76,9 @@ FILE *regfileFP; + /* standard header files */ + /*=========================================================================*/ + #include ++#include ++#include ++#include + + /*=========================================================================*/ + SLPDDatabase G_SlpdDatabase; +@@ -919,11 +922,176 @@ static void SLPDDatabaseWatcher_fd(int f + } + } + ++enum { ++ SS_UNKNOWN, ++ SS_ESTABLISHED, ++ SS_SYN_SENT, ++ SS_SYN_RECV, ++ SS_FIN_WAIT1, ++ SS_FIN_WAIT2, ++ SS_TIME_WAIT, ++ SS_CLOSE, ++ SS_CLOSE_WAIT, ++ SS_LAST_ACK, ++ SS_LISTEN, ++ SS_CLOSING, ++ SS_MAX ++}; ++ ++#define SS_ALL ((1< 0) { ++ if (sendmsg(*fd, &msg, 0) >= 0) ++ break; ++ ++ if (reconnect_nl(fd)) { ++ SLPDLog("Lost TCPDIAG netlink connection and attempts to " ++ "re-establish have failed. Falling back to /proc/net/tcp " ++ "for dead/alive updates.\n"); ++ *fd = -1; ++ return; ++ } ++ sched_yield(); ++ } ++ ++ iov.iov_base = buf; ++ iov.iov_len = sizeof(buf); ++ ++ dh = SLPDatabaseOpen(&G_SlpdDatabase.database); ++ while (!status) { ++ struct nlmsghdr *h; ++ ++ status = recvmsg(*fd, &msg, 0); ++ if (status < 0) { ++ if (errno == EINTR) ++ continue; ++ goto retry_sendmsg; ++ } ++ ++ /* Socket has shut down */ ++ if (status == 0) ++ goto retry_sendmsg; ++ ++ for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, status); ++ h = NLMSG_NEXT(h, status)) { ++ SLPDatabaseEntry *entry; ++ struct inet_diag_msg *r = NLMSG_DATA(h); ++ ++ if (h->nlmsg_seq != 123456) ++ continue; ++ ++ if (h->nlmsg_type == NLMSG_DONE) ++ goto close; ++ ++ if (h->nlmsg_type == NLMSG_ERROR) { ++ struct nlmsgerr *err = NLMSG_DATA(h); ++ if (h->nlmsg_len >= NLMSG_LENGTH(sizeof(*err))) ++ status = EINVAL; ++ else ++ status = -err->error; ++ break; ++ } ++ ++ if (r->idiag_family != AF_INET && r->idiag_family != AF_INET6) ++ continue; ++ ++ if (r->idiag_family == AF_INET && ++ ipv4_loopback.s_addr == r->id.idiag_src[0]) ++ continue; ++ ++ if (r->idiag_family == AF_INET6 && ++ !memcmp(ipv6_loopback.s6_addr32, r->id.idiag_src, ++ sizeof(ipv6_loopback))) ++ continue; ++ ++ port = ntohs(r->id.idiag_sport); ++ if (!(porthash[(port / 8) & 255] & (1 << (port & 7)))) ++ continue; ++ ++ SLPDatabaseRewind(dh); ++ ++ while ((entry = SLPDatabaseEnum(dh)) != 0) { ++ SLPSrvReg *srvreg = &(entry->msg->body.srvreg); ++ if (!(srvreg->watchflags & flag)) ++ continue; ++ if (port == srvreg->watchport) ++ srvreg->watchflags &= ~SLP_REG_WATCH_CHECKING; ++ } ++ } ++ } ++ ++close: ++ SLPDatabaseClose(dh); ++} ++ + /*=========================================================================*/ + void SLPDDatabaseWatcher(void) + { + static int initialized = 0; +- static int proctcp, procudp, proctcp6, procudp6; ++ static int proctcp, procudp, proctcp6, procudp6, inet_diag = -1; + unsigned char porthash[256]; + int flags, port; + SLPDatabaseHandle dh; +@@ -931,6 +1099,7 @@ void SLPDDatabaseWatcher(void) + SLPSrvReg* srvreg; + + if (!initialized) { ++ inet_diag = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); + proctcp = open("/proc/net/tcp_listen", O_RDONLY); + if (proctcp == -1) + proctcp = open("/proc/net/tcp", O_RDONLY); +@@ -955,8 +1124,12 @@ void SLPDDatabaseWatcher(void) + } + SLPDatabaseClose(dh); + if ((flags & SLP_REG_WATCH_TCP) != 0) { +- SLPDDatabaseWatcher_fd(proctcp, SLP_REG_WATCH_TCP, porthash); +- SLPDDatabaseWatcher_fd(proctcp6, SLP_REG_WATCH_TCP, porthash); ++ if (inet_diag >= 0) ++ SLPDDatabaseWatcher_nl(&inet_diag, SLP_REG_WATCH_TCP, porthash); ++ if (inet_diag < 0) { /* Fallback if _nl fails */ ++ SLPDDatabaseWatcher_fd(proctcp, SLP_REG_WATCH_TCP, porthash); ++ SLPDDatabaseWatcher_fd(proctcp6, SLP_REG_WATCH_TCP, porthash); ++ } + } + if ((flags & SLP_REG_WATCH_UDP) != 0) { + SLPDDatabaseWatcher_fd(procudp, SLP_REG_WATCH_UDP, porthash);