blob: 4bac0f8028c77508dccdb3a43671314f735876a3 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.apf;
import android.annotation.NonNull;
import android.net.MacAddress;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public final class ProcfsParsingUtils {
public static final String TAG = ProcfsParsingUtils.class.getSimpleName();
private static final String IPV6_CONF_PATH = "/proc/sys/net/ipv6/conf/";
private static final String IPV6_ANYCAST_PATH = "/proc/net/anycast6";
private static final String ETHER_MCAST_PATH = "/proc/net/dev_mcast";
private static final String IPV6_MCAST_PATH = "/proc/net/igmp6";
private ProcfsParsingUtils() {
}
/**
* Reads the contents of a text file line by line.
*
* @param filePath The absolute path to the file to read.
* @return A List of Strings where each String represents a line from the file.
* If an error occurs during reading, an empty list is returned, and an error is logged.
*/
private static List<String> readFile(final String filePath) {
final List<String> lines = new ArrayList<>();
try (BufferedReader reader =
Files.newBufferedReader(Paths.get(filePath), StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
} catch (IOException e) {
Log.wtf(TAG, "failed to read " + filePath, e);
}
return lines;
}
/**
* Parses the Neighbor Discovery traffic class from a list of strings.
*
* This function expects a list containing a single string representing the ND traffic class.
* If the list is empty or contains multiple lines, it assumes a default traffic class of 0.
*
* @param lines A list of strings, ideally containing one line with the ND traffic class.
* @return The parsed ND traffic class as an integer, or 0 if the input is invalid.
*/
@VisibleForTesting
public static int parseNdTrafficClass(final List<String> lines) {
if (lines.size() != 1) {
return 0; // default
}
return Integer.parseInt(lines.get(0));
}
/**
* Parses anycast6 addresses associated with a specific interface from a list of strings.
*
* This function searches the input list for a line containing the specified interface name.
* If found, it extracts the IPv6 address from that line and
* converts it into an `Inet6Address` object.
*
* @param lines A list of strings where each line is expected to contain
* interface and address information.
* @param ifname The name of the network interface to search for.
* @return A list of The `Inet6Address` representing the anycast address
* associated with the specified interface,
* If an error occurs during parsing, an empty list is returned.
*/
@VisibleForTesting
public static List<Inet6Address> parseAnycast6Addresses(
@NonNull List<String> lines, @NonNull String ifname) {
final List<Inet6Address> addresses = new ArrayList<>();
try {
for (String line : lines) {
final String[] fields = line.split("\\s+");
if (!fields[1].equals(ifname)) {
continue;
}
final byte[] addr = HexDump.hexStringToByteArray(fields[2]);
addresses.add((Inet6Address) InetAddress.getByAddress(addr));
}
} catch (UnknownHostException e) {
Log.wtf("failed to convert to Inet6Address.", e);
addresses.clear();
}
return addresses;
}
/**
* Parses Ethernet multicast MAC addresses with a specific interface from a list of strings.
*
* @param lines A list of strings, each containing interface and MAC address information.
* @param ifname The name of the network interface for which to extract multicast addresses.
* @return A list of MacAddress objects representing the parsed multicast addresses.
*/
@VisibleForTesting
public static List<MacAddress> parseEtherMulticastAddresses(
@NonNull List<String> lines, @NonNull String ifname) {
final List<MacAddress> addresses = new ArrayList<>();
for (String line: lines) {
final String[] fields = line.split("\\s+");
if (!fields[1].equals(ifname)) {
continue;
}
final byte[] addr = HexDump.hexStringToByteArray(fields[4]);
addresses.add(MacAddress.fromBytes(addr));
}
return addresses;
}
/**
* Parses IPv6 multicast addresses associated with a specific interface from a list of strings.
*
* @param lines A list of strings, each containing interface and IPv6 address information.
* @param ifname The name of the network interface for which to extract multicast addresses.
* @return A list of Inet6Address objects representing the parsed IPv6 multicast addresses.
* If an error occurs during parsing, an empty list is returned.
*/
@VisibleForTesting
public static List<Inet6Address> parseIPv6MulticastAddresses(
@NonNull List<String> lines, @NonNull String ifname) {
final List<Inet6Address> addresses = new ArrayList<>();
try {
for (String line: lines) {
final String[] fields = line.split("\\s+");
if (!fields[1].equals(ifname)) {
continue;
}
final byte[] addr = HexDump.hexStringToByteArray(fields[2]);
addresses.add((Inet6Address) InetAddress.getByAddress(addr));
}
} catch (UnknownHostException e) {
Log.wtf(TAG, "failed to convert to Inet6Address.", e);
addresses.clear();
}
return addresses;
}
/**
* Returns the traffic class for the specified interface.
* The function loads the existing traffic class from the file
* `/proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass`. If the file does not exist, the
* function returns 0.
*
* @param ifname The name of the interface.
* @return The traffic class for the interface.
*/
public static int getNdTrafficClass(final String ifname) {
final String ndTcPath = IPV6_CONF_PATH + ifname + "/ndisc_tclass";
final List<String> lines = readFile(ndTcPath);
return parseNdTrafficClass(lines);
}
/**
* The function loads the existing IPv6 anycast address from the file `/proc/net/anycast6`.
* If the file does not exist or the interface is not found, the function
* returns an empty list.
*
* @param ifname The name of the interface.
* @return A list of the IPv6 anycast addresses for the interface.
*/
public static List<Inet6Address> getAnycast6Addresses(@NonNull String ifname) {
final List<String> lines = readFile(IPV6_ANYCAST_PATH);
return parseAnycast6Addresses(lines, ifname);
}
/**
* The function loads the existing Ethernet multicast addresses from
* the file `/proc/net/dev_mcast`.
* If the file does not exist or the interface is not found, the function returns empty list.
*
* @param ifname The name of the interface.
* @return A list of MacAddress objects representing the multicast addresses
* found for the interface.
* If the file cannot be read or there are no addresses, an empty list is returned.
*/
public static List<MacAddress> getEtherMulticastAddresses(@NonNull String ifname) {
final List<String> lines = readFile(ETHER_MCAST_PATH);
return parseEtherMulticastAddresses(lines, ifname);
}
/**
* The function loads the existing IPv6 multicast addresses from the file `/proc/net/igmp6`.
* If the file does not exist or the interface is not found, the function returns empty list.
*
* @param ifname The name of the network interface to query.
* @return A list of Inet6Address objects representing the IPv6 multicast addresses
* found for the interface.
* If the file cannot be read or there are no addresses, an empty list is returned.
*/
public static List<Inet6Address> getIpv6MulticastAddresses(@NonNull String ifname) {
final List<String> lines = readFile(IPV6_MCAST_PATH);
return parseIPv6MulticastAddresses(lines, ifname);
}
}