unlang(5) FreeRADIUS Processing un-language unlang(5)

unlang - زبان پردازش در فایل‌های پیکربندی FreeRADIUS (un-language)

سرور FreeRADIUS از یک زبان پردازش ساده در فایل‌های پیکربندی خود پشتیبانی می‌کند. ما آن را یک «un-language» می‌نامیم زیرا هدف، ایجاد یک زبان برنامه‌نویسی جدید دیگر نبوده است. اگر به قابلیتی پیچیده‌تر از آنچه در اینجا شرح داده شده نیاز دارید، پیشنهاد می‌کنیم از ماژول‌های پرل یا پایتون، یعنی rlm_perl یا rlm_python استفاده کنید.

هدف این زبان فراهم کردن امکان نگارش سیاست‌های ساده با کمترین زحمت است. این سیاست‌ها سپس هنگام پردازش یک درخواست اعمال می‌شوند. درخواست‌ها از طریق سرورهای مجازی (شامل سرور پیش‌فرض)، در بخش‌هایی با عناوین "authorize" ،"authenticate" ،"post-auth" ،"preacct" ،"accounting" ،"pre-proxy" ،"post-proxy" و "session" پردازش می‌گردند.

این سیاست‌ها را نمی‌توان در هیچ بخش دیگری از فایل‌های پیکربندی، مانند پیکربندی ماژول‌ها یا کلاینت‌ها، به کار برد.

کلیدواژه‌های این زبان ترکیبی از کلیدواژه‌های از پیش تعریف‌شده و ارجاع به نام ماژول‌های قابل بارگذاری هستند. ما در اینجا تنها کلیدواژه‌های از پیش تعریف‌شده را مستند می‌کنیم.

با در نظر گرفتن چند محدودیت که در زیر شرح داده شده، هر کلیدواژه‌ای می‌تواند در هر زمینه‌ای ظاهر شود. این زبان شامل مجموعه‌ای از مدخل‌ها است که هر کدام در یک خط قرار دارند. هر مدخل با یک کلیدواژه آغاز می‌شود. مدخل‌ها در قالب فهرست‌ها سازماندهی می‌شوند. پردازش زبان خط به خط، از ابتدای فهرست تا انتهای آن انجام می‌گیرد. عملیات به ازای هر کلیدواژه اجرا می‌شوند.

ارجاعی به ماژول نام‌گذاری‌شده. هنگامی که پردازش به این نقطه می‌رسد، ماژول کامپایل‌شده فراخوانی می‌شود. ماژول ممکن است موفق شود یا شکست بخورد، و در این صورت وضعیتی را به "unlang" بازمی‌گرداند. این وضعیت را می‌توان در یک شرط بررسی کرد. متن "شرط‌های ساده" در بخش CONDITIONS و بخش MODULE RETURN CODES را در زیر ببینید. اگر نام بخش (section-name) ارائه شود، باعث می‌شود ماژول به‌گونه‌ای اجرا شود که گویی در بخش نام‌گذاری‌شده درج شده است.
chap  # فراخوانی ماژول CHAP
sql   # فراخوانی ماژول SQL
...

یک شرط خاص را بررسی می‌کند. اگر درست (true) باشد، بلوک بعد از شرط پردازش می‌شود. در غیر این صورت، بلوک نادیده گرفته می‌شود. برای مستندات مربوط به قالب شرط‌ها، بخش CONDITIONS را در زیر ببینید.
if (condition) {
	...
}

بلوکی را تعریف می‌کند که تنها در صورتی اجرا می‌شود که شرط "if" قبلی مقدار نادرست (false) بازگردانده باشد.
else {
	...
}

بلوکی را تعریف می‌کند که تنها در صورتی اجرا می‌شود که شرط "if" قبلی مقدار نادرست (false) بازگردانده باشد و شرط مشخص‌شده کنونی مقدار درست (true) ارزیابی شود.
elsif (condition) {
	...
}

روی مقادیر یک ویژگی (attribute) حلقه می‌زند و بلوک را برای هر مقدار اجرا می‌کند. مقدار بازگشتی بلوک، مقدار بازگشتی آخرین عبارت اجراشده است. با استفاده از کلیدواژه "break" می‌توان حلقه را زودتر از موعد خاتمه داد. بر خلاف زبان‌های دیگر، "break" در اینجا به معنای «خروج از حلقه در تکرار بعدی» است، نه «خروج فوری از حلقه». نتیجه این است که هر عبارتی پس از کلیدواژه "break" همچنان اجرا خواهد شد. توصیه می‌کنیم از "break" تنها زمانی استفاده کنید که آخرین عبارت در یک بلوک "foreach" باشد.

درون بلوک "foreach"، ویژگی‌ای که روی آن حلقه زده می‌شود را می‌توان با نام "Foreach-Variable-#" ارجاع داد؛ که در آن "#" عمق حلقه است که از "0" شروع می‌شود؛ مانند "Foreach-Variable-0". حلقه‌ها را می‌توان تا عمق هشت (8) لایه تودرتو کرد، اگرچه این کار توصیه نمی‌شود.

foreach &Attribute-Reference {
	...
}

عبارت "switch" یک آرگومان می‌گیرد و شامل مجموعه‌ای از عبارات "case" است. هنگامی که یک عبارت "switch" دیده می‌شود، آرگومان "switch" به نوبت با آرگومان هر عبارت "case" مقایسه و ارزیابی می‌شود. اولین عبارت "case" که مطابقت داشته باشد اجرا می‌گردد. تمام عبارات "case" دیگر نادیده گرفته می‌شوند. با حذف آرگومان، می‌توان یک عبارت "case" پیش‌فرض تعریف کرد.

