We ended up using having to use lookup instead of inputlookup. This is what we came up with: base search | call_to_macro(ip_field, port_field) The macro adds a field named translated_IP to the event with either the PAT translated IP or the original IP if it's not a PAT IP. For the macro: eval translated_IP=$ip_field$, port=$port_field$ | rex field=translated_IP "(?<first3octets>\d{1,3}\.\d{1,3}\.\d{1,3})(?<lastoctet>\.\d{1,3})" ```This lookup returns all port ranges for that group of the first 3 octets of the address as 3 separate multivalue fields.``` | lookup PAT_Address_Translation Public_Address AS first3octets OUTPUT Private_Address, Lower_Port, Upper_Port ```mvzip ties together the values of 2 multivalue fields in the order they appear. We have to nest them since we have 3 multivalue fields.``` | eval port_range=mvzip(mvzip(Private_Address,Lower_Port),Upper_Port) ```In cases where the input IP is not in the PAT IP range, we need to make sure port_range is not null or mvexpand errors out.``` | eval port_range=coalesce(port_range, "") ```mvexpand turns each possible value into it's own row.``` | mvexpand port_range ```we then separate the fields and use a where command to eliminate the values that the port_field isn't within the range of.``` | rex field=port_range "(?<Private_Address>\d{1,3}\.\d{1,3}\.\d{1,3}),(?<Lower_Port>\d+),(?<Upper_Port>\d+)" | where (Lower_Port<=port AND Upper_Port>=port) OR port_range="" | eval internal_IP=Private_Address.lastoctet ```Finally, we make sure translated_IP is either the translated result or the original IP if it's not in the PAT table``` | eval translated_IP=coalesce(internal_IP,translated_IP) ```Clean up of added fields``` | fields - Lower_Port,Upper_Port,Private_Address,first3octets,lastoctet,internal_IP,port_range
... View more