int MapRefItem::parse( const char * &pFormatStr, const char * pEnd, const RewriteMapList * pMaps ) { const char * pMapName = pFormatStr + 2; const char * pClose = StringTool::findCloseBracket( pMapName, pEnd ); if ( pClose == pEnd ) { HttpLog::parse_error( s_pCurLine, "missing '}'" ); return -1; } const char * pColon = StringTool::findCharInBracket( pMapName, pClose, ':' ); if ( pColon == NULL ) { HttpLog::parse_error( s_pCurLine, "missing ':'" ); return -1; } else { char achName[1024]; memmove( achName, pMapName, pColon - pMapName ); achName[pColon - pMapName] = 0; RewriteMapList::iterator iter = pMaps->find( achName ); if ( iter == pMaps->end() ) { HttpLog::parse_error( s_pCurLine, "rewrite map is not defined" ); return -1; } m_pMap = iter.second(); } pFormatStr = pClose + 1; const char * pDefault = StringTool::findCharInBracket( pMapName, pClose, '|' ); if ( pDefault != NULL ) { assert( !m_pDefaultFormat ); m_pDefaultFormat = new RewriteSubstFormat(); if ( !m_pDefaultFormat ) { ERR_NO_MEM( "new SubstFormat()" ); return -1; } if ( m_pDefaultFormat->parse( pDefault+1, pClose, pMaps ) ) return -1; } else pDefault = pClose; if ( ++pColon == pDefault ) { HttpLog::parse_error( s_pCurLine, "missing map key" ); return -1; } assert( !m_pKeyFormat ); m_pKeyFormat = new RewriteSubstFormat(); if ( !m_pKeyFormat ) { ERR_NO_MEM( "new SubstFormat()" ); return -1; } return m_pKeyFormat->parse( pColon, pDefault, pMaps ); }
int SubstFormat::parse( const char * pCurLine, const char * pFormatStr, const char * pEnd, int isSSI, char varChar ) { while(( pFormatStr < pEnd )&&( isspace( *pFormatStr ))) ++pFormatStr; int err = 0; char achVarChar[2]; LinkedObj * pLast = head(); SubstItem * pItem; achVarChar[0] = varChar; achVarChar[1] = 0; while( pFormatStr < pEnd ) { pItem = new SubstItem(); if ( !pItem ) { ERR_NO_MEM( "new SubstItem()" ); return -1; } if ( *pFormatStr == varChar ) { if ( pFormatStr + 1 == pEnd ) { HttpLog::parse_error( pCurLine , "Line ended with '$'" ); err = 1; } if ( isdigit( *( pFormatStr + 1 ) ) ) { pItem->setType( REF_RULE_SUBSTR ); pItem->setIndex( *(pFormatStr + 1) - '0' ); pFormatStr += 2; } else { ++pFormatStr; if ( pItem->parseServerVar( pCurLine, pFormatStr, pEnd, isSSI ) ) { err = 1; } } } else { pItem->parseString( pFormatStr, pEnd, achVarChar ); } if ( err ) { delete pItem; return -1; } else { pLast->addNext( pItem ); pLast = pItem; } } return 0; }
AutoStr2 * SubstItem::setStr( const char * pStr, int len ) { m_value.m_pStr = new AutoStr2( pStr, len ); if ( !m_value.m_pStr ) { ERR_NO_MEM( "new AutoStr2()" ); } return m_value.m_pStr; }
int RewriteEngine::parseRules( char * &pRules, RewriteRuleList * pRuleList, const RewriteMapList * pMapList ) { LinkedObj * pLast = pRuleList->tail(); if ( !pLast ) pLast = pRuleList->head(); while( *pRules ) { while( isspace( *pRules ) ) ++pRules; if ( !*pRules ) break; if ((( strncasecmp( pRules, "RewriteCond", 11 ) == 0 )&& ( isspace( *(pRules + 11)) ))|| (( strncasecmp( pRules, "RewriteRule", 11 ) == 0 )&& ( isspace( *(pRules + 11)) ))) { RewriteRule * pRule = new RewriteRule(); if ( !pRule ) { ERR_NO_MEM( "new RewriteRule()" ); return -1; } int ret = pRule->parse( pRules, pMapList ); if ( ret ) { delete pRule; return 0; } pLast->addNext( pRule ); pLast = pRule; } else { char * pLineEnd = strchr( pRules, '\n' ); if ( pLineEnd ) *pLineEnd = 0; if ( *pRules != '#' ) { LOG_ERR(( "Invalid rewrite directive: %s", pRules )); } if ( pLineEnd ) *pLineEnd = '\n'; else break; pRules = pLineEnd + 1; } } return 0; }
int HttpListener::addConnection( struct conn_data * pCur, int *iCount ) { int fd = pCur->fd; if ( checkAccess( pCur )) { no_timewait( fd ); close( fd ); --(*iCount); return 0; } HttpConnection* pConn = HttpConnPool::getConnection(); if ( !pConn ) { ERR_NO_MEM( "HttpConnPool::getConnection()" ); close( fd ); --(*iCount); return -1; } VHostMap * pMap; if ( m_pSubIpMap ) { pMap = getSubMap( fd ); } else pMap = getVHostMap(); pConn->setVHostMap( pMap ); pConn->setLogger( getLogger()); pConn->setRemotePort( ntohs( ((sockaddr_in *)(pCur->achPeerAddr))->sin_port) ); if ( pConn->setLink( pCur->fd, pCur->pInfo, pMap->getSSLContext() ) ) { HttpConnPool::recycle( pConn ); close( fd ); --(*iCount); return -1; } fcntl( fd, F_SETFD, FD_CLOEXEC ); fcntl( fd, F_SETFL, HttpGlobals::getMultiplexer()->getFLTag() ); //pConn->tryRead(); return 0; }
int RewriteRule::parseCookieAction( const char *pCookie, const char * pEnd ) { if ( memchr( pCookie, ':', pEnd - pCookie ) == NULL ) { HttpLog::parse_error( s_pCurLine, "missing ':' in cookie string" ); return -1; } RewriteSubstFormat* pFormat = new RewriteSubstFormat(); if ( !pFormat ) { ERR_NO_MEM( "new SubstFormat()" ); return -1; } if ( pFormat->parse( pCookie, pEnd, NULL ) ) { HttpLog::parse_error( s_pCurLine, "failed to parse cookie string" ); delete pFormat; return -1; } pFormat->setType( RewriteSubstFormat::COOKIE ); m_env.append( pFormat ); return 0; }
int RewriteRule::parseOneFlag( const char *&pRuleStr, const char * pEnd ) { switch( *pRuleStr ) { case 'B': case 'b': m_flag |= RULE_FLAG_BR_ESCAPE; ++pRuleStr; break; case 'C': case 'c': if ( (*(pRuleStr+1) | 0x20) == 'o' ) { pRuleStr += 2; if ( strncasecmp( pRuleStr, "okie", 4 ) == 0 ) pRuleStr += 4; if ( *pRuleStr == '=' ) { ++pRuleStr; size_t n = strcspn( pRuleStr, ",] \t\r\n" ); if ( n > 0 ) { const char * pCookie = pRuleStr; pRuleStr += n; return parseCookieAction( pCookie, pRuleStr ); } else { HttpLog::parse_error( s_pCurLine, "invalid cookie action string" ); return -1; } } break; } m_flag |= RULE_FLAG_CHAIN; if ( strncasecmp( pRuleStr, "chain", 5 ) == 0 ) pRuleStr += 5; else ++pRuleStr; break; case 'D': case 'd': if ( strncasecmp( pRuleStr, "DPI", 3 ) == 0 ) { pRuleStr += 3; m_flag |= RULE_FLAG_DPI; } else if ( strncasecmp( pRuleStr, "discardpathinfo", 15 ) == 0 ) { pRuleStr += 15; m_flag |= RULE_FLAG_DPI; } else ++pRuleStr; break; case 'E': case 'e': if ( strncasecmp( pRuleStr, "end", 3 ) == 0 ) { pRuleStr += 3; m_flag |= RULE_FLAG_END; m_flag |= RULE_FLAG_LAST; break; } if ( strncasecmp( pRuleStr, "env", 3 ) == 0 ) pRuleStr += 3; else ++pRuleStr; if ( *pRuleStr == '=' ) { ++pRuleStr; size_t n = strcspn( pRuleStr, ",] \t\r\n" ); if ( n > 0 ) { const char * pEnv = pRuleStr; pRuleStr += n; if ( memchr( pEnv, ':', n ) == NULL ) { HttpLog::parse_error( s_pCurLine, "missing ':' in env string" ); return -1; } RewriteSubstFormat* pFormat = new RewriteSubstFormat(); if ( !pFormat ) { ERR_NO_MEM( "new SubstFormat()" ); return -1; } if ( pFormat->parse( pEnv, pRuleStr, NULL ) ) { HttpLog::parse_error( s_pCurLine, "failed to parse env string" ); delete pFormat; return -1; } pFormat->setType( RewriteSubstFormat::ENV ); m_env.append( pFormat ); } else { HttpLog::parse_error( s_pCurLine, "invalid env string, empty string" ); return -1; } } break; case 'F': case 'f': m_action = RULE_ACTION_FORBID; m_flag |= RULE_FLAG_LAST; m_statusCode = SC_403; if ( strncasecmp( pRuleStr, "forbidden", 9 ) == 0 ) pRuleStr += 9; else ++pRuleStr; break; case 'G': case 'g': m_action = RULE_ACTION_GONE; m_flag |= RULE_FLAG_LAST; m_statusCode = SC_410; if ( strncasecmp( pRuleStr, "gone", 4 ) == 0 ) pRuleStr += 4; else ++pRuleStr; break; case 'L': case 'l': m_flag |= RULE_FLAG_LAST; if ( strncasecmp( pRuleStr, "last", 4 ) == 0 ) { pRuleStr += 4; } else // 'L' ++pRuleStr; break; case 'n': case 'N': if ( strncasecmp( pRuleStr, "nocase", 6 ) == 0 ) { m_flag |= RULE_FLAG_NOCASE; pRuleStr += 6; } else if ( strncasecmp( pRuleStr, "nc", 2 ) == 0 ) { m_flag |= RULE_FLAG_NOCASE; pRuleStr += 2; } else if ( strncasecmp( pRuleStr, "nosubreq", 8 ) == 0 ) { m_flag |= RULE_FLAG_NOSUBREQ; pRuleStr += 8; } else if ( strncasecmp( pRuleStr, "ns", 2 ) == 0 ) { m_flag |= RULE_FLAG_NOSUBREQ; pRuleStr += 2; } else if ( strncasecmp( pRuleStr, "noescape", 8 ) == 0 ) { m_flag |= RULE_FLAG_NOESCAPE; pRuleStr += 8; } else if ( strncasecmp( pRuleStr, "ne", 2 ) == 0 ) { m_flag |= RULE_FLAG_NOESCAPE; pRuleStr += 2; } else if ( strncasecmp( pRuleStr, "next", 4 ) == 0 ) { m_flag |= RULE_FLAG_NEXT; pRuleStr += 4; } else // 'N' { m_flag |= RULE_FLAG_NEXT; ++pRuleStr; } break; case 'P': case 'p': if ( strncasecmp( pRuleStr, "passthrough", 11 ) == 0 ) { m_flag |= RULE_FLAG_PASSTHRU; pRuleStr += 11; } else if ( strncasecmp( pRuleStr, "pt", 2 ) == 0 ) { m_flag |= (RULE_FLAG_PASSTHRU | RULE_FLAG_LAST); pRuleStr += 2; } else { m_action = RULE_ACTION_PROXY; m_flag |= RULE_FLAG_LAST; m_statusCode = -2; //proxy if ( strncasecmp( pRuleStr, "proxy", 5 ) == 0 ) { pRuleStr += 5; } else // 'P' { ++pRuleStr; } } break; case 'Q': case 'q': if ( strncasecmp( pRuleStr, "qsappend", 8 ) == 0 ) { m_flag |= RULE_FLAG_QSAPPEND; pRuleStr += 8; } else if ( strncasecmp( pRuleStr, "qsa", 3 ) == 0 ) { m_flag |= RULE_FLAG_QSAPPEND; pRuleStr += 3; } else if ( strncasecmp( pRuleStr, "qsdiscard", 8 ) == 0 ) { m_flag |= RULE_FLAG_QSDISCARD; pRuleStr += 8; } else if ( strncasecmp( pRuleStr, "qsd", 3 ) == 0 ) { m_flag |= RULE_FLAG_QSDISCARD; pRuleStr += 3; } else { HttpLog::parse_error( s_pCurLine, "Unknown rewrite rule flag" ); return -1; } break; case 'R': case 'r': m_action = RULE_ACTION_REDIRECT; if ( strncasecmp( pRuleStr, "redirect", 8 ) == 0 ) { pRuleStr += 8; } else { ++pRuleStr; } if ( *pRuleStr == '=' ) { ++pRuleStr; size_t n = strcspn( pRuleStr, ",] \t\r\n" ); if ( n == 0 ) { m_statusCode = SC_302; } else if (( strncasecmp( pRuleStr, "temp", 4 ) == 0 )&&( n == 4 )) { pRuleStr += 4; m_statusCode = SC_302; } else if (( strncasecmp( pRuleStr, "permanent", 9 ) == 0 )&&( n == 9 )) { pRuleStr += 9; m_statusCode = SC_301; } else if (( strncasecmp( pRuleStr, "seeother", 8 ) == 0 )&&( n == 8 )) { pRuleStr += 8; m_statusCode = SC_303; } else { m_statusCode = HttpStatusCode::codeToIndex( pRuleStr ); if ( m_statusCode == -1 ) m_statusCode = SC_302; else pRuleStr += n; } } else { m_statusCode = SC_302; } break; case 'S': case 's': if ( strncasecmp( pRuleStr, "skip", 4 ) == 0 ) { pRuleStr += 4; } else ++pRuleStr; if ( *pRuleStr == '=' ) { ++pRuleStr; char * p; m_skipRules = strtol( pRuleStr, &p, 10 ); if ( p == pRuleStr ) { HttpLog::parse_error( s_pCurLine, "invalid number in 'skip' flag" ); return -1; } pRuleStr = p; } else { HttpLog::parse_error( s_pCurLine, "invalid 'skip' flag, '=' expected" ); return -1; } break; case 'T': case 't': case 'H': case 'h': if ( strncasecmp( pRuleStr, "type", 4 ) == 0 ) { pRuleStr += 4; } else if ( strncasecmp( pRuleStr, "handler", 7 ) == 0 ) pRuleStr += 7; else ++pRuleStr; if ( *pRuleStr == '=' ) { ++pRuleStr; size_t n = strcspn( pRuleStr, ",] \t\r\n" ); if ( n == 0 ) { HttpLog::parse_error( s_pCurLine, "invalid 'type' flag, missing mime type." ); return -1; } m_sMimeType.setStr( pRuleStr, n ); pRuleStr += n; } else { HttpLog::parse_error( s_pCurLine, "invalid 'type' flag, '=' expected" ); return -1; } break; default: HttpLog::parse_error( s_pCurLine, "Unknown rewrite rule flag" ); return -1; break; } return 0; }
int RewriteSubstFormat::parse( const char * pFormatStr, const char * pEnd, const RewriteMapList * pMaps ) { while(( pFormatStr < pEnd )&&( isspace( *pFormatStr ))) ++pFormatStr; int err = 0; LinkedObj * pLast = head(); RewriteSubstItem * pItem; while( pFormatStr < pEnd ) { pItem = new RewriteSubstItem(); if ( !pItem ) { ERR_NO_MEM( "new SubstItem()" ); return -1; } switch( *pFormatStr ) { case '$': if ( pFormatStr + 1 == pEnd ) { HttpLog::parse_error( s_pCurLine, "Line ended with '$'" ); err = 1; break; } if ( *( pFormatStr + 1 ) == '{' ) { if ( !pMaps ) { HttpLog::parse_error( s_pCurLine, "No rewrite map defined" ); err = 1; break; } pItem->setType( REF_MAP ); MapRefItem * pMapRef = new MapRefItem(); if ( !pMapRef ) { ERR_NO_MEM( "new MapRefItem()" ); err = 1; break; } if ( pMapRef->parse( pFormatStr, pEnd, pMaps ) ) { delete pMapRef; err = 1; break; } pItem->setMapRef( pMapRef ); } else if ( isdigit( *( pFormatStr + 1 ) ) ) { pItem->setType( REF_RULE_SUBSTR ); pItem->setIndex( *(pFormatStr + 1) - '0' ); pFormatStr += 2; } else { HttpLog::parse_error( s_pCurLine, "'$' should be followed by a digit for a RewriteRule backreference." ); pItem->setType( REF_STRING ); pItem->setStr( pFormatStr, 1 ); ++pFormatStr; } break; case '%': if ( pFormatStr + 1 == pEnd ) { HttpLog::parse_error( s_pCurLine, "Line ended with '%'" ); err = 1; break; } if ( *( pFormatStr + 1 ) == '{' ) { ++pFormatStr; if ( pItem->parseServerVar( s_pCurLine, pFormatStr, pEnd ) ) { err = 1; break; } } else if ( isdigit( *( pFormatStr + 1 ) ) ) { pItem->setType( REF_COND_SUBSTR ); pItem->setIndex( *(pFormatStr + 1) - '0' ); pFormatStr += 2; } else { HttpLog::parse_error( s_pCurLine, "'%' should be followed by a digit for a RewriteCond backreference." ); pItem->setType( REF_STRING ); pItem->setStr( pFormatStr, 1 ); ++pFormatStr; } break; case '\\': default: pItem->parseString( pFormatStr, pEnd, "$%" ); break; } if ( err ) { delete pItem; return -1; } else { pLast->addNext( pItem ); pLast = pItem; } } return 0; }
int RewriteRule::parse( char * &pRule, const RewriteMapList * pMaps ) { char * pCur; char * pLineEnd; LinkedObj * pLast = m_conds.head(); assert( pLast->next() == NULL ); while( *pRule ) { while( isspace( *pRule ) ) ++pRule; if ( !*pRule ) break; pCur = pRule; pLineEnd = strchr( pCur, '\n' ); if ( !pLineEnd ) { pLineEnd = pCur + strlen( pCur ); pRule = pLineEnd; } else { pRule = pLineEnd + 1; *pLineEnd = 0; } s_pCurLine = pCur; if ( *pCur != '#' ) { if (( strncasecmp( pCur, "RewriteCond", 11 ) == 0 )&& ( isspace( *(pCur + 11)) )) { RewriteCond * pCond = new RewriteCond(); if ( !pCond ) { ERR_NO_MEM( "new RewriteCond()" ); return -1; } if ( pCond->parse( pCur+12, pLineEnd, pMaps ) ) { delete pCond; HttpLog::parse_error( s_pCurLine, "invalid rewrite condition" ); return -1; } pLast->addNext( pCond ); pLast = pCond; } else if (( strncasecmp( pCur, "RewriteRule", 11 ) == 0 )&& ( isspace( *(pCur + 11)) )) { int ret = parseRule( pCur+12, pLineEnd, pMaps ); pCur = pLineEnd+1; return ret; } else { HttpLog::parse_error( s_pCurLine, "invalid rewrite directive " ); return -1; } } } return -1; }
int HttpListener::batchAddConn( struct conn_data * pBegin, struct conn_data *pEnd, int *iCount ) { struct conn_data * pCur = pBegin; int n = pEnd - pBegin; while( pCur < pEnd ) { if ( checkAccess( pCur)) { no_timewait( pCur->fd ); close( pCur->fd ); pCur->fd = -1; --(*iCount); --n; } ++pCur; } if ( n <= 0 ) return 0; HttpConnection* pConns[CONN_BATCH_SIZE]; int ret = HttpConnPool::getConnections( pConns, n); pCur = pBegin; if ( ret <= 0 ) { ERR_NO_MEM( "HttpConnPool::getConnections()" ); LOG_ERR(( "need %d connections, allocated %d connections!", n, ret )); while( pCur < pEnd ) { if ( pCur->fd != -1 ) { close( pCur->fd ); --(*iCount); } ++pCur; } return -1; } HttpConnection** pConnEnd = &pConns[ret]; HttpConnection** pConnCur = pConns; VHostMap * pMap; int flag = HttpGlobals::getMultiplexer()->getFLTag(); while( pCur < pEnd ) { register int fd = pCur->fd; if ( fd != -1 ) { assert( pConnCur < pConnEnd ); HttpConnection * pConn = *pConnCur; if ( m_pSubIpMap ) { pMap = getSubMap( fd ); } else pMap = getVHostMap(); pConn->setVHostMap( pMap ); pConn->setLogger( getLogger()); pConn->setRemotePort( ntohs( ((sockaddr_in *)(pCur->achPeerAddr))->sin_port) ); // if ( getDedicated() ) // { // //pConn->accessGranted(); // } if ( !pConn->setLink( fd, pCur->pInfo, pMap->getSSLContext() ) ) { fcntl( fd, F_SETFD, FD_CLOEXEC ); fcntl( fd, F_SETFL, flag ); ++pConnCur; //pConn->tryRead(); } else { close( fd ); --(*iCount); } } ++pCur; } if ( pConnCur < pConnEnd ) { HttpConnPool::recycle( pConnCur, pConnEnd - pConnCur); } return 0; }
/* * int pmapFilterSetupBitmap(uint32_t **bitmap, uint32_t **bitmap_size, * skPrefixMap_t *prefix_map, * char *opt_arg, char *pmap_path); * * Parses 'opt_arg', a string representation of comma-separated * pmap values to filter on with respect to the given 'prefix_map', * and sets the relevant bits in the bit-vector 'bitmap', whose * current size is 'bitmap_size'. Creates the bitmap if necessary * and may adjust the bitmap's size. Returns -1 if the argument * was not parsable or if there is a memory allocation error. */ static int pmapFilterSetupBitmap( uint32_t **bitmap_arg, uint32_t *bitmap_size, const skPrefixMap_t *prefix_map, const char *opt_arg, const char *pmap_path) { uint32_t bmap_len; char *arg_copy = NULL; char *label; char *next_token; uint32_t code; uint32_t *bitmap = NULL; int rv = -1; if (ignore_prefix_map) { return 0; } assert(bitmap_arg); assert(prefix_map); assert(opt_arg); /* Get a pointer to the bitmap---creating it if required */ if (*bitmap_arg) { bitmap = *bitmap_arg; } else { /* Allocate the bitmap. */ bmap_len = skPrefixMapDictionaryGetWordCount(prefix_map); bitmap = (uint32_t*)calloc(PMAP_BMAP_SIZE(bmap_len), sizeof(uint32_t)); if (NULL == bitmap) { ERR_NO_MEM(bitmap); goto END; } *bitmap_size = bmap_len; } /* Make a modifiable copy of the user's argument */ arg_copy = strdup(opt_arg); if (arg_copy == NULL) { ERR_NO_MEM(arg_copy); goto END; } /* Find each token which should be a label in the pmap */ next_token = arg_copy; while ((label = strsep(&next_token, ",")) != NULL) { code = skPrefixMapDictionaryLookup(prefix_map, label); if (SKPREFIXMAP_NOT_FOUND == code) { /* label was not found in dictionary. if label is a * number and if any key in the prefix map has that number * as its value, set that position in the bitmap, * reallocating the bitmap if necessary */ if (skStringParseUint32(&code, label, 0, SKPREFIXMAP_MAX_VALUE)) { skAppPrintErr(("The label '%s' was not found in prefix map\n" "\tdictionary loaded from '%s'"), label, pmap_path); goto END; } if (0 == pmapCheckValueIsValid(prefix_map, code)) { skAppPrintErr(("The value '%s' was not found in prefix map\n" "\tdictionary loaded from '%s'"), label, pmap_path); goto END; } /* ensure bitmap can set the bit 'code' */ bmap_len = code + 1; /* see if we need to grow the bitmap */ if (PMAP_BMAP_SIZE(bmap_len) > PMAP_BMAP_SIZE(*bitmap_size)) { uint32_t *old = bitmap; bitmap = (uint32_t*)realloc(bitmap, (PMAP_BMAP_SIZE(bmap_len) * sizeof(uint32_t))); if (NULL == bitmap) { bitmap = old; ERR_NO_MEM(bitmap); goto END; } memset(&bitmap[PMAP_BMAP_SIZE(*bitmap_size)], 0, ((PMAP_BMAP_SIZE(bmap_len)-PMAP_BMAP_SIZE(*bitmap_size)) * sizeof(uint32_t))); } /* alway set bitmap size to maximum number */ if (bmap_len > *bitmap_size) { *bitmap_size = bmap_len; } } PMAP_BMAP_SET(bitmap, code); } /* Success */ rv = 0; *bitmap_arg = bitmap; END: if (*bitmap_arg == NULL && bitmap != NULL) { free(bitmap); } if (arg_copy) { free(arg_copy); } return rv; }
/* * skplugin_err_t pmapfile_handler(const char *opt_arg, void *cbdata) * * Handler for --pmap-file option. Actually registers the filter and * fields. */ static skplugin_err_t pmapfile_handler( const char *opt_arg, void UNUSED(*cbdata)) { /* Whether we have seen any unnamed pmaps */ static int have_unnamed_pmap = 0; skPrefixMapErr_t map_error = SKPREFIXMAP_OK; skstream_t *stream = NULL; skPrefixMap_t *prefix_map = NULL; pmap_data_t *pmap_data = NULL; int ok; const char *filename; const char *sep; const char *mapname; char *prefixed_name = NULL; char *short_prefixed_name; size_t namelen = 0; size_t i; int rv = SKPLUGIN_ERR; skplugin_callbacks_t regdata; /* We can only have one pmap whenever we any any pmap without a * mapname. If we've seen one and enter this function a second * time, it is an error */ if (have_unnamed_pmap) { skAppPrintErr(("Invalid %s: You may use only one prefix map" " when you are\n" "\tusing a prefix map without specifying a mapname"), pmap_file_option); return SKPLUGIN_ERR; } /* Parse the argument into a field name and file name */ sep = strchr(opt_arg, ':'); if (NULL == sep) { /* We do not have a mapname. We'll check for one in the pmap * once we read it. */ mapname = NULL; filename = opt_arg; } else { /* A mapname was supplied on the command line */ if (sep == opt_arg) { skAppPrintErr("Invalid %s: Zero length mapnames are not allowed", pmap_file_option); return SKPLUGIN_ERR; } if (memchr(opt_arg, ',', sep - opt_arg) != NULL) { skAppPrintErr("Invalid %s: The mapname may not include a comma", pmap_file_option); return SKPLUGIN_ERR; } mapname = opt_arg; filename = sep + 1; namelen = sep - opt_arg; } ok = skpinOpenDataInputStream(&stream, SK_CONTENT_SILK, filename); if (ok == -1) { /* problem opening file */ skAppPrintErr("Failed to open the prefix map file '%s'", filename); return SKPLUGIN_ERR; } if (ok == 1) { /* master needs to process the file, since it may contain the * map name we use for creating switches */ if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK)) || (rv = skStreamBind(stream, filename)) || (rv = skStreamOpen(stream))) { skStreamPrintLastErr(stream, rv, &skAppPrintErr); skStreamDestroy(&stream); return SKPLUGIN_ERR; } /* the master can ignore the file for filtering */ ignore_prefix_map = 1; } map_error = skPrefixMapRead(&prefix_map, stream); if (SKPREFIXMAP_OK != map_error) { if (SKPREFIXMAP_ERR_IO == map_error) { skStreamPrintLastErr(stream, skStreamGetLastReturnValue(stream), &skAppPrintErr); } else { skAppPrintErr("Failed to read the prefix map file '%s': %s", opt_arg, skPrefixMapStrerror(map_error)); } skStreamDestroy(&stream); return SKPLUGIN_ERR; } skStreamDestroy(&stream); if (NULL == mapname) { /* No mapname was supplied on the command line. Check for a * mapname insided the pmap. */ mapname = skPrefixMapGetMapName(prefix_map); if (mapname) { /* The pmap supplied a mapname */ namelen = strlen(mapname); } else { /* No mapname. Accept for legacy purposes, unless we have * read any other pmaps */ have_unnamed_pmap = 1; if (skVectorGetCount(pmap_vector) != 0) { skAppPrintErr(("Invalid %s: You may use only one prefix map" " when you are\n" "\t using a prefix map without" " specifying a mapname"), pmap_file_option); goto END; } } } /* Allocate the pmap_data structure */ pmap_data = (pmap_data_t *)calloc(1, sizeof(*pmap_data)); if (pmap_data == NULL) { ERR_NO_MEM(pmap_data); rv = SKPLUGIN_ERR_FATAL; goto END; } /* pmap_data now "owns" prefix_map */ pmap_data->pmap = prefix_map; prefix_map = NULL; /* Cache the content type */ pmap_data->type = skPrefixMapGetContentType(pmap_data->pmap); /* Fill the direction structure for each direction */ pmap_data->sdir.dir = DIR_SOURCE; pmap_data->ddir.dir = DIR_DEST; pmap_data->adir.dir = DIR_ANY; pmap_data->sdir.data = pmap_data; pmap_data->ddir.data = pmap_data; pmap_data->adir.data = pmap_data; /* Record the path to the pmap file */ pmap_data->filepath = strdup(filename); if (NULL == pmap_data->filepath) { ERR_NO_MEM(pmap_data->filepath); rv = SKPLUGIN_ERR_FATAL; goto END; } if (mapname == NULL) { /* Pmap without a mapname. */ /* Add the proper legacy option names to the pmap_data structure */ switch (pmap_data->type) { case SKPREFIXMAP_CONT_ADDR_V4: case SKPREFIXMAP_CONT_ADDR_V6: pmap_data->sdir.filter_option = strdup(pmap_saddress_option); pmap_data->ddir.filter_option = strdup(pmap_daddress_option); pmap_data->adir.filter_option = strdup(pmap_aaddress_option); break; case SKPREFIXMAP_CONT_PROTO_PORT: pmap_data->sdir.filter_option = strdup(pmap_sport_proto_option); pmap_data->ddir.filter_option = strdup(pmap_dport_proto_option); pmap_data->adir.filter_option = strdup(pmap_aport_proto_option); break; } if ((pmap_data->sdir.filter_option == NULL) || (pmap_data->ddir.filter_option == NULL) || (pmap_data->adir.filter_option == NULL)) { ERR_NO_MEM(filter_option); rv = SKPLUGIN_ERR_FATAL; goto END; } pmap_data->mapname = strdup(pmap_title_val); pmap_data->sdir.field_name = strdup(pmap_title_sval); pmap_data->ddir.field_name = strdup(pmap_title_dval); if ((pmap_data->mapname == NULL) || (pmap_data->sdir.field_name == NULL) || (pmap_data->ddir.field_name == NULL)) { ERR_NO_MEM(field_name); rv = SKPLUGIN_ERR_FATAL; goto END; } } else { /* if (mapname == NULL) */ /* Create the field names*/ pmap_data->mapname = (char*)malloc(namelen + 1); if (NULL == pmap_data->mapname) { ERR_NO_MEM(pmap_data->mapname); rv = SKPLUGIN_ERR_FATAL; goto END; } strncpy(pmap_data->mapname, mapname, namelen); pmap_data->mapname[namelen] = '\0'; /* Allocate space for the [pmap-]{src-,dst-}<mapname> string */ prefixed_name = (char*)malloc(namelen + pmap_prefix_len + dir_name_len + 1); if (NULL == prefixed_name) { ERR_NO_MEM(prefixed_name); rv = SKPLUGIN_ERR_FATAL; goto END; } /* Copy in the pmap- prefix */ strncpy(prefixed_name, pmap_prefix, pmap_prefix_len); /* short name (for fields) starts at the {src-,dst-} */ short_prefixed_name = prefixed_name + pmap_prefix_len; /* add in the actual field name, and zero terminate it */ strncpy(short_prefixed_name + dir_name_len, mapname, namelen); short_prefixed_name[namelen + dir_name_len] = '\0'; /* Create the destination-themed names */ strncpy(short_prefixed_name, src_dir_name, dir_name_len); pmap_data->sdir.filter_option = strdup(prefixed_name); pmap_data->sdir.field_name = strdup(short_prefixed_name); if ((pmap_data->sdir.filter_option == NULL) || (pmap_data->sdir.field_name == NULL)) { ERR_NO_MEM(pmap_data->sdir); rv = SKPLUGIN_ERR_FATAL; goto END; } strncpy(short_prefixed_name, dst_dir_name, dir_name_len); pmap_data->ddir.filter_option = strdup(prefixed_name); pmap_data->ddir.field_name = strdup(short_prefixed_name); if ((pmap_data->ddir.filter_option == NULL) || (pmap_data->ddir.field_name == NULL)) { ERR_NO_MEM(pmap_data->ddir); rv = SKPLUGIN_ERR_FATAL; goto END; } strncpy(short_prefixed_name, any_dir_name, dir_name_len); pmap_data->adir.filter_option = strdup(prefixed_name); if (pmap_data->adir.filter_option == NULL) { ERR_NO_MEM(pmap_data->adir); rv = SKPLUGIN_ERR_FATAL; goto END; } /* Free the temporary name buffer */ free(prefixed_name); prefixed_name = NULL; } /* if (mapname == NULL) */ /* Verify unique field names */ for (i = 0; i < skVectorGetCount(pmap_vector); i++) { pmap_data_t *p; skVectorGetValue(&p, pmap_vector, i); if ((strcmp(pmap_data->mapname, p->mapname) == 0) || (strcmp(pmap_data->sdir.field_name, p->sdir.field_name) == 0) || (strcmp(pmap_data->ddir.field_name, p->ddir.field_name) == 0)) { skAppPrintErr(("Invalid %s: Multiple pmaps use the mapname '%s':\n" "\t%s\n\t%s"), pmap_file_option, pmap_data->mapname, p->filepath, pmap_data->filepath); rv = SKPLUGIN_ERR; goto END; } } /* Register fields and filter options */ memset(®data, 0, sizeof(regdata)); regdata.init = pmap_field_init; regdata.column_width = 0; regdata.bin_bytes = 4; regdata.rec_to_text = pmap_text_fn; regdata.rec_to_bin = pmap_bin_fn; regdata.bin_to_text = pmap_bin_to_text_fn; for (i = 0; i < 2; ++i) { directed_pmap_data_t *dir = ((0 == i) ? &pmap_data->sdir : &pmap_data->ddir); skpinRegField(&dir->field, dir->field_name, NULL, ®data, dir); skpinRegOption2(dir->filter_option, REQUIRED_ARG, NULL, &pmap_filter_help, &pmap_handle_filter_option, dir, 1, SKPLUGIN_FN_FILTER); } /* Register the "any" filter separately */ skpinRegOption2(pmap_data->adir.filter_option, REQUIRED_ARG, NULL, &pmap_filter_help, &pmap_handle_filter_option, &pmap_data->adir, 1, SKPLUGIN_FN_FILTER); if (skVectorAppendValue(pmap_vector, &pmap_data)) { rv = SKPLUGIN_ERR_FATAL; goto END; } rv = SKPLUGIN_OK; END: /* Free the temporary name buffer */ if (prefixed_name) { free(prefixed_name); } if (rv != SKPLUGIN_OK) { if (prefix_map) { skPrefixMapDelete(prefix_map); } if (pmap_data) { pmap_data_destroy(pmap_data); } } return (skplugin_err_t)rv; }
/* Public entry point */ skplugin_err_t skPrefixMapAddFields( uint16_t major_version, uint16_t minor_version, void UNUSED(*data)) { skplugin_err_t err; #define PMAP_FILE_HELP(str_arg) \ ("Prefix map file to read. Def. None. When the argument has\n" \ "\tthe form \"<mapfile>:<filename>\"," \ " the \"mapname\" is used to generate\n" \ str_arg) assert(strlen(src_dir_name) == strlen(dst_dir_name)); /* Check API version */ err = skpinSimpleCheckVersion(major_version, minor_version, PLUGIN_API_VERSION_MAJOR, PLUGIN_API_VERSION_MINOR, skAppPrintErr); if (err != SKPLUGIN_OK) { return err; } /* Initialize global variables */ pmap_vector = skVectorNew(sizeof(pmap_data_t *)); if (pmap_vector == NULL) { ERR_NO_MEM(pmap_vector); return SKPLUGIN_ERR; } /* Add --pmap-file to apps that accept RWREC: rwcut, rwsort, etc */ err = skpinRegOption2(pmap_file_option, REQUIRED_ARG, PMAP_FILE_HELP( "\tfield names. As such, this switch must" " precede the --fields switch."), NULL, pmapfile_handler, NULL, 2, SKPLUGIN_FN_REC_TO_TEXT, SKPLUGIN_FN_REC_TO_BIN); if (err == SKPLUGIN_ERR_FATAL) { return err; } /* Add --pmap-column-width to apps that produce TEXT: rwcut, rwuniq */ err = skpinRegOption2(pmap_column_width_option, REQUIRED_ARG, "Maximum column width to use for output.", NULL, pmap_column_width_handler, NULL, 2, SKPLUGIN_FN_REC_TO_TEXT, SKPLUGIN_FN_BIN_TO_TEXT); if (err == SKPLUGIN_ERR_FATAL) { return err; } /* Add --pmap-file to rwfilter */ err = skpinRegOption2(pmap_file_option, REQUIRED_ARG, PMAP_FILE_HELP( "\tfiltering switches. This switch must" " precede other --pmap-* switches."), NULL, pmapfile_handler, NULL, 1, SKPLUGIN_FN_FILTER); if (err == SKPLUGIN_ERR_FATAL) { return err; } /* Register cleanup function */ skpinRegCleanup(pmap_teardown); return SKPLUGIN_OK; }