Search code examples
perleximexim4

Exim getting random credential in exim.conf


I have been trying to get perl subroutine value and substitution to get the required part of string from randomips subroutine in exim.conf. However when i use string substitution i get error as follow:

Here is what I am trying to achieve

I am trying to split string by colon and get first occurrence as "interface". I'll be using second occurrence as the "helo_data.

exim.pl

sub randomhosts {
@inet = ("x.x.x.1:hostname1.domain.com","x.x.x.2:hostname2.domain.com","x.x.x.3:hostname3.domain.com"
);

return $inet[int rand($#inet+1)];

}

exim.conf

dkim_remote_smtp:
  driver = smtp
  interface = "${perl{randomhosts}%:*}"
  helo_data = "${sender_address_domain}"

Error I get is as follow:

"failed to expand "interface" option for dkim_remote_smtp transport: missing '}' after 'perl'". Probably the syntax. Any help?


Solution

  • The code that you are trying to copy was written by someone who doesn't know much about Perl. It includes this line:

    return $inet[int rand($#inet+1)];
    

    A Perl programmer would write this as

    return $inet[rand @inet];
    

    I think there are a couple of issues here - one with your Exim syntax and one with your Perl syntax.

    Exim is giving you this error:

    failed to expand "interface" option for dkim_remote_smtp transport: missing '}' after 'perl'

    I don't know anything about calling Perl from Exim, but this page mentions a syntax like ${perl{foo}} (which is similar to the one used in the page you are copying from) and one like ${perl{foo}{argument}} for calling a subroutine and passing it an argument. Nowhere does it mention syntax like yours:

    ${perl{randomhosts}%:*}
    

    I'm not sure where you have got that syntax from, but it seems likely that this is what is causing your first error.

    In a comment, you say

    I am stying to get first part of string before colon for each random array value for "interface" and part after colon for "helo_data"

    It seems to me that Exim doesn't support this requirement. You would need to call the function twice to get the two pieces of information that you require. You might be able to do this in the Perl using something like state variables - but it would be far more complex than the code you currently have there.

    Secondly, your Perl code has a syntax error, so even if Exim was able to call your code, it wouldn't work.

    The code you're copying sets up @inet like this:

    @inet = ("x.x.x.1", "x.x.x.2", "x.x.x.3", "x.x.x.4");
    

    Your equivalent code is this:

    @inet = (
      "x.x.x.1:hostname1.domain.com",
      "x.x.x.2:hostname2.domain.com,
      x.x.x.3:hostname3.domain.com
     );
    

    I've reformatted it, to make the problems more obvious. You are missing a number of quote marks around the elements of the array. (Note: I see that while I have been writing this answer, you have fixed that.)

    Update: Ok, here is some code to put into exim.pl that does what you want.

    use feature qw[state];
    
    sub randomhosts {
      state $current;
    
      my @inet = (
        "x.x.x.1:hostname1.domain.com",
        "x.x.x.2:hostname2.domain.com",
        "x.x.x.3:hostname3.domain.com"
      );
    
      if ($_[0] eq 'generate') {
        shift;
        @{$current}{qw[ip host]} = split /:/, $inet[rand @inet];
      }
    
      return $current->{$_[0]};
    }
    

    It generates a new ip/host pair if its first argument is 'generate'. It will then return either the hostname or the ip address from the generated pair. I think you can probably call it from your Exim config file like this:

    dkim_remote_smtp:
      driver = smtp
      interface = "${perl{randomhosts}{generate}{ip}}"
      helo_data = "${perl{randomhosts}{host}}"
    

    But I'm no expert in Exim, so that syntax might need tweaking.