FreeRADIUS Processing un-language unlang - FreeRADIUS Processing un-languageDESCRIPTION FreeRADIUS supports a simple processing language in its configuration files. We call it an "un-language" because the intention is NOT to create yet another programming language. If you need something more complicated than what is described here, we suggest using the Perl or Python modules rlm_perl, or rlm_python.
这个是一种在Freeradius配置文件中简单的处理语言。我们之所以叫他“UN语言”是因为我们不去创造另一门编程语言。如果你需要比这里描述功能还复杂的功能,我们建议你使用rlm_perl或者rlm_python模块吧。 The goal of the language is to allow simple policies to be written with minimal effort. Those policies are then applied when a request is being processed. Requests are processed through virtual servers (including the default one), in the sections titled "authorize", "authenticate", "post-auth", "preacct", "accounting", "pre-proxy", "post-proxy", and "session".These policies cannot be used in any other part of the configuration files, such as module or client configuration.
这个语言的目标是,使用尽量简单的精力来写一个简单的策略。这些策略在请求处理的时候发挥作用。请求都是通过虚拟服务处理的(包括默认的default),在以下几个模块中处理的。“authorize”,“authenticate“,”post-auth",“preacct”,“accounting”,“pre-proxy",”post-proxy",还有“session”部分。这些策略不能用到任何的其它部分,比如模块还有客户端配置等位置。
KEYWORDS
The keywords for the language are a combination of pre-defined keywords, and references to loadable module names. We document only the pre-defined keywords here.
Subject to a few limitations described below, any keyword can appear in any context. The language consists of a series of entries, each one one line.Each entry begins with a keyword. Entries are organized into lists. Processing of the language is line by line, from the start of the list to the end. Actions are executed per-keyword.
关键字是已经定义关键字的组合,还有一些模块的名称。我们只在这里记录已经预定义的关键字。除了一些小的限制,任何关键字可以出现在任何的位置。这个语言由一系列的实体组成。每个实体以一个关键字开头。实体们构成列表。这个语言的处理是一行一行的,从头到尾的顺序执行。
module-name A reference to the named module. When processing reaches this point, the pre-compiled module is called. The module may succeed or fail, and will return a status to "unlang" if so. This status can be tested in a condition. See the "Simple Conditions" text in the CONDITIONS section, and MODULE RETURN CODES, below.
模块的名称
指的是模块的名称。当处理到这个关键点的是时候,预编译的模块就会被调用。这个模块要么成功,要么失败,然后返回给unlang对应的值。这个状态可以在条件中测试,请看在条件部分的简单的状态文本,并且模块返回结果: chap # call the CHAP module sql # call the SQL module ... if Checks for a particular condition. If true, the block after the condition is processed. Otherwise, the block is ignored. See CONDITIONS, below, for documentation on the format of the conditions.
检查一些条件,如果条件成立,则后面的代码就会执行。否则,后面的代码就会被忽略掉,条件的话请参考后面的文档说明。
if (condition) { ... } else
efine a block to be executed only if the previous "if" condition returned false. else { ... } elsif
Define a block to be executed only if the previous "if" condition returned false, and if the specified condition evaluates to true. elsif (condition) { ... }
大体意思就是说,if else 和 if elsif 的判断
switch Evaluate the given string, and choose the first matching "case" statement inside of the current block. If the string is surrounded by double quotes, it is expanded as described in the DATA TYPES section, below.
评估下给的字符串,找到第一个合适的匹配语句。如果字符串被双引号引在内部,它 it is expanded as described in the DATA TYPES section, below.
No statement other than "case" can appear in a "switch" block. 只允许case语句出现在switch模块中 switch "string" { ... } case Define a static string to match a parent "switch" statement. The strings given here are not expanded as is done with the parent "switch" statement. 定义一个case字符串,用来和父级的switch语句进行匹配。 A "case" statement cannot appear outside of a "switch" block. case语句决不能在switch模块外出现 case string { ... } A default entry can be defined by omitting the static string. This entry will be used if no other "case" entry matches. Only one default entry can exist in a "switch" section. case { #这种默认的语句是如果没有相同的语句,就可以执行默认值了,像是其他语言的default
... } update
Update a particular attribute list, based on the attributes given in the current block. 根据当前属性集,修改特定属性列表: update <list> { attribute = value ... } The <list> can be one of "request", "reply", "proxy-request", "proxy-reply", "coa", "disconnect", or "control". The "control" list is the list of attributes maintainted internally by the server that controls how the server processes the request. Any attribute that does not go in a packet on the network will generally be placed in the "control" list.
list可以是很多模块的东西,但是 control 模块比较特殊。“control”模块是服务器内部维护的属性,控制服务器如何处理请求。任何在网络上不在包中的属性都会被放到控制列表里面。
For backwards compatibility with older versions, "check" is accepted as a synonym for "control". The use of "check" is deprecated, and will be removed in a future release.为了向前的兼容性,“check”属性也能被当做control的缩写使用,“check”的使用已经废弃,将会在下一个发行版中去除,尽量不要再使用。 For EAP methods with tunneled authentication sessions (i.e. PEAP and EAP-TTLS), the inner tunnel session can also reference "outer.request", "outer.reply", and "outer.control".Those references allow you to address the relevant list in the outer tunnel session. The "coa" and "disconnect" sections can only be used when the server receives an Access-Request or Accounting-Request. Use "request" and "reply" instead of "coa" when the server receives a CoA-Request or Disconnect-Request packet. dding one or more attributes to either of the "coa" or "disconnect" list causes server to originate a CoA-Request or Disconnect-Request packet. That packet is sent when the current Access-Request or Accounting-Request has been finished, and a reply sent to the NAS. See raddb/sites-available/originate-coa for additional information. 更改已经授权的授权,使radius产生CoA-Request 或者 Disconnect-Request包, Change of Authorization,位于 raddb/sites-avaiable/originate-coa The only contents permitted in an "update" section are attributes and values. The contents of the "update" section are described in the ATTRIBUTES section below.
在 Update 部分唯一允许的内容是:属性和值。 update 区域的描述在下面的 属性部分 有描述redundant
This section contains a simple list of modules. The first module is called when the section is being processed. If the first module succeeds in its operation,then the server stops processing the section, and returns to the parent section.
这个部分包含一系列的模块,在处理开始的时候,第一个模块开始被调用。如果第一个模块就执行成功,那么服务器将会停止执行这个模块的操作,并且返回到它的父模块部分。 If, however, the module fails, then the next module in the list is tried, as described above. The processing continues until one module succeeds, or until the list has been exhausted.
如果这个部分前一个模块处理失败,那么就会执行下一个模块,正如上面描述的一样,只有到某个模块执行成功后,才会退出,或者所有模块消耗殆尽,都没有成功也会退出。 Redundant sections can contain only a list of modules, and cannot contain keywords that perform conditional operations (if, else, etc) or update an attribute list.
Redundant 部分 只能包含一个列表的模块,不能包含 执行条件操作的关键字(比如if,else)也不能更新一个属性列表。 redundant { sql1 # try this sql2 # try this only if sql1 fails. ... }
load-balance
this section contains a simple list of modules. When the section is entered, one module is chosen at random to process the request. All of the modules in the list should be the same type (e.g. ldap or sql). All of the modules in the list should behave identically, otherwise the load-balance section will return different results for the same request.
这个部分包含了一个简单的模块列表。当进入这个区域,模块是被随机调用来处理请求。所有在这个列表中的模块必须是相同类型的(比如ldap或者sql)。列表中的每个模块都得表现的具有一致性,否者负载均衡部分不同模块的处理结果不同,最终将会返回不同的结果。 Load-balance sections can contain only a list of modules, and cannot contain keywords that perform conditional operations (if, else, etc) or update an attribute list.
负载均衡区域只能包含一个列表的模块,并且无法包含执行条件操作的关键字(if,else)也不能更新一个属性列表。 load-balance { ldap1 # 50% of requests go here ldap2 # 50% of requests go here } In general, we recommend using "redundant-load-balance" instead of "load-balance".
一般我们推荐使用redundant-load-balance取代 load-balance 模块。
redundant-load-balance
This section contains a simple list of modules. When the section is entered, one module is chosen at random to process the request. If that module succeeds,then the server stops processing the section. If, however, the module fails, then one of the remaining modules is chosen at random to process the request.This process repeats until one module succeeds, or until the list has been exhausted.
这个区域包含了一个简单列表的模块。当进入到这个区域时,将会随机选择一个模块来处理这个请求。如果那个模块成功了,然后服务器就会停止处理这个区域。但是,如果模块失败了,然后剩下的这些模块又被随机的选择来处理这个请求。这个过程不断地重复知道返回成功,或者消耗掉了所有的模块。 All of the modules in the list should be the same type (e.g. ldap or sql). All of the modules in the list should behave identically, otherwise the load-balance section will return different results for the same request. Load-balance sections can contain only a list of modules, and cannot contain keywords that perform conditional operations (if, else, etc) or update an attribute list. redundant-load-balance { ldap1 # 50%, unless ldap2 is down, then 100% ldap2 # 50%, unless ldap1 is down, then 100% }
CONDITIONS
The conditions are similar to C conditions in syntax, though quoted strings are supported, as with the Unix shell.
这些条件和C语言语句差不多,当然也支持“”内的字符串,和Unix的shell一样。 Simple conditions 最简单的条件语句~ (foo) Evalutes to true if 'foo' is a non-empty string (single quotes, double quotes, or back-quoted). Also evaluates to true if 'foo' is a non-zero number. Note that the language is poorly typed, so the string "0000" can be interpreted as a numerical zero. This issue can be avoided by comparings strings to an empty string, rather than by evaluating the string by itself.
如果foo不是一个空的字符串(单引号,双引号,或者反单引号)。同时检验foo是不是一个非零的数字。因为这个是弱类型的语言,0000会被翻译成一个0.为了防止这种问题,可以和一个空的字符串相比较,而不是让他自己比较自己。If the word 'foo' is not a quoted string, then it can be taken as a reference to a named attribute. See "Referencing attribute lists", below, for examples of attribute references. The condition evaluates to true if the named attribute exists.
Otherwise, if the word 'foo' is not a quoted string, and is not an attribute reference, then it is interpreted as a reference to a module return code. The condition evaluates to true if the most recent module return code matches the name given here. Valid module return codes are given in MODULE RETURN CODES, below.
如果没有采用引号包含,那么它会被当做一个attribut【属性】对待。如果这个属性存在的话,这个条件就为真。如果foo既不是引用的字符串也不是属性索引,那它就会被当做一个模块返回值。这种情况下,如果最近一个模块的返回值和这个值相同时条件成立。可用的模块返回值在 MODULE RETURN CODES ↓ Negation 取反 (!foo) Evalutes to true if 'foo' evaluates to false, and vice-versa. Short-circuit operators (foo || bar) (foo && bar) "&&" and "||" are short-circuit operators. "&&" evaluates the first condition, and evaluates the second condition if and only if the result of the first condition is true. "||" is similar, but executes the second command if and only if the result of the first condition is false. Comparisons (foo == bar) Compares 'foo' to 'bar', and evaluates to true if the comparison holds true. Valid comparison operators are "==", "!=", "<", "<=", ">", ">=", "=~", and "!~",all with their usual meanings. Invalid comparison operators are ":=" and "=" 这些值不可用也就是(:= 和 =) Conditions may be nested to any depth, subject only to line length limitations (8192 bytes).
条件可以嵌套任意深度,只有长度限制8192个字节DATA TYPES There are only a few data types supported in the language. Reference to attributes, numbers, and strings. Any data type can appear in stand-alone condition, in which case they are evaluated as described in "Simple conditions", above. They can also appear (with some exceptions noted below) on the left-hand or on the right-hand side of a comparison.
数据类型:只有很少量的数据类型允许存在,可以出现在条件等中: numbers Numbers are composed of decimal digits. Floating point, hex, and octal numbers are not supported. The maximum value for a number is machine-dependent, but is usually 32-bits, including one bit for a sign value.
数字类型只支持整型,不支持浮点,十六进制,八进制等。最大的值取决于不同的系统,一般是32位长,包含一个位的符号位。 word Text that is not enclosed in quotes is interpreted differently depending on where it occurs in a condition. On the left hand side of a condition, it is interpreted as a reference to an attribute. On the right hand side, it is interpreted as a simple string, in the same manner as a single-quoted string.
字类型如果不在引号内的话,那就根据不用的情况翻译成不同的结果。如果在左边,那会被当做一个属性翻译。如果在右边,仅仅被当做一个字符串,在单引号内的也是这样的行为。 Using attribute references permits limited type-specific comparisons, as seen in the examples below. if (User-Name == "bob") { ... if (Framed-IP-Address > 127.0.0.1) { ... if (Service-Type == Login-User) { "strings" Double-quoted strings are expanded by inserting the value of any variables (see VARIABLES, below) before being evaluated. If the result is a number it is evaluated in a numerical context.
String length is limited by line-length, usually about 8000 characters. A double quote character can be used in a string via the normal back-slash escaping method. ("like \"this\" !") 'strings' 就是相等,不会进行任何翻译或者转移 Single-quoted strings are evaluated as-is. Their values are not expanded as with double-quoted strings above, and they are not interpreted as attribute references. `strings` 比较有意思,这里面东西的执行结果 Back-quoted strings are evaluated by expanding the contents of the string, as described above for double-quoted strings. The resulting command given inside of the string in a sub-shell, and taking the output as a string. This behavior is much the same as that of Unix shells. Note that for security reasons, the input string is split into command and arguments before variable expansion is done. For performance reasons, we suggest that the use of back-quoted strings be kept to a minimum. Executing external programs is relatively expensive, and executing a large number of programs for every request can quickly use all of the CPU time in a server. If you believe that you need to execute many programs, we suggest finding alternative ways to achieve the same result. In some cases, using a real language may be sufficient. /regex/i These strings are valid only on the right-hand side of a comparison, and then only when the comparison operator is "=~" or "!~". They are regular expressions,as implemented by the local regular expression library on the system. This is usually Posix regular expressions. The trailing 'i' is optional, and indicates that the regular expression match should be done in a case-insensitive fashion. i选项的作用是采用大小写不敏感的方式 If the comparison operator is "=~", then parantheses in the regular expression will define variables containing the matching text, as described below in the VARIABLES section.VARIABLES Run-time variables are referenced using the following syntax 变量,运行时的变量通过如下的语法进行引用: %{Variable-Name} Note that unlike C, there is no way to declare variables, or to refer to them outside of a string context. All references to variables MUST be contained inside of a double-quoted or back-quoted string.
注意啦:这个和C语言不通,没有办法声明变量,也不能在字符串外进行引用。所有调用的变量都得包含在 双引号,或者反单引号内 "" `` Many potential variables are defined in the dictionaries that accompany the server. These definitions define only the name and type, and do not define the value of the variable. When the server receives a packet, it uses the packet contents to look up entries in the dictionary, and instantiates variables with a name taken from the dictionaries, and a value taken from the packet contents. This process means that if a variable does not exist, it is usually because it was not mentioned in a packet that the server received.
许多的潜在变量在字典中定义了。定义只定义了名称和类型,并没有定义变量的值。当服务器收到一个包,它使用包内容查找字典中的实体,然后使用从字典文件中获取的变量名,并且从包中取的变量的值。这意味着,如果一个变量不存在,一般是因为她没在包中提到。 Once the variable is instantiated, it is added to an appropriate attribute list, as described below. In many cases, attributes and variables are inter-changeble, and are often talked about that way. However, variables can also refer to run-time calls to modules, which may perform operations like SQL SELECTs, and which may return the result as the value of the variable. Referencing attribute lists Attribute lists may be referenced via the following syntax %{<list>:Attribute-Name} Where <list> is one of "request", "reply", "control", "proxy-request", "proxy-reply", or "outer.request", "outer.reply", "outer.control", "outer.proxy-request", or "outer.proxy-reply". just as with the "update" section, above. The "<list>:" prefix is optional, and if omitted, is assumed to refer to the "request" list. When a variable is encountered, the given list is examined for an attribute of the given name. If found, the variable reference in the string is replaced with the value of that attribute. Some examples are: %{User-Name} %{request:User-Name} # same as above %{reply:User-Name} %{outer.reqest:User-Name} # from inside of a TTLS/PEAP tunnel Results of regular expression matches If a regular expression match has previously been performed, then the special variable %{0} will contain a copy of the input string. The variables %{1} through %{8} will contain the substring matches, starting from the left-most parantheses, and onwards. If there are more than 8 parantheses, the additional results will not be placed into any variables. Obtaining results from databases It is useful to query a database for some information, and to use the result in a condition. The following syntax will call a module, pass it the given string, and replace the variable reference with the resulting string returned from the module. %{module: string ...} The syntax of the string is module-specific. Please read the module documentation for additional details. Conditional Syntax Conditional syntax similar to that used in Unix shells may also be used. %{%{Foo}:-bar} If %{Foo} has a value, returns that value. Otherwise, returns literal string "bar". %{%{Foo}:-%{Bar}} If %{Foo} has a value, returns that value. Otherwise, returns the expansion of %{Bar}. These conditional expansions can be nested to almost any depth, such as with %{%{One}:-%{%{Two}:-%{Three}}} String lengths and arrays Similar to a Unix shell, there are ways to reference string lenths, and the second or more instance of an attribute in a list. If you need this functionality,we recommend using a real language. %{#string} The number of characters in %{string}. If %{string} is not set, then the length is not set. e.g. %{#Junk-junk:-foo} will yeild the string "foo". %{Attribute-Name#} Will print the integer value of the attribute, rather than a decoded VALUE or date. This feature applies only to attributes of type "date", "integer", "byte", and "short". It has no effect on any other attributes. It is used when the numerical value is needed (e.g. Unix seconds), rather than a humanly-readable string. e.g. If a request contains "Service-Type = Login-User", the expansion of %{Service-Type#} will yeild "1". %{Attribute-Name[index]} Reference the N'th occurance of the given attribute. The syntax %{<list>:Attribute-Name[index]} may also be used. The indexes start at zero. This fea‐ ture is NOT available for non-attribute dynamic translations, like %{sql:...}. For example, %{User-Name[0]} is the same as %{User-Name} The variable %{Cisco-AVPair[2]} will reference the value of the THIRD Cisco-AVPair attribute (if it exists) in the request packet, %{Attribute-Name[#]} Returns the total number of attributes of that name in the relevant attribute list. The number will usually be between 0 and 200. For most requests, %{request:User-Name[#]} == 1 %{Attribute-Name[*]} Expands to a single string, with the value of each array member separated by a newline. %{#Attribute-Name[index]} Expands to the length of the string %{Attribute-Name[index]}.ATTRIBUTES The attribute lists described above may be edited by listing one or more attributes in an "update" section. Once the attributes have been defined, they may be referenced as described above in the VARIABLES section. The following syntax defines attributes in an "update" section. Each attribute and value has to be all on one line in the configuration file. There is no need for commas or semi-colons after the value. Attribute-Name = value Attribute names The Attribute-Name must be a name previously defined in a dictionary. If an undefined name is used, the server will return an error, and will not start. Operators The operator used to assign the value of the attribute may be one of the following, with the given meaning. = Add the attribute to the list, if and only if an attribute of the same name is not already present in that list. := Add the attribute to the list. If any attribute of the same name is already present in that list, its value is replaced with the value of the current attribute. += Add the attribute to the tail of the list, even if attributes of the same name are already present in the list. Enforcement and Filtering Operators The following operators may also be used in addition to the ones listed above. Their function is to perform enforcement or filtering on attributes in a list. -= Remove all matching attributes from the list. Both the attribute name and value have to match in order for the attribute to be removed from the list. == Keep all matching attributes. Both the attribute name and value have to match in order for the attribute to remain in the list. Note that this operator is very different than the '=' operator listed above! <= Keep all attributes having values less than, or equal to, the value given here. Any larger value is replaced by the value given here. If no attribute exists, it is added with the value given here, as with "+=". This operator is valid only for attributes of integer type. >= Keep all attributes having values greater than, or equal to, the value given here. Any larger value is replaced by the value given here. If no attribute exists, it is added with the value given here, as with "+=". This operator is valid only for attributes of integer type. !* Delete all occurances of the named attribute, no matter what the value. Values The format of the value is attribute-specific, and is usually a string, integer, IP address, etc. Prior to the attribute being instantiated, the value may be expanded as described above in the DATA TYPES section, above. This flexibility means that, for example, you can assign an IP address value to an attribute by specifying the IP address directly, or by having the address returned from a database query, or by having the address returned as the output of a program that is executed. When string values are finally assigned to a variable, they can have a maximum length of 253 characters. This limit is due in part to both protocol and internal server requirements. That is, the strings in the language can be nearly 8k in length, say for a long SQL query. However, the output of that SQL query should be no more than 253 characters in length.OTHER KEYWORDS Other keywords in the language are taken from the names of modules loaded by the server. These keywords are dependent on both the modules, and the local configuration. Some use keywords that are defined in the default configuration file are: fail Cause the request to be treated as if a database failure had occurred. noop Do nothing. This also serves as an instruction to the configurable failover tracking that nothing was done in the current section. ok Instructs the server that the request was processed properly. This keyword can be used to over-ride earlier failures, if the local administrator determines that the faiures are not catastrophic. reject Causes the request to be immediately rejectedMODULE RETURN CODES When a module is called, it returns one of the following codes to "unlang", with the following meaning. notfound information was not found noop the module did nothing ok the module succeeded updated the module updated the request fail the module failed reject the module rejected the request userlock the user was locked out invalid the configuration was invalid handled the module has handled the request itself These return codes can be tested for in a condition, as described above in the CONDITIONS section. See also the file doc/configurable_failover for additional methods of trapping and modifying module return codes.FILES /etc/raddb/radiusd.confSEE ALSO radiusd.conf(5), dictionary(5)AUTHOR Alan DeKok <aland@deployingradius.com>