MikroTik DynDNS/DDNS Script Hetzner API (IPv4 and/or IPv6)

I just had the problem, that the MikroTik build in Cloud DDNS service struggling in the last days. Sometime it was simple not reachable, but today they created a IPv6 (AAAA) entry for my cloud unique domain - but IPv6 is not enabled between my upstream modem and my MikroTik router. So I decided to create a simple script which updates only the IPv4 and/or IPv6 address of my recods directly on the Hetzner DNS API. To detect my current public IP address (external WAN adress) I added support for multiple services which will be tried in a row.

Basic setup

  1. Setup Hetzner DNS
    1. Create DNS A and/or AAAA records with a TTL of 30s in a Zone. Use @ for a full domain or a subdomain. This step is important to avoid DNS caching issues.
    2. Create a API token for Hetzner's DNS API
  2. Create a new Script System -> Scripts
    1. Name: ddns-hetzner
    2. Policy: read, write, test, uncheck everything else
    3. Source: Copy the script here
  3. Configure the script to your needs, check the description in the script or below for information how to configure it
  4. This script requires Winand's mikrotik-json-parser. Create another new script
    1. Name: JParseFunctions
    2. Policy: read, write, test uncheck everything else
    3. Source: The content of mikrotik-json-parser
  5. Create a new Schedule System -> Schedule
    1. Name: ddns-hetzner
    2. Start Date: leave it as it is
    3. Start Time: leave it as it is
    4. Interval: 00:02:00
    5. Policy: read, write, test uncheck everything else
    6. On Event: ddns-hetzner
  6. Setup script configuration:

Script configuration

Variable name Data type Example Description
apiKey string "3su1OLc0gUhUdwxn1bmKFss5V19mBhBx"; This variable requires a valid API token for the Hetzner DNS API. You can create an API token here.
ipv4detectList array of strings {"https://api4.ipify.org/?format=text", "https://api4.my-ip.io/ip.txt"; "http://v4.ipv6-test.com/api/myip.php"} Web services which returns the remote IPv4 adress as simple text. No need to change.
ipv6detectList array of strings {"https://api6.ipify.org/?format=text", "https://api6.my-ip.io/ip.txt"; "http://v6.ipv6-test.com/api/myip.php"} Web services which returns the remote IPv6 adress as simple text. No need to change.
domainEntryConfig arrays of strings :local domainEntryConfig {{"domain.com";"A";"@";"60";};{"domain.com";"AAAA";"@";"60";};}; See below how to format the arrays correctly.

domainEntryConfig array data sheet

The domainEntryConfig array consists of multiple arrays. Each of the is configuring a DNS record for a given domain in a zone.

The data sheet below describes the formatting of the DNS records arrays.

Array index Data Data type Example Description
0 zone string "domain.com" Zone which should be used to set a record to.
1 record type string "A" Valid values A, AAAA. The type of record which will be set. Also determines which IP (v4/v6) will be fetched.
2 record name string "@" The record name which should be updated. Use @ for the root of your domain.
3 record TTL string "60" TTL value of the record in seconds, for a dynamic entry a short lifetime like 60s is recommended.

Configuration example:

:local domainEntryConfig {
    {"mydomain.tld";"A";"ddns";"60";}; # Example
    {"mydomain.tld";"AAAA";"ddns";"60";}; # Example
    {"mydns.com";"AAAA","@";"60";}; # Example
};

This example will create & update those DNS records:

  • mydomain.tld
    • IPv4
    • IPv6
  • mydns.com
    • IPv6

Script

# -------------------------------------------------------------------------------
# DDNS update script for Hetzner's DNS API
# with external IP detection
# 
# by foorschtbar (https://blog.fotto.de/mikrotik-dyndns-ddns-script-hetzner-api-ipv4-and-or-ipv6/)
# Version 1.0
#
# Credits:
# - 'ShokiNN (https://github.com/shokinn/hetzner-ddns-for-mikrotik)
# - kroteau (https://gist.github.com/kroteau/de05fa01c367a3329f85f99c0930e81)
# -------------------------------------------------------------------------------