اگر آرگومان یک رشته با نقل‌قول دوگانه (مانند "%{exec:1 + 2}") باشد، همان‌طور که در بخش DATA TYPES در زیر شرح داده شده است بسط می‌یابد. سپس تطبیق روی رشته حاصل از بسط انجام می‌شود. اگر آرگومان ارجاعی به یک ویژگی باشد (مانند &User-Name)، تطبیق روی مقدار آن ویژگی انجام می‌گیرد. در غیر این صورت، آرگومان به عنوان یک رشته لفظی در نظر گرفته شده و تطبیق از طریق مقایسه ساده انجام می‌شود.

هیچ عبارتی غیر از "case" نمی‌تواند در بلوک "switch" ظاهر شود.

switch <argument> {
	...
}

یک جایگاه منطبق با آرگومان عبارت والد "switch" فراهم می‌کند.

عبارت "case" نمی‌تواند خارج از یک بلوک "switch" ظاهر شود.

اگر آرگومان یک رشته با نقل‌قول دوگانه باشد (مانند "%{exec:1 + 2}")، همان‌طور که در بخش DATA TYPES در زیر شرح داده شده بسط می‌یابد. سپس تطبیق روی رشته حاصل از بسط انجام می‌شود. اگر آرگومان ارجاع به یک ویژگی باشد (مانند &User-Name)، تطبیق روی مقدار آن ویژگی انجام می‌گیرد. در غیر این صورت، آرگومان یک رشته لفظی در نظر گرفته شده و تطبیق با مقایسه ساده انجام می‌شود.

case <argument> {
	...
}

یک مدخل پیش‌فرض را می‌توان با حذف آرگومان تعریف کرد، همان‌طور که در زیر نشان داده شده است. این مدخل در صورتی استفاده خواهد شد که هیچ مدخل "case" دیگری مطابقت نداشته باشد. تنها یک مدخل پیش‌فرض می‌تواند در یک بخش "switch" وجود داشته باشد.

case {
	...
}

یک فهرست ویژگی خاص را بر اساس ویژگی‌های ارائه‌شده در بلوک جاری به‌روزرسانی می‌کند.
update <list> {
	&Attribute-Reference = value
	...
}

مقدار <list> می‌تواند یکی از موارد "request" ،"reply" ،"proxy-request" ،"proxy-reply" ،"coa" ،"disconnect" ،"session-state" یا "control" باشد. از نسخه ۳ به بعد، <list> می‌تواند حذف شود که در این صورت مقدار "request" در نظر گرفته می‌شود.

فهرست "control" فهرستی از ویژگی‌ها است که به صورت داخلی توسط سرور نگهداری می‌شود و نحوه پردازش درخواست توسط سرور را کنترل می‌کند. هر ویژگی که در قالب یک بسته روی شبکه ارسال نشود، عموماً در فهرست "control" قرار می‌گیرد.

برای روش‌های EAP دارای نشست‌های احراز هویت تونل‌شده (مانند PEAP و EAP-TTLS)، نشست تونل داخلی می‌تواند به "outer.request" ،"outer.reply" و "outer.control" نیز ارجاع دهد. این ارجاعات به شما امکان می‌دهند فهرست مربوطه را در نشست تونل خارجی آدرس‌دهی کنید.

بخش‌های "coa" و "disconnect" تنها زمانی قابل استفاده هستند که سرور یک بسته Access-Request یا Accounting-Request دریافت کند. هنگامی که سرور یک بسته CoA-Request یا Disconnect-Request دریافت می‌کند، به جای "coa" از "request" و "reply" استفاده کنید.

افزودن یک یا چند ویژگی به هر یک از فهرست‌های "coa" یا "disconnect" باعث می‌شود سرور یک بسته CoA-Request یا Disconnect-Request تولید کند. آن بسته پس از اتمام Access-Request یا Accounting-Request جاری و ارسال پاسخ به NAS فرستاده می‌شود. برای اطلاعات بیشتر raddb/sites-available/originate-coa را ببینید.

فهرست "session-state" اساساً برای EAP استفاده می‌شود. ویژگی‌های قرار داده شده در فهرست "session-state" برای بسته بعدی در همان نشست ذخیره می‌شوند. آنها با دریافت بسته بعدی به طور خودکار بازیابی می‌گردند.

تنها محتوای مجاز در یک بخش "update"، ویژگی‌ها و مقادیر هستند. محتوای بخش "update" در بخش‌های ATTRIBUTE REFERENCE و ATTRIBUTE ASSIGNMENT در زیر تشریح شده است.

این بخش شامل فهرستی ساده از ماژول‌ها است. هنگام پردازش این بخش، اولین ماژول فراخوانی می‌شود. اگر عملیات اولین ماژول موفقیت‌آمیز باشد، سرور پردازش بخش را متوقف کرده و به بخش والد بازمی‌گردد.

با این حال، اگر ماژول شکست بخورد، ماژول بعدی در فهرست آزمایش می‌شود، همان‌طور که در بالا توضیح داده شد. پردازش تا زمانی ادامه می‌یابد که یک ماژول موفق شود یا فهرست به پایان برسد.

بخش‌های Redundant فقط می‌توانند شامل فهرستی از ماژول‌ها باشند و نمی‌توانند حاوی کلیدواژه‌هایی باشند که عملیات شرطی (if، else و غیره) را انجام می‌دهند یا یک فهرست ویژگی را به‌روزرسانی می‌کنند.

redundant {
	sql1	# این را امتحان کن
	sql2	# این را فقط اگر sql1 شکست خورد امتحان کن.
	...
}
این بخش شامل فهرستی ساده از ماژول‌ها است. هنگام ورود به این بخش، یک ماژول به صورت تصادفی برای پردازش درخواست انتخاب می‌شود. تمام ماژول‌های موجود در فهرست باید از یک نوع باشند (مانند ldap یا sql). تمام ماژول‌های موجود در فهرست باید رفتاری یکسان داشته باشند، در غیر این صورت بخش load-balance برای یک درخواست یکسان نتایج متفاوتی بازمی‌گرداند.

