1
/* parsing routines for the counted string class. for generic
2
* informaton see parse.h.
4
* begun 2005-09-15 rgerhards
7
* Rainer Gerhards and Adiscon GmbH. All Rights Reserved.
8
* This code is placed under the GPL.
17
#include <arpa/inet.h>
18
#include <sys/types.h>
19
#include <sys/socket.h>
22
#include "net.h" /* struct NetAddr */
25
/* ################################################################# *
27
* ################################################################# */
31
/* ################################################################# *
33
* ################################################################# */
37
* Destruct a rsPars object and its associated string.
38
* rgerhards, 2005-09-26
40
rsRetVal rsParsDestruct(rsParsObj *pThis)
42
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
44
if(pThis->pCStr != NULL)
45
rsCStrDestruct (pThis->pCStr);
52
* Construct a rsPars object.
54
rsRetVal rsParsConstruct(rsParsObj **ppThis)
58
assert(ppThis != NULL);
60
if((pThis = (rsParsObj*) calloc(1, sizeof(rsParsObj))) == NULL)
61
return RS_RET_OUT_OF_MEMORY;
63
rsSETOBJTYPE(pThis, OIDrsPars);
70
* Construct a rsPars object and populate it with a
71
* classical zero-terinated C-String.
72
* rgerhards, 2005-09-27
74
rsRetVal rsParsConstructFromSz(rsParsObj **ppThis, unsigned char *psz)
80
assert(ppThis != NULL);
83
/* create string for parser */
84
if((iRet = rsCStrConstructFromszStr(&pCS, psz)) != RS_RET_OK)
88
if((iRet = rsParsConstruct(&pThis)) != RS_RET_OK) {
93
/* assign string to parser */
94
if((iRet = rsParsAssignString(pThis, pCS)) != RS_RET_OK) {
95
rsParsDestruct(pThis);
104
* Assign the to-be-parsed string.
106
rsRetVal rsParsAssignString(rsParsObj *pThis, rsCStrObj *pCStr)
108
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
109
rsCHECKVALIDOBJECT(pCStr, OIDrsCStr);
111
pThis->pCStr = pCStr;
117
/* parse an integer. The parse pointer is advanced to the
118
* position directly after the last digit. If no digit is
119
* found at all, an error is returned and the parse pointer
121
* PORTABILITY WARNING: this function depends on the
122
* continues representation of digits inside the character
124
* rgerhards 2005-09-27
126
rsRetVal parsInt(rsParsObj *pThis, int* pInt)
131
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
132
assert(pInt != NULL);
135
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
137
/* order of checks is important, else we might do
138
* mis-addressing! (off by one)
140
if(pThis->iCurrPos >= rsCStrLen(pThis->pCStr))
141
return RS_RET_NO_MORE_DATA;
142
if(!isdigit((int)*pC))
143
return RS_RET_NO_DIGIT;
145
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && isdigit((int)*pC)) {
146
iVal = iVal * 10 + *pC - '0';
156
/* Skip everything up to a specified character.
157
* Returns with ParsePointer set BEHIND this character.
158
* Returns RS_RET_OK if found, RS_RET_NOT_FOUND if not
159
* found. In that case, the ParsePointer is moved to the
160
* last character of the string.
161
* 2005-09-19 rgerhards
163
rsRetVal parsSkipAfterChar(rsParsObj *pThis, char c)
165
register unsigned char *pC;
168
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
170
pC = rsCStrGetBufBeg(pThis->pCStr);
172
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
173
if(pC[pThis->iCurrPos] == c)
178
/* delimiter found? */
179
if(pC[pThis->iCurrPos] == c) {
180
if(pThis->iCurrPos+1 < rsCStrLen(pThis->pCStr)) {
182
pThis->iCurrPos++; /* 'eat' delimiter */
184
iRet = RS_RET_FOUND_AT_STRING_END;
187
iRet = RS_RET_NOT_FOUND;
193
/* Skip whitespace. Often used to trim parsable entries.
194
* Returns with ParsePointer set to first non-whitespace
195
* character (or at end of string).
197
rsRetVal parsSkipWhitespace(rsParsObj *pThis)
199
register unsigned char *pC;
201
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
203
pC = rsCStrGetBufBeg(pThis->pCStr);
205
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
206
if(!isspace((int)*(pC+pThis->iCurrPos)))
214
/* Parse string up to a delimiter.
217
* cDelim - the delimiter
218
* The following two are for whitespace stripping,
219
* 0 means "no", 1 "yes"
224
* ppCStr Pointer to the parsed string - must be freed by caller!
226
rsRetVal parsDelimCStr(rsParsObj *pThis, rsCStrObj **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing)
228
register unsigned char *pC;
232
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
234
if((pCStr = rsCStrConstruct()) == NULL)
235
return RS_RET_OUT_OF_MEMORY;
238
parsSkipWhitespace(pThis);
240
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
242
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
244
if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
245
rsCStrDestruct (pCStr);
253
++pThis->iCurrPos; /* eat delimiter */
256
/* We got the string, now take it and see if we need to
257
* remove anything at its end.
259
if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) {
260
rsCStrDestruct (pCStr);
265
if((iRet = rsCStrTrimTrailingWhiteSpace(pCStr))
267
rsCStrDestruct (pCStr);
277
/* Parse a quoted string ("-some-data") from the given position.
278
* Leading whitespace before the first quote is skipped. During
279
* parsing, escape sequences are detected and converted:
280
* \\ - backslash character
281
* \" - quote character
282
* any other value \<somechar> is reserved for future use.
284
* After return, the parse pointer is paced after the trailing
288
* ppCStr Pointer to the parsed string - must be freed by caller and
289
* does NOT include the quotes.
290
* rgerhards, 2005-09-19
292
rsRetVal parsQuotedCStr(rsParsObj *pThis, rsCStrObj **ppCStr)
294
register unsigned char *pC;
298
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
300
if((iRet = parsSkipAfterChar(pThis, '"')) != RS_RET_OK)
302
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
304
/* OK, we most probably can obtain a value... */
305
if((pCStr = rsCStrConstruct()) == NULL)
306
return RS_RET_OUT_OF_MEMORY;
308
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
310
break; /* we are done! */
311
} else if(*pC == '\\') {
314
if(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
315
/* in this case, we copy the escaped character
316
* to the output buffer (but do not rely on this,
317
* we might later introduce other things, like \007!
319
if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
320
rsCStrDestruct (pCStr);
324
} else { /* regular character */
325
if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
326
rsCStrDestruct (pCStr);
335
++pThis->iCurrPos; /* 'eat' trailing quote */
337
/* error - improperly quoted string! */
338
rsCStrDestruct (pCStr);
339
return RS_RET_MISSING_TRAIL_QUOTE;
342
/* We got the string, let's finish it... */
343
if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) {
344
rsCStrDestruct (pCStr);
354
* Parsing routine for IPv4, IPv6 and domain name wildcards.
356
* Parses string in the format <addr>[/bits] where
357
* addr can be a IPv4 address (e.g.: 127.0.0.1), IPv6 address (e.g.: [::1]),
358
* full hostname (e.g.: localhost.localdomain) or hostname wildcard
359
* (e.g.: *.localdomain).
362
rsRetVal parsAddrWithBits(rsParsObj *pThis, struct NetAddr **pIP, int *pBits)
367
struct addrinfo hints, *res = NULL;
371
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
373
assert(pBits != NULL);
375
if((pCStr = rsCStrConstruct()) == NULL)
376
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
378
parsSkipWhitespace(pThis);
379
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
381
/* we parse everything until either '/', ',' or
382
* whitespace. Validity will be checked down below.
384
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
385
&& *pC != '/' && *pC != ',' && !isspace((int)*pC)) {
386
if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
387
rsCStrDestruct (pCStr);
394
/* We got the string, let's finish it... */
395
if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) {
396
rsCStrDestruct (pCStr);
400
/* now we have the string and must check/convert it to
401
* an NetAddr structure.
403
CHKiRet(rsCStrConvSzStrAndDestruct(pCStr, &pszIP, 0));
405
*pIP = calloc(1, sizeof(struct NetAddr));
407
if (*((char*)pszIP) == '[') {
408
pszTmp = (uchar*)strchr ((char*)pszIP, ']');
409
if (pszTmp == NULL) {
411
return RS_RET_INVALID_IP;
415
memset (&hints, 0, sizeof (struct addrinfo));
416
hints.ai_family = AF_INET6;
417
hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
419
switch(getaddrinfo ((char*)pszIP+1, NULL, &hints, &res)) {
421
(*pIP)->addr.NetAddr = malloc (res->ai_addrlen);
422
memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen);
426
F_SET((*pIP)->flags, ADDR_NAME|ADDR_PRI6);
427
(*pIP)->addr.HostWildcard = strdup ((const char*)pszIP+1);
436
/* mask bits follow, let's parse them! */
437
++pThis->iCurrPos; /* eat slash */
438
if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) {
443
/* we need to refresh pointer (changed by parsInt()) */
444
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
446
/* no slash, so we assume a single host (/128) */
449
} else { /* now parse IPv4 */
450
memset (&hints, 0, sizeof (struct addrinfo));
451
hints.ai_family = AF_INET;
452
hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
454
switch(getaddrinfo ((char*)pszIP, NULL, &hints, &res)) {
456
(*pIP)->addr.NetAddr = malloc (res->ai_addrlen);
457
memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen);
461
F_SET((*pIP)->flags, ADDR_NAME);
462
(*pIP)->addr.HostWildcard = strdup ((const char*)pszIP);
471
/* mask bits follow, let's parse them! */
472
++pThis->iCurrPos; /* eat slash */
473
if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) {
478
/* we need to refresh pointer (changed by parsInt()) */
479
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
481
/* no slash, so we assume a single host (/32) */
485
free(pszIP); /* no longer needed */
487
/* skip to next processable character */
488
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
489
&& (*pC == ',' || isspace((int)*pC))) {
499
#endif /* #ifdef SYSLOG_INET */
502
/* tell if the parsepointer is at the end of the
503
* to-be-parsed string. Returns 1, if so, 0
504
* otherwise. rgerhards, 2005-09-27
506
int parsIsAtEndOfParseString(rsParsObj *pThis)
508
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
510
return (pThis->iCurrPos < rsCStrLen(pThis->pCStr)) ? 0 : 1;
514
/* return the position of the parse pointer
516
int rsParsGetParsePointer(rsParsObj *pThis)
518
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
520
if(pThis->iCurrPos < rsCStrLen(pThis->pCStr))
521
return pThis->iCurrPos;
523
return rsCStrLen(pThis->pCStr) - 1;
526
/* peek at the character at the parse pointer
527
* the caller must ensure that the parse pointer is not
528
* at the end of the parse buffer (e.g. by first calling
529
* parsIsAtEndOfParseString).
530
* rgerhards, 2005-09-27
532
char parsPeekAtCharAtParsPtr(rsParsObj *pThis)
534
rsCHECKVALIDOBJECT(pThis, OIDrsPars);
535
assert(pThis->iCurrPos < rsCStrLen(pThis->pCStr));
537
return(*(pThis->pCStr->pBuf + pThis->iCurrPos));
540
/* return the current position inside the parse object.
541
* rgerhards, 2007-07-04
543
int parsGetCurrentPosition(rsParsObj *pThis)
545
return pThis->iCurrPos;