[LINUX] IPsec gateway VPN construction with CentOS 8 and openSUSE (Raspberry Pi) --2 StrongSwan VPN connection confirmation

Assumptions and preparations

Linux server building article

-Building a file server with Samba (CentOS 8.1 / openSUSE 15.1 / Ubuntu 20.04) -Source compilation of Apache2.4 + PHP7.4 on Linux-- 1. Apache introduction / [Raspberry Pi] / items / 67686eccaaec73251458) -Source compilation of Apache2.4 + PHP7.4 on Linux-- 2. PHP introduction / [[Raspberry Pi]](https://qiita.com/kazumi75kitty / items / 50f1a447f6ebc2ee2b61) -Source compilation of Apache2.4 + PHP7.4 on Linux-- 3. MySQL introduction/[[Raspberry Pi]](https://qiita.com/kazumi75kitty / items / 4212dacc45944f27ca94) -Apache2.4 + PHP7.4 on Linux --4 Security (chown and firewalld) -Build an IPsec gateway on Linux VPN-- 1. Introduce StrongSwan / [[Ubuntu 20.04 + Raspberry Pi]](https://qiita.com/kazumi75kitty/ items / 08259681247a6c2ebd0d) --Build an IPsec gateway on Linux --2 Confirm connection to VPN [This article] / [Ubuntu 20.04 + Raspberry Pi]

Last time, we built an IPsec-VPN environment by compiling StrongSwan source, but this time let's check if we can actually connect to VPN! (˶ ・ ᴗ ・) ੭⚐⚑

environment

Premise

--Minimal installation of OS. Also, the OS must be updated in the latest state. --User installed as root (in my verification, it is an administrator account called admin, and it is processed by sudo from there) --For all distributions, the firewall uses firewalld (I want to use firewalld for common operations in the distribution rather than the firewall in the distribution dialect). --For CentOS, do not use SELinux with built-in file system because SELinux is complicated (restart is required after editing / etc / selinux / config), and use firewalld.

CentOS8.1


# vi /etc/selinux/config

/etc/selinux/config


SELINUX=disabled

CentOS8.1


# reboot

Server conditions

IP address and network construction diagram

--Network segment: --Internet connection possible: 192.168.1.0/24 --Raspberry Pi (negotiation receiving side on the left of the figure) Secure segment: 192.168.2.0/24 --CentOS 8 (negotiation originator on the right of the figure) Secure segment: 192.168.5.0/24

--Terminals that connect to VPN: --Client (Ubuntu 20.04): 192.168.2.2 (belongs to 192.168.2.0/24) --Linux Web server (CentOS 8.1): 192.168.5.2 (belongs to 192.168.5.0/24)

Ability and version to download and install individual packages (as of September 2020)

Other required packages are installed with the distribution's standard package commands (dnf, apt, etc.) and do not need to be downloaded individually.

For download, you can access the official website, download from there and transfer it by FTP, or you can get it with wget if you know the URL of the download file, but the acquisition method is omitted.

Work procedure

Connect server and client to VPN

IP address allocation in the VPN area

Last time, eth1 just added a network adapter, and no IP address has been assigned yet. In the case of openSUSE (Raspberry Pi), it was easy to manually assign an IP address to eth1 with YaST, but in the case of CentOS 8.1 (Hyper-V virtual machine), when I tried to do it with NetworkManager, it did not work. It was (´ • ̥̥̥ω • ̥̥̥`)

CentOS8.1(Hyper-V/x64)


# nmcli c modify eth1 ipv4.address 192.168.5.1/24
error:Unknown connection'eth1'.

I gave up this time and decided to copy the configuration file of / etc / sysconfig / network-scripts / from the one of eth0 and edit it.

CentOS8.1(Hyper-V/x64)


# cd /etc/sysconfig/network-scripts/
# cp ifcfg-eth0 ifcfg-eth1
# vi ifcfg-eth1

/etc/sysconfig/network-scripts/ifcfg-eth1


TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="none"
DEFROUTE="yes"			← "no"change to
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="eth0"← Additional adapter. here"eth1"change to
UUID="daccf09e-f112-4817-8ade-016524d946d5"← Delete the line itself
DEVICE="eth0"← Additional adapter. here"eth1"change to
ONBOOT="yes"
IPADDR="192.168.1.18"← Additional adapter. here"192.168.5.1"change to
PREFIX="24"
GATEWAY="192.168.1.1"← Delete the line itself
DNS1="192.168.1.1"← Delete the line itself
IPV6_PRIVACY="no"

CentOS8.1(Hyper-V/x64)


# systemctl restart NetworkManager
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether [MAC address of the network adapter from the beginning] brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.18/24 brd 192.168.1.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 [IPv6 address of the network adapter from the beginning] scope global dynamic noprefixroute
       valid_lft 14373sec preferred_lft 12573sec
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether [MAC address of the extension network adapter] brd ff:ff:ff:ff:ff:ff
    inet 192.168.5.1/24 brd 192.168.5.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 [IPv6 address of extension network adapter] scope link noprefixroute
       valid_lft forever preferred_lft forever

# ip route
default via 192.168.1.1 dev eth0 proto static metric 100
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.18 metric 100
192.168.5.0/24 dev eth1 proto kernel scope link src 192.168.5.1 metric 101

This time, I loaded it into NetworkManager using this steady method and set the IP address in eth1. Of course, 192.168.5.0/24 was also recognized in the routing.

On the other hand, Raspberry Pi's openSUSE was easy to allocate 192.168.2.1 to the new eth1 in YaST! The added adapter is also attached in an easy-to-understand manner! !!

openSUSE15.1(RaspberryPi)


# yast
"System"-> "Network Settings"
IP address is 192.168.2.Set to 1

YaST・IPアドレス設定前

↓ The additional USB net adapter I used has the device name "AX88772B", so set the IP address there. ↓

YaST・IPアドレス設定後

openSUSE15.1(RaspberryPi)


# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether [MAC address of the network adapter from the beginning] brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.22/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 [IPv6 address of the network adapter from the beginning] scope global dynamic
       valid_lft 14373sec preferred_lft 12573sec
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether [MAC address of the extension network adapter] brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.1/24 brd 192.168.5.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 [IPv6 address of extension network adapter] scope link
       valid_lft forever preferred_lft forever

# ip route
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.22
192.168.2.0/24 dev eth1 proto kernel scope link src 192.168.2.1

Allocate firewalld zones

Since the default zone of firewalld is "public", all the rules of firewall-cmd that have been added and edited so far are in the public zone, so the public zone is eth0 on the Internet side and eth1 on the VPN area side is the internal zone. I decided to allocate. This is the same for CentOS for Hyper-V virtual machines and openSUSE for Raspberry Pi.

# firewall-cmd --zone=public --change-interface=eth0 --permanent
# firewall-cmd --zone=internal --change-interface=eth1 --permanent
# firewall-cmd --reload

# firewall-cmd --get-active-zones
internal
  interfaces: eth1
public
  interfaces: eth0

Connect the server and client to the network in the VPN area with a LAN cable

Needless to say this. Connect the server and client with a LAN cable and set the IP address manually (the DHCP server is not in the VPN area, so you have to set it manually)

As shown in "Server Conditions", assign an IP address with a LAN cable connection as shown in the figure below. Of course, in the case of a virtual machine, all you have to do is assign a virtual switch.

--Connect Ubuntu client to Raspberry Pi (192.168.2.0/24). Set IP address to 192.168.2.2 --Connect the Linux web server to the Hyper-V virtual machine (192.168.5.0/24). Set IP address to 192.168.5.2 IPsecゲートウェイ以内のVPNに接続する図

VPN network connection operation check

Ping is going at this point

IPアドレスが適切なだけでもPingは通る

I set the IP address for VPN properly, so I used Ping to check if the Ubuntu client (192.168.2.2) could reach the web server (192.168.5.2) in the opposite VPN area, and it passed easily (´´). థ ౪ థ)

I checked the state of nftables because firewalld of CentOS 8.1 of Hyper-V virtual machine uses nftables, but it seems that the filter rule of nftables always allows ICMP transfer (nftables). I won't go into details here ...).

That doesn't mean that the Web can be seen over the VPN area at that point.

この時点ではIPsec-VPN越しサーバーのwgetは不可 Of course, wget also says "No route". .. ..

Allow firewalld transfer, but give up because of the linkage of CentOS 8.1 nftables

Packets tunneled by IPsec also have to add a forwarding permission rule in the firewalld of the IPsec gateway, so I opened the port where the server and client in the VPN communicate. Here, since the client is 192.168.2.2 and the server is 192.168.5.2, transfer permission to 192.168.2.0/24 → 192.168.5.0/24 is added to the rule, but in the case of firewalld, --direct must be specified. ..

The port used by the web server is 80, 443, 8080, 8443, which is the web, so of course, if you enter the following command, the IPsec gateway should forward it over the VPN.

[192.168.2.0/24 → 192.168.5.0/24 HTTP permission]
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 80 -j ACCEPT
[192.168.2.0/24 → 192.168.5.0/24 HTTPS permission]
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 443 -j ACCEPT
[192.168.2.0/24 → 192.168.5.0/24 Port 8080 Allowed]
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 8080 -j ACCEPT
[192.168.2.0/24 → 192.168.5.0/24 port 8443 permit]
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 8443 -j ACCEPT

[To check]
# firewall-cmd --direct --get-all-rules
ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 80 -j ACCEPT
ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 443 -j ACCEPT
ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 8080 -j ACCEPT
ipv4 filter FORWARD_direct 1 -s 192.168.2.0/24 -p tcp -d 192.168.5.0/24 --dport 8443 -j ACCEPT

However, a problem occurred there (´ • ̥̥̥ω • ̥̥̥`) Raspberry Pi (openSUSE) confirmed that packets were passed on both sides of eth0 and eth1 by tcpdump, but ** In CentOS 8.1 of Hyper-V virtual machine, packets received by eth0 are rejected (reject .admin prohibited filter) And the ICMP message is returned to the Ubuntu client) **, and wget still says "No route" ...

