Why does ip6tables -A INPUT -j DROP blocks outgoing server connections

I'm willing to configure both iptables & ip6tables for IPv6. But for some unknown reason last ip6tables rule in my config block any outgoing connection for my server (apt-get, wget, ping, ping6 etc.). Server is Debian 8.1, this is a DO droplet with IPv6 configured.

Here's the config:

#!/bin/sh
# Flush all existing first
sudo iptables -F

# Disable tracking
sudo iptables -t raw -I PREROUTING -p tcp --dport 80 -j NOTRACK
sudo iptables -t raw -I PREROUTING -p tcp --dport 22 -j NOTRACK
sudo iptables -t raw -I OUTPUT -p tcp --dport 80 -j NOTRACK
sudo iptables -t raw -I OUTPUT -p tcp --dport 22 -j NOTRACK

# Local
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

# DNS
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p udp --sport 53 --dport 1024:65535 -j ACCEPT

# Custom rules
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow ping from inside
sudo iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
sudo iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

# Allow ping from outside
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
sudo iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

# Drop everything else
sudo iptables -A INPUT -j DROP

# IPv6

# Flush all existing first
sudo ip6tables -F

# Disable tracking
sudo ip6tables -t raw -I PREROUTING -p tcp --dport 80 -j NOTRACK
sudo ip6tables -t raw -I PREROUTING -p tcp --dport 22 -j NOTRACK
sudo ip6tables -t raw -I OUTPUT -p tcp --dport 80 -j NOTRACK
sudo ip6tables -t raw -I OUTPUT -p tcp --dport 22 -j NOTRACK

# Local
sudo ip6tables -A INPUT -i lo -j ACCEPT
sudo ip6tables -A OUTPUT -o lo -j ACCEPT

# DNS
sudo ip6tables -A INPUT -p udp --dport 53 -j ACCEPT
sudo ip6tables -A OUTPUT -p udp --sport 53 --dport 1024:65535 -j ACCEPT

# Custom rules
sudo ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow ping from inside
sudo ip6tables -A OUTPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT

# Allow ping from outside
sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
sudo ip6tables -A OUTPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT

# Drop everything else
sudo ip6tables -A INPUT -j DROP

If I delete this last rule (ip6tables -A INPUT -j DROP) everything's working fine. What could be the problem?

UPD. Thanks to those who've answered for invaluable info on the whole set of rules. In case anyone needs the configuration that's working now, this is for a basic web server with 80 and 22 ports opened, stateless (for high traffic apps):

#!/bin/sh
# Flush all existing first
sudo iptables -F

# Local
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

# Allow outbound DNS
sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT  -p udp --sport 53 -j ACCEPT

# Allow inbound HTTP (apt-get, wget etc.)
sudo iptables -A INPUT -p tcp --sport 80 -j ACCEPT

# Custom rules
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow ICMP
sudo iptables -A INPUT -p icmp -j ACCEPT
sudo iptables -A OUTPUT -p icmp -j ACCEPT

# Drop everything else
sudo iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited

# IPv6

# Flush all existing first
sudo ip6tables -F

# Local
sudo ip6tables -A INPUT -i lo -j ACCEPT
sudo ip6tables -A OUTPUT -o lo -j ACCEPT

# Allow outbound DNS
sudo ip6tables -A OUTPUT -p udp --dport 53 -j ACCEPT
sudo ip6tables -A INPUT  -p udp --sport 53 -j ACCEPT

# Allow inbound HTTP (apt-get, wget etc.)
sudo ip6tables -A INPUT -p tcp --sport 80 -j ACCEPT

# Custom rules
sudo ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow ICMP
sudo ip6tables -A INPUT -p icmpv6 -j ACCEPT
sudo ip6tables -A OUTPUT -p icmpv6 -j ACCEPT

# Drop everything else
sudo ip6tables -A INPUT -j REJECT --reject-with icmp6-adm-prohibited

Solution 1:

The rule is not blocking outgoing connections. It is however dropping the replies sent to all your outgoing connections.

That's not the only flaw in your rules. You are dropping lots of ICMPv6 packets, which are required for correct operation. Moreover silently dropping packets is not a good practice because it will make problems harder to debug and introduce additional problems which wouldn't be there if you were sending the proper error messages.

To fix the first problem you need to either enable connection tracking such that replies to your outgoing connections will be allowed to come in. Or carefully evaluate what outgoing connections you need and decide on a set of stateless rules to allow incoming traffic matching that outgoing traffic.

To fix the second problem you need to allow all ICMPv6 error messages incoming as well as neighbor discovery.

To fix the third problem use REJECT --reject-with icmp6-adm-prohibited instead of DROP.

Solution 2:

The only packets allowed on INPUT (IPv6) is:

  • everything on lo
  • UDP with destination port 53
  • TCP with destination port 80
  • TCP with destination port 22
  • ICMPv6 type echo-reply

In practice you are blocking all other incoming packets, including replies to your outgoing packets. You should look into "stateful firewalling" using the "state"-module. See https://www.sixxs.net/wiki/IPv6_Firewalling for some examples.

You are also blocking too much ICMPv6. Both router advertisement and neigbor discovery are examples of ICMPv6 that'll likely need.