بخش‌های Load-balance فقط می‌توانند شامل فهرستی از ماژول‌ها باشند و نمی‌توانند حاوی کلیدواژه‌هایی باشند که عملیات شرطی (if، else و غیره) را انجام می‌دهند یا یک فهرست ویژگی را به‌روزرسانی می‌کنند.

load-balance {
	ldap1	# ۵۰٪ درخواست‌ها به اینجا می‌روند
	ldap2	# ۵۰٪ درخواست‌ها به اینجا می‌روند
}

به طور کلی، پیشنهاد می‌کنیم به جای "load-balance" از "redundant-load-balance" استفاده کنید.

این بخش شامل فهرستی ساده از ماژول‌ها است. هنگام ورود به این بخش، یک ماژول به صورت تصادفی برای پردازش درخواست انتخاب می‌شود. اگر آن ماژول موفق شود، سرور پردازش بخش را متوقف می‌کند. با این حال، اگر ماژول شکست بخورد، یکی از ماژول‌های باقی‌مانده به طور تصادفی برای پردازش درخواست انتخاب می‌شود. این فرآیند تا زمانی که یک ماژول موفق شود یا فهرست به پایان برسد تکرار می‌گردد.

تمام ماژول‌های موجود در فهرست باید از یک نوع باشند (مانند ldap یا sql). تمام ماژول‌های موجود در فهرست باید رفتار یکسانی داشته باشند، در غیر این صورت بخش load-balance برای همان درخواست نتایج متفاوتی بازمی‌گرداند.

بخش‌های Load-balance فقط می‌توانند شامل فهرستی از ماژول‌ها باشند و نمی‌توانند شامل کلیدواژه‌هایی باشند که عملیات شرطی (if، else و غیره) انجام می‌دهند یا یک فهرست ویژگی را به‌روزرسانی می‌کنند. لطفاً برای نمونه‌های بیشتر پیکربندی، بخش "instantiate" را در raddb/radiusd.conf مشاهده فرمایید.

redundant-load-balance {
	ldap1	# ۵۰٪، مگر اینکه ldap2 از کار افتاده باشد که در این صورت ۱۰۰٪
	ldap2	# ۵۰٪، مگر اینکه ldap1 از کار افتاده باشد که در این صورت ۱۰۰٪
}

از بخش سطح بالای جاری، مانند "authorize" یا "authenticate" بازمی‌گردد. این کلیدواژه عمدتاً برای جلوگیری از لایه‌های تودرتوی عبارات "if" و "else" استفاده می‌شود.
authorize {
	if (...) {
		...
		return
	}
	...  # هنگامی که عبارت "if" اجرا شود
	...  # این خطوط هرگز اجرا نخواهند شد
}

ویژگی‌ها را می‌توان از طریق نحو زیر ارجاع داد:

&Attribute-Name
&Attribute-Name:TAG
&Attribute-Name[NUM]
&<list>:Attribute-Name
&<list>:Attribute-Name:TAG[NUM]

که در آن <list> دقیقاً مانند بخش "update" در بالا، یکی از موارد "request" ،"reply" ،"control" ،"proxy-request" ،"proxy-reply" یا "outer.request" ،"outer.reply" ،"outer.control" ،"outer.proxy-request" یا "outer.proxy-reply" است. پیشوند ":<list>" اختیاری است و در صورت حذف، پیش‌فرض ارجاع به فهرست "request" در نظر گرفته می‌شود.

بخش TAG یک عدد صحیح دهدهی بین ۱ و ۳۱ است. لطفاً برای اطلاعات بیشتر درباره تگ‌ها به RFC 2868 مراجعه فرمایید. تگ‌ها تنها برای ویژگی‌هایی قابل استفاده هستند که در دیکشنری به عنوان "has_tag" علامت‌گذاری شده باشند.

بخش NUM زمانی استفاده می‌شود که چندین ویژگی هم‌نام در یک فهرست وجود داشته باشد. ارجاع "Attribute-Name" اولین ویژگی را برمی‌گرداند. استفاده از آفست آرایه به سیاست اجازه می‌دهد تا به ویژگی دوم و موارد بعدی ارجاع دهد.

اگر در بخش NUM از '*' استفاده شود، به تمامی نمونه‌های آن ویژگی در درخواست ارزیابی می‌شود.

اگر در بخش NUM از 'n' استفاده شود، به آخرین نمونه ویژگی در درخواست ارزیابی می‌شود.

هنگامی که با نام یک ویژگی برخورد می‌شود، فهرست مورد نظر برای یافتن ویژگی با آن نام بررسی می‌گردد. چند مثال عبارتند از:

User-Name
request:User-Name # همانند مورد بالا
reply:User-Name
Tunnel-Password:1
Cisco-AVPAir[2]
outer.request:User-Name # از درون یک تونل TTLS/PEAP

توجه داشته باشید که بر خلاف زبان C، هیچ راهی برای تعریف ویژگی‌های جدید در زمان اجرا وجود ندارد. آنها باید حتماً در یک فایل دیکشنری اعلام شده و هنگام راه‌اندازی سرور بارگذاری شوند.

تمامی ویژگی‌ها در دیکشنری‌هایی که همراه با سرور ارائه می‌شوند تعریف شده‌اند. این تعاریف تنها نام و نوع را مشخص می‌کنند و مقدار ویژگی را تعیین نمی‌نمایند. هنگامی که سرور بسته‌ای دریافت می‌کند، از محتویات بسته برای جستجوی مدخل‌ها در دیکشنری استفاده کرده و ویژگی‌هایی با نام برگرفته از دیکشنری‌ها و مقداری برگرفته از محتویات بسته نمونه‌سازی می‌کند. این فرآیند بدان معناست که اگر ویژگی خاصی وجود ندارد، معمولاً به این دلیل است که در بسته دریافت شده توسط سرور قرار نداشته است.

