View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2026 Christian Kohlschütter
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.newsclub.net.unix.vsock;
19  
20  import java.io.File;
21  import java.io.IOException;
22  
23  import org.newsclub.net.unix.AFServerSocket;
24  import org.newsclub.net.unix.AFServerSocketConnector;
25  import org.newsclub.net.unix.AFSocketAddress;
26  import org.newsclub.net.unix.AFUNIXSocketAddress;
27  import org.newsclub.net.unix.AFVSOCKSocketAddress;
28  import org.newsclub.net.unix.AddressUnavailableSocketException;
29  
30  import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
31  
32  /**
33   * Provides access to AF_VSOCK connections that aren't directly accessible but exposed via a
34   * proxying/multiplexing Unix domain socket.
35   *
36   * @author Christian Kohlschütter
37   * @see #openFirecrackerStyleConnector(File, int)
38   * @see #openDirectConnector()
39   */
40  @SuppressFBWarnings("PATH_TRAVERSAL_IN")
41  public final class AFVSOCKProxyServerSocketConnector implements
42      AFServerSocketConnector<AFVSOCKSocketAddress, AFSocketAddress> {
43    private static final AFServerSocketConnector<AFVSOCKSocketAddress, AFSocketAddress> DIRECT_CONNECTOR =
44        new AFServerSocketConnector<AFVSOCKSocketAddress, AFSocketAddress>() {
45  
46          @Override
47          public AFServerSocket<? extends AFSocketAddress> bind(AFVSOCKSocketAddress addr)
48              throws IOException {
49            return addr.newForceBoundServerSocket();
50          }
51        };
52  
53    private final String listenAddressPrefix;
54    private final int allowedCID;
55  
56    private AFVSOCKProxyServerSocketConnector(String listenAddressPrefix, int allowedCID) {
57      this.listenAddressPrefix = listenAddressPrefix;
58      this.allowedCID = allowedCID;
59    }
60  
61    /**
62     * Returns an instance that is configured to support
63     * [Firecracker-style](https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md)
64     * Unix domain sockets.
65     *
66     * @param listenAddressPrefix The prefix of any listening socket. The actual socket will have
67     *          <code>_<em>vsockPort</em></code> appended to it (with {@code vsockPort} being replaced
68     *          by the corresponding port number).
69     * @param allowedCID The permitted CID, or {@link AFVSOCKSocketAddress#VMADDR_CID_ANY} for "any".
70     * @return The instance.
71     */
72    public static AFServerSocketConnector<AFVSOCKSocketAddress, AFSocketAddress> openFirecrackerStyleConnector(
73        File listenAddressPrefix, int allowedCID) {
74      return new AFVSOCKProxyServerSocketConnector(listenAddressPrefix.getAbsolutePath(), allowedCID);
75    }
76  
77    /**
78     * Returns an instance that is configured to connect directly to the given address.
79     *
80     * @return The direct instance.
81     */
82    public static AFServerSocketConnector<AFVSOCKSocketAddress, AFSocketAddress> openDirectConnector() {
83      return DIRECT_CONNECTOR;
84    }
85  
86    @Override
87    public AFServerSocket<?> bind(AFVSOCKSocketAddress addr) throws IOException {
88      int cid = addr.getVSOCKCID();
89      if (cid != allowedCID && cid != AFVSOCKSocketAddress.VMADDR_CID_ANY
90          && allowedCID != AFVSOCKSocketAddress.VMADDR_CID_ANY) {
91        throw new AddressUnavailableSocketException("Factory does not cover CID " + cid);
92      }
93  
94      return AFUNIXSocketAddress.of(new File(listenAddressPrefix + "_" + addr.getVSOCKPort()))
95          .newForceBoundServerSocket();
96    }
97  }