Of course, I definitely added a direct filter rule to firewalld with --direct. So, I investigated nftables which is back-based with firewalld of CentOS 8.1.

I have referred to various things related to nftables! (´ • ̥ ̫ • ̥ `)-̗̀ ♡ ̖ ́-

-Solve the story that the name cannot be resolved from the Docker container with centOS8 with the nft command -Relationship between netfilter, firewalld, iptables and nftables -Introduction to the new packet filtering tool "nftables" in Linux --Knowledge of Sakura

Probably the nftables table used for firewalld seems to be "inet firewalld", but the original nftables filter rule seems to use "ip filter". So, I used the nftables operation command "nft" to find out where the direct rule added by the --direct option with firewall-cmd is in.

CentOS8.1(Hyper-V/x64)


[Forwarding rules in table ip filter]
# nft list chain ip filter FORWARD
table ip filter {
        chain FORWARD {
                type filter hook forward priority filter; policy accept;
                meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 80 counter packets 0 bytes 0 accept
                meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 443 counter packets 0 bytes 0 accept
                meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 8080 counter packets 0 bytes 0 accept
                meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 8443 counter packets 0 bytes 0 accept
        }
}

CentOS8.1(Hyper-V/x64)


[Forwarding rules in the table inet firewalld. Nested several times with jump]
# nft list chain inet firewalld filter_FORWARD
table inet firewalld {
        chain filter_FORWARD {
                type filter hook forward priority filter + 10; policy accept;
                ct state { established, related } accept
                ct status dnat accept
                iifname "lo" accept
                ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 type addr-unreachable
                jump filter_FORWARD_IN_ZONES_SOURCE
                jump filter_FORWARD_IN_ZONES
                jump filter_FORWARD_OUT_ZONES_SOURCE
                jump filter_FORWARD_OUT_ZONES
                ct state { invalid } drop
                reject with icmpx type admin-prohibited
        }
}
# nft list chain inet firewalld filter_FORWARD_IN_ZONES
table inet firewalld {
        chain filter_FORWARD_IN_ZONES {
                iifname "eth0" goto filter_FWDI_public
                iifname "eth1" goto filter_FWDI_internal
                goto filter_FWDI_public
        }
}
# nft list chain inet firewalld filter_FWDI_public
table inet firewalld {
        chain filter_FWDI_public {
                jump filter_FWDI_public_pre
                jump filter_FWDI_public_log
                jump filter_FWDI_public_deny
                jump filter_FWDI_public_allow
                jump filter_FWDI_public_post
                meta l4proto { icmp, ipv6-icmp } accept
        }
}
# nft list chain inet firewalld filter_FWDI_public_deny
table inet firewalld {
        chain filter_FWDI_public_deny {
        }
}
# nft list chain inet firewalld filter_FWDI_public_allow
table inet firewalld {
        chain filter_FWDI_public_allow {
        }
}

The result of this command is that even though I added a rule with --direct with ** firewall-cmd, no rule is applied to the inet firewalld table and it goes into the ip filter. Furthermore, the forwarding rule in the ip filter is ignored, and only the inet firewalld rule is executed, and as a result, when I follow the inet firewalld forwarding rule, it enters the reject rule of "reject with icmpx type admin-prohibited". It seems that it has been acting as **.

The priority is certainly that ip filter (0) should be referenced before inet firewalld (+10), but if you don't understand why ip filter is ignored and even find a config file that references the main rule It wasn't (it's pre-installed in the compiled module and can't be edited directly with vi ??).

Probably, it seems that the direct interface of nftables and firewalld are incompatible bugs at the moment, so I manually add a forwarding rule (filter_FWDI_public_allow that describes the permission target) to the table of inet firewalld with nft at Linux startup. There was only. .. .. (´ • ̥̥̥ω • ̥̥̥`)

