istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/istio-iptables/pkg/log/nflog.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package log
    16  
    17  import (
    18  	"context"
    19  	golog "log"
    20  	"net"
    21  	"os"
    22  
    23  	"github.com/florianl/go-nflog/v2"
    24  	"golang.org/x/net/ipv4"
    25  
    26  	"istio.io/istio/pkg/env"
    27  	"istio.io/istio/pkg/log"
    28  )
    29  
    30  var TraceLoggingEnabled = env.Register(
    31  	"IPTABLES_TRACE_LOGGING",
    32  	false,
    33  	"When enable, all iptables actions will be logged. "+
    34  		"This requires NET_ADMIN privilege and has noisy logs; as a result, this is intended for debugging only").Get()
    35  
    36  var iptablesTrace = log.RegisterScope("iptables", "trace logs for iptables")
    37  
    38  // ReadNFLOGSocket reads from the nflog socket, sending output to logs.
    39  // This is intended for debugging only.
    40  func ReadNFLOGSocket(ctx context.Context) {
    41  	if !TraceLoggingEnabled {
    42  		return
    43  	}
    44  	iptablesTrace.Infof("starting nftable log")
    45  	// We expect to read logs from rules like:
    46  	// `-j NFLOG --nflog-group 1337`
    47  	config := nflog.Config{
    48  		Group:    1337,
    49  		Copymode: nflog.CopyPacket,
    50  		Logger:   golog.New(os.Stdout, "nflog log", 0),
    51  	}
    52  
    53  	nf, err := nflog.Open(&config)
    54  	if err != nil {
    55  		log.Errorf("could not open nflog socket: %v", err)
    56  		return
    57  	}
    58  	defer nf.Close()
    59  
    60  	fn := func(attrs nflog.Attribute) int {
    61  		src, dst := "", ""
    62  		if attrs.Payload != nil {
    63  			v4, err := ipv4.ParseHeader(*attrs.Payload)
    64  			if err == nil {
    65  				src = v4.Src.String()
    66  				dst = v4.Dst.String()
    67  			}
    68  		}
    69  		prefix := ""
    70  		if attrs.Prefix != nil {
    71  			prefix = *attrs.Prefix
    72  		}
    73  		comment := IDToCommand[prefix].Comment
    74  		uid, gid := uint32(0), uint32(0)
    75  		if attrs.UID != nil {
    76  			uid = *attrs.UID
    77  		}
    78  		if attrs.GID != nil {
    79  			gid = *attrs.GID
    80  		}
    81  		inDev, outDev := "", ""
    82  		if attrs.InDev != nil {
    83  			ii, err := net.InterfaceByIndex(int(*attrs.InDev))
    84  			if err == nil {
    85  				inDev = ii.Name
    86  			}
    87  		}
    88  		if attrs.OutDev != nil {
    89  			ii, err := net.InterfaceByIndex(int(*attrs.OutDev))
    90  			if err == nil {
    91  				outDev = ii.Name
    92  			}
    93  		}
    94  		iptablesTrace.WithLabels(
    95  			"command", prefix,
    96  			"uid", uid,
    97  			"gid", gid,
    98  			"inDev", inDev,
    99  			"outDev", outDev,
   100  			"src", src,
   101  			"dst", dst,
   102  		).Infof(comment)
   103  		return 0
   104  	}
   105  
   106  	// Register our callback for the nflog
   107  	err = nf.RegisterWithErrorFunc(ctx, fn, func(e error) int {
   108  		iptablesTrace.Warnf("log failed: %v", e)
   109  		return 0
   110  	})
   111  	if err != nil {
   112  		log.Errorf("failed to register nflog callback: %v", err)
   113  		return
   114  	}
   115  
   116  	// Block util the context expires
   117  	<-ctx.Done()
   118  }