#============= START OF CONFIG ===============
# --- Define variables --- 
# Enter all required variables and secrets here. -- All secrets are stored unencrypted!
# API Key to authenticate to Hetzners API
:local apiKey ""; # Example: "3su1OLc0gUhUdwxn1bmKFss5V19mBhBx"; -- This one is invalid, you don't need to try ;)
# Online services which respond with your IPv4
:local ipv4detectList {"https://api4.ipify.org/?format=text", "https://api4.my-ip.io/ip.txt"; "http://v4.ipv6-test.com/api/myip.php"} 
# Online services which respond with your IPv6
:local ipv6detectList {"https://api6.ipify.org/?format=text", "https://api6.my-ip.io/ip.txt"; "http://v6.ipv6-test.com/api/myip.php"}

# --- Domain config ---
# Zone
# Zone which should be used to set a record to
# Data Type: String
# Example: "domain.com";
#
# Record type
# The type of record which will be set
# Data Type: String
# Valid values: "A", "AAAA"
# Example: "A";
#
# Record name
# Record name to be used to set a DNS entry
# Data Type: String
# Example: "@"; -- use @ to setup an entry at the root of your domain, e.g. "domain.com"
#
# Record TTL
# TTL value of the record in seconds, for a dynamic entry a short lifetime like 300 is recommended
# Data Type: String
# Example: "300";
#
# Array structure
# {
#     "domain.com"; # Zone
#     "A"; # Record type
#     "@"; # Record name
#     60; # Record TTL
# };
:local domainEntryConfig {
    {"mydomain.tld";"A";"ddns";"60";}; # Example
    {"mydomain.tld";"AAAA";"ddns";"60";}; # Example
    {"mydns.com";"AAAA","@";"60";}; # Example
};
#============= END OF CONFIG ===============

:local logPrefix "[Hetzner DDNS]";
:local apiUrl "https://dns.hetzner.com/api/v1";

:local getLocalIp do={
    #:local ip [/ip address get [:pick [find interface="$configInterface"] 0] address];
    #:return [:pick $ip 0 [:find $ip /]];
     # Parameters: 1 - list of urls
    :local extIP;
    :foreach url in=$1 do={
        :do { :set extIP ([/tool fetch url=$url output=user as-value]->"data")} on-error={ :log error "DDNS: Service $url failed" };
        if ( [:len "$extIP"]>0 ) do={ :return $extIP };
    };
};

:local getRemoteIpv4 do={
    :do {
        :local ip [:resolve "$configDomain"];
        :return "$ip";
    } on-error={
        return "";
    };
};

:local getRemoteIpv6 do={
    :local result [:toarray ""]
    :local maxwait 5
    :local cnt 0
    :local listname "tmp-resolve$cnt"
    /ipv6 firewall address-list {
        :do {
            :while ([:len [find list=$listname]] > 0) do={
                :set cnt ($cnt + 1);
                :set listname "tmp-resolve$cnt";
            };
            :set cnt 0;
            add list=$listname address=$1;
            :while ([find list=$listname && dynamic] = "" && $cnt < $maxwait) do={
                :delay 1;:set cnt ($cnt +1)
            };
            :foreach i in=[find list=$listname && dynamic] do={
                 :local rawip [get $i address];
                 :set result ($result, [:pick $rawip 0 [:find $rawip "/"]]);
            };
            remove [find list=$listname && !dynamic];
        };
    };
    :return $result;
};

:local apiGetZones do={
    [/system script run "JParseFunctions"; global JSONLoad; global JSONLoads; global JSONUnload];

    :local apiPage -0;
    :local apiNextPage 1;
    :local apiLastPage 0;
    :local apiResponse "";
    :local returnArr [:toarray ""];

    :do {
        :set apiResponse ([/tool/fetch "$apiUrl/zones?page=$apiNextPage&search_name=$configZone" http-method=get http-header-field="Auth-API-Token:$apiKey" output=user as-value]->"data");

        :set apiPage ([$JSONLoads $apiResponse]->"meta"->"pagination"->"page");
        :set apiNextPage ([$JSONLoads $apiResponse]->"meta"->"pagination"->"next_page");
        :set apiLastPage ([$JSONLoads $apiResponse]->"meta"->"pagination"->"last_page");

        :set returnArr ($returnArr , ([:toarray ([$JSONLoads $apiResponse]->"zones")]));
    } while=($apiPage != $apiLastPage);
    $JSONUnload;

    :return $returnArr;
};

:local apiGetZoneId do={
    :foreach responseZone in=$responseZones do={
        :if (($responseZone->"name") = $configZone) do={
            :return ($responseZone->"id");
        };
    };
};

