func (f *flow) toHostFlow(localAddrs []string, fports FilterPorts) *HostFlow {
	var (
		direction  FlowDirection
		addr, port string
	)
	for _, localAddr := range localAddrs {
		if f.originalSaddr == localAddr && (len(fports.Active) == 0 || contains(fports.Active, f.originalDport)) {
			direction, addr, port = FlowActive, f.originalDaddr, f.originalDport
			break
		}
		if f.replyDaddr == localAddr && (len(fports.Active) == 0 || contains(fports.Active, f.replySport)) {
			direction, addr, port = FlowActive, f.replySaddr, f.replySport
			break
		}
		if f.originalDaddr == localAddr && contains(fports.Passive, f.originalDport) {
			direction, addr, port = FlowPassive, f.originalSaddr, f.originalDport  
			break
		}
		if f.replySaddr == localAddr && contains(fports.Passive, f.replySport) {
			direction, addr, port = FlowPassive, f.replyDaddr, f.replySport  
			break
		}
	}
	switch direction {
	case FlowUnknown:
		return nil
	case FlowActive:
		return &HostFlow{
			Direction: FlowActive,
			Local:     &AddrPort{Addr: "localhost", Port: "many"},
			Peer:      &AddrPort{Addr: addr, Port: port},
			Stat: &HostFlowStat{
				TotalInboundPackets:  f.replyPackets,
				TotalInboundBytes:    f.replyBytes,
				TotalOutboundPackets: f.originalPackets,
				TotalOutboundBytes:   f.originalBytes,
			},
		}
	case FlowPassive:
		return &HostFlow{
			Direction: FlowPassive,
			Local:     &AddrPort{Addr: "localhost", Port: port},
			Peer:      &AddrPort{Addr: addr, Port: "many"},
			Stat: &HostFlowStat{
				TotalInboundPackets:  f.originalPackets,
				TotalInboundBytes:    f.originalBytes,
				TotalOutboundPackets: f.replyPackets,
				TotalOutboundBytes:   f.replyBytes,
			},
		}
	}
	return nil
}
toHostFlow converts into HostFlow.
package conntrack
import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"strconv"
	"strings"
	"github.com/yuuki/lsconntrack/netutil"
)
type FlowDirection int
const (
	FlowUnknown FlowDirection = 1 << iota
	FlowActive
	FlowPassive
)
func (c FlowDirection) MarshalJSON() ([]byte, error) {
	switch c {
	case FlowActive:
		return json.Marshal("active")
	case FlowPassive:
		return json.Marshal("passive")
	case FlowUnknown:
		return json.Marshal("unknown")
	}
	return nil, errors.New("unreachable code")
}
type FilterPorts struct {
	Active  []string
	Passive []string
}
type flow struct {
	originalSaddr   string
	originalDaddr   string
	originalSport   string
	originalDport   string
	originalPackets int64
	originalBytes   int64
	replySaddr      string
	replyDaddr      string
	replySport      string
	replyDport      string
	replyPackets    int64
	replyBytes      int64
}
type HostFlowStat struct {
	TotalInboundPackets  int64 `json:"total_inbound_packets"`
	TotalInboundBytes    int64 `json:"total_inbound_bytes"`
	TotalOutboundPackets int64 `json:"total_outbound_packets"`
	TotalOutboundBytes   int64 `json:"total_outbound_bytes"`
}
func (s *HostFlowStat) String() string {
	return fmt.Sprintf("%d \t%d \t%d \t%d", s.TotalInboundPackets, s.TotalInboundBytes, s.TotalOutboundPackets, s.TotalOutboundBytes)
}
type AddrPort struct {
	Addr string `json:"addr"`
	Port string `json:"port"`
}
func (a *AddrPort) String() string {
	return net.JoinHostPort(a.Addr, a.Port)
}
type HostFlow struct {
	Direction FlowDirection `json:"direction"`
	Local     *AddrPort     `json:"local"`
	Peer      *AddrPort     `json:"peer"`
	Stat      *HostFlowStat `json:"stat"`
}
func (f *HostFlow) HasDirection(dire FlowDirection) bool {
	return f.Direction&dire == 0
}
func (f *HostFlow) String() string {
	switch f.Direction {
	case FlowActive:
		return fmt.Sprintf("%s\t --> \t%s \t%s", f.Local, f.Peer, f.Stat)
	case FlowPassive:
		return fmt.Sprintf("%s\t <-- \t%s \t%s", f.Local, f.Peer, f.Stat)
	}
	return ""
}
func (f *HostFlow) ReplaceLookupedName() {
	f.Peer.Addr = netutil.ResolveAddr(f.Peer.Addr)
}
func (f *HostFlow) UniqKey() string {
	return fmt.Sprintf("%d-%s-%s", f.Direction, f.Local, f.Peer)
}
type HostFlows map[string]*HostFlow
func (hf HostFlows) insert(flow *HostFlow) {
	key := flow.UniqKey()
	if _, ok := hf[key]; !ok {
		hf[key] = flow
		return
	}
	switch flow.Direction {
	case FlowActive:
		hf[key].Stat.TotalInboundPackets += flow.Stat.TotalInboundPackets
		hf[key].Stat.TotalInboundBytes += flow.Stat.TotalInboundBytes
		hf[key].Stat.TotalOutboundPackets += flow.Stat.TotalOutboundPackets
		hf[key].Stat.TotalOutboundBytes += flow.Stat.TotalOutboundBytes
	case FlowPassive:
		hf[key].Stat.TotalInboundPackets += flow.Stat.TotalInboundPackets
		hf[key].Stat.TotalInboundBytes += flow.Stat.TotalInboundBytes
		hf[key].Stat.TotalOutboundPackets += flow.Stat.TotalOutboundPackets
		hf[key].Stat.TotalOutboundBytes += flow.Stat.TotalOutboundBytes
	}
	return
}
func (hf HostFlows) MarshalJSON() ([]byte, error) {
	list := make([]HostFlow, 0, len(hf))
	for _, f := range hf {
		list = append(list, *f)
	}
	return json.Marshal(list)
}