Unfortunately, the Apache SetEnvIf module doesn’t support logical conditions, like OR
& AND
. More specifically, it is not possible to set a variable only if condition1 AND/OR condition2 are verified.
For example, to log all the POST queries made from the loopback interface in a separate log file, you can’t do this:
1
2
CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
SetEnvIf Remote_Addr "^127\.0\.0\.1$" AND Request_Method "POST" posting_myself
The first line is valid, it asks the server to log all the requests to the mentioned file, only if the environment variable posting_myself
is set.
The second line attemps to set the posting_myself
variable if two conditions are met (use of a logical AND), which is not a supported syntax.
On a first attempt to work around this problem, I came up with this (this does not work):
1
2
3
4
5
CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
SetEnv loopback_ip 0
SetEnvIf Remote_Addr "^127\.0\.0\.1$" loopback_ip=1
SetEnvIf Request_Method "POST" posting_myself
SetEnvIf loopback_ip 0 !posting_myself
The first line is unchanged.
The second line unconditionally sets the variable loopback_ip
to zero (meaning : false).
The third line sets the same variable to one (“true”) if the requests indeed comes from the loopback IP.
The fourth line sets the variable posting_myself
to true if the request method is POST.
Note that at this stage, the posting_myself
variable can be true, even if somebody else made the request.
This is taken care of at the last line, where posting_myself
is unset if the variable posting_myself
is equal to zero (false).
After the last line, we will have the posting_myself
variable set only if the request comes from the loopback IP and if the request is a POST.
Unfortunately, this doesn’t work either, for a subtle reason : the SetEnv
directive is executed after the SetEnvIf
directives, according to the Apache documentation. This means that when SetEnv
sets loopback_ip
to zero, it’s way too late.
So, I came up with this other version to emulate a SetEnvIf
logical AND:
1
2
3
4
5
CustomLog /var/log/apache2/loopback_posts.log combined env=posting_myself
SetEnvIf Remote_Addr "^" loopback_ip=0
SetEnvIf Remote_Addr "^127\.0\.0\.1$" loopback_ip=1
SetEnvIf Request_Method "POST" posting_myself
SetEnvIf loopback_ip 0 !posting_myself
This is similar to the previous attempt, only the second line changes: I have to use SetEnIfv
, to artificially set loopback_ip
to zero, unconditionally. To do this, I use a regex that will always match : “^”. Note that I used Remote_Addr
, but I could have used Request_Protocol
, Request_URI
or anything else: the only important thing is that it always matches and does set loopback_ip
to zero.
Now, to emulate a SetEnvIf
logical OR, this is way easier:
1
2
SetEnvIf Remote_Addr "^192\.168\.0\." my_networks
SetEnvIf Remote_Addr "^127\.0\.0\.1$" my_networks
Here, the variable my_networks
will be set if the remote address starts with “192.168.0.” or is “127.0.0.1”. It’s that simple.
Well, I could have used a smarter regex to do this in one line, but it would have ruined my logical OR example! :)