560 lines
13 KiB
C++
560 lines
13 KiB
C++
#include "private.h"
|
|
#include "new.tmh"
|
|
|
|
#define NLB_MAX_PORT_STRING_SIZE 128 // in WCHARS, including ending NULL
|
|
|
|
BOOL
|
|
gen_port_rule_string(
|
|
IN PWLBS_PORT_RULE pPr,
|
|
OUT LPWSTR pString // At least NLB_MAX_PORT_STRING_SIZE wchars
|
|
);
|
|
|
|
BOOL
|
|
parse_port_rule_string(
|
|
IN LPCWSTR pString,
|
|
OUT PWLBS_PORT_RULE pPr
|
|
);
|
|
|
|
VOID
|
|
test_port_rule_string(VOID)
|
|
{
|
|
|
|
LPCWSTR RuleStrings[] =
|
|
{
|
|
L"",
|
|
L" \t \n ",
|
|
L"n=v",
|
|
L" \t \n n=v",
|
|
L" \t \n n \t \n = \t \n v",
|
|
L"na=v1 nb=v2 nc=v3",
|
|
L"\t na \t = \t v1 \t nb \t \n =\t \n v2 \t \n nc \t = \n v3 ",
|
|
#if 1
|
|
L"ip=1.1.1.1 protocol=TCP start=80 end=288 mode=SINGLE"
|
|
L" priority=1",
|
|
L"ip=1.1.1.1 protocol=UDP start=80 end=288 mode=MULTIPLE"
|
|
L" affinity=SINGLE load=80",
|
|
L"ip=1.1.1.1 protocol=UDP start=80 end=288 mode=MULTIPLE"
|
|
L" affinity=NONE load=80",
|
|
L"ip=1.1.1.1 protocol=UDP start=80 end=288 mode=MULTIPLE"
|
|
L" affinity=CLASSC",
|
|
L"ip=1.1.1.1 protocol=BOTH start=80 end=288 mode=DISABLED",
|
|
#endif // 0
|
|
|
|
NULL // Must be last
|
|
};
|
|
|
|
|
|
for (LPCWSTR *ppRs = RuleStrings; *ppRs!=NULL; ppRs++)
|
|
{
|
|
LPCWSTR szRule = *ppRs;
|
|
WCHAR szGenString[NLB_MAX_PORT_STRING_SIZE];
|
|
printf("ORIG: %ws\n", szRule);
|
|
WLBS_PORT_RULE Pr;
|
|
BOOL fRet;
|
|
fRet = parse_port_rule_string(
|
|
szRule,
|
|
&Pr
|
|
);
|
|
if (fRet == FALSE)
|
|
{
|
|
printf("parse_port_rule_string returned FAILURE.\n");
|
|
continue;
|
|
}
|
|
fRet = gen_port_rule_string(
|
|
&Pr,
|
|
szGenString
|
|
);
|
|
if (fRet == FALSE)
|
|
{
|
|
printf("gen_port_rule_string returned FAILURE.\n");
|
|
continue;
|
|
}
|
|
printf("GEN: %ws\n", szGenString);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
gen_port_rule_string(
|
|
IN PWLBS_PORT_RULE pPr,
|
|
OUT LPWSTR pString // At least NLB_MAX_PORT_STRING_SIZE wchars
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
LPCWSTR szProtocol = L"";
|
|
LPCWSTR szMode = L"";
|
|
LPCWSTR szAffinity = L"";
|
|
|
|
ZeroMemory(pString, NLB_MAX_PORT_STRING_SIZE*sizeof(WCHAR));
|
|
|
|
switch(pPr->protocol)
|
|
{
|
|
case CVY_TCP:
|
|
szProtocol = L"TCP";
|
|
break;
|
|
case CVY_UDP:
|
|
szProtocol = L"UDP";
|
|
break;
|
|
case CVY_TCP_UDP:
|
|
szProtocol = L"BOTH";
|
|
break;
|
|
default:
|
|
goto end; // bad parse
|
|
}
|
|
|
|
switch(pPr->mode)
|
|
{
|
|
case CVY_SINGLE:
|
|
szMode = L"SINGLE";
|
|
break;
|
|
case CVY_MULTI:
|
|
szMode = L"MULTIPLE";
|
|
switch(pPr->mode_data.multi.affinity)
|
|
{
|
|
case CVY_AFFINITY_NONE:
|
|
szAffinity = L"NONE";
|
|
break;
|
|
case CVY_AFFINITY_SINGLE:
|
|
szAffinity = L"SINGLE";
|
|
break;
|
|
case CVY_AFFINITY_CLASSC:
|
|
szAffinity = L"CLASSC";
|
|
break;
|
|
default:
|
|
goto end; // bad parse
|
|
}
|
|
break;
|
|
case CVY_NEVER:
|
|
szMode = L"DISABLED";
|
|
break;
|
|
default:
|
|
goto end; // bad parse
|
|
}
|
|
|
|
*pString = 0;
|
|
_snwprintf(
|
|
pString,
|
|
NLB_MAX_PORT_STRING_SIZE-1,
|
|
L"ip=%ws protocol=%ws start=%u end=%u mode=%ws ",
|
|
pPr->virtual_ip_addr,
|
|
szProtocol,
|
|
pPr->start_port,
|
|
pPr->end_port,
|
|
szMode
|
|
);
|
|
|
|
UINT Len = wcslen(pString);
|
|
if (Len >= (NLB_MAX_PORT_STRING_SIZE-1))
|
|
{
|
|
goto end; // not enough space.
|
|
}
|
|
|
|
if (pPr->mode == CVY_MULTI)
|
|
{
|
|
if (pPr->mode_data.multi.equal_load)
|
|
{
|
|
_snwprintf(
|
|
pString+Len,
|
|
(NLB_MAX_PORT_STRING_SIZE-1-Len),
|
|
L"affinity=%ws",
|
|
szAffinity
|
|
);
|
|
}
|
|
else
|
|
{
|
|
_snwprintf(
|
|
pString+Len,
|
|
(NLB_MAX_PORT_STRING_SIZE-1-Len),
|
|
L"affinity=%ws load=%u",
|
|
szAffinity,
|
|
pPr->mode_data.multi.load
|
|
);
|
|
}
|
|
}
|
|
else if (pPr->mode == CVY_SINGLE)
|
|
{
|
|
_snwprintf(
|
|
pString+Len,
|
|
(NLB_MAX_PORT_STRING_SIZE-1-Len),
|
|
L"priority=%u",
|
|
pPr->mode_data.single.priority
|
|
);
|
|
}
|
|
if (pString[NLB_MAX_PORT_STRING_SIZE-1] !=0)
|
|
{
|
|
// out of space
|
|
goto end;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
end:
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL
|
|
parse_port_rule_string(
|
|
IN LPCWSTR pString,
|
|
OUT PWLBS_PORT_RULE pPr
|
|
)
|
|
{
|
|
//
|
|
// Look for following name=value pairs
|
|
//
|
|
// ip=1.1.1.1
|
|
// protocol=[TCP|UDP|BOTH]
|
|
// start=122
|
|
// end=122
|
|
// mode=[SINGLE|MULTIPLE|DISABLED]
|
|
// affinity=[NONE|SINGLE|CLASSC]
|
|
// load=80
|
|
// priority=1"
|
|
//
|
|
|
|
#define INVALID_VALUE ((DWORD)-1)
|
|
LPWSTR psz = NULL;
|
|
WCHAR szCleanedString[2*NLB_MAX_PORT_STRING_SIZE];
|
|
WCHAR c;
|
|
BOOL fRet = FALSE;
|
|
DWORD protocol= INVALID_VALUE;
|
|
DWORD start_port= INVALID_VALUE;
|
|
DWORD end_port= INVALID_VALUE;
|
|
DWORD mode= INVALID_VALUE;
|
|
DWORD affinity= INVALID_VALUE;
|
|
DWORD load= INVALID_VALUE;
|
|
DWORD priority= INVALID_VALUE;
|
|
|
|
ZeroMemory(pPr, sizeof(*pPr));
|
|
|
|
//
|
|
// Set szCleanedString to be a version of pString in "canonical" form:
|
|
// extraneous whitespace stripped out and whitspace represented by a
|
|
// single '\b' character.
|
|
{
|
|
UINT Len = wcslen(pString);
|
|
if (Len > (sizeof(szCleanedString)/sizeof(WCHAR)))
|
|
{
|
|
goto end;
|
|
}
|
|
wcscpy(szCleanedString, pString);
|
|
|
|
//
|
|
// convert different forms of whitespace into blanks
|
|
//
|
|
for (psz=szCleanedString; (c=*psz)!=0; psz++)
|
|
{
|
|
if (c == ' ' || c == '\t' || c == '\n')
|
|
{
|
|
*psz = ' ';
|
|
}
|
|
}
|
|
|
|
//
|
|
// convert runs of whitespace into a single blank
|
|
// also get rid of initial whitespace
|
|
//
|
|
LPWSTR psz1 = szCleanedString;
|
|
BOOL fRun = TRUE; // initial value of TRUE gets rid of initial space
|
|
for (psz=szCleanedString; (c=*psz)!=0; psz++)
|
|
{
|
|
if (c == ' ')
|
|
{
|
|
if (fRun)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
fRun = TRUE;
|
|
}
|
|
}
|
|
else if (c == '=')
|
|
{
|
|
if (fRun)
|
|
{
|
|
//
|
|
// The '=' was preceed by whitespace -- delete that
|
|
// whitespace. We keep fRun TRUE so subsequent whitespace
|
|
// is eliminated.
|
|
//
|
|
if (psz1 == szCleanedString)
|
|
{
|
|
// we're just starting, and we get an '=' -- bad
|
|
goto end;
|
|
}
|
|
psz1--;
|
|
if (*psz1 != ' ')
|
|
{
|
|
ASSERT(*psz1 == '=');
|
|
goto end; // two equals in a row, not accepted!
|
|
}
|
|
}
|
|
}
|
|
else // non blank and non '=' chracter
|
|
{
|
|
fRun = FALSE;
|
|
}
|
|
*psz1++ = c;
|
|
}
|
|
*psz1=0;
|
|
}
|
|
|
|
wprintf(L"CLEANED: \"%ws\"\n", szCleanedString);
|
|
|
|
//
|
|
// Now actually do the parse.
|
|
//
|
|
psz = szCleanedString;
|
|
while(*psz!=0)
|
|
{
|
|
WCHAR Name[32];
|
|
WCHAR Value[32];
|
|
|
|
//
|
|
// Look for the Name in Name=Value pair.
|
|
//
|
|
if (swscanf(psz, L"%16[a-zA-Z]=%16[0-9.a-zA-Z]", Name, Value) != 2)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Skip past the name=value pair -- it contains no blanks
|
|
//
|
|
for (; (c=*psz)!=NULL; psz++)
|
|
{
|
|
if (c==' ')
|
|
{
|
|
psz++; // to skip past the blank
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Now look for the specific name/values
|
|
//
|
|
// ip=1.1.1.1
|
|
// protocol=[TCP|UDP|BOTH]
|
|
// start=122
|
|
// end=122
|
|
// mode=[SINGLE|MULTIPLE|DISABLED]
|
|
// affinity=[NONE|SINGLE|CLASSC]
|
|
// load=80
|
|
// priority=1"
|
|
//
|
|
if (!_wcsicmp(Name, L"ip"))
|
|
{
|
|
if (swscanf(Value, L"%15[0-9.]", pPr->virtual_ip_addr) != 1)
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"protocol"))
|
|
{
|
|
if (!_wcsicmp(Value, L"TCP"))
|
|
{
|
|
protocol = CVY_TCP;
|
|
}
|
|
else if (!_wcsicmp(Value, L"UDP"))
|
|
{
|
|
protocol = CVY_UDP;
|
|
}
|
|
else if (!_wcsicmp(Value, L"BOTH"))
|
|
{
|
|
protocol = CVY_TCP_UDP;
|
|
}
|
|
else
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"protocol"))
|
|
{
|
|
}
|
|
else if (!_wcsicmp(Name, L"start"))
|
|
{
|
|
if (swscanf(Value, L"%u", &start_port)!=1)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
if (start_port > 65535)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"end"))
|
|
{
|
|
if (swscanf(Value, L"%u", &end_port)!=1)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
if (end_port > 65535)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"mode"))
|
|
{
|
|
if (!_wcsicmp(Value, L"SINGLE"))
|
|
{
|
|
mode = CVY_SINGLE;
|
|
}
|
|
else if (!_wcsicmp(Value, L"MULTIPLE"))
|
|
{
|
|
mode = CVY_MULTI;
|
|
}
|
|
else if (!_wcsicmp(Value, L"DISABLED"))
|
|
{
|
|
mode = CVY_NEVER;
|
|
}
|
|
else
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"affinity"))
|
|
{
|
|
if (!_wcsicmp(Value, L"NONE"))
|
|
{
|
|
affinity = CVY_AFFINITY_NONE;
|
|
}
|
|
else if (!_wcsicmp(Value, L"SINGLE"))
|
|
{
|
|
affinity = CVY_AFFINITY_SINGLE;
|
|
}
|
|
else if (!_wcsicmp(Value, L"CLASSC"))
|
|
{
|
|
affinity = CVY_AFFINITY_CLASSC;
|
|
}
|
|
else
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"load"))
|
|
{
|
|
if (swscanf(Value, L"%u", &load)!=1)
|
|
{
|
|
if (load > 100)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
else if (!_wcsicmp(Name, L"priority"))
|
|
{
|
|
if (swscanf(Value, L"%u", &priority)!=1)
|
|
{
|
|
if (priority > 31)
|
|
{
|
|
// bad parse;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bad parse
|
|
goto end;
|
|
}
|
|
printf("SUCCESSFUL PARSE: %ws = %ws\n", Name, Value);
|
|
}
|
|
|
|
|
|
//
|
|
// Set up the PARAMS structure, doing extra parameter validation along the
|
|
// way.
|
|
//
|
|
switch(mode)
|
|
{
|
|
case CVY_SINGLE:
|
|
|
|
if (load != INVALID_VALUE || affinity != INVALID_VALUE)
|
|
{
|
|
goto end; // bad parse;
|
|
}
|
|
if ((priority < CVY_MIN_PRIORITY) || (priority > CVY_MAX_PRIORITY))
|
|
{
|
|
goto end; // bad parse
|
|
}
|
|
pPr->mode_data.single.priority = priority;
|
|
break;
|
|
|
|
case CVY_MULTI:
|
|
|
|
if (priority != INVALID_VALUE)
|
|
{
|
|
goto end; // bad parse;
|
|
}
|
|
|
|
switch(affinity)
|
|
{
|
|
case CVY_AFFINITY_NONE:
|
|
break;
|
|
case CVY_AFFINITY_SINGLE:
|
|
break;
|
|
case CVY_AFFINITY_CLASSC:
|
|
break;
|
|
case INVALID_VALUE:
|
|
default:
|
|
goto end; // bad parse;
|
|
}
|
|
|
|
pPr->mode_data.multi.affinity = affinity;
|
|
|
|
if (load == INVALID_VALUE)
|
|
{
|
|
// this means it's unassigned, which means equal.
|
|
pPr->mode_data.multi.equal_load = 1;
|
|
}
|
|
else if (load > CVY_MAX_LOAD)
|
|
{
|
|
goto end; // bad parse
|
|
}
|
|
else
|
|
{
|
|
pPr->mode_data.multi.load = load;
|
|
}
|
|
break;
|
|
|
|
case CVY_NEVER:
|
|
|
|
if (load != INVALID_VALUE || affinity != INVALID_VALUE
|
|
|| priority != INVALID_VALUE)
|
|
{
|
|
goto end; // bad parse;
|
|
}
|
|
break;
|
|
|
|
case INVALID_VALUE:
|
|
default:
|
|
goto end; // bad parse;
|
|
|
|
}
|
|
|
|
pPr->mode = mode;
|
|
pPr->end_port = end_port;
|
|
pPr->start_port = start_port;
|
|
pPr->protocol = protocol;
|
|
|
|
|
|
fRet = TRUE;
|
|
|
|
end:
|
|
|
|
return fRet;
|
|
}
|
|
|