From f4555f5b3e7826d83635b30125fb0e343852179a Mon Sep 17 00:00:00 2001 From: David Trihy Date: Mon, 2 Sep 2024 17:06:31 +0100 Subject: [PATCH] Add support for subdomain checking in aliases and socket aliases --- cfg.lex | 2 ++ cfg.y | 31 +++++++++++++++++++++++++++++-- ip_addr.h | 2 +- name_alias.c | 4 ++-- name_alias.h | 37 ++++++++++++++++++++++++++++++------- socket_info.c | 10 +++++----- 6 files changed, 69 insertions(+), 17 deletions(-) diff --git a/cfg.lex b/cfg.lex index 49f46de852f..76c016a0aec 100644 --- a/cfg.lex +++ b/cfg.lex @@ -341,6 +341,7 @@ CR \n ANY "any" ANYCAST ("anycast"|"ANYCAST") +SUBDOMAIN ("subdomain"|"SUBDOMAIN") FRAG ("frag"|"FRAG") REUSE_PORT ("reuse_port"|"REUSE_PORT") @@ -615,6 +616,7 @@ SPACE [ ] {CR} { count();/* return CR;*/ } {ANY} { count(); return ANY; } {ANYCAST} { count(); return ANYCAST; } +{SUBDOMAIN} { count(); return SUBDOMAIN; } {REUSE_PORT} { count(); return REUSE_PORT; } {FRAG} { count(); return FRAG; } {SLASH} { count(); return SLASH; } diff --git a/cfg.y b/cfg.y index 3b4660e045b..0359a095861 100644 --- a/cfg.y +++ b/cfg.y @@ -185,6 +185,7 @@ struct listen_param { char *auto_scaling_profile; } p_tmp; static void fill_socket_id(struct listen_param *param, struct socket_id *s); +static void fill_alias_socket(struct listen_param *param, struct socket_id *s); union route_name_var { int iname; @@ -466,6 +467,7 @@ extern int cfg_parse_only_routes; %token COLON %token ANY %token ANYCAST +%token SUBDOMAIN %token FRAG %token REUSE_PORT %token SCRIPTVARERR @@ -491,6 +493,7 @@ extern int cfg_parse_only_routes; %type socket_def %type id_lst %type alias_def +%type any_alias %type listen_id_def %type phostport phostportrange %type proto port any_proto @@ -694,7 +697,7 @@ phostportrange: proto COLON MULT { IFOR(); } ; -alias_def: listen_id { IFOR(); +any_alias: listen_id { IFOR(); $$=mk_listen_id($1, PROTO_NONE, 0); } | ANY COLON listen_id { IFOR(); $$=mk_listen_id($3, PROTO_NONE, 0); } @@ -707,6 +710,23 @@ alias_def: listen_id { IFOR(); | phostport ; +id_lst_param: SUBDOMAIN { IFOR(); + p_tmp.flags |= SI_IS_SUBDOMAIN_ALIAS; + } + ; + +id_lst_params: id_lst_param + | id_lst_param id_lst_params + ; + +alias_def: any_alias { $$=$1; } + | any_alias { IFOR(); + memset(&p_tmp, 0, sizeof(p_tmp)); + } id_lst_params { IFOR(); + $$=$1; fill_alias_socket(&p_tmp, $$); + } + ; + id_lst: alias_def { IFOR(); $$=$1 ; } | alias_def id_lst { IFOR(); $$=$1; $$->next=$2; } ; @@ -730,6 +750,9 @@ socket_def_param: ANYCAST { IFOR(); | REUSE_PORT { IFOR(); p_tmp.flags |= SI_REUSEPORT; } + | SUBDOMAIN { IFOR(); + p_tmp.flags |= SI_IS_SUBDOMAIN_ALIAS; + } | USE_WORKERS NUMBER { IFOR(); p_tmp.workers=$2; } @@ -1484,7 +1507,7 @@ assign_stm: LOGLEVEL EQUAL snumber { IFOR(); | ALIAS EQUAL id_lst { IFOR(); for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) add_alias(lst_tmp->name, strlen(lst_tmp->name), - lst_tmp->port, lst_tmp->proto); + lst_tmp->port, lst_tmp->proto, lst_tmp->flags); } | ALIAS EQUAL error { yyerror("hostname expected (use quotes" " if the hostname includes config keywords)"); } @@ -2771,6 +2794,10 @@ static void fill_socket_id(struct listen_param *param, struct socket_id *s) } } +static void fill_alias_socket(struct listen_param *param, struct socket_id *s) { + s->flags |= param->flags; +} + static struct multi_str *new_string(char *s) { struct multi_str *ms = pkg_malloc(sizeof(struct multi_str)); diff --git a/ip_addr.h b/ip_addr.h index 2eb9f956f28..257fb8204e9 100644 --- a/ip_addr.h +++ b/ip_addr.h @@ -89,7 +89,7 @@ union sockaddr_union{ enum si_flags { SI_NONE=0, SI_IS_IP=1, SI_IS_LO=2, SI_IS_MCAST=4, - SI_IS_ANYCAST=8, SI_FRAG=16, SI_REUSEPORT=32, SI_INTERNAL=64 }; + SI_IS_ANYCAST=8, SI_FRAG=16, SI_REUSEPORT=32, SI_INTERNAL=64, SI_IS_SUBDOMAIN_ALIAS=128 }; struct receive_info { struct ip_addr src_ip; diff --git a/name_alias.c b/name_alias.c index ff91eea1618..e2fa8817ce6 100644 --- a/name_alias.c +++ b/name_alias.c @@ -28,7 +28,6 @@ #include #include "name_alias.h" - struct host_alias* aliases=0; /* name aliases list */ struct alias_function* alias_fcts = NULL; @@ -40,7 +39,7 @@ struct alias_function* alias_fcts = NULL; * if proto==0, the alias will match all the protocols * returns 1 if a new alias was added, 0 if a matching alias was already on * the list and -1 on error */ -int add_alias(char* name, int len, unsigned short port, unsigned short proto) +int add_alias(char* name, int len, unsigned short port, unsigned short proto, enum si_flags flags) { struct host_alias* a; @@ -63,6 +62,7 @@ int add_alias(char* name, int len, unsigned short port, unsigned short proto) a->alias.s[len]=0; /* null terminate for easier printing*/ a->port=port; a->proto=proto; + a->flags=flags; a->next=aliases; aliases=a; return 1; diff --git a/name_alias.h b/name_alias.h index 60231dceda6..b6262364e3b 100644 --- a/name_alias.h +++ b/name_alias.h @@ -33,6 +33,7 @@ #include #include "str.h" #include "dprint.h" +#include "ip_addr.h" #include "mem/mem.h" @@ -41,6 +42,7 @@ struct host_alias{ str alias; unsigned short port; unsigned short proto; + enum si_flags flags; struct host_alias* next; }; @@ -65,17 +67,39 @@ static inline int grep_aliases(char* name, int len, unsigned short port, { struct host_alias* a; struct alias_function *af; + char *name_to_compare, *alias_to_compare; + int len_to_compare, index_offset; if ((len>2)&&((*name)=='[')&&(name[len-1]==']')){ /* ipv6 reference, skip [] */ name++; len-=2; } - for(a=aliases;a;a=a->next) - if ((a->alias.len==len) && ((a->port==0) || (port==0) || - (a->port==port)) && ((a->proto==0) || (proto==0) || - (a->proto==proto)) && (strncasecmp(a->alias.s, name, len)==0)) - return 1; + + for(a=aliases;a;a=a->next) { + if (((a->port==0) || (port==0) || (a->port==port)) && + ((a->proto==0) || (proto==0) || (a->proto==proto))) { + /* Check if the alias is a subdomain alias and if so calculate the index offset to start the comparison + * Given an alias my.domain.com or my.great.domain.com and a subdomain of domain.com the comparison should start at domain.com + * a host of domain.com will also match, if the flag is not set then do a strict comparison + */ + if (a->flags & SI_IS_SUBDOMAIN_ALIAS) { + index_offset = len - a->alias.len; + if (index_offset < 0) // the host we're checking is a shorter len than the alias so no need to compare + continue; + + name_to_compare = name + index_offset; + alias_to_compare = a->alias.s; + + len_to_compare = a->alias.len; + + if (strncasecmp(alias_to_compare, name_to_compare, len_to_compare)==0) + return 1; + } else if (len == a->alias.len && strncasecmp(a->alias.s, name, len)==0) { + return 1; + } + } + } for( af=alias_fcts ; af ; af=af->next ) { if ( af->alias_f(name,len,port,proto)>0 ) @@ -84,9 +108,8 @@ static inline int grep_aliases(char* name, int len, unsigned short port, return 0; } - /* adds an alias to the list (only if it isn't already there) */ -int add_alias(char* name, int len, unsigned short port, unsigned short proto); +int add_alias(char* name, int len, unsigned short port, unsigned short proto, enum si_flags flags); /* register a new function for detecting aliases */ int register_alias_fct( is_alias_fct *fct ); diff --git a/socket_info.c b/socket_info.c index 93792e439b6..a65e6e0cc5b 100644 --- a/socket_info.c +++ b/socket_info.c @@ -668,7 +668,7 @@ int fix_socket_list(struct socket_info_full **list) /* check if we got the official name */ if (strcasecmp(he->h_name, si->name.s)!=0){ if (auto_aliases && add_alias(si->name.s, si->name.len, - si->port_no, si->proto)<0){ + si->port_no, si->proto, si->flags)<0){ LM_ERR("add_alias failed\n"); } /* change the official name */ @@ -684,7 +684,7 @@ int fix_socket_list(struct socket_info_full **list) /* add the aliases*/ if (auto_aliases) { for(h=he->h_aliases; h && *h; h++) - if (add_alias(*h, strlen(*h), si->port_no, si->proto)<0){ + if (add_alias(*h, strlen(*h), si->port_no, si->proto, si->flags)<0){ LM_ERR("add_alias failed\n"); } } @@ -724,11 +724,11 @@ int fix_socket_list(struct socket_info_full **list) }else{ /* add the aliases*/ if (add_alias(he->h_name, strlen(he->h_name), - si->port_no, si->proto)<0){ + si->port_no, si->proto, si->flags)<0){ LM_ERR("add_alias failed\n"); } for(h=he->h_aliases; h && *h; h++) - if (add_alias(*h,strlen(*h),si->port_no,si->proto)<0){ + if (add_alias(*h,strlen(*h),si->port_no,si->proto, si->flags)<0){ LM_ERR(" add_alias failed\n"); } } @@ -859,7 +859,7 @@ int fix_socket_list(struct socket_info_full **list) (sl->name.len!=si->name.len)|| (strncmp(sl->name.s, si->name.s, si->name.len)!=0)) ) - if (add_alias(sl->name.s,sl->name.len,sl->port_no,sl->proto)<0) + if (add_alias(sl->name.s,sl->name.len,sl->port_no,sl->proto,sl->flags)<0) LM_ERR(" add_alias failed\n"); /* remove l*/