پس از آنکه ویژگی نمونه‌سازی شد، به یک فهرست اضافه می‌شود. سپس می‌توان به آن ارجاع داد، آن را به‌روزرسانی کرد، جایگزین نمود و غیره.

شرط‌ها از نظر نحو شبیه به شرط‌های زبان C هستند، اگرچه همانند پوسته یونیکس از رشته‌های دارای نقل‌قول پشتیبانی می‌شود.

شرط‌های ساده

(foo)

اگر 'foo' یک رشته غیرخالی باشد (نقل‌قول تکی، نقل‌قول دوگانه یا نقل‌قول معکوس)، به درست (true) ارزیابی می‌شود. همچنین اگر 'foo' یک عدد غیرصفر باشد به درست ارزیابی می‌گردد. توجه داشته باشید که این زبان دارای سیستم نوع‌بندی ضعیفی است، بنابراین رشته "0000" ممکن است به عنوان عدد صفر تفسیر شود. برای جلوگیری از این مشکل می‌توان به جای ارزیابی خود رشته به تنهایی، آن را با یک رشته خالی مقایسه کرد.

اگر واژه 'foo' یک رشته نقل‌قول‌شده نباشد، می‌تواند به عنوان ارجاعی به یک ویژگی نام‌گذاری‌شده در نظر گرفته شود. برای نمونه‌های ارجاع به ویژگی‌ها، بخش «ارجاع به ویژگی‌ها» را در بالا ببینید. اگر ویژگی نام‌گذاری‌شده وجود داشته باشد، شرط به درست (true) ارزیابی می‌شود.

در غیر این صورت، اگر واژه 'foo' رشته نقل‌قول‌شده نباشد و ارجاع به ویژگی نیز نباشد، به عنوان ارجاعی به یک کد بازگشتی ماژول تفسیر می‌شود. اگر آخرین کد بازگشتی ماژول با نام ارائه‌شده در اینجا مطابقت داشته باشد، شرط به درست ارزیابی می‌شود. کدهای بازگشتی معتبر ماژول در بخش MODULE RETURN CODES در زیر آمده است.

نقیض (Negation)
(!foo)

اگر 'foo' نادرست ارزیابی شود به درست ارزیابی می‌شود و بالعکس.

عملگرهای اتصال کوتاه (Short-circuit)


(foo || bar)
(foo && bar)

عملگرهای "&&" و "||" عملگرهای اتصال کوتاه هستند. عملگر "&&" شرط اول را ارزیابی می‌کند و تنها در صورتی شرط دوم را ارزیابی می‌نماید که نتیجه شرط اول درست باشد. عملگر "||" مشابه است، اما دستور دوم را تنها در صورتی اجرا می‌کند که نتیجه شرط اول نادرست باشد.

مقایسه‌ها (Comparisons)
(foo == bar)

مقدار 'foo' را با 'bar' مقایسه می‌کند و اگر مقایسه برقرار باشد به درست ارزیابی می‌شود. عملگرهای مقایسه معتبر عبارتند از "==" ،"!=" ،"<" ،"<=" ،">" ،">=" ،"=~" و "!~" که همگی معانی معمول خود را دارند. عملگرهای ":=" ،"^=" و "=" عملگرهای انتساب هستند و برای مقایسه مجاز نمی‌باشند.

عملگرهای "<" ،"<=" ،">" و ">=" همچنین برای بررسی قرار داشتن یک نشانی IP در یک شبکه مجاز هستند. به عنوان مثال:

if (<ipaddr>192.0.2.1 < 192.0.2.0/24) {

این مقایسه موفقیت‌آمیز است، زیرا نشانی 192.0.2.1 در شبکه 192.0.2.0/24 قرار دارد.

مقایسه ویژگی‌ها (Attribute Comparisons)
هنگام انجام مقایسه ویژگی‌ها، نوع داده ویژگی برای تعیین نوع داده آرگومان سمت راست به کار می‌رود.
(&User-Name == "foo")

مقدار ویژگی User-Name را با رشته 'foo' مقایسه می‌کند و در صورت برقرار بودن مقایسه، به درست ارزیابی می‌شود.

به همین ترتیب،

(&Framed-IP-Address == 192.0.2.1)

مقدار ویژگی Framed-IP-Address را با نشانی IP برابر با 192.0.2.1 مقایسه می‌کند. این نشانی IP نیازی به قرار گرفتن در نقل‌قول ندارد.

مقایسه میان‌ویژگی (Inter-Attribute Comparisons)
(&User-Name == &Filter-Id)

مقدار ویژگی User-Name را با محتویات ویژگی Filter-Id مقایسه کرده و در صورت برقرار بودن مقایسه، به درست ارزیابی می‌شود. بر خلاف مثال قبلی، این مقایسه به روشی امن از نظر نوع داده (type-safe) انجام می‌گیرد. به عنوان مثال، مقایسه نشانی‌های IP برابر با 1.2.3.4 و 127.0.0.1 به صورت رشته، نتایج متفاوتی نسبت به مقایسه آنها به عنوان نشانی IP در پی خواهد داشت.

نویسه "&" در شرط به این معناست که مقایسه به ویژگی Filter-Id «ارجاع» می‌دهد. در صورت حذف آن، به این معنا خواهد بود که ویژگی User-Name با رشته لفظی "Filter-Id" مقایسه می‌شود.

در صورتی که سمت چپ یک ویژگی باشد، می‌توان نویسه "&" را حذف کرد. با این حال، به منظور سازگاری با نسخه‌های پیشین مجاز است؛ به عنوان مثال مقایسه "(&User-Name == &Filter-Id)" معادل مثال بالاست.

پیشنهاد می‌کنیم به جای چاپ ویژگی‌ها در قالب رشته، از ارجاع ویژگی استفاده کنید؛ مانند (User-Name == "%{Filter-Id}"). ارجاع ویژگی سریع‌تر و بهینه‌تر خواهد بود.

شرط‌ها تنها اولین رخداد یک ویژگی را بررسی می‌کنند. اگر بیش از یک نمونه از ویژگی وجود داشته باشد، باید از نحو زیر استفاده شود:

(&Attribute-Name[*] == "foo")

استفاده از نحو "[*]" بدین معناست که تمام نمونه‌های ویژگی نام‌برده بررسی می‌شوند. اگر یک ویژگی مطابقت داشته باشد، شرط برقرار است و اگر هیچ‌کدام مطابقت نداشته باشد، شرط شکست می‌خورد.

تبدیل نوع (Casts)
(<type>foo == bar)

سمت چپ یک شرط را می‌توان به یک نوع داده خاص «تبدیل» (cast) کرد. نوع داده باید از انواعی باشد که برای دیکشنری‌ها معتبر است؛ مانند "integer" ،"ipaddr" و غیره.

این مقایسه همانند «مقایسه میان‌ویژگی» در بالا، به شیوه‌ای امن از نظر نوع انجام می‌شود. هر دو طرف شرط در قالب ویژگی‌های موقت تجزیه می‌شوند و ویژگی‌ها از طریق روش‌های مختص آن نوع مقایسه می‌گردند. این ویژگی‌های موقت هیچ تأثیر دیگری ندارند و در جایی ذخیره نمی‌شوند.

تبدیل نوع به شرط‌ها اجازه می‌دهد تا مقایسه‌های ویژه یک نوع خاص را انجام دهند. در نسخه‌های قبلی سرور، داده‌ها باید به صورت دستی در یک یا چند ویژگی واسط قرار داده می‌شدند و سپس ویژگی‌ها با یکدیگر مقایسه می‌شدند. استفاده از تبدیل نوع امکان نگارش سیاست‌های ساده‌تری را فراهم می‌سازد.

تبدیل نوع تنها روی آرگومان سمت چپ یک شرط مجاز است.

شرط‌ها را می‌توان تا هر عمقی تودرتو کرد و تنها محدود به محدودیت طول خط (۸۱۹۲ بایت) است.

در این زبان تنها چند نوع داده پشتیبانی می‌شود: ارجاع به ویژگی‌ها، اعداد و رشته‌ها. هر نوع داده‌ای می‌تواند در یک شرط مستقل ظاهر شود که در این صورت همان‌طور که در "شرط‌های ساده" در بالا شرح داده شد ارزیابی می‌شود. آنها همچنین می‌توانند (با برخی استثنائات ذکر شده در زیر) در سمت چپ یا سمت راست یک مقایسه ظاهر شوند.

اعداد (numbers)
اعداد از ارقام دهدهی تشکیل شده‌اند. اعداد ممیز شناور، هگزادسیمال و اکتال پشتیبانی نمی‌شوند. حداکثر مقدار مجاز برای یک عدد وابسته به معماری ماشین است، اما معمولاً ۳۲ بیتی بوده و شامل یک بیت برای علامت عدد است.

کلمه (word)

متنی که داخل نقل‌قول قرار نگرفته باشد بسته به محل قرارگیری آن در شرط، به شیوه‌های متفاوتی تفسیر می‌شود. در سمت چپ یک شرط، به عنوان ارجاع به یک ویژگی تفسیر می‌شود. در سمت راست، به صورت یک رشته ساده تفسیر می‌گردد؛ دقیقاً همانند یک رشته با نقل‌قول تکی.

استفاده از ارجاع ویژگی، مقایسه‌های محدودی را بر اساس نوع داده میسر می‌سازد، همان‌گونه که در مثال‌های زیر دیده می‌شود:

if (&User-Name == "bob") {
	...
if (&Framed-IP-Address > 127.0.0.1) {
	...
if (&Service-Type == Login-User) {
"رشته‌ها (strings)"
رشته‌های با نقل‌قول دوگانه پیش از ارزیابی، با درج مقدار ویژگی‌ها (بخش ATTRIBUTE REFERENCES را در بالا ببینید) بسط می‌یابند. اگر نتیجه یک عدد باشد، در یک بافت عددی ارزیابی می‌شود.

طول رشته به طول خط محدود است که معمولاً حدود ۸۰۰۰ نویسه می‌باشد. از علامت نقل‌قول دوگانه می‌توان از طریق روش معمول گریز با بک‌اسلش در یک رشته استفاده کرد ("!like \"this\"").

'رشته‌ها'
رشته‌های با نقل‌قول تکی همان‌گونه که هستند ارزیابی می‌شوند. مقادیر آنها همانند رشته‌های با نقل‌قول دوگانه در بالا بسط داده نمی‌شوند و به عنوان ارجاع به ویژگی نیز تفسیر نمی‌گردند.
`رشته‌ها`
رشته‌های درون بک‌تیک از طریق بسط محتویات رشته، همان‌گونه که در بالا برای رشته‌های با نقل‌قول دوگانه شرح داده شد، ارزیابی می‌شوند. دستور حاصل درون رشته در یک زیرپوسته (sub-shell) اجرا شده و خروجی آن به عنوان یک رشته دریافت می‌شود. این رفتار بسیار شبیه به پوسته‌های یونیکس است.

توجه داشته باشید که به دلایل امنیتی، رشته ورودی پیش از انجام بسط رشته، به دستور و آرگومان‌ها تقسیم می‌شود.

به دلایل کارایی، پیشنهاد می‌کنیم استفاده از رشته‌های درون بک‌تیک به حداقل ممکن برسد. اجرای برنامه‌های خارجی نسبتاً پرهزینه است و اجرای تعداد زیادی برنامه برای هر درخواست می‌تواند به سرعت تمام زمان پردازنده (CPU) سرور را مصرف کند. اگر حس می‌کنید نیاز به اجرای برنامه‌های متعددی دارید، پیشنهاد می‌کنیم راه‌های جایگزینی برای دستیابی به همان نتیجه بیابید. در برخی موارد، استفاده از یک زبان واقعی ممکن است کافی باشد.

/regex/im
این رشته‌ها تنها در سمت راست یک مقایسه معتبر هستند، و آن هم فقط زمانی که عملگر مقایسه "=~" یا "!~" باشد. آنها عبارات باقاعده (regular expressions) هستند که توسط کتابخانه عبارات باقاعده محلی روی سیستم پیاده‌سازی شده‌اند. این معمولاً عبارات باقاعده سازگار با پوزیکس (Posix) است.

پسوند 'i' اختیاری است و نشان می‌دهد که تطبیق عبارت باقاعده باید بدون حساسیت به حروف کوچک و بزرگ انجام شود.

پسوند 'm' نیز اختیاری است و نشان می‌دهد که لنگرهای هشتک '^' و دلار '$' علاوه بر ابتدا و انتهای رشته اصلی، باید با خطوط جدید نیز مطابقت داشته باشند.

اگر عملگر مقایسه "=~" باشد، پرانتزها در عبارت باقاعده متغیرهایی حاوی متن منطبق را تعریف خواهند کرد، همان‌طور که در بالا در بخش ATTRIBUTE REFERENCES شرح داده شد.

ویژگی‌ها با استفاده از نحو ATTRIBUTE REFERENCE که در بالا شرح داده شد، و با قرار دادن ارجاع میان "%{...}" بسط می‌یابند.

%{Attribute-Reference}

نتیجه رشته‌ای خواهد بود که حاوی مقدار ویژگی ارجاع‌داده‌شده به صورت یک رشته قابل چاپ است. اگر ویژگی وجود نداشته باشد، نتیجه یک رشته خالی خواهد بود.

نتایج حاصل از تطبیق عبارات باقاعده

اگر قبلاً تطبیق یک عبارت باقاعده انجام شده باشد، متغیر ویژه %{0} شامل کپی از بخش منطبق رشته ورودی خواهد بود. متغیرهای %{1} تا %{32} شامل زیررشته‌های منطبق، از اولین گروه تسخیر (capture group) از سمت چپ به بعد خواهند بود. اگر بیش از ۳۲ گروه تسخیر وجود داشته باشد، نتایج اضافی در دسترس نخواهند بود. اگر سرور با کتابخانه libpcre کامپایل شده باشد، نتایج گروه‌های تسخیر نام‌گذاری‌شده با استفاده از بسط "%{regex:capture group}" در دسترس خواهند بود. آنها همچنین از طریق متغیرهایی که در بالا شرح داده شد قابل دسترسی هستند. هر بار که یک عبارت باقاعده ارزیابی می‌شود، چه تطبیق پیدا کند یا خیر، مقادیر گروه‌های تسخیر پاک خواهند شد.

دریافت نتایج از پایگاه‌های داده

پرس‌وجو از یک پایگاه داده برای کسب برخی اطلاعات و استفاده از نتیجه در یک شرط بسیار مفید است. نحو زیر یک ماژول را فراخوانی می‌کند، رشته مورد نظر را به آن پاس می‌دهد و بسط رشته را با رشته بازگشتی از ماژول جایگزین می‌نماید.
%{module: string ...}

نحو رشته به ماژول مربوطه بستگی دارد. لطفاً برای جزئیات بیشتر مستندات ماژول را مطالعه فرمایید.

نحو شرطی

نحو شرطی مشابه آنچه در پوسته‌های یونیکس استفاده می‌شود نیز می‌تواند به کار رود.
%{%{Foo}:-bar}
اگر %{Foo} دارای مقدار باشد، همان مقدار را برمی‌گرداند.
در غیر این صورت، رشته لفظی "bar" را بازمی‌گرداند.
%{%{Foo}:-%{Bar}}
اگر %{Foo} دارای مقدار باشد، همان مقدار را برمی‌گرداند.
در غیر این صورت، بسط %{Bar} را بازمی‌گرداند.

این بسط‌های شرطی را می‌توان تقریباً تا هر عمقی تودرتو کرد، مانند %{%{One}:-%{%{Two}:-%{Three}}}

طول رشته‌ها و آرایه‌ها

مشابه پوسته یونیکس، روش‌هایی برای ارجاع به طول رشته‌ها و دومین نمونه یا نمونه‌های بیشتر از یک ویژگی در یک فهرست وجود دارد. اگر به قابلیتی فراتر از این نیاز دارید، پیشنهاد می‌کنیم از یک زبان برنامه‌نویسی واقعی استفاده کنید.
%{strlen:string}
تعداد نویسه‌ها در "string". اگر "string" وجود نداشته باشد، طول نیز به جای صفر بودن، وجود نخواهد داشت.

رشته "string" پیش از محاسبه طول بسط داده می‌شود.

%{integer:Attribute-Name}
مقدار عددی صحیح Attribute-Name به جای نام شمارشی آن.

به عنوان مثال، اگر درخواستی حاوی "Service-Type = Login-User" باشد، بسط %{integer:Service-Type} مقدار "1" را تولید خواهد کرد.

%{hex:Attribute-Name}
مقدار هگزادسیمال Attribute-Name، در قالب مجموعه‌ای از ارقام هگز.

به عنوان مثال، اگر درخواستی حاوی "Framed-IP-Address = 127.0.0.1" باشد، بسط %{hex:Framed-IP-Address} مقدار "0x7f000001" را نتیجه خواهد داد.

%{Attribute-Name[#]}
تعداد نمونه‌های موجود از Attribute-Name.

به عنوان مثال اگر درخواستی شامل "User-Name = bob" باشد، بسط %{User-Name[#]} مقدار "1" را بازمی‌گرداند.

%{Attribute-Name[*]}
تمامی مقادیر Attribute-Name که با کاما (',') به عنوان جداکننده به هم متصل شده‌اند.
%{List-Name:[#]}
تعداد ویژگی‌های موجود در فهرست نام‌گذاری‌شده.
%{List-Name:[*]}
تمامی مقادیر ویژگی‌های موجود در فهرست نام‌گذاری‌شده که با کاما (',') به عنوان جداکننده به هم متصل شده‌اند. از %{pairs:} xlat برای به دست آوردن فهرستی از ویژگی‌ها و مقادیر استفاده کنید.

به عنوان مثال اگر پاسخی شامل "Reply-Message = 'Hello', Reply-Message = 'bob'" باشد، بسط "%{reply:Reply-Message[*]}" مقدار "Hello\nbob" را تولید خواهد کرد.

فهرست‌های ویژگی شرح داده شده در بالا را می‌توان با درج یک یا چند ویژگی در بخش "update" ویرایش کرد. پس از تعریف ویژگی‌ها، می‌توان همان‌طور که در بخش ATTRIBUTE REFERENCES در بالا گفته شد به آنها ارجاع داد.

نحو زیر ویژگی‌ها را در یک بخش "update" تعریف می‌کند. هر ویژگی و مقدار باید همگی در یک خط در فایل پیکربندی قرار گیرند. نیازی به کاما یا نقطه‌ویرگول پس از مقدار نیست.

Attribute-Reference = value

ارجاع به ویژگی

مقدار Attribute-Reference باید یک ارجاع (به بالا مراجعه فرمایید) با استفاده از نامی باشد که پیش‌تر در یک دیکشنری تعریف شده است. اگر از نامی تعریف‌نشده استفاده شود، سرور خطایی برمی‌گرداند و راه‌اندازی نخواهد شد.
عملگرها (Operators)
عملگر مورد استفاده برای انتساب مقدار ویژگی می‌تواند یکی از موارد زیر با معانی ذکر شده باشد.
=
ویژگی را تنها در صورتی به فهرست اضافه می‌کند که ویژگی‌ای با همین نام از قبل در آن فهرست موجود نباشد.
:=
ویژگی را به فهرست اضافه می‌کند. اگر هر ویژگی دیگری با همین نام از قبل در فهرست وجود داشته باشد، مقدار آن با مقدار ویژگی جاری جایگزین می‌شود.
+=
ویژگی را به انتهای فهرست اضافه می‌کند، حتی اگر ویژگی‌هایی با همین نام از قبل در فهرست وجود داشته باشند. هنگامی که سمت راست عبارت به چندین مقدار منتهی شود، بدین معناست که تمام مقادیر به انتهای فهرست اضافه شوند.
^=
ویژگی را به ابتدای فهرست اضافه می‌کند، حتی اگر ویژگی‌هایی با همین نام از قبل در فهرست وجود داشته باشند. هنگامی که سمت راست عبارت به چندین مقدار منتهی شود، بدین معناست که تمام مقادیر به ابتدای فهرست افزوده شوند.

عملگرهای اعمال و پالایش (Enforcement and Filtering Operators)

عملگرهای زیر نیز می‌توانند علاوه بر موارد فهرست‌شده در بالا به کار روند. وظیفه آنها انجام اعمال مقررات یا پالایش روی ویژگی‌های موجود در یک فهرست است.
-=
تمام ویژگی‌های منطبق را از فهرست حذف می‌کند. برای حذف ویژگی از فهرست، هم نام ویژگی و هم مقدار آن باید مطابقت داشته باشند.
==
تمام ویژگی‌های منطبق را نگه می‌دارد. برای باقی ماندن ویژگی در فهرست، هم نام ویژگی و هم مقدار آن باید مطابقت داشته باشند.

توجه داشته باشید که این عملگر با عملگر '=' که در بالا فهرست شده بسیار متفاوت است!

!=
تمام ویژگی‌های دارای نام منطبق و مقداری غیر از مقدار داده شده را نگه می‌دارد.
<
تمام ویژگی‌های دارای مقادیر کمتر از مقدار داده‌شده در اینجا را نگه می‌دارد. هر مقدار بزرگ‌تر با مقدار داده‌شده در اینجا جایگزین می‌شود. اگر هیچ ویژگی‌ای وجود نداشته باشد، همانند "+=" با مقدار داده‌شده در اینجا اضافه می‌شود.
<=
تمام ویژگی‌های دارای مقادیر کمتر یا مساوی مقدار داده‌شده در اینجا را نگه می‌دارد. هر مقدار بزرگ‌تر با مقدار داده‌شده در اینجا جایگزین می‌شود. اگر هیچ ویژگی‌ای وجود نداشته باشد، همانند "+=" با مقدار داده‌شده در اینجا اضافه می‌شود.
>
تمام ویژگی‌های دارای مقادیر بزرگ‌تر از مقدار داده‌شده در اینجا را نگه می‌دارد. هر مقدار کوچک‌تر با مقدار داده‌شده در اینجا جایگزین می‌شود. اگر هیچ ویژگی‌ای وجود نداشته باشد، همانند "+=" با مقدار داده‌شده در اینجا اضافه می‌شود.
>=
تمام ویژگی‌های دارای مقادیر بزرگ‌تر یا مساوی مقدار داده‌شده در اینجا را نگه می‌دارد. هر مقدار کوچک‌تر با مقدار داده‌شده در اینجا جایگزین می‌شود. اگر هیچ ویژگی‌ای وجود نداشته باشد، همانند "+=" با مقدار داده‌شده در اینجا اضافه می‌شود.
!*
تمام رخدادهای ویژگی نام‌برده را بدون توجه به مقدار آن حذف می‌کند.
=~
تمام ویژگی‌هایی را که مقادیر آنها با عبارت باقاعده داده‌شده مطابقت دارد نگه می‌دارد. اگر هیچ ویژگی‌ای مطابقت نداشته باشد، کار دیگری انجام نمی‌شود.
!~
تمام ویژگی‌هایی را که مقادیر آنها با عبارت باقاعده داده‌شده مطابقت ندارد نگه می‌دارد. اگر هیچ ویژگی‌ای مطابقت نداشته باشد، اقدام دیگری انجام نمی‌شود.
مقادیر (Values)

مقدار می‌تواند ارجاعی به یک ویژگی یا یک رشته مختص ویژگی باشد.

هنگامی که مقدار، ارجاع به یک ویژگی است، باید به شکل "&Attribute-Name" باشد. علامت "&" در ابتدا نشان‌دهنده ارجاع بودن مقدار است. نام "Attribute-Name" یک نام ویژگی است، مانند "User-Name" یا "request:User-Name". هنگامی که از ارجاع ویژگی استفاده می‌شود، هر دو ویژگی باید دارای نوع داده یکسان باشند. برای مثال، عبارت "User-Name := &NAS-Port" نامعتبر است، زیرا "User-Name" یک رشته و "NAS-Port" یک عدد صحیح است.

پیشنهاد می‌کنیم برای به‌روزرسانی‌ها به جای "Attribute-1 = "%{Attribute-2}" از شکل "Attribute-1 = &Attribute-2" استفاده کنید. نسخه اول داده‌های ویژگی را فارغ از قالب آن کپی می‌کند. نسخه دوم Attribute-2 را به یک رشته تبدیل کرده و سپس برای ایجاد مقدار Attribute-1 آن را تجزیه می‌کند. این نسخه دوم کندتر و شکننده‌تر از نسخه اول است.

هنگامی که مقدار یک رشته مختص ویژگی باشد، می‌تواند یک رشته، عدد صحیح، نشانی IP و غیره باشد. مقدار ممکن است همان‌طور که در بخش DATA TYPES در بالا تشریح شد بسط یابد. به عنوان مثال، تعیین "Framed-IP-Address = 127.0.0.1" باعث می‌شود ویژگی "Framed-IP-Address" روی نشانی IP با مقدار "127.0.0.1" تنظیم شود. با این حال، استفاده از "

این انعطاف‌پذیری به این معناست که شما می‌توانید یک نشانی IP را با تعیین مستقیم آن، یا از طریق دریافت نشانی از یک پرس‌وجوی پایگاه داده، یا از طریق بازگردانده شدن نشانی به عنوان خروجی یک برنامه اجرایی، انتساب دهید.

هنگامی که مقادیر رشته‌ای در نهایت به یک ویژگی اختصاص می‌یابند، حداکثر می‌توانند ۲۵۳ نویسه طول داشته باشند. این محدودیت تا حدی به الزامات پروتکل و تا حدی به نیازمندی‌های داخلی سرور مربوط می‌شود. بدین معنا که رشته‌ها در این زبان می‌توانند نزدیک به 8k طول داشته باشند (مثلاً برای یک کوئری طولانی SQL). با این حال، خروجی آن پرس‌وجوی SQL نباید بیش از ۲۵۳ نویسه طول داشته باشد.

سایر کلیدواژه‌ها در این زبان از نام ماژول‌های بارگذاری‌شده توسط سرور برگرفته می‌شوند. این کلیدواژه‌ها هم به ماژول‌ها و هم به پیکربندی محلی وابسته هستند.

برخی کلیدواژه‌های پرکاربرد که در فایل پیکربندی پیش‌فرض تعریف شده‌اند عبارتند از:

باعث می‌شود با درخواست به گونه‌ای رفتار شود که گویی خطای پایگاه داده رخ داده است.
کاری انجام نده. این همچنین به عنوان دستوری برای ردیابی جابه‌جایی پشتیبان (failover) قابل پیکربندی عمل می‌کند که نشان دهد در بخش جاری کاری انجام نشده است.
به سرور اعلام می‌کند که درخواست به درستی پردازش شده است. اگر مدیر محلی سیستم تشخیص دهد که خرابی‌ها بحرانی نیستند، از این کلیدواژه می‌توان برای نادیده گرفتن شکست‌های قبلی استفاده کرد.
باعث رد فوری درخواست می‌شود.

هنگامی که یک ماژول فراخوانی می‌شود، یکی از کدهای زیر را با معانی داده‌شده به "unlang" بازمی‌گرداند.

notfound        اطلاعات یافت نشد
noop            ماژول کاری انجام نداد
ok              عملیات ماژول موفقیت‌آمیز بود
updated         ماژول درخواست را به‌روزرسانی کرد
fail            ماژول با شکست مواجه شد
reject          ماژول درخواست را رد کرد
userlock        کاربر قفل شده بود
invalid         پیکربندی نامعتبر بود
handled         ماژول خودش درخواست را مدیریت کرده است

این کدهای بازگشتی را می‌توان در یک شرط بررسی کرد، همان‌طور که در بالا در بخش CONDITIONS تشریح شد.

همچنین فایل doc/configurable_failover را برای روش‌های بیشتر به دام انداختن و اصلاح کدهای بازگشتی ماژول ببینید.

/etc/raddb/radiusd.conf

radiusd.conf(5), dictionary(5)

Alan DeKok <aland@deployingradius.com>

16 February 2021