:local apiSetRecord do={
    #apiUrl=$apiUrl apiKey=$apiKey zoneId=$zoneId configType=$configType configRecord=$configRecord configTtl=$configTtl interfaceIp=$interfaceIp
    [/system script run "JParseFunctions"; global JSONLoad; global JSONLoads; global JSONUnload];

    :local recordId "";
    :local apiResponse "";
    :local payload "{\"zone_id\": \"$zoneId\",\"type\": \"$configType\",\"name\": \"$configRecord\",\"value\": \"$interfaceIp\",\"ttl\": $([:tonum $configTtl])}";
    :local records ([$JSONLoads ([/tool/fetch "$apiUrl/records?zone_id=$zoneId" http-method=get http-header-field="Auth-API-Token:$apiKey" output=user as-value]->"data")]->"records");

    :foreach record in=$records do={
        :if ((($record->"name") = $configRecord) && (($record->"type") = $configType)) do={
            :set recordId ($record->"id");
        }
    };

    :if ($recordId != "") do={
        :set apiResponse ([/tool/fetch "$apiUrl/records/$recordId" http-method=put http-header-field="Content-Type:application/json,Auth-API-Token:$apiKey" http-data=$payload output=user as-value]->"status");
    } else={
        :set apiResponse ([/tool/fetch "$apiUrl/records" http-method=post http-header-field="Content-Type:application/json,Auth-API-Token:$apiKey" http-data=$payload output=user as-value]->"status");
    };

    $JSONUnload;
    return $apiResponse;
};

# Log "run of script"
:log info "$logPrefix running";

:local index 0;
:foreach i in=$domainEntryConfig do={
    :local configZone ("$($i->0)");
    :local configType ("$($i->1)");
    :local configRecord ("$($i->2)");
    :local configTtl ("$($i->3)");
    :local configDomain "";
    :local interfaceIp "";
    :local dnsIp "";
    :local startLogMsg "$logPrefix Start configuring domain:";
    :local endLogMsg "$logPrefix Finished configuring domain:";

    :if ($configRecord = "@") do={
        :set configDomain ("$($i->0)");
    } else={
        :set configDomain ("$($i->2).$($i->0)");
    };

    :if ($configType = "A") do={
        :log info "$startLogMsg $configDomain - Type A record";

        :set interfaceIp [$getLocalIp $ipv4detectList];
        :set dnsIp [$getRemoteIpv4 configDomain=$configDomain];

        :if ($interfaceIp != $dnsIp) do={
            :log info "$logPrefix $configDomain: local IP ($interfaceIp) differs from DNS IP ($dnsIp) - Updating entry";

            :local responseZones [$apiGetZones apiUrl=$apiUrl apiKey=$apiKey configZone=$configZone];
            :local zoneId [$apiGetZoneId responseZones=$responseZones configZone=$configZone];
            :local responseSetRecord [$apiSetRecord apiUrl=$apiUrl apiKey=$apiKey zoneId=$zoneId configType=$configType configRecord=$configRecord configTtl=$configTtl interfaceIp=$interfaceIp];
            :if ($responseSetRecord = "finished") do={
                :log info "$logPrefix $configDomain: update successful"
            };
        } else={
            :log info "$logPrefix $configDomain: local IP and DNS IP are equal - Nothing to do";
        }

        :log info "$endLogMsg $configDomain - Type A record";
    };

    :if ($configType = "AAAA") do={
        :log info "$startLogMsg $configDomain - Type AAAA record";

        :set interfaceIp [$getLocalIp $ipv6detectList];
        :set dnsIp [$getRemoteIpv6 $configDomain];

        :if ($interfaceIp != $dnsIp) do={
            :log info "$logPrefix $configDomain: local IP ($interfaceIp) differs from DNS IP ($dnsIp) - Updating entry";

            :local responseZones [$apiGetZones apiUrl=$apiUrl apiKey=$apiKey configZone=$configZone];
            :local zoneId [$apiGetZoneId responseZones=$responseZones configZone=$configZone];
            :local responseSetRecord [$apiSetRecord apiUrl=$apiUrl apiKey=$apiKey zoneId=$zoneId configType=$configType configRecord=$configRecord configTtl=$configTtl interfaceIp=$interfaceIp];
            :if ($responseSetRecord = "finished") do={
                :log info "$logPrefix $configDomain: update successful"
            };
        } else={
            :log info "$logPrefix $configDomain: local IP and DNS IP are equal - Nothing to do";
        }

        :log info "$endLogMsg $configDomain - Type AAAA record";
    };

    :if (($configType != "A") && ($configType != "AAAA")) do={
        :log error ("$logPrefix Wrong record type for array index number " . $index . " (Value: $configType)");
    };

    :set index ($index+1);
};
:set index;