As of September 7, 2020, the version of nftables is v0.9.3 and the version of firewalld is v0.8.0.

CentOS8.1(Hyper-V/x64)


# nft add rule inet firewalld filter_FWDI_public_allow meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 80 accept
# nft add rule inet firewalld filter_FWDI_public_allow meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 443 accept
# nft add rule inet firewalld filter_FWDI_public_allow meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 8080 accept
# nft add rule inet firewalld filter_FWDI_public_allow meta l4proto tcp ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 8443 accept

# nft list chain inet firewalld filter_FWDI_public_allow
table inet firewalld {
        chain filter_FWDI_public_allow {
                meta nfproto ipv4 ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 80 accept
                meta nfproto ipv4 ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 443 accept
                meta nfproto ipv4 ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 8080 accept
                meta nfproto ipv4 ip saddr 192.168.2.0/24 ip daddr 192.168.5.0/24 tcp dport 8443 accept
        }
}

Check if you can access the web server

The incompatibility between firewalld and nftables was a drag, but for now nftables decided to manually allow the firewall to be forwarded (´-ε- `) If both the IPsec gateways were able to allow the forwarding safely , I tried to access the server in VPN from Ubuntu client via VPN.

サーバーアクセス成功

Again, ** Ubuntu client is 192.168.2.2, from which screen is accessing the server (192.168.5.2) in the opposite VPN beyond the network segment of 192.168.1.0/24 by IPsec tunneling ** is. I also tried to connect with SSH (˶ ・ ᴗ ・) ੭⚐⚑

Even with tcpdump, you can see that plaintext packets are tunneled with ESP.

Security check

Are packets across the IPsec gateway encrypted? ??

I think this is the point of IPsec-VPN. Since it is IPsec, there is an increased risk of eavesdropping if it is tunneled in plain text without being encrypted at 192.168.1.0/24 passing through the Internet side ;;

パケットがIPsec暗号化されている!

Yeah, it's encrypted! !! (˶ ・ ᴗ ・) ੭ ♡♡

I tried to access the page from the server with the client without encrypting "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ ..." with HTTPS, but when I picked it up by tunneling between IPsec gateways, it was encrypted. I did! !!

Can you access from inside the VPN area to the outside? ??

I also checked if the Ubuntu client (192.168.2.2) could actually access the outer segment of 192.168.1.0/24.

セキュア外部は接続不可 セキュア外部は接続不可

This is because all terminals in the VPN area send packets to the IPsec gateway, which is the entrance to the VPN, to 192.168.1.0/24, which is not allowed by the IPsec gateway (192.168.2.0/24 → 192.168.5.0). Only / 24 is allowed). On the contrary, even if it is permitted, the terminal of 192.168.2.2 → 192.168.1.0/24 will send the Ubuntu client to the IPsec gateway which is the entrance as the default gateway, and the outbound route from the IPsec gateway to the target terminal will reach. On the return route, on the contrary, the terminal in 192.168.1.0/24 does not know the routing to return to 192.168.2.0/24, so communication will not be possible unless the network segment in the VPN area is added to the routing table. ..

Is it possible to access the VPN area from the outside? ??

Especially this is the most worrisome place ... ♆ (⃔ `꒳´ \ *) ⃕ ↝ But as mentioned above, if the terminal at 192.168.1.0/24 doesn't know the route to the VPN, there should be no problem in routing.

