mirror of
https://github.com/3proxy/3proxy.git
synced 2026-09-02 12:55:49 +08:00
Move patternmatch from common.c
This commit is contained in:
parent
9529a1dfcf
commit
8971fcf991
241
src/acl.c
241
src/acl.c
@ -8,6 +8,247 @@
|
||||
|
||||
#include "proxy.h"
|
||||
|
||||
/* The pattern engine lives here rather than in common.c: common.c is linked
|
||||
into the standalone binaries as well, and those carry neither the regular
|
||||
expression code this calls nor a use for a host pattern. */
|
||||
/* Host lists in access rules have always accepted name, name*, *name and
|
||||
*name*, with the leading and trailing star recorded as a match type rather
|
||||
than kept in the string. The parser and the comparison are here so that
|
||||
anything else matching a name against a pattern - the http command, and
|
||||
whatever replaces the star with a regular expression later - behaves the same
|
||||
way and gains the same syntax at the same time.
|
||||
*/
|
||||
/* A pattern written as a regular expression carries a prefix. Both spellings
|
||||
are taken so a configuration reads the way its author thinks of it. */
|
||||
static unsigned char * regexprefix(unsigned char *arg)
|
||||
{
|
||||
if(!strncmp((char *)arg, "pcre:", 5)) return arg + 5;
|
||||
if(!strncmp((char *)arg, "regex:", 6)) return arg + 6;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Shared by every pattern the configuration can carry. Returns 0 on success. */
|
||||
static int compileregex(struct hostname *h, unsigned char *pattern)
|
||||
{
|
||||
#ifdef WITH_PCRE
|
||||
char err[256];
|
||||
|
||||
h->re = pcre_pattern_compile(pattern, err, sizeof(err));
|
||||
if(!h->re){
|
||||
fprintf(stderr, "Bad regular expression '%s': %s\n", pattern, err);
|
||||
return 1;
|
||||
}
|
||||
h->matchtype = MATCHREGEX;
|
||||
h->name = (unsigned char *)strdup((char *)pattern);
|
||||
return h->name? 0 : 1;
|
||||
#else
|
||||
fprintf(stderr, "Regular expression '%s' needs a build with PCRE\n", pattern);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int parsepattern(struct hostname *h, unsigned char *arg)
|
||||
{
|
||||
int arglen;
|
||||
unsigned char *pattern;
|
||||
|
||||
h->re = NULL;
|
||||
if((pattern = regexprefix(arg))) return compileregex(h, pattern);
|
||||
|
||||
arglen = (int)strlen((char *)arg);
|
||||
h->matchtype = 3;
|
||||
pattern = arg;
|
||||
|
||||
if(arglen && pattern[arglen-1] == '*'){
|
||||
arglen--;
|
||||
pattern[arglen] = 0;
|
||||
h->matchtype ^= MATCHEND;
|
||||
}
|
||||
if(arglen && pattern[0] == '*'){
|
||||
pattern++;
|
||||
arglen--;
|
||||
h->matchtype ^= MATCHBEGIN;
|
||||
}
|
||||
|
||||
h->name = (unsigned char *)strdup((char *)pattern);
|
||||
return h->name? 0 : 1;
|
||||
}
|
||||
|
||||
/* Matches str against a pattern and reports the part a star stood for. Where a
|
||||
pattern has a star at both ends the trailing one is reported, since that is
|
||||
the part following the text that was matched. An exact pattern leaves an
|
||||
empty span. */
|
||||
int patternmatchpos(const struct hostname *h, const unsigned char *str, int *start, int *len)
|
||||
{
|
||||
int lname, lstr, pos = 0, match = 0;
|
||||
char *found;
|
||||
|
||||
if(!h->name || !str) return 0;
|
||||
if(h->matchtype == MATCHREGEX || h->matchtype == MATCHGLOB){
|
||||
struct capture caps[MAXCAPTURES];
|
||||
|
||||
if(!patternmatchcaps(h, str, caps, NULL)) return 0;
|
||||
if(start) *start = caps[1].start;
|
||||
if(len) *len = caps[1].len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lname = (int)strlen((char *)h->name);
|
||||
lstr = (int)strlen((char *)str);
|
||||
|
||||
switch(h->matchtype){
|
||||
case 0:
|
||||
#ifndef _WIN32
|
||||
found = strcasestr((char *)str, (char *)h->name);
|
||||
#else
|
||||
found = strstr((char *)str, (char *)h->name);
|
||||
#endif
|
||||
if(found){
|
||||
match = 1;
|
||||
pos = (int)(found - (char *)str) + lname;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if(!strncasecmp((char *)str, (char *)h->name, lname)){
|
||||
match = 1;
|
||||
pos = lname;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if(lstr >= lname &&
|
||||
!strncasecmp((char *)str + (lstr - lname), (char *)h->name, lname)){
|
||||
match = 1;
|
||||
pos = 0;
|
||||
if(start) *start = 0;
|
||||
if(len) *len = lstr - lname;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if(!strcasecmp((char *)str, (char *)h->name)){
|
||||
match = 1;
|
||||
pos = lstr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(!match) return 0;
|
||||
|
||||
if(start) *start = pos;
|
||||
if(len) *len = lstr - pos;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int patternmatch(const struct hostname *h, const unsigned char *str)
|
||||
{
|
||||
return patternmatchcaps(h, str, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Match a glob, recording what each star stood for.
|
||||
|
||||
A single star stands for any run of characters within one element of the
|
||||
path, so it stops at a slash; a double star crosses them. Stars are
|
||||
numbered in the order they appear, which is how a template refers to them.
|
||||
*/
|
||||
static int globmatch(const unsigned char *pat, const unsigned char *str,
|
||||
const unsigned char *subject, struct capture *caps, int maxcaps, int star)
|
||||
{
|
||||
while(*pat){
|
||||
if(*pat == '*'){
|
||||
int crosses = (pat[1] == '*');
|
||||
const unsigned char *rest = pat + (crosses? 2 : 1);
|
||||
int len;
|
||||
|
||||
for(len = 0; ; len++){
|
||||
if(star < maxcaps && caps){
|
||||
caps[star].start = (int)(str - subject);
|
||||
caps[star].len = len;
|
||||
}
|
||||
if(globmatch(rest, str + len, subject, caps, maxcaps, star + 1)) return 1;
|
||||
if(!str[len]) return 0;
|
||||
if(!crosses && str[len] == '/') return 0;
|
||||
}
|
||||
}
|
||||
if(*pat != *str) return 0;
|
||||
pat++;
|
||||
str++;
|
||||
}
|
||||
return *str == 0;
|
||||
}
|
||||
|
||||
/* Match a pattern of any kind and report what its stars or groups stood for.
|
||||
caps may be NULL when only the yes or no answer is wanted. */
|
||||
int patternmatchcaps(const struct hostname *h, const unsigned char *str,
|
||||
struct capture *caps, int *ncaps)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if(ncaps) *ncaps = 0;
|
||||
if(!h || !str) return 0;
|
||||
|
||||
if(h->matchtype == MATCHREGEX){
|
||||
#ifdef WITH_PCRE
|
||||
struct capture local[MAXCAPTURES];
|
||||
|
||||
n = pcre_pattern_match(h->re, str, caps? caps : local, MAXCAPTURES);
|
||||
if(ncaps) *ncaps = n;
|
||||
return n > 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(h->matchtype == MATCHGLOB){
|
||||
struct capture local[MAXCAPTURES];
|
||||
struct capture *use = caps? caps : local;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAXCAPTURES; i++){
|
||||
use[i].start = 0;
|
||||
use[i].len = 0;
|
||||
}
|
||||
use[0].start = 0;
|
||||
use[0].len = (int)strlen((char *)str);
|
||||
if(!h->name) return 0;
|
||||
if(!globmatch(h->name, str, str, use, MAXCAPTURES, 1)) return 0;
|
||||
if(ncaps){
|
||||
for(n = MAXCAPTURES - 1; n > 0 && !use[n].len && !use[n].start; n--);
|
||||
*ncaps = n + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* the star at one end or both, as an access rule has always written it */
|
||||
if(caps){
|
||||
int start = 0, len = 0;
|
||||
|
||||
if(!patternmatchpos(h, str, &start, &len)) return 0;
|
||||
caps[0].start = 0;
|
||||
caps[0].len = (int)strlen((char *)str);
|
||||
caps[1].start = start;
|
||||
caps[1].len = len;
|
||||
if(ncaps) *ncaps = 2;
|
||||
return 1;
|
||||
}
|
||||
return patternmatchpos(h, str, NULL, NULL);
|
||||
}
|
||||
|
||||
/* A URL in an http rule: stars anywhere, or a regular expression. */
|
||||
int parsepathpattern(struct hostname *h, unsigned char *arg)
|
||||
{
|
||||
unsigned char *pattern;
|
||||
|
||||
h->re = NULL;
|
||||
if((pattern = regexprefix(arg))) return compileregex(h, pattern);
|
||||
|
||||
h->matchtype = MATCHGLOB;
|
||||
h->name = (unsigned char *)strdup((char *)arg);
|
||||
return h->name? 0 : 1;
|
||||
}
|
||||
|
||||
int IPInentry(struct sockaddr *sa, struct iplist *ipentry){
|
||||
int addrlen;
|
||||
unsigned char *ip, *ipf, *ipt;
|
||||
|
||||
238
src/common.c
238
src/common.c
@ -810,244 +810,6 @@ int bindwithrange(struct clientparam *param, SOCKET sock, PROXYSOCKADDRTYPE *sa,
|
||||
return param->srv->so._bind(param->sostate, sock, (struct sockaddr *)sa, SASIZE(sa));
|
||||
}
|
||||
|
||||
/* Host lists in access rules have always accepted name, name*, *name and
|
||||
*name*, with the leading and trailing star recorded as a match type rather
|
||||
than kept in the string. The parser and the comparison are here so that
|
||||
anything else matching a name against a pattern - the http command, and
|
||||
whatever replaces the star with a regular expression later - behaves the same
|
||||
way and gains the same syntax at the same time.
|
||||
*/
|
||||
/* A pattern written as a regular expression carries a prefix. Both spellings
|
||||
are taken so a configuration reads the way its author thinks of it. */
|
||||
static unsigned char * regexprefix(unsigned char *arg)
|
||||
{
|
||||
if(!strncmp((char *)arg, "pcre:", 5)) return arg + 5;
|
||||
if(!strncmp((char *)arg, "regex:", 6)) return arg + 6;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Shared by every pattern the configuration can carry. Returns 0 on success. */
|
||||
static int compileregex(struct hostname *h, unsigned char *pattern)
|
||||
{
|
||||
#ifdef WITH_PCRE
|
||||
char err[256];
|
||||
|
||||
h->re = pcre_pattern_compile(pattern, err, sizeof(err));
|
||||
if(!h->re){
|
||||
fprintf(stderr, "Bad regular expression '%s': %s\n", pattern, err);
|
||||
return 1;
|
||||
}
|
||||
h->matchtype = MATCHREGEX;
|
||||
h->name = (unsigned char *)strdup((char *)pattern);
|
||||
return h->name? 0 : 1;
|
||||
#else
|
||||
fprintf(stderr, "Regular expression '%s' needs a build with PCRE\n", pattern);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int parsepattern(struct hostname *h, unsigned char *arg)
|
||||
{
|
||||
int arglen;
|
||||
unsigned char *pattern;
|
||||
|
||||
h->re = NULL;
|
||||
if((pattern = regexprefix(arg))) return compileregex(h, pattern);
|
||||
|
||||
arglen = (int)strlen((char *)arg);
|
||||
h->matchtype = 3;
|
||||
pattern = arg;
|
||||
|
||||
if(arglen && pattern[arglen-1] == '*'){
|
||||
arglen--;
|
||||
pattern[arglen] = 0;
|
||||
h->matchtype ^= MATCHEND;
|
||||
}
|
||||
if(arglen && pattern[0] == '*'){
|
||||
pattern++;
|
||||
arglen--;
|
||||
h->matchtype ^= MATCHBEGIN;
|
||||
}
|
||||
|
||||
h->name = (unsigned char *)strdup((char *)pattern);
|
||||
return h->name? 0 : 1;
|
||||
}
|
||||
|
||||
/* Matches str against a pattern and reports the part a star stood for. Where a
|
||||
pattern has a star at both ends the trailing one is reported, since that is
|
||||
the part following the text that was matched. An exact pattern leaves an
|
||||
empty span. */
|
||||
int patternmatchpos(const struct hostname *h, const unsigned char *str, int *start, int *len)
|
||||
{
|
||||
int lname, lstr, pos = 0, match = 0;
|
||||
char *found;
|
||||
|
||||
if(!h->name || !str) return 0;
|
||||
if(h->matchtype == MATCHREGEX || h->matchtype == MATCHGLOB){
|
||||
struct capture caps[MAXCAPTURES];
|
||||
|
||||
if(!patternmatchcaps(h, str, caps, NULL)) return 0;
|
||||
if(start) *start = caps[1].start;
|
||||
if(len) *len = caps[1].len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lname = (int)strlen((char *)h->name);
|
||||
lstr = (int)strlen((char *)str);
|
||||
|
||||
switch(h->matchtype){
|
||||
case 0:
|
||||
#ifndef _WIN32
|
||||
found = strcasestr((char *)str, (char *)h->name);
|
||||
#else
|
||||
found = strstr((char *)str, (char *)h->name);
|
||||
#endif
|
||||
if(found){
|
||||
match = 1;
|
||||
pos = (int)(found - (char *)str) + lname;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if(!strncasecmp((char *)str, (char *)h->name, lname)){
|
||||
match = 1;
|
||||
pos = lname;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if(lstr >= lname &&
|
||||
!strncasecmp((char *)str + (lstr - lname), (char *)h->name, lname)){
|
||||
match = 1;
|
||||
pos = 0;
|
||||
if(start) *start = 0;
|
||||
if(len) *len = lstr - lname;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if(!strcasecmp((char *)str, (char *)h->name)){
|
||||
match = 1;
|
||||
pos = lstr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(!match) return 0;
|
||||
|
||||
if(start) *start = pos;
|
||||
if(len) *len = lstr - pos;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int patternmatch(const struct hostname *h, const unsigned char *str)
|
||||
{
|
||||
return patternmatchcaps(h, str, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Match a glob, recording what each star stood for.
|
||||
|
||||
A single star stands for any run of characters within one element of the
|
||||
path, so it stops at a slash; a double star crosses them. Stars are
|
||||
numbered in the order they appear, which is how a template refers to them.
|
||||
*/
|
||||
static int globmatch(const unsigned char *pat, const unsigned char *str,
|
||||
const unsigned char *subject, struct capture *caps, int maxcaps, int star)
|
||||
{
|
||||
while(*pat){
|
||||
if(*pat == '*'){
|
||||
int crosses = (pat[1] == '*');
|
||||
const unsigned char *rest = pat + (crosses? 2 : 1);
|
||||
int len;
|
||||
|
||||
for(len = 0; ; len++){
|
||||
if(star < maxcaps && caps){
|
||||
caps[star].start = (int)(str - subject);
|
||||
caps[star].len = len;
|
||||
}
|
||||
if(globmatch(rest, str + len, subject, caps, maxcaps, star + 1)) return 1;
|
||||
if(!str[len]) return 0;
|
||||
if(!crosses && str[len] == '/') return 0;
|
||||
}
|
||||
}
|
||||
if(*pat != *str) return 0;
|
||||
pat++;
|
||||
str++;
|
||||
}
|
||||
return *str == 0;
|
||||
}
|
||||
|
||||
/* Match a pattern of any kind and report what its stars or groups stood for.
|
||||
caps may be NULL when only the yes or no answer is wanted. */
|
||||
int patternmatchcaps(const struct hostname *h, const unsigned char *str,
|
||||
struct capture *caps, int *ncaps)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if(ncaps) *ncaps = 0;
|
||||
if(!h || !str) return 0;
|
||||
|
||||
if(h->matchtype == MATCHREGEX){
|
||||
#ifdef WITH_PCRE
|
||||
struct capture local[MAXCAPTURES];
|
||||
|
||||
n = pcre_pattern_match(h->re, str, caps? caps : local, MAXCAPTURES);
|
||||
if(ncaps) *ncaps = n;
|
||||
return n > 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(h->matchtype == MATCHGLOB){
|
||||
struct capture local[MAXCAPTURES];
|
||||
struct capture *use = caps? caps : local;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAXCAPTURES; i++){
|
||||
use[i].start = 0;
|
||||
use[i].len = 0;
|
||||
}
|
||||
use[0].start = 0;
|
||||
use[0].len = (int)strlen((char *)str);
|
||||
if(!h->name) return 0;
|
||||
if(!globmatch(h->name, str, str, use, MAXCAPTURES, 1)) return 0;
|
||||
if(ncaps){
|
||||
for(n = MAXCAPTURES - 1; n > 0 && !use[n].len && !use[n].start; n--);
|
||||
*ncaps = n + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* the star at one end or both, as an access rule has always written it */
|
||||
if(caps){
|
||||
int start = 0, len = 0;
|
||||
|
||||
if(!patternmatchpos(h, str, &start, &len)) return 0;
|
||||
caps[0].start = 0;
|
||||
caps[0].len = (int)strlen((char *)str);
|
||||
caps[1].start = start;
|
||||
caps[1].len = len;
|
||||
if(ncaps) *ncaps = 2;
|
||||
return 1;
|
||||
}
|
||||
return patternmatchpos(h, str, NULL, NULL);
|
||||
}
|
||||
|
||||
/* A URL in an http rule: stars anywhere, or a regular expression. */
|
||||
int parsepathpattern(struct hostname *h, unsigned char *arg)
|
||||
{
|
||||
unsigned char *pattern;
|
||||
|
||||
h->re = NULL;
|
||||
if((pattern = regexprefix(arg))) return compileregex(h, pattern);
|
||||
|
||||
h->matchtype = MATCHGLOB;
|
||||
h->name = (unsigned char *)strdup((char *)arg);
|
||||
return h->name? 0 : 1;
|
||||
}
|
||||
|
||||
int scanaddr(const unsigned char *s, uint32_t * ip, uint32_t * mask) {
|
||||
unsigned d1, d2, d3, d4, m;
|
||||
int res;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user