:log info "$logPrefix finished";

Credits for the base scripts:

MikroTik Conditional DNS Zone Forwarding

MikroTik does not have a built-in feature to forward individual DNS zones to different external DNS servers. This functionality is often necessary when connecting multiple sites via VPN and utilizing multiple internal DNS servers. However, with the following workaround, you can achieve conditional DNS zone forwarding without the need for scripting:

/ip firewall layer7-protocol
add name="MyDomain DNS port forward" regexp="my.local.domain|[0-9]+.[0-9]+.168.192.in-addr.arpa"
/ip firewall nat add action=masquerade chain=srcnat comment="NAT to MyDomain DNS" disabled=no dst-address=192.168.0.1/32 dst-port=53 protocol=udp
/ip firewall nat add action=dst-nat chain=dstnat disabled=no dst-address-type=local dst-port=53 layer7-protocol="MyDomain DNS port forward" protocol=udp to-addresses=192.168.0.1 to-ports=53

A little tip: the name of the protocol in the first command is used again in the last command, so they must be identical

You may need to allow remote DNS queries on the remote DNS server. if it is also a MikroTik you could use the following command:

/ip dns set allow-remote-requests=yes

Source 1, 2, 3

MikroTik SMS to Telegram – A SMS Gateway Forwarder Script

I needed a way to forward SMS messages from my Mikrotik router with modem. The easiest way was to forward the SMS to a Telegram chat.

The script retrieves incoming SMS messages, extracts essential information such as the sender, message content, and timestamp, and forwards them to the Telegram Bot API. It also includes basic error handling and provides feedback on the success or failure of the forwarding process. Multiple chat IDs are also possible.

Basic setup

  1. Setup modem and test sending and reciving without the script
  2. Register Telegram Bot and get API Token. I don't want to explain this here, there are enough tutorials on the internet.
  3. Get Chat ID. Send a message for example to @chatIDrobot and get the Chat ID.

Script setup

  1. Create a new script forward-incoming-sms in the Mikrotik router and paste the script code:

# ------------------------------------------------- #
# SMS to Telegram - A SMS Gateway Forwarder Script  #
# ------------------------------------------------- #

# Description
# This script will forward all SMS messages to a Telegram chat.

# Author
# 2024-01-11 foorschtbar
# https://blog.spaps.de/

# Credits
# http://blog.redax.hu/2021/02/mikrotik-sms-to-sms-forwarding.html
# https://medium.com/@dedanirungu/forwarding-sms-messages-with-mikrotik-to-website-url-via-modem-12d926615834
# https://github.com/eworm-de/routeros-scripts/blob/main/sms-forward.rsc

# Configuration
:local token "12345678:AAABBCCC...XXXYYYZZZZ"
:local chatids {"12345678";"12345678"}

:put "== Starting SMS forwarder script =="

# Check if receiving is enabled
:if ([ /tool/sms/get receive-enabled ] = false) do={
  :log warning ("Receiving of SMS is not enabled.")
  :error ("exit script");
}

# Check if the modem is in running state
:local Settings [ /tool/sms/get ];
:if ([ /interface/lte/get ($Settings->"port") running ] != true) do={
  :log warning ("The LTE interface is not in running state, skipping.")
  :error ("exit script");
}