VPN外部からVPN内部にアクセスしようとすると…

192.168.1.0/24というVPN外部から、192.168.2.0/24と192.168.5.0/24の2つのVPN領域内のサーバーやクライアントに、PingやWebアクセスしようとしても、接続されることはないことを確認。

Unless you tell a modem such as FLET'S Hikari Aggregation in 192.168.1.0/24, which is directly connected to the Internet, the segment to such a VPN area, it is basically safe in that it is unlikely that the VPN will be accessed from the outside. think. However, I think that the IPsec gateway that divides the VPN area should firmly restrict both the port number that should be allowed to pass and the destination / source with a firewall.

Summary

I tried to build an IPsec gateway with StrongSwan on Raspberry Pi (openSUSE) and CentOS 8.1 of Hyper-V virtual machine and verified whether it can meet the usage as IPsec-VPN, but the aspect of preventing external eavesdropping Although it is highly effective, I felt that it would be necessary to be careful where it would hurt later if the VPN area was properly accessed.

If possible, the terminals in the external area that can access the VPN are limited to the IPsec gateway, and the SSH in the VPN is also a public key method, so there is still a limit unless you select complex security, not limited to firewall and IPsec. I think ...

Recommended Posts

IPsec gateway VPN construction with CentOS 8 and openSUSE (Raspberry Pi) --2 StrongSwan VPN connection confirmation
Simple VPN construction of IPsec gateway with CentOS 8 and openSUSE (Raspberry Pi) ―― 1. StrongSwan introduced
Simple VPN construction of IPsec gateway with Ubuntu 20.04 and Raspberry Pi --2 StrongSwan VPN connection confirmation
Simple VPN construction of IPsec gateway with Ubuntu 20.04 and Raspberry Pi ―― 1. StrongSwan introduced
VPN server construction with Raspberry Pi
Pet monitoring with Rekognition and Raspberry pi
MQTT RC car with Arduino and Raspberry Pi
Easy connection between Raspberry Pi and AWS IoT
Get temperature and humidity with DHT11 and Raspberry Pi
Raspberry Pi and AWS IoT connection program example
Edit and debug the code in the Raspberry Pi with VS Code's SSH connection feature
Distributed environment construction with Raspberry PI series (Part 4: NFS server construction and client OS import)
Record temperature and humidity with systemd on Raspberry Pi
Machine learning with Raspberry Pi 4 and Coral USB Accelerator
Detect mask wearing status with OpenCV and Raspberry Pi
Getting Started with Yocto Project with Raspberry Pi 4 and WSL2
Troubleshoot with installing OpenCV on Raspberry Pi and capturing
Distributed environment construction with Raspberry PI series (7: tftp route setting and startup test for each Raspberry Pi)
GPGPU with Raspberry Pi
DigitalSignage with Raspberry Pi
Easy introduction to home hack with Raspberry Pi and discord.py
Create a web surveillance camera with Raspberry Pi and OpenCV
Python beginner opens and closes interlocking camera with Raspberry Pi
Create an LCD (16x2) game with Raspberry Pi and Python
I tried connecting Raspberry Pi and conect + with Web API
Production of temperature control system with Raspberry Pi and ESP32 (1)
Measure and compare temperature with Raspberry Pi and automatically generate graph