# forward SMS in a loop
:local smsCount [ :len [ /tool/sms/inbox/find ] ]
:put ("Found ".$smsCount." SMS to process")
:local index 0
:foreach sms in=[ /tool/sms/inbox/find ] do={
    :set index ($index + 1)
    :put ("> Processing ".$index." of ".$smsCount)

    :local smsVal [ /tool/sms/inbox/get $sms ];
    :local smsPhone ($smsVal->"phone")
    :local smsType ($smsVal->"type")
    :local smsMessage ($smsVal->"message")
    :local smsTime ($smsVal->"timestamp")

    :local logmsg ("SMS from ".$smsPhone." on ".$smsTime." (".$smsType."):\n".$smsMessage)
    :put ($logmsg);
    :log info ("Forwarding ". $logmsg);

    # URL safe message
  :local urlMessage ""
    :for i from=0 to=([:len $logmsg] - 1) do={ 
      :local char [:pick $logmsg $i]

      :if ($char = "\n") do={
        :set $char "%0A";
      }

      :if ($char = " ") do={
        :set $char "%20";
      }

      :if ($char = "-") do={
        :set $char "%2D";
      }

      :if ($char = "\?") do={
        :set $char "%3F";
      }

      :if ($char = "!") do={
        :set $char "%21";
      }

      :if ($char = "+") do={
        :set $char "%2B";
      }

      :if ($char = "%") do={
        :set $char "%22";
      }

      :if ($char = "'") do={
        :set $char "%27";
      }

      :if ($char = "(") do={
        :set $char "%28";
      }

      :if ($char = ")") do={
        :set $char "%29";
      }

      :if ($char = ",") do={
        :set $char "%2C";
      }

      :if ($char = ".") do={
        :set $char "%2E";
      }

      :if ($char = ":") do={
        :set $char "%3A";
      }

      :if ($char = ";") do={
        :set $char "%3B";
      }

      :if ($char = "=") do={
        :set $char "%3D";
      }

      :if ($char = "&") do={
        :set $char "%26";
      }

      :if ($char = "*") do={
        :set $char "%2A";
      }

      :if ($char = "/") do={
        :set $char "%2F";
      } 

        :set urlMessage ($urlMessage . $char);

    }

    # send POST
    :local noerror true
    :local chatIdx 1
    :local chatsTotal [ :len $chatids ]
    :foreach chatid in=$chatids do={
        :put ("> Sending HTTP request ". $chatIdx . " of " . $chatsTotal."...")
        :local url ("https://api.telegram.org/bot" .$token . "/sendMessage")
        :local parameters ("?chat_id=" . $chatid . "&text=" . $urlMessage)
        :local fullurl ($url . $parameters)
        :local responseStr [/tool fetch url=$fullurl http-method=get as-value output=user]
        :put ("Status: ".$responseStr->"status")
        :put ("Data: ".$responseStr->"data")
        :if ($responseStr->"status" = "finished") do={
            :put ("Successfully forwarded message ID: " . $index. " to chat ID: " . $chatid)
            :log info ("Successfully forwarded message ID: " . $index. " to chat ID: " . $chatid)
        } else={
            :put ("Failed to forward message ID: " . $index. " to chat ID: " . $chatid)
            :log error ("Failed to forward message ID: " . $index. " to chat ID: " . $chatid)
            :set noerror false
        }
        :set chatIdx ($chatIdx + 1)
    }

    :if ($noerror) do={
        /tool sms inbox remove $sms
        :put ("Deleted message ID: " . $index)
    }
}

:put "== Finished SMS forwarder script =="
  1. Change the configuration variables in the script: tokenand chatids
  2. Test the script by running it manually /system script run forward-incoming-sms
  3. Create a new scheduler forward-incoming-sms. You can use the following command or create it in the Webfig
    /system scheduler add name=forward-incoming-sms interval=10s on-event="/system script run forward-incoming-sms" start-time=startup

How to downgrade Unifi Controller Software

  1. You need a backup file from the version you want to downgrade. If you haven`t, you can stop here.
  2. SSH into your controller
ssh {user}@{controller-ip}
  1. Removed existing downloads
rm -f unifi_sysvinit_all.deb*
  1. Uninstall current controller package
apt purge unifi -y
  1. Download old controller package (replace version in url with your needs)
wget https://dl.ui.com/unifi/6.5.54/unifi_sysvinit_all.deb
  1. Install package
dpkg -i unifi_sysvinit_all.deb
  1. Remove download
rm unifi_sysvinit_all.deb
  1. Access UniFi Controller WebUI and restore backup

Mikrotik RouterOS WireGuard dynamic DNS endpoint refresh

MikroTik RouterOS doesn't yet support DNS names for peer entpoints (v7.1.1). As a workaround, you can set the endpoint address using the CLI, but RouterOS will not re-resolve the DNS name. If the IP addresses behind the DNS name change at some point, for example if you use DDNS, the WireGuard tunnel will eventually stop working. As a solution, you can use a script that checks if the peer endpoint address still matches the dns name and if not, updates to the latest ip address of the DNS name.

Script:

Add under System > Scheduler a new script and choose a useful interval.

:local wgPeerComment
:local wgPeerDns

:set wgPeerComment "Peer #1 Comment"
:set wgPeerDns "dns.example.com"

:if ([interface wireguard peers get number=[find comment="$wgPeerComment"] value-name=endpoint-address] != [resolve $wgPeerDns]) do={
  interface wireguard peers set number=[find comment="$wgPeerComment"] endpoint-address=[/resolve $wgPeerDns]
}
Example:

Configure local Systemd-resolved DNS Resolver for Company Domains behind VPN

To send queries for the company internal (sub)-domains to the company DNS resolvers behind the VPN, the resolver can be configured with the following commands:

# Configure internal corporate domain name resolvers:
resolvectl dns tun0 192.0.2.53 192.0.2.54

# Only use the internal corporate resolvers for domain names under these:
resolvectl domain tun0 "~example.com"

# Not super nice, but might be needed:
resolvectl dnssec tun0 off

[via]https://www.gabriel.urdhr.fr/2020/03/17/systemd-revolved-dns-configuration-for-vpn/[/via]

How to easily clone a (encrypted hard) disk over network (with dd and netcat)

The task was simple: two computers (notebooks). One - we call it A - with a working operating system (Xubuntu) and a new one - we call it B - without operating system. This is how I proceeded:

  1. Create bootable flash drive with in my case Arch-Linux
  2. In the Arch-Linux boot loader, press [TAB] and add "copytoram" to the boot command to load the squashfs image into ram. I needed this because in this case I only had a flash drive at hand. If you have two, you don't need this.
  3. List network devices:
    ip address
  4. Assign a IP adress to computer A with:
    ip address add <machine A ip adress> dev <ethernet device>

  5. To identify source disk, list all block devices with:
    lslbk

  6. Prepare the copy operation (do not execute yet!) with
    dd if=/dev/<source block device> bs=32M status=progress | nc <machine B ip adress> <random port number>

  7. Boot machine B from the same or different flash drive
  8. Assign different IP adress
  9. Identify target device
  10. Prepare the receiving copy operation with
    nc -l -p <same port number as A> | dd of=/dev/<destination block device> bs=32M status=progress

  11. Execute the command on Machine B
  12. Then execute the command on Machine A
  13. Wait until the copying process is completed.
  14. Use at least the Sync command to synchronize corresponding file data in volatile storage and permanent storage
  15. Restart the machine, you are done

How it works/remarks
dd reads the source drive bit by bit into the normal output stream. The output stream is piped to netcat, which sends it over the network to a receiving netcat process (server with -l). Therefore the server must be started first. The server receives the bits and piped them back to dd, which writes them to the target on machine B.

Maybe this is not the best and/or most efficient way, but transfer speed in my case of 75MB/s (poor performance on screenshots is from a setup with two vm's) is in IHMO very good for this simple setup.

Thanks to pmenke for his support.

IPsec VPN between Sophos UTM and AVM Fritz!Box (LTE) with a dynamic IP-Adresss

Use the following settings to configure a Fritz!Box - also a LTE version - to connect to a Sophos UTM (v9.7)

  • Sophos UTM Settings
  • Fritz!Box VPN VPN-Configfile
vpncfg {
        connections {
                enabled = yes;
                conn_type = conntype_lan;
                name = "Sophos IPsec";
                always_renew = yes;
                reject_not_encrypted = no;
                dont_filter_netbios = yes;
                localip = 0.0.0.0;
                local_virtualip = 0.0.0.0;
                remoteip = AAA.BBB.CCC.DDD; // Change to Sophos External IP
                remote_virtualip = 0.0.0.0;
                localid {
                        fqdn = "my.fqdn.net"; // No change needed. Is ignored from the UTN
                }
                remoteid {
                        ipaddr = "AAA.BBB.CCC.DDD"; // Change
                }
                mode = phase1_mode_idp; // Main Mode
                phase1ss = "dh14/aes/sha";
                keytype = connkeytype_pre_shared;
                key = "MySecr3tPassw0rd!"; // has to be changed
                cert_do_server_auth = no;
                use_nat_t = yes;
                use_xauth = no;
                use_cfgmode = no;
                phase2localid {
                        ipnet {
                                ipaddr = 192.168.0.1; // change to local network
                                mask = 255.255.255.0;   // change to local subnet
                        }
                }
                phase2remoteid {
                        ipnet {
                                ipaddr = 172.16.0.0; // change to remote network
                                mask = 255.255.255.0; // change to remote subnet
                        }
                }
                phase2ss = "esp-aes256-3des-sha/ah-no/comp-lzs-no/pfs";
                accesslist = "permit ip any 172.16.0.0 255.255.255.0"; // to remote network
        }
        ike_forward_rules = "udp 0.0.0.0:500 0.0.0.0:500",
                            "udp 0.0.0.0:4500 0.0.0.